pp_expand.c (45435B)
1 /* pp_expand.c — macro table, #define/#undef, substitution, paste, stringize, 2 * argument prescan, func/object macro expansion. Macro-expansion availability 3 * uses the cpplib disabled-frame model (Macro.disabled_depth + the per-token 4 * TF_NO_EXPAND bit), not a per-token Prosser hideset; see pp.c / the identifier 5 * test in pp_pull_into below. */ 6 7 #include "pp/pp_priv.h" 8 9 static int body_tokens_equal(Pp* pp, const Tok* a, u32 na, const Tok* b, 10 u32 nb); 11 static int macros_equal(Pp* pp, const Macro* a, const Macro* b); 12 13 /* ============================================================ 14 * #define / #undef 15 * ============================================================ */ 16 /* mt_get / mt_put / mt_del are inlined Sym-indexed loads in pp_priv.h 17 * (MacroTab, a SYMTAB mapping Sym -> Macro*). */ 18 19 void do_define(Pp* pp, const Tok* line, u32 n) { 20 Macro* m; 21 u32 i = 0; 22 Sym name; 23 LocRef def_loc; 24 Macro* existing; 25 26 if (i >= n || line[i].kind != TOK_IDENT) { 27 compiler_panic(pp->c, 28 n ? pp_materialize_loc(pp, line[0].loc) : (SrcLoc){0, 0, 0}, 29 "#define: expected macro name"); 30 } 31 name = tok_ident(&line[i]); 32 def_loc = line[i].loc; 33 ++i; 34 35 m = arena_znew(pp->arena, Macro); 36 m->name = name; 37 m->def_loc = def_loc; 38 39 /* Function-like vs object-like: '(' immediately after the name with no 40 * intervening whitespace. */ 41 if (i < n && line[i].kind == TOK_PUNCT && tok_punct(&line[i]) == '(' && 42 (line[i].flags & TF_HAS_SPACE) == 0) { 43 Sym* params = NULL; 44 u32 pcap = 0, pn = 0; 45 ++i; 46 m->is_func = 1; 47 if (i < n && line[i].kind == TOK_PUNCT && tok_punct(&line[i]) == ')') { 48 ++i; 49 } else { 50 for (;;) { 51 if (i >= n) { 52 compiler_panic(pp->c, pp_materialize_loc(pp, def_loc), 53 "#define: unterminated parameter list"); 54 } 55 if (line[i].kind == TOK_PUNCT && tok_punct(&line[i]) == P_ELLIPSIS) { 56 /* Append a synthetic __VA_ARGS__ param so body-rewrite 57 * matches the standard identifier directly. */ 58 if (pn == pcap) { 59 u32 nc = pcap ? pcap * 2 : 4; 60 Sym* nb = arena_array(pp->arena, Sym, nc); 61 if (pcap) memcpy(nb, params, sizeof(Sym) * pcap); 62 params = nb; 63 pcap = nc; 64 } 65 params[pn++] = pp->sym_va_args; 66 m->is_variadic = 1; 67 ++i; 68 } else if (line[i].kind == TOK_IDENT) { 69 if (pn == pcap) { 70 u32 nc = pcap ? pcap * 2 : 4; 71 Sym* nb = arena_array(pp->arena, Sym, nc); 72 if (pcap) memcpy(nb, params, sizeof(Sym) * pcap); 73 params = nb; 74 pcap = nc; 75 } 76 params[pn++] = tok_ident(&line[i]); 77 ++i; 78 /* GNU named variadic: `args...` — the named parameter itself collects 79 * the trailing arguments (the body refers to it by name rather than 80 * __VA_ARGS__). The variadic arg-collection below is positional on 81 * the last param, so we just mark the macro variadic and eat the 82 * ellipsis; the "'...' must be last" check still fires if a comma 83 * follows. Linux UAPI headers use this (e.g. <linux/stddef.h>'s 84 * __struct_group). */ 85 if (i < n && line[i].kind == TOK_PUNCT && 86 tok_punct(&line[i]) == P_ELLIPSIS) { 87 m->is_variadic = 1; 88 ++i; 89 } 90 } else { 91 compiler_panic(pp->c, pp_materialize_loc(pp, line[i].loc), 92 "#define: bad parameter list"); 93 } 94 if (i >= n) { 95 compiler_panic(pp->c, pp_materialize_loc(pp, def_loc), 96 "#define: unterminated parameter list"); 97 } 98 if (line[i].kind == TOK_PUNCT && tok_punct(&line[i]) == ')') { 99 ++i; 100 break; 101 } 102 if (m->is_variadic) { 103 compiler_panic(pp->c, pp_materialize_loc(pp, line[i].loc), 104 "#define: '...' must be last parameter"); 105 } 106 if (line[i].kind == TOK_PUNCT && tok_punct(&line[i]) == ',') { 107 ++i; 108 continue; 109 } 110 compiler_panic(pp->c, pp_materialize_loc(pp, line[i].loc), 111 "#define: expected ',' or ')'"); 112 } 113 } 114 m->params = params; 115 m->n_params = pn; 116 } 117 118 /* Refuse define/undef of a few names the spec reserves: `defined` 119 * and a small set of mandatory predefined macros. */ 120 if (name == pp->sym_defined || name == pp->sym_line__ || 121 name == pp->sym_file__ || name == pp->sym_date__ || 122 name == pp->sym_time__) { 123 compiler_panic(pp->c, pp_materialize_loc(pp, def_loc), 124 "#define of a reserved / predefined name is not allowed"); 125 } 126 /* Static predefineds are already in the macro table; redefining 127 * with a different body is caught by the existing macros_equal 128 * check below, but #define of __STDC__ et al. with the SAME body 129 * should also be rejected. */ 130 if (name == pp->sym_stdc__ || name == pp->sym_stdc_hosted__ || 131 name == pp->sym_stdc_version__) { 132 /* Allow re-registration of the predefined value at pp_new time 133 * but reject user-level redefinition. We detect "user-level" 134 * by checking whether it's already in the table — at pp_new the 135 * first call goes through cleanly. */ 136 if (mt_get(pp, name)) { 137 compiler_panic(pp->c, pp_materialize_loc(pp, def_loc), 138 "#define of a mandatory predefined macro is not allowed"); 139 } 140 } 141 142 /* Body: rewrite parameter occurrences to TOK_PP_PARAM. */ 143 { 144 u32 body_n = n - i; 145 u32 j; 146 m->body = body_n ? arena_array(pp->arena, Tok, body_n) : NULL; 147 m->body_len = body_n; 148 for (j = 0; j < body_n; ++j) { 149 Tok t = line[i + j]; 150 if (t.kind == TOK_PP_PASTE) m->has_paste = 1; 151 if (m->is_func && t.kind == TOK_IDENT) { 152 u32 p; 153 for (p = 0; p < m->n_params; ++p) { 154 if (m->params[p] == tok_ident(&t)) { 155 /* Rewrite in place to TOK_PP_PARAM; leave `text` as the original 156 * TEXT_SRC span (the param-name spelling, needed by the 157 * redefinition compare). The parameter index lives in `aux`. */ 158 t.kind = TOK_PP_PARAM; 159 t.aux = p; 160 break; 161 } 162 } 163 } 164 /* §6.10.3 ¶5: __VA_ARGS__ outside a variadic macro is 165 * undefined behavior; we diagnose. */ 166 if (!m->is_variadic && t.kind == TOK_IDENT && 167 tok_ident(&t) == pp->sym_va_args) { 168 compiler_panic(pp->c, pp_materialize_loc(pp, t.loc), 169 "__VA_ARGS__ may only appear in a variadic macro body"); 170 } 171 m->body[j] = t; 172 } 173 /* Drop the leading-space bit on the first body token: it reflects 174 * the whitespace between the macro name (or close-paren) and the 175 * body, which is irrelevant to expansion output. */ 176 if (m->body_len) m->body[0].flags &= (u16)~TF_HAS_SPACE; 177 } 178 179 existing = mt_get(pp, name); 180 if (existing) { 181 if (!macros_equal(pp, existing, m)) { 182 compiler_panic(pp->c, pp_materialize_loc(pp, def_loc), 183 "macro redefined with different replacement"); 184 } 185 return; 186 } 187 mt_put(pp, name, m); 188 } 189 190 void do_undef(Pp* pp, const Tok* line, u32 n) { 191 Sym name; 192 if (!n || line[0].kind != TOK_IDENT) { 193 compiler_panic(pp->c, 194 n ? pp_materialize_loc(pp, line[0].loc) : (SrcLoc){0, 0, 0}, 195 "#undef: expected identifier"); 196 } 197 name = tok_ident(&line[0]); 198 if (name == pp->sym_defined || name == pp->sym_line__ || 199 name == pp->sym_file__ || name == pp->sym_date__ || 200 name == pp->sym_time__ || name == pp->sym_stdc__ || 201 name == pp->sym_stdc_hosted__ || name == pp->sym_stdc_version__) { 202 compiler_panic(pp->c, pp_materialize_loc(pp, line[0].loc), 203 "#undef of a mandatory predefined name is not allowed"); 204 } 205 mt_del(pp, name); 206 } 207 208 /* ============================================================ 209 * Body comparison helpers 210 * ============================================================ */ 211 212 static int body_tokens_equal(Pp* pp, const Tok* a, u32 na, const Tok* b, 213 u32 nb) { 214 u32 i; 215 if (na != nb) return 0; 216 for (i = 0; i < na; ++i) { 217 KitSlice as, bs; 218 if (a[i].kind != b[i].kind) return 0; 219 /* Two body tokens are equal iff their exact spellings match (§6.10.3 ¶1). 220 * Compare the resolved bytes directly: a TOK_PP_PARAM keeps its original 221 * param-name span, so identical parameters compare equal byte-for-byte, 222 * and interned/source spellings compare the same way the old Sym-equality 223 * did (identical interned spelling == identical bytes). */ 224 as = pp_text_slice(pp, &a[i]); 225 bs = pp_text_slice(pp, &b[i]); 226 if (as.len != bs.len || (as.len && memcmp(as.s, bs.s, as.len) != 0)) { 227 return 0; 228 } 229 /* Whitespace separation must match (§6.10.3 ¶2). The first body 230 * token's leading-space bit is meaningless (it's whatever was 231 * between macro name and body); skip i==0 for that bit. */ 232 if (i > 0) { 233 if ((a[i].flags & TF_HAS_SPACE) != (b[i].flags & TF_HAS_SPACE)) { 234 return 0; 235 } 236 } 237 } 238 return 1; 239 } 240 241 static int macros_equal(Pp* pp, const Macro* a, const Macro* b) { 242 if (a->is_func != b->is_func) return 0; 243 if (a->is_variadic != b->is_variadic) return 0; 244 if (a->n_params != b->n_params) return 0; 245 { 246 u32 i; 247 for (i = 0; i < a->n_params; ++i) { 248 if (a->params[i] != b->params[i]) return 0; 249 } 250 } 251 return body_tokens_equal(pp, a->body, a->body_len, b->body, b->body_len); 252 } 253 254 /* ============================================================ 255 * Object-macro expansion 256 * ============================================================ */ 257 258 static void subst_phase2(Pp* pp, const Tok* in, u32 nin, const Tok* invoke, 259 TokVec* out); 260 261 /* Build a buffer of the macro's body (with hidesets) and push it. The 262 * first expanded token inherits the invocation token's TF_AT_BOL / 263 * TF_HAS_SPACE so output formatting matches the invocation site. */ 264 static void expand_object_macro(Pp* pp, Macro* m, const Tok* invoke) { 265 TokVec body = {0}; 266 Tok* tmp; 267 u32 i; 268 269 if (m->body_len == 0) { 270 return; /* placemarker: nothing to push */ 271 } 272 /* No `##`: an object body has no params and no placemarkers, so the paste 273 * phase is a pure identity copy. Skip both copies — replay the immutable 274 * definition-time m->body by pointer, applying the per-invocation loc and 275 * first-token flag transfer at read time (push_buf_replay). Byte-identical 276 * to the slow path (same tokens, same loc, same first-token flags), with 277 * zero per-invocation token copies or body allocs. The frame disables `m` 278 * for the whole rescan of its replacement (cpplib model). */ 279 if (!m->has_paste) { 280 u16 ff = (u16)((m->body[0].flags & ~(TF_AT_BOL | TF_HAS_SPACE)) | 281 (invoke->flags & (TF_AT_BOL | TF_HAS_SPACE))); 282 push_buf_replay(pp, m->body, m->body_len, m, invoke->loc, ff); 283 return; 284 } 285 286 /* Run the body through the paste phase: object-like macros may use 287 * `##`. There are no parameters, so phase 1 reduces to a copy. */ 288 tmp = arena_array(pp->xarena, Tok, m->body_len); 289 for (i = 0; i < m->body_len; ++i) tmp[i] = m->body[i]; 290 subst_phase2(pp, tmp, m->body_len, invoke, &body); 291 292 if (body.n == 0) return; 293 294 /* Transfer invocation flags onto the first emitted token. */ 295 body.data[0].flags = 296 (u16)((body.data[0].flags & ~(TF_AT_BOL | TF_HAS_SPACE)) | 297 (invoke->flags & (TF_AT_BOL | TF_HAS_SPACE))); 298 for (i = 0; i < body.n; ++i) body.data[i].loc = invoke->loc; 299 300 push_buf_uniform(pp, body.data, body.n, m); 301 } 302 303 /* ============================================================ 304 * Function-like macro expansion 305 * ============================================================ */ 306 307 /* Peek for an open paren after the just-consumed identifier (which named 308 * a function-like macro). Newlines are whitespace inside an invocation. 309 * Returns 1 with `*ws_has_space_out` indicating whether any whitespace 310 * (newlines or HAS_SPACE) sat between the ident and the `(`. Returns 0 if 311 * no `(` follows; pushed-back tokens (NLs + the non-`(` token, if any) 312 * are restored as a buffer source so subsequent reads still see them. */ 313 int peek_for_invoke_paren(Pp* pp, int* ws_has_space_out) { 314 TokVec saved = {0}; 315 int saw_ws = 0; 316 Tok t; 317 318 for (;;) { 319 t = src_next_raw(pp, NULL); 320 if (t.kind == TOK_NEWLINE) { 321 saw_ws = 1; 322 tv_push(pp, &saved, t); 323 continue; 324 } 325 if (t.kind == TOK_EOF) { 326 /* No '(' — push back saved tokens, leave EOF for next read. */ 327 if (saved.n) push_buf(pp, saved.data, saved.n); 328 *ws_has_space_out = saw_ws; 329 return 0; 330 } 331 if (t.flags & TF_HAS_SPACE) saw_ws = 1; 332 if (t.kind == TOK_PUNCT && tok_punct(&t) == '(') { 333 /* Consumed. The newlines we walked past are whitespace and 334 * dropped (per spec); they don't go back on the stack. */ 335 *ws_has_space_out = saw_ws; 336 return 1; 337 } 338 /* Save this non-`(` token too and push back. */ 339 tv_push(pp, &saved, t); 340 push_buf(pp, saved.data, saved.n); 341 *ws_has_space_out = saw_ws; 342 return 0; 343 } 344 } 345 346 /* Run macro expansion on a fixed token sequence to completion, yielding the 347 * fully-expanded token sequence. Used to pre-expand each function-macro 348 * argument before substitution (§6.10.3.1 ¶1). */ 349 void expand_arg_to_eof(Pp* pp, Tok* in, u32 nin, TokVec* out) { 350 TokSrc src; 351 Tok t; 352 353 memset(&src, 0, sizeof(src)); 354 src.kind = SRC_BUF; 355 src.scope_top = 1; 356 src.toks = in; 357 src.n = nin; 358 src_push(pp, src); 359 360 for (;;) { 361 pp_next_raw(pp, &t); /* drives macro expansion within this scope */ 362 if (t.kind == TOK_EOF) break; 363 if (t.kind == TOK_NEWLINE) { 364 /* Newlines inside an arg act as whitespace; convert to 365 * "next-token has TF_HAS_SPACE". Drop the NL token itself. */ 366 continue; 367 } 368 tv_push(pp, out, t); 369 } 370 /* Pop our scope source directly (not src_pop). This is the one place the 371 * disabled-frame decrement in src_pop is intentionally bypassed: the 372 * arg-prescan scope frame is pushed above with src.disabled_owner == NULL (it 373 * disables no macro — arguments are pre-expanded with the invoking macro NOT 374 * yet disabled), so there is no disabled_depth to decrement here. */ 375 --pp->nsources; 376 } 377 378 /* Argument list for a function-like invocation. Stored as parallel 379 * (start, end) ranges into a flat unexpanded token vector and a flat 380 * expanded token vector. */ 381 typedef struct ArgList { 382 /* Unexpanded arg tokens (raw as collected from invocation). */ 383 Tok* raw; 384 u32 raw_n; 385 u32* raw_start; /* size n_args + 1 (sentinel = raw_n) */ 386 /* Pre-expanded tokens. */ 387 Tok* exp; 388 u32 exp_n; 389 u32* exp_start; /* size n_args + 1 (sentinel = exp_n) */ 390 u32 n_args; 391 } ArgList; 392 393 /* Collect arguments. Caller has just consumed the opening `(`. Returns the 394 * close-paren's token (used as the invocation's last source location). */ 395 static Tok read_invocation_args(Pp* pp, const Macro* m, LocRef invoke_loc, 396 ArgList* out) { 397 TokVec raw = {0}; 398 u32* starts; 399 u32 starts_cap = 0; 400 u32 n_args = 0; 401 u32 cur_start = 0; 402 int depth = 0; 403 Tok t; 404 int first_token_of_arg = 1; 405 Tok close_tok; 406 407 memset(out, 0, sizeof(*out)); 408 starts = arena_array(pp->xarena, u32, 8); 409 starts_cap = 8; 410 starts[0] = 0; 411 412 for (;;) { 413 t = src_next_raw(pp, NULL); 414 if (t.kind == TOK_EOF) { 415 compiler_panic(pp->c, pp_materialize_loc(pp, invoke_loc), 416 "unterminated function-like macro invocation"); 417 } 418 if (t.kind == TOK_NEWLINE) { 419 /* A newline inside an invocation is just whitespace; drop it. 420 * The lexer already records the surrounding-whitespace bits on 421 * the next token, so nothing needs to be carried across here. */ 422 continue; 423 } 424 425 if (t.kind == TOK_PUNCT) { 426 u32 p = tok_punct(&t); 427 if (p == '(') { 428 ++depth; 429 } else if (p == ')') { 430 if (depth == 0) { 431 /* End of invocation. Close the current argument. The 432 * empty-args case (no commas seen, no tokens 433 * collected) emits a slot only when the macro expects 434 * at least one argument; arity-0 macros take none. */ 435 close_tok = t; 436 { 437 int empty_call = 438 (n_args == 0 && raw.n == cur_start && first_token_of_arg); 439 int want_slot = !empty_call || (m->n_params > 0) || m->is_variadic; 440 if (want_slot) { 441 if (n_args + 1 >= starts_cap) { 442 u32 nc = starts_cap * 2; 443 u32* nb = arena_array(pp->xarena, u32, nc); 444 memcpy(nb, starts, sizeof(u32) * starts_cap); 445 starts = nb; 446 starts_cap = nc; 447 } 448 ++n_args; 449 starts[n_args] = raw.n; 450 } 451 } 452 goto done; 453 } 454 --depth; 455 } else if (p == ',' && depth == 0) { 456 /* Variadic: once we've filled all named params, the rest 457 * (commas included) collect into __VA_ARGS__. */ 458 if (m->is_variadic && n_args + 1 >= m->n_params) { 459 /* This comma is part of __VA_ARGS__. Push it. */ 460 tv_push(pp, &raw, t); 461 first_token_of_arg = 0; 462 continue; 463 } 464 /* Close current arg, start next. */ 465 if (n_args + 1 >= starts_cap) { 466 u32 nc = starts_cap * 2; 467 u32* nb = arena_array(pp->xarena, u32, nc); 468 memcpy(nb, starts, sizeof(u32) * starts_cap); 469 starts = nb; 470 starts_cap = nc; 471 } 472 ++n_args; 473 starts[n_args] = raw.n; 474 cur_start = raw.n; 475 first_token_of_arg = 1; 476 continue; 477 } 478 } 479 tv_push(pp, &raw, t); 480 first_token_of_arg = 0; 481 } 482 done: 483 /* Validate arity. */ 484 { 485 u32 expected = m->n_params; 486 if (m->is_variadic) { 487 if (n_args < (expected ? expected - 1 : 0)) { 488 /* Allow exactly expected-1 (empty __VA_ARGS__) by 489 * synthesizing an empty trailing arg. */ 490 if (n_args + 1 == (expected ? expected - 1 : 0)) { 491 /* off by one — fall through to error */ 492 } 493 compiler_panic(pp->c, pp_materialize_loc(pp, invoke_loc), 494 "too few arguments to variadic macro invocation"); 495 } 496 /* Synthesize an empty __VA_ARGS__ if caller passed exactly 497 * the named-parameter count. */ 498 if (n_args + 1 == expected) { 499 if (n_args + 1 >= starts_cap) { 500 u32 nc = starts_cap * 2; 501 u32* nb = arena_array(pp->xarena, u32, nc); 502 memcpy(nb, starts, sizeof(u32) * starts_cap); 503 starts = nb; 504 starts_cap = nc; 505 } 506 ++n_args; 507 starts[n_args] = raw.n; 508 } 509 } else { 510 if (n_args != expected) { 511 /* Spec: arity-0 macro `M()` invoked as `M()` is allowed and 512 * has 0 args. Above logic produces 0 in that case. */ 513 compiler_panic(pp->c, pp_materialize_loc(pp, invoke_loc), 514 "wrong number of arguments to function-like macro"); 515 } 516 } 517 } 518 out->raw = raw.data; 519 out->raw_n = raw.n; 520 out->raw_start = starts; 521 out->n_args = n_args; 522 return close_tok; 523 } 524 525 /* Build pre-expanded args. */ 526 static void preexpand_args(Pp* pp, ArgList* a) { 527 TokVec exp = {0}; 528 u32* exp_start; 529 u32 i; 530 exp_start = arena_array(pp->xarena, u32, a->n_args + 1); 531 exp_start[0] = 0; 532 for (i = 0; i < a->n_args; ++i) { 533 u32 lo = a->raw_start[i]; 534 u32 hi = a->raw_start[i + 1]; 535 if (hi > lo) { 536 /* Copy the slice into a fresh buffer so expand_arg_to_eof can 537 * own it without aliasing. */ 538 Tok* slice = arena_array(pp->xarena, Tok, hi - lo); 539 memcpy(slice, &a->raw[lo], sizeof(Tok) * (hi - lo)); 540 expand_arg_to_eof(pp, slice, hi - lo, &exp); 541 } 542 exp_start[i + 1] = exp.n; 543 } 544 a->exp = exp.data; 545 a->exp_n = exp.n; 546 a->exp_start = exp_start; 547 } 548 549 /* Build a stringized TOK_STR from the unexpanded argument tokens 550 * `arg[lo..hi)`. The first token's leading-space flag is ignored (leading 551 * whitespace stripped). Inside string/char-literal spellings, '"' and '\' 552 * are escaped. */ 553 static Tok make_stringize(Pp* pp, const Tok* arg, u32 lo, u32 hi, LocRef loc) { 554 CharBuf b = {0}; 555 u32 i; 556 Tok t; 557 558 cb_putc(pp, &b, '"'); 559 for (i = lo; i < hi; ++i) { 560 const Tok* at = &arg[i]; 561 KitSlice sl = pp_text_slice(pp, at); 562 const char* s = sl.s; 563 size_t slen = sl.len; 564 if (i > lo && (at->flags & TF_HAS_SPACE)) cb_putc(pp, &b, ' '); 565 if (s && slen) { 566 int esc = (at->kind == TOK_STR || at->kind == TOK_CHR); 567 size_t k; 568 for (k = 0; k < slen; ++k) { 569 char c = s[k]; 570 if (esc && (c == '\\' || c == '"')) cb_putc(pp, &b, '\\'); 571 cb_putc(pp, &b, c); 572 } 573 } 574 } 575 cb_putc(pp, &b, '"'); 576 577 memset(&t, 0, sizeof(t)); 578 t.kind = TOK_STR; 579 t.aux = 0; 580 t.loc = loc; 581 t.text = text_intern_ref(pp, (KitSlice){.s = b.data, .len = b.len}); 582 return t; 583 } 584 585 /* Concatenate two token spellings and re-lex into a single token. Empty 586 * (placemarker) sides collapse to the other side per §6.10.3.3 ¶2. */ 587 static Tok paste_tokens(Pp* pp, Tok lhs, Tok rhs, LocRef loc) { 588 char buf[1024]; 589 size_t alen = 0, blen = 0; 590 const char* a; 591 const char* b; 592 Lexer* lex; 593 Tok t1, t2; 594 595 if (lhs.kind == TOK_PP_PLACEMARKER) return rhs; 596 if (rhs.kind == TOK_PP_PLACEMARKER) return lhs; 597 598 { 599 KitSlice s = pp_text_slice(pp, &lhs); 600 if (s.len) { 601 a = s.s; 602 alen = s.len; 603 } else { 604 a = ""; 605 } 606 } 607 { 608 KitSlice s = pp_text_slice(pp, &rhs); 609 if (s.len) { 610 b = s.s; 611 blen = s.len; 612 } else { 613 b = ""; 614 } 615 } 616 if (alen + blen + 2 > sizeof(buf)) { 617 compiler_panic(pp->c, pp_materialize_loc(pp, loc), 618 "token paste: spelling too long"); 619 } 620 if (alen) memcpy(buf, a, alen); 621 if (blen) memcpy(buf + alen, b, blen); 622 buf[alen + blen] = '\n'; 623 buf[alen + blen + 1] = 0; 624 /* INVARIANT for the re-lex's no-splice fast path: this buffer is two 625 * already-folded token spellings (a, b) followed by exactly one '\n'. A 626 * token spelling never ends in a lone '\\' immediately before that '\n' (a 627 * backslash-newline would have been folded out at the original lex), so the 628 * buffer is free of `\<newline>` line-splices and the paste lexer is opened 629 * with SRC_NO_SPLICES to skip the splice scan. */ 630 631 /* Intern the "<paste>" name once and reuse a single lexer across pastes: the 632 * lexer is re-pointed (not reallocated) per paste, but still draws a fresh 633 * sequential file_id so the file_id order matches a per-paste open exactly. 634 * t1.loc is overwritten below, so the paste file_id is dead for output. */ 635 if (!pp->paste_name_sym) { 636 pp->paste_name_sym = kit_sym_intern(pp->c, kit_slice_cstr("<paste>")); 637 } 638 { 639 SourceSpec spec; 640 memset(&spec, 0, sizeof spec); 641 spec.name_sym = pp->paste_name_sym; 642 spec.bytes = buf; 643 spec.len = (u32)(alen + blen + 1); 644 spec.flags = SRC_NO_SPLICES; 645 if (pp->paste_lex) { 646 lex_reset(pp->paste_lex, &spec); 647 } else { 648 pp->paste_lex = lex_open(pp->c, &spec); 649 } 650 } 651 lex = pp->paste_lex; 652 lex_next(lex, &t1); 653 lex_next(lex, &t2); 654 if (t1.kind == TOK_EOF) { 655 /* Both empty (shouldn't reach here since we handled placemarkers). */ 656 return lhs; 657 } 658 if (t2.kind != TOK_NEWLINE && t2.kind != TOK_EOF) { 659 compiler_panic(pp->c, pp_materialize_loc(pp, loc), 660 "token pasting yields multiple tokens, invalid"); 661 } 662 663 /* The paste buffer is transient (a stack array re-pointed per paste), so a 664 * source-derived spelling must be interned before the buffer is reused. */ 665 if (t1.text.kind == TEXT_SRC) { 666 t1.text = text_intern_ref(pp, lex_text_slice(lex, t1.text)); 667 } 668 669 /* Inherit positional flags from LHS (it sat in the same slot). */ 670 t1.flags = (u16)((t1.flags & ~(TF_AT_BOL | TF_HAS_SPACE)) | 671 (lhs.flags & (TF_AT_BOL | TF_HAS_SPACE))); 672 t1.loc = loc; 673 return t1; 674 } 675 676 /* Phase 1 (param substitution). For each parameter occurrence in the 677 * body: if adjacent to ## or # (handled separately), substitute the raw 678 * argument tokens; otherwise substitute the pre-expanded form. Empty raw 679 * args become a TOK_PP_PLACEMARKER which phase 2 collapses. 680 * 681 * `no_paste` is the no-`##` fast path (set only when m->has_paste == 0, so the 682 * body provably has no TOK_PP_PASTE and adj_paste is always false): instead of 683 * emitting a placemarker for an empty arg, it accumulates the empty arg's 684 * BOL/SPACE flags into a `carry` and ORs them onto the NEXT emitted token — 685 * exactly what phase 2's placemarker-strip would do. The output is then already 686 * placemarker-free and identity under phase 2, so substitute_body can skip the 687 * second pass entirely. A trailing empty arg's carry has no surviving token to 688 * land on and is dropped, matching phase 2 (which leaves a trailing carry 689 * unused). */ 690 static void subst_phase1_impl(Pp* pp, const Macro* m, ArgList* a, 691 const Tok* invoke, TokVec* out, int no_paste) { 692 u32 j; 693 u16 carry = 0; /* no_paste only: pending BOL/SPACE from stripped empty args */ 694 /* Reserve a cheap upper bound up front so the per-expansion output vector 695 * doesn't re-grow from cap 0 (0->8->16->32 doubling memcpys); arg expansion 696 * may exceed it, which just falls back to the doubling. */ 697 tv_grow(pp, out, m->body_len + 4u); 698 for (j = 0; j < m->body_len; ++j) { 699 const Tok* bt = &m->body[j]; 700 if (bt->kind == TOK_PP_HASH) { 701 /* §6.10.3.2: # must be followed by a parameter. EXCEPT under 702 * assembler-with-cpp (__ASSEMBLER__ defined), where a `#` not before a 703 * parameter is the assembler's immediate prefix (e.g. `cmp r0, #0` inside 704 * a function-like macro) — pass it through literally, matching gcc/clang. 705 * It is emitted mid-line, so it never starts a directive downstream. */ 706 if (j + 1 >= m->body_len || m->body[j + 1].kind != TOK_PP_PARAM) { 707 if (mt_get(pp, pp->sym_assembler)) { 708 Tok lit = *bt; 709 if (carry) { 710 lit.flags |= carry; 711 carry = 0; 712 } 713 tv_push(pp, out, lit); 714 continue; 715 } 716 compiler_panic(pp->c, pp_materialize_loc(pp, bt->loc), 717 "'#' is not followed by a macro parameter"); 718 } 719 { 720 u32 p = m->body[j + 1].aux; 721 u32 lo = a->raw_start[p]; 722 u32 hi = a->raw_start[p + 1]; 723 Tok s = make_stringize(pp, a->raw, lo, hi, invoke->loc); 724 s.flags = (u16)((s.flags & ~(TF_AT_BOL | TF_HAS_SPACE)) | 725 (bt->flags & (TF_AT_BOL | TF_HAS_SPACE))); 726 if (carry) { 727 s.flags |= carry; 728 carry = 0; 729 } 730 tv_push(pp, out, s); 731 ++j; 732 continue; 733 } 734 } 735 if (bt->kind == TOK_PP_PARAM) { 736 u32 p = bt->aux; 737 int adj_paste = 738 (j > 0 && m->body[j - 1].kind == TOK_PP_PASTE) || 739 (j + 1 < m->body_len && m->body[j + 1].kind == TOK_PP_PASTE); 740 741 u32 lo, hi; 742 if (adj_paste) { 743 lo = a->raw_start[p]; 744 hi = a->raw_start[p + 1]; 745 } else { 746 lo = a->exp_start[p]; 747 hi = a->exp_start[p + 1]; 748 } 749 750 if (lo == hi) { 751 if (no_paste) { 752 /* No-`##` fast path: a placemarker only ever matters as a phase-2 753 * strip carrier, so skip it and accumulate its BOL/SPACE for the 754 * next emitted token (identical to phase 2's strip carry). */ 755 carry |= bt->flags & (TF_AT_BOL | TF_HAS_SPACE); 756 } else { 757 /* Empty argument → placemarker. */ 758 Tok pm; 759 memset(&pm, 0, sizeof(pm)); 760 pm.kind = TOK_PP_PLACEMARKER; 761 pm.flags = bt->flags & (TF_AT_BOL | TF_HAS_SPACE); 762 pm.loc = invoke->loc; 763 tv_push(pp, out, pm); 764 } 765 } else { 766 u32 k; 767 int first = 1; 768 Tok* src = adj_paste ? a->raw : a->exp; 769 for (k = lo; k < hi; ++k) { 770 Tok t = src[k]; 771 if (first) { 772 t.flags = (u16)((t.flags & ~(TF_AT_BOL | TF_HAS_SPACE)) | 773 (bt->flags & (TF_AT_BOL | TF_HAS_SPACE))); 774 first = 0; 775 } 776 if (carry) { 777 t.flags |= carry; 778 carry = 0; 779 } 780 tv_push(pp, out, t); 781 } 782 } 783 continue; 784 } 785 if (carry) { 786 Tok t = *bt; 787 t.flags |= carry; 788 carry = 0; 789 tv_push(pp, out, t); 790 } else { 791 tv_push(pp, out, *bt); 792 } 793 } 794 /* A trailing carry (empty arg(s) at the very end with no following token) 795 * is dropped, matching phase 2: its strip pass leaves a trailing carry with 796 * no surviving token to OR onto. */ 797 (void)carry; 798 } 799 800 /* Phase 1 in the general (placemarker-emitting) form; phase 2 follows. */ 801 static void subst_phase1(Pp* pp, const Macro* m, ArgList* a, const Tok* invoke, 802 TokVec* out) { 803 subst_phase1_impl(pp, m, a, invoke, out, /*no_paste=*/0); 804 } 805 806 /* Phase 2 (paste). Walk the post-substitute buffer; for each TOK_PP_PASTE, 807 * splice the previous output token with the next input token. Then strip 808 * remaining placemarkers. */ 809 static void subst_phase2(Pp* pp, const Tok* in, u32 nin, const Tok* invoke, 810 TokVec* out) { 811 u32 i; 812 /* Track whether any placemarker actually lands in `out`. The strip pass 813 * below is a full O(out->n) re-walk + element-wise compaction; the common 814 * macro body has no empty-arg/paste placemarkers, so when none was emitted 815 * we skip the second walk entirely. */ 816 int had_pm = 0; 817 /* Phase-2 output is at most the input length (paste/placemarker only 818 * shrink); reserve it to avoid re-growing from cap 0. */ 819 tv_grow(pp, out, nin); 820 for (i = 0; i < nin; ++i) { 821 Tok t = in[i]; 822 if (t.kind == TOK_PP_PASTE) { 823 Tok lhs, rhs, pasted; 824 if (out->n == 0 || i + 1 >= nin) { 825 compiler_panic(pp->c, pp_materialize_loc(pp, invoke->loc), 826 "'##' at start or end of replacement list"); 827 } 828 lhs = out->data[--out->n]; 829 rhs = in[++i]; 830 /* paste_tokens collapses a placemarker operand to the other side, so 831 * the result is a placemarker only when both operands were. */ 832 pasted = paste_tokens(pp, lhs, rhs, invoke->loc); 833 if (pasted.kind == TOK_PP_PLACEMARKER) had_pm = 1; 834 tv_push(pp, out, pasted); 835 continue; 836 } 837 if (t.kind == TOK_PP_PLACEMARKER) had_pm = 1; 838 tv_push(pp, out, t); 839 } 840 if (!had_pm) return; /* no placemarker to strip — skip the compaction walk */ 841 /* Strip placemarkers, preserving leading-space flag on the next token. */ 842 { 843 u32 r = 0, w = 0; 844 u16 carry = 0; 845 for (r = 0; r < out->n; ++r) { 846 if (out->data[r].kind == TOK_PP_PLACEMARKER) { 847 carry |= out->data[r].flags & (TF_AT_BOL | TF_HAS_SPACE); 848 continue; 849 } 850 if (carry) { 851 out->data[r].flags |= carry; 852 carry = 0; 853 } 854 if (w != r) out->data[w] = out->data[r]; 855 ++w; 856 } 857 out->n = w; 858 } 859 } 860 861 /* Wrapper: phases 1 and 2 in sequence, plus invocation-loc / flag transfer. */ 862 static void substitute_body(Pp* pp, const Macro* m, ArgList* a, 863 const Tok* invoke, TokVec* out) { 864 TokVec phase1 = {0}; 865 u32 i; 866 if (!m->has_paste) { 867 /* No `##` in the body: phase 2 (paste + placemarker strip) is the identity 868 * on phase-1 output once empty-arg placemarkers are elided. Run phase 1 in 869 * its no_paste mode straight into `out`, skipping the second full-body copy 870 * + re-walk. Byte-identical: no_paste carries empty-arg BOL/SPACE forward 871 * exactly as the strip pass would, and with no TOK_PP_PASTE there is no 872 * paste work to do. */ 873 subst_phase1_impl(pp, m, a, invoke, out, /*no_paste=*/1); 874 } else { 875 subst_phase1(pp, m, a, invoke, &phase1); 876 subst_phase2(pp, phase1.data, phase1.n, invoke, out); 877 } 878 /* Invocation flags onto first emitted token. */ 879 if (out->n) { 880 out->data[0].flags = 881 (u16)((out->data[0].flags & ~(TF_AT_BOL | TF_HAS_SPACE)) | 882 (invoke->flags & (TF_AT_BOL | TF_HAS_SPACE))); 883 } 884 /* Locations to invocation site. */ 885 for (i = 0; i < out->n; ++i) out->data[i].loc = invoke->loc; 886 } 887 888 /* Expand a function-like macro invocation: peek for `(`, collect args, 889 * pre-expand them, substitute the body, push the result. Returns 1 if 890 * the invocation was performed, 0 if there was no `(` (the caller should 891 * emit the identifier as-is). */ 892 static int try_expand_func_macro(Pp* pp, Macro* m, const Tok* invoke) { 893 int saw_ws; 894 ArgList args; 895 TokVec body = {0}; 896 Tok close_tok; 897 898 if (!peek_for_invoke_paren(pp, &saw_ws)) { 899 return 0; 900 } 901 (void)saw_ws; 902 read_invocation_args(pp, m, invoke->loc, &args); 903 /* Note: assigned to silence unused-result; we don't use the close tok yet. */ 904 close_tok.kind = 0; 905 (void)close_tok; 906 preexpand_args(pp, &args); 907 908 substitute_body(pp, m, &args, invoke, &body); 909 910 /* Push the substituted body as a disabled frame owned by `m`: the macro is 911 * unavailable for the whole rescan of this replacement (cpplib model), so a 912 * recursive occurrence of `m` is returned permanently un-expanded. The 913 * arguments were already pre-expanded above with `m` NOT disabled. */ 914 push_buf_uniform(pp, body.data, body.n, m); 915 return 1; 916 } 917 918 /* ============================================================ 919 * pp_next_raw — mutual recursion entry (called from expand_arg_to_eof) 920 * Defined here; also declared in pp_priv.h so pp.c can call it. 921 * ============================================================ */ 922 923 /* pp_pull_into: shared core of pp_next_raw / pp_next_into. Reads from the 924 * top source into *out, applies macro expansion when an identifier names a 925 * macro that isn't blue-painted, and consumes directives in-place. 926 * 927 * `skip_nl` short-circuits the parser-facing newline drop ONE FRAME LOWER: the 928 * public pp_next (the C-parser feed) discards every non-directive TOK_NEWLINE 929 * at the top of its loop, and 51% of all produced tokens are exactly those 930 * newlines. When skip_nl is set, such a newline is consumed here (the loop just 931 * continues) instead of being returned and round-tripped through pp_next's sret 932 * — the token never escapes this frame. This is sound because a TOK_NEWLINE can 933 * never be a directive introducer (TOK_PP_HASH), a macro-name TOK_IDENT, or 934 * TOK_EOF, so in the un-skipped path it falls straight through to the trailing 935 * `return`; continuing the loop instead is byte-identical to the caller having 936 * read and dropped it, modulo the (idempotent) arena-reset re-check at the loop 937 * head. skip_nl is set ONLY by pp_next, which never runs during #if expansion, 938 * so the in_if_expansion `defined`-operator state machine below is unaffected. 939 * pp_emit_text and the pragma-swallow / hash-peek paths pass skip_nl=0 so they 940 * still observe newlines for -E line reconstruction and directive termination. 941 * 942 * Tok is 24B, so the by-value form (pp_next_raw) returns indirectly via sret 943 * and pays a 24B inter-frame copy at every `return t`. Writing through `out` 944 * lets the token — and lex_next's own sret — land in the caller's slot 945 * directly. The hot SRC_BUF case (macro replay) is inlined here so the common 946 * token never pays a call into src_next_raw_into. */ 947 static void pp_pull_into(Pp* pp, Tok* out, int skip_nl) { 948 u8 src_kind; 949 for (;;) { 950 TokSrc* s; 951 /* Reclaim the transient expansion scratch whenever the source stack has 952 * drained back to a lexer. A SRC_BUF always sits above every SRC_LEX (a 953 * macro can't #include), so a lexer on top means no expansion buffer is 954 * live -- nothing in xarena is referenced, and the previously returned 955 * token was a value copy with a pool-interned spelling. This is the only 956 * reset site; it never fires mid-expansion (a SRC_BUF, incl. the 957 * scope_top arg-prescan buffer, is on top then) nor during raw argument 958 * collection (which uses src_next_raw, not this function). Skipped inside 959 * #if expansion, whose bounded condition keeps its scratch live. The reset 960 * is further skipped when the xarena is already at its baseline (a plain 961 * lexer run that allocated no scratch): kit_arena_is_empty is the pristine 962 * guard, so the dead reset on plain-token runs is elided -- byte-identical 963 * since resetting an already-pristine arena does nothing. */ 964 if (!pp->in_if_expansion && 965 (pp->nsources == 0 || pp->sources[pp->nsources - 1].kind == SRC_LEX)) { 966 if (!kit_arena_is_empty(pp->xarena)) kit_arena_reset(pp->xarena); 967 } 968 /* Fast path: top source is a non-exhausted SRC_BUF (the dominant 969 * macro-replay case). Pull the token and kind inline so the common token 970 * avoids the call + sret setup of src_next_raw_into. The scope_top-EOF and 971 * #line-delta cases never apply to a plain in-bounds SRC_BUF read, so they 972 * stay on the general (cold) path. */ 973 if (pp->nsources != 0 && 974 (s = &pp->sources[pp->nsources - 1])->kind == SRC_BUF && s->i < s->n) { 975 *out = s->toks[s->i]; 976 src_kind = SRC_BUF; 977 /* Pointer-replayed body: apply the per-invocation loc and (first token 978 * only) BOL/SPACE flags the old fresh-copy path baked in. Identical to 979 * the slow read site in src_next_raw_into so both paths agree. */ 980 if (s->has_loc_override) { 981 if (s->i == 0) { 982 out->flags = (u16)((out->flags & ~(TF_AT_BOL | TF_HAS_SPACE)) | 983 s->first_flags_or); 984 } 985 out->loc = s->loc_override; 986 } 987 ++s->i; 988 } else { 989 src_next_raw_into(pp, out, &src_kind); 990 } 991 if (out->kind == TOK_EOF) return; 992 /* §C.3a/§C.3b: absorb the parser-facing non-directive newline drop here so 993 * it never round-trips up through pp_next's sret. A newline is whitespace, 994 * not a directive introducer, so dropping it before the directive / macro 995 * checks below is the same as pp_next dropping it after the return. 996 * 997 * §C.3b drains a run of newlines in place via src_next_raw_into rather than 998 * `continue`-ing the outer loop per newline. The outer loop's only 999 * per-iteration work before this point is the xarena reclaim 1000 * (kit_arena_reset, a real call) and the SRC_BUF fast-path probe; for a 1001 * newline both are redundant — the source stack is unchanged between a 1002 * newline and the token that follows it (a newline never pushes a source, 1003 * and a SRC_BUF can only sit *above* the SRC_LEX a file newline came from, 1004 * so it is not on top here). Skipping them is byte-identical to the §C.3a 1005 * `continue` while removing one kit_arena_reset call + probe per dropped 1006 * newline (51% of produced tokens). The drained token re-enters the normal 1007 * directive / macro flow below, so a `#` or content token after the 1008 * newline is handled exactly as before. */ 1009 if (skip_nl && out->kind == TOK_NEWLINE) { 1010 do { 1011 src_next_raw_into(pp, out, &src_kind); 1012 } while (out->kind == TOK_NEWLINE); 1013 if (out->kind == TOK_EOF) return; 1014 } 1015 if (out->kind == TOK_PP_HASH && (out->flags & TF_AT_BOL) && 1016 src_kind == SRC_LEX) { 1017 process_directive(pp, out->loc); 1018 /* No synthesized newline: the comparator collapses 1019 * whitespace, so blank-line replacement of consumed 1020 * directives isn't observable here. Directives that produce 1021 * content (e.g. #include, #embed, #pragma) push their own 1022 * tokens onto the source stack, which the next loop 1023 * iteration picks up. */ 1024 continue; 1025 } 1026 /* While expanding an #if condition, suppress macro expansion of 1027 * `defined`-operator operands so a `defined(X)` produced by a 1028 * macro body whose argument was pasted via ## doesn't accidentally 1029 * expand an already-defined X to its body (typically empty). See 1030 * the `defined_skip` field comment in pp_priv.h. */ 1031 if (pp->in_if_expansion) { 1032 if (pp->defined_skip == 2) { 1033 if (out->kind == TOK_PUNCT && tok_punct(out) == '(') { 1034 pp->defined_skip = 3; 1035 } else if (out->kind == TOK_IDENT) { 1036 /* `defined IDENT` (no parens): mark the operand and reset. */ 1037 out->flags |= TF_NO_EXPAND; 1038 pp->defined_skip = 0; 1039 } else { 1040 pp->defined_skip = 0; 1041 } 1042 } else if (pp->defined_skip == 3) { 1043 if (out->kind == TOK_IDENT) { 1044 out->flags |= TF_NO_EXPAND; 1045 pp->defined_skip = 4; 1046 } else if (out->kind == TOK_PUNCT && tok_punct(out) == ')') { 1047 pp->defined_skip = 0; 1048 } 1049 } else if (pp->defined_skip == 4) { 1050 if (out->kind == TOK_PUNCT && tok_punct(out) == ')') { 1051 pp->defined_skip = 0; 1052 } 1053 } else if (out->kind == TOK_IDENT && tok_ident(out) == pp->sym_defined) { 1054 pp->defined_skip = 2; 1055 } 1056 } 1057 if (out->kind == TOK_IDENT && (out->flags & TF_NO_EXPAND) == 0) { 1058 Sym id = tok_ident(out); 1059 1060 /* Dynamic predefined macros: __LINE__ / __FILE__ / 1061 * __DATE__ / __TIME__. Always expand, ignoring the macro 1062 * table. */ 1063 if (id == pp->sym_line__) { 1064 char tmp[16], buf[16]; 1065 int k = 0, j = 0; 1066 u32 ln = pp_materialize_loc(pp, out->loc).line; 1067 if (ln == 0) 1068 buf[k++] = '0'; 1069 else { 1070 while (ln) { 1071 tmp[j++] = (char)('0' + ln % 10); 1072 ln /= 10; 1073 } 1074 while (j > 0) buf[k++] = tmp[--j]; 1075 } 1076 out->kind = TOK_NUM; 1077 out->aux = 0; 1078 out->text = text_intern_ref(pp, (KitSlice){.s = buf, .len = (size_t)k}); 1079 return; 1080 } 1081 if (id == pp->sym_file__) { 1082 /* pp_materialize_file resolves the __FILE__ name at this location, 1083 * applying any active #line overlay; no current-lexer probe needed. */ 1084 Sym name = pp_materialize_file(pp, out->loc); 1085 size_t nlen = 0; 1086 const char* nstr = NULL; 1087 char* buf; 1088 if (name) { 1089 KitSlice s = kit_sym_str(pp->pool->c, name); 1090 nstr = s.s; 1091 nlen = s.len; 1092 } 1093 /* The source name is the raw filesystem path (or a #line override, 1094 * destringized to logical bytes by do_line). Re-stringize it as a 1095 * valid C string literal: escape '\\' and '"'. On POSIX paths use 1096 * '/' so this was a no-op; on Windows the path holds backslashes 1097 * (e.g. C:\\Users\\...), and emitting them raw turns '\\U'/'\\u'/'\\x' 1098 * into bogus escape sequences (the "malformed UCN" on '\\Users'). */ 1099 { 1100 size_t bn = 0; 1101 size_t i; 1102 buf = (char*)arena_alloc(pp->xarena, nlen * 2 + 2, 1); 1103 buf[bn++] = '"'; 1104 for (i = 0; i < nlen; ++i) { 1105 char ch = nstr[i]; 1106 if (ch == '\\' || ch == '"') buf[bn++] = '\\'; 1107 buf[bn++] = ch; 1108 } 1109 buf[bn++] = '"'; 1110 out->kind = TOK_STR; 1111 out->aux = 0; 1112 out->text = text_intern_ref(pp, (KitSlice){.s = buf, .len = bn}); 1113 } 1114 return; 1115 } 1116 if (id == pp->sym_date__) { 1117 out->kind = TOK_STR; 1118 out->aux = 0; 1119 out->text = text_sym_ref(pp->val_date_str); 1120 return; 1121 } 1122 if (id == pp->sym_time__) { 1123 out->kind = TOK_STR; 1124 out->aux = 0; 1125 out->text = text_sym_ref(pp->val_time_str); 1126 return; 1127 } 1128 if (id == pp->sym__pragma) { 1129 if (try_expand_pragma_op(pp, out)) continue; 1130 /* No '(' — fall through and emit as plain ident. */ 1131 } 1132 1133 { 1134 Macro* m = mt_get(pp, id); 1135 if (m && m->disabled_depth != 0) { 1136 /* cpplib: the macro is disabled because one of its own 1137 * replacement-list frames is still being rescanned. Mark this 1138 * occurrence permanently un-expandable, so the bit survives if this 1139 * token is later captured as an argument, substituted into another 1140 * macro, or replayed (this is what keeps `foo(foo)(1)` and 1141 * `id(foo(foo)(1))` as `foo(1)`). */ 1142 out->flags |= TF_NO_EXPAND; 1143 return; 1144 } 1145 if (m) { 1146 if (!m->is_func) { 1147 expand_object_macro(pp, m, out); 1148 continue; 1149 } 1150 if (try_expand_func_macro(pp, m, out)) { 1151 continue; 1152 } 1153 /* Function-like macro name NOT followed by '(': emit as a plain 1154 * identifier WITHOUT setting TF_NO_EXPAND, so a later rescan that 1155 * sees a '(' supplied by another macro can still expand it (keeps 1156 * `id(f L 1))` with `#define L (` able to become `1`). */ 1157 } 1158 } 1159 } 1160 return; 1161 } 1162 } 1163 1164 /* pp_next_raw: public out-pointer form (pp.h), every token surfaced 1165 * (TOK_NEWLINE preserved for pp_emit_text and for directive/pragma line 1166 * termination). The mutual-recursion entry: expand_arg_to_eof and the -E loop 1167 * call it; it drives directives and expansion. */ 1168 void pp_next_raw(Pp* pp, Tok* out) { pp_pull_into(pp, out, /*skip_nl=*/0); } 1169 1170 /* pp_next_into: out-pointer form for the C-parser feed (pp_next_parse). 1171 * Identical to pp_next_raw but drops non-directive newlines internally, so the 1172 * 51% of produced tokens that pp_next_parse would otherwise discard never 1173 * escape this frame. Declared in pp_priv.h. */ 1174 void pp_next_into(Pp* pp, Tok* out) { pp_pull_into(pp, out, /*skip_nl=*/1); }