kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

commit b34c6beecd811a5aa7ac5bdbd2cc67c6ba99a032
parent 0e5337e33c91ef60bf270d726103e970d665e1d5
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Mon, 15 Jun 2026 17:09:58 -0700

Merge Phase 2: parser input ring (ParserInput 3-cell ring)

Diffstat:
Mlang/c/parse/parse.c | 208+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
Mlang/c/parse/parse_expr.c | 147+++++++++++++++++++++++++++++++++++++++----------------------------------------
Mlang/c/parse/parse_init.c | 161+++++++++++++++++++++++++++++++++++++++----------------------------------------
Mlang/c/parse/parse_priv.h | 55+++++++++++++++++++++++++++++++++++++++++++++++++------
Mlang/c/parse/parse_stmt.c | 102++++++++++++++++++++++++++++++++++++++++----------------------------------------
Mlang/c/parse/parse_type.c | 142++++++++++++++++++++++++++++++++++++++++---------------------------------------
6 files changed, 442 insertions(+), 373 deletions(-)

diff --git a/lang/c/parse/parse.c b/lang/c/parse/parse.c @@ -2,7 +2,8 @@ * * Contains: * - kw_names[] table (used by parse_c to intern keywords) - * - Diagnostics/token helpers (perr, advance, peek1, fetch_tok, ...) + * - Diagnostics/token helpers (perr, advance, peek1) over the input ring + * (parser_advance, parser_fill_to, parser_peek; see parse_priv.h) * - Scope/tag operations * - Type helpers (ty_int, ty_size_t) * - Local-variable slot allocation (make_local, make_local_aligned) @@ -15,6 +16,7 @@ * All expression, type, initializer, and statement code lives in * parse_expr.c, parse_type.c, parse_init.c, and parse_stmt.c. */ +#include <assert.h> #include <stdarg.h> #include <string.h> @@ -85,7 +87,7 @@ static SrcLoc tok_loc(Parser* p, const Tok* t) { _Noreturn void perr(Parser* p, const char* fmt, ...) { va_list ap; - SrcLoc loc = tok_loc(p, &p->cur); + SrcLoc loc = tok_loc(p, p_cur(p)); va_start(ap, fmt); compiler_panicv(p->c, loc, fmt, ap); } @@ -104,13 +106,16 @@ static size_t str_prefix_len(u16 flags) { #define STR_ENC_MASK (TF_STR_WIDE | TF_STR_U8 | TF_STR_U16 | TF_STR_U32) -/* Fuse two adjacent TOK_STR tokens into one per C11 §6.4.5 ¶5. */ -static Tok fuse_string_lits(Parser* p, Tok a, Tok b) { - u16 ae = (u16)(a.flags & STR_ENC_MASK); - u16 be = (u16)(b.flags & STR_ENC_MASK); +/* Fuse two adjacent TOK_STR cells into one per C11 §6.4.5 ¶5, writing the fused + * result back into *dst in place: dst->loc (first literal's location) is kept, + * while dst->text (TEXT_SYM interned) and dst->flags (combined encoding) are + * overwritten. The synthetic spelling is interned so it outlives pp_free. */ +static void fuse_string_lits_into(Parser* p, CFeCell* dst, const CFeCell* b) { + u16 ae = (u16)(dst->flags & STR_ENC_MASK); + u16 be = (u16)(b->flags & STR_ENC_MASK); u16 fused_enc; - KitSlice a_sl = pp_text_slice(p->pp, &a); - KitSlice b_sl = pp_text_slice(p->pp, &b); + KitSlice a_sl = pp_text_slice(p->pp, dst); + KitSlice b_sl = pp_text_slice(p->pp, b); size_t alen = a_sl.len, blen = b_sl.len; const char* as = a_sl.s; const char* bs = b_sl.s; @@ -121,7 +126,6 @@ static Tok fuse_string_lits(Parser* p, Tok a, Tok b) { Heap* h = kit_compiler_context(p->c)->heap; char* buf; size_t k = 0; - Tok out; if (!as || !bs) perr(p, "bad string literal in concatenation"); if (ae != 0 && be != 0 && ae != be) { perr(p, @@ -129,8 +133,8 @@ static Tok fuse_string_lits(Parser* p, Tok a, Tok b) { "encoding prefixes"); } fused_enc = ae ? ae : be; - apfx = str_prefix_len(a.flags); - bpfx = str_prefix_len(b.flags); + apfx = str_prefix_len(dst->flags); + bpfx = str_prefix_len(b->flags); if (alen < apfx + 2 || as[apfx] != '"' || as[alen - 1] != '"' || blen < bpfx + 2 || bs[bpfx] != '"' || bs[blen - 1] != '"') { perr(p, "malformed string literal in concatenation"); @@ -156,61 +160,82 @@ static Tok fuse_string_lits(Parser* p, Tok a, Tok b) { k += b_content_len; } buf[k++] = '"'; - out = a; - out.text = + dst->text = text_sym_ref(kit_sym_intern(p->pool->c, (KitSlice){.s = buf, .len = k})); - out.flags = (u16)((a.flags & ~STR_ENC_MASK) | fused_enc); + dst->flags = (u16)((dst->flags & ~STR_ENC_MASK) | fused_enc); h->free(h, buf, 0); - return out; } -/* Pull one logical token from pp, collapsing adjacent TOK_STR runs. */ -static Tok fetch_tok(Parser* p) { - Tok t; - if (p->has_pending) { - t = p->pending; - p->has_pending = 0; +/* Fill one ring slot with the next logical token, collapsing adjacent TOK_STR + * runs. Source priority: replay buffer (if active), then a pushed-back pending + * cell, then pp. A non-string cell pulled while collapsing a TOK_STR run is + * stashed in the one-cell pending slot. */ +static void parser_fill_one(Parser* p, CFeCell* slot) { + if (p->replay_active) { + if (p->replay_pos < p->replay_len) { + *slot = p->replay[p->replay_pos++]; + return; + } + p->replay_active = 0; + } + if (p->input.has_pending) { + *slot = p->input.pending; + p->input.has_pending = 0; } else { - pp_next_parse(p->pp, &t); + pp_next_parse(p->pp, slot); } - if (t.kind != TOK_STR) return t; + if (slot->kind != TOK_STR) return; for (;;) { - Tok n; + CFeCell n; + /* A replay run records lexeme cells with adjacent strings already fused, so + * fusion only ever pulls follow-on cells from pp. */ pp_next_parse(p->pp, &n); if (n.kind != TOK_STR) { - p->pending = n; - p->has_pending = 1; - return t; + p->input.pending = n; + p->input.has_pending = 1; + return; } - t = fuse_string_lits(p, t, n); + fuse_string_lits_into(p, slot, &n); } } -void advance(Parser* p) { - if (p->replay_active) { - if (p->replay_pos < p->replay_len) { - p->cur = p->replay[p->replay_pos++]; - return; - } - p->replay_active = 0; - } - if (p->has_next) { - p->cur = p->next; - p->has_next = 0; - } else { - p->cur = fetch_tok(p); +/* Fill the ring tail until `depth` is valid (i.e. depth+1 cells from cur). */ +void parser_fill_to(Parser* p, u32 depth) { + ParserInput* in = &p->input; + assert(depth < 3u); + while (in->nvalid <= depth) { + assert(in->nvalid < 3u); + parser_fill_one(p, &in->cells[parser_ring_idx(in, in->nvalid)]); + in->nvalid++; } + assert(in->cur < 3u && in->nvalid <= 3u); +} + +/* Advance to the next token: rotate cur and fill the freed tail slot on demand. + * Never copies/moves live cells between slots. */ +void parser_advance(Parser* p) { + ParserInput* in = &p->input; + in->cur = (u8)((in->cur + 1u) % 3u); + if (in->nvalid) in->nvalid--; + parser_fill_to(p, 0); + assert(in->cur < 3u && in->nvalid >= 1u && in->nvalid <= 3u); } +/* Borrowed pointer to the cell at lookahead `depth` (0 == current), valid until + * the next advance or replay-source switch. */ +const CFeCell* parser_peek(Parser* p, u32 depth) { + ParserInput* in = &p->input; + if (in->nvalid <= depth) parser_fill_to(p, depth); + return &in->cells[parser_ring_idx(in, depth)]; +} + +void advance(Parser* p) { parser_advance(p); } + +/* LL(1) lookahead: returns the depth-1 cell by value (a copy), matching all + * callers and avoiding any borrowed-pointer lifetime trap. */ Tok peek1(Parser* p) { - if (p->replay_active && p->replay_pos < p->replay_len) { - return p->replay[p->replay_pos]; - } - if (!p->has_next) { - p->next = fetch_tok(p); - p->has_next = 1; - } - return p->next; + parser_fill_to(p, 1); + return p->input.cells[parser_ring_idx(&p->input, 1)]; } void expect_punct(Parser* p, u32 punct, const char* what) { @@ -220,7 +245,7 @@ void expect_punct(Parser* p, u32 punct, const char* what) { } int accept_punct(Parser* p, u32 punct) { - if (is_punct(&p->cur, punct)) { + if (is_punct(p_cur(p), punct)) { advance(p); return 1; } @@ -231,7 +256,7 @@ int accept_punct(Parser* p, u32 punct) { * parser's replay buffer. */ void record_braced_block(Parser* p) { int depth = 0; - if (!is_punct(&p->cur, '{')) perr(p, "internal: record on non-'{'"); + if (!is_punct(p_cur(p), '{')) perr(p, "internal: record on non-'{'"); p->replay_len = 0; for (;;) { if (p->replay_len == p->replay_cap) { @@ -244,28 +269,36 @@ void record_braced_block(Parser* p) { p->replay = nv; p->replay_cap = new_cap; } - p->replay[p->replay_len++] = p->cur; - if (is_punct(&p->cur, '{')) { + p->replay[p->replay_len++] = *p_cur(p); + if (is_punct(p_cur(p), '{')) { ++depth; - } else if (is_punct(&p->cur, '}')) { + } else if (is_punct(p_cur(p), '}')) { --depth; if (depth == 0) break; - } else if (p->cur.kind == TOK_EOF) { + } else if (p_cur(p)->kind == TOK_EOF) { perr(p, "unexpected end of file in initializer"); } advance(p); } } -/* After record_braced_block, rewind to replay from the start. */ -void replay_rewind(Parser* p) { - if (p->replay_len == 0) perr(p, "internal: replay_rewind with empty buffer"); - p->cur = p->replay[0]; +/* Switch the input source to the parser's replay buffer, starting at replay[0]. + * A source switch invalidates outstanding ring lookahead, so the ring is reset: + * cur=0, the single valid cell is replay[0], and any stashed pending cell is + * dropped. The caller must have set replay/replay_cap/replay_len beforehand. */ +void parser_replay_begin(Parser* p) { + if (p->replay_len == 0) perr(p, "internal: replay_begin with empty buffer"); + p->input.cur = 0; + p->input.nvalid = 1; + p->input.cells[0] = p->replay[0]; + p->input.has_pending = 0; p->replay_pos = 1; p->replay_active = 1; - p->has_next = 0; } +/* After record_braced_block, rewind to replay from the start. */ +void replay_rewind(Parser* p) { parser_replay_begin(p); } + /* Count top-level items in a recorded brace list. */ u32 count_recorded_top_level_items(const Tok* vec, u32 len) { u32 count; @@ -689,9 +722,10 @@ static int type_array_depth(const Type* ty) { static void eval_param_vla_count(Parser* p, const ParamVLABoundExpr* expr, FrameSlot slot) { - Tok save_cur = p->cur; - Tok save_next = p->next; - int save_has_next = p->has_next; + /* Whole-ring save/restore (POD, trivially copyable) plus the replay + * quintuple. The replay-source switch resets the ring, so the saved + * ParserInput must be restored verbatim afterward. */ + ParserInput save_input = p->input; Tok* save_replay = p->replay; u32 save_cap = p->replay_cap; u32 save_len = p->replay_len; @@ -707,25 +741,19 @@ static void eval_param_vla_count(Parser* p, const ParamVLABoundExpr* expr, memset(&replay[expr->ntoks], 0, sizeof(Tok)); replay[expr->ntoks].kind = TOK_EOF; - p->cur = replay[0]; - p->next.kind = TOK_EOF; - p->has_next = 0; p->replay = replay; p->replay_cap = expr->ntoks + 1u; p->replay_len = expr->ntoks + 1u; - p->replay_pos = 1; - p->replay_active = 1; + parser_replay_begin(p); parse_assign_expr(p); to_rvalue(p); - if (p->cur.kind != TOK_EOF) { + if (p_cur(p)->kind != TOK_EOF) { perr(p, "unexpected token in VLA parameter bound"); } store_top_to_size_slot(p, slot); - p->cur = save_cur; - p->next = save_next; - p->has_next = save_has_next; + p->input = save_input; p->replay = save_replay; p->replay_cap = save_cap; p->replay_len = save_len; @@ -821,7 +849,7 @@ static void parse_init_declarator(Parser* p, const DeclSpecs* specs) { /*is_member=*/0); if (specs->storage == DS_TYPEDEF) { - if (is_punct(&p->cur, '=')) { + if (is_punct(p_cur(p), '=')) { perr(p, "typedef declarator cannot have initializer"); } { @@ -852,7 +880,7 @@ static void parse_init_declarator(Parser* p, const DeclSpecs* specs) { "invalid storage-class specifier for block-scope function " "declaration"); } - if (is_punct(&p->cur, '=')) { + if (is_punct(p_cur(p), '=')) { perr(p, "function declarator cannot have initializer"); } (void)declare_function(p, name, var_ty, specs, loc, NULL, dinfo.asm_label, @@ -981,7 +1009,7 @@ static void parse_init_declarator(Parser* p, const DeclSpecs* specs) { } /* Non-VLA local. */ { - int has_init = is_punct(&p->cur, '='); + int has_init = is_punct(p_cur(p), '='); FrameSlot s; if (has_init && var_ty && var_ty->kind == TY_ARRAY && var_ty->arr.incomplete) { @@ -1010,7 +1038,7 @@ static void parse_init_declarator(Parser* p, const DeclSpecs* specs) { if (accept_punct(p, '=')) { c_cg_set_loc(p, loc); if ((var_ty->kind == TY_STRUCT || var_ty->kind == TY_UNION) && - !is_punct(&p->cur, '{')) { + !is_punct(p_cur(p), '{')) { parse_assign_expr(p); emit_struct_copy_into_slot(p, s, var_ty, 0, var_ty); } else if (var_ty->kind == TY_ARRAY || var_ty->kind == TY_STRUCT || @@ -1070,10 +1098,10 @@ void parse_param_list(Parser* p, ParamInfo** infos_out, u16* nparams_out, *infos_out = NULL; *nparams_out = 0; - if (is_punct(&p->cur, ')')) { + if (is_punct(p_cur(p), ')')) { return; } - if (is_kw(p, &p->cur, KW_VOID)) { + if (is_kw(p, p_cur(p), KW_VOID)) { Tok n2 = peek1(p); if (is_punct(&n2, ')')) { advance(p); /* `void` */ @@ -1382,7 +1410,7 @@ static void parse_external_decl(Parser* p) { validate_decl_type_constraints(p, &specs, tty, tty && tty->kind == TY_FUNC, /*is_member=*/0); - if (is_punct(&p->cur, '=')) { + if (is_punct(p_cur(p), '=')) { perr(p, "typedef declarator cannot have initializer"); } { @@ -1422,7 +1450,7 @@ static void parse_external_decl(Parser* p) { &fn_section_id, &fn_decl_flags, &fn_alias_target); attr_list_append(&fent->attrs, dattrs); - if (is_punct(&p->cur, '{')) { + if (is_punct(p_cur(p), '{')) { int suppress_body_codegen = specs.storage == DS_EXTERN && ((specs.flags | fn_decl_flags) & DF_INLINE); if (fent->defined) perr(p, "redefinition of function"); @@ -1475,7 +1503,7 @@ static void parse_external_decl(Parser* p) { /* Global object declaration. */ for (;;) { - int has_init = is_punct(&p->cur, '='); + int has_init = is_punct(p_cur(p), '='); int is_pure_extern = (specs.storage == DS_EXTERN || specs.storage == DS_REGISTER) && !has_init; @@ -1579,7 +1607,7 @@ static void parse_file_scope_asm(Parser* p) { size_t nbytes; advance(p); /* asm / __asm__ */ for (;;) { - if (is_kw(p, &p->cur, + if (is_kw(p, p_cur(p), KW_VOLATILE)) { /* matches `volatile` and `__volatile__` */ advance(p); continue; @@ -1587,10 +1615,10 @@ static void parse_file_scope_asm(Parser* p) { break; } expect_punct(p, '(', "'(' after file-scope asm"); - if (p->cur.kind != TOK_STR) { + if (p_cur(p)->kind != TOK_STR) { perr(p, "expected string literal in file-scope asm"); } - bytes = decode_string_literal(p, &p->cur, &nbytes); + bytes = decode_string_literal(p, p_cur(p), &nbytes); advance(p); expect_punct(p, ')', "')' after file-scope asm"); expect_punct(p, ';', "';' after file-scope asm"); @@ -1602,16 +1630,16 @@ static void parse_file_scope_asm(Parser* p) { } static void parse_translation_unit(Parser* p) { - while (p->cur.kind != TOK_EOF) { - if (p->cur.kind == TOK_NEWLINE || is_pp_hash(&p->cur)) { + while (p_cur(p)->kind != TOK_EOF) { + if (p_cur(p)->kind == TOK_NEWLINE || is_pp_hash(p_cur(p))) { advance(p); continue; } - if (is_kw(p, &p->cur, KW_STATIC_ASSERT)) { + if (is_kw(p, p_cur(p), KW_STATIC_ASSERT)) { parse_static_assert(p); continue; } - if (is_kw(p, &p->cur, KW_ASM) || is_kw(p, &p->cur, KW_BUILTIN_ASM)) { + if (is_kw(p, p_cur(p), KW_ASM) || is_kw(p, p_cur(p), KW_BUILTIN_ASM)) { parse_file_scope_asm(p); continue; } @@ -1802,7 +1830,9 @@ void parse_c(Compiler* c, Pool* pool, Pp* pp, DeclTable* decls, CG* cg, p.scope = scope_new(&p, NULL); - p.cur = fetch_tok(&p); + /* Prime the input ring: p was zero-initialized (cur=0, nvalid=0), so this + * fills cells[0] with the first token. */ + parser_fill_to(&p, 0); parse_translation_unit(&p); } diff --git a/lang/c/parse/parse_expr.c b/lang/c/parse/parse_expr.c @@ -483,7 +483,7 @@ static void c_const_guard_note_at(Parser* p, SrcLoc loc, const char* message) { } static void c_const_guard_note(Parser* p, const char* message) { - c_const_guard_note_at(p, pp_materialize_loc(p->pp, p->cur.loc), message); + c_const_guard_note_at(p, pp_materialize_loc(p->pp, p_cur(p)->loc), message); } static void c_const_guard_not_eval_push(Parser* p) { @@ -945,8 +945,8 @@ static int parse_builtin_clear_cache_call(Parser* p, Sym name, SrcLoc loc) { } static MemOrder parse_atomic_mem_order(Parser* p) { - if (p->cur.kind == TOK_NUM) { - return (MemOrder)eval_const_int(p, pp_materialize_loc(p->pp, p->cur.loc)); + if (p_cur(p)->kind == TOK_NUM) { + return (MemOrder)eval_const_int(p, pp_materialize_loc(p->pp, p_cur(p)->loc)); } parse_assign_expr(p); to_rvalue(p); @@ -994,13 +994,13 @@ static int offsetof_find_member(Parser* p, const Type* rec_ty, Sym mname, static const Type* offsetof_designator(Parser* p, const Type* base, u32* off) { const Type* cur = base; - if (p->cur.kind != TOK_IDENT || - ident_kw_inline(p, tok_ident(&p->cur)) != KW_NONE) { + if (p_cur(p)->kind != TOK_IDENT || + ident_kw_inline(p, tok_ident(p_cur(p))) != KW_NONE) { perr(p, "expected member name in __builtin_offsetof"); } for (;;) { if (cur->kind == TY_STRUCT || cur->kind == TY_UNION) { - Sym mname = tok_ident(&p->cur); + Sym mname = tok_ident(p_cur(p)); const Type* mty = NULL; u32 moff = 0; if (!offsetof_find_member(p, cur, mname, &mty, &moff)) @@ -1013,17 +1013,17 @@ static const Type* offsetof_designator(Parser* p, const Type* base, u32* off) { } else { perr(p, "__builtin_offsetof step into non-aggregate"); } - if (is_punct(&p->cur, '.')) { + if (is_punct(p_cur(p), '.')) { advance(p); - if (p->cur.kind != TOK_IDENT || - ident_kw_inline(p, tok_ident(&p->cur)) != KW_NONE) { + if (p_cur(p)->kind != TOK_IDENT || + ident_kw_inline(p, tok_ident(p_cur(p))) != KW_NONE) { perr(p, "expected member name after '.'"); } continue; } - if (is_punct(&p->cur, '[')) { + if (is_punct(p_cur(p), '[')) { advance(p); - i64 idx = eval_const_int(p, pp_materialize_loc(p->pp, p->cur.loc)); + i64 idx = eval_const_int(p, pp_materialize_loc(p->pp, p_cur(p)->loc)); expect_punct(p, ']', "']' in __builtin_offsetof"); if (cur->kind != TY_ARRAY) { perr(p, "__builtin_offsetof '[' on non-array"); @@ -1455,8 +1455,8 @@ static int parse_kit_syscall_call(Parser* p, Sym name, SrcLoc loc) { } static int try_parse_builtin_call(Parser* p) { - Sym name = tok_ident(&p->cur); - SrcLoc loc = pp_materialize_loc(p->pp, p->cur.loc); + Sym name = tok_ident(p_cur(p)); + SrcLoc loc = pp_materialize_loc(p->pp, p_cur(p)->loc); if (c_const_guard_active(p) && name != p->sym_b_offsetof && name != p->sym_b_constant_p) { @@ -1568,7 +1568,7 @@ static int try_parse_builtin_call(Parser* p) { if (name == p->sym_b_return_address || name == p->sym_b_frame_address) { /* GCC requires the level to be an integer constant expression. */ int is_return = (name == p->sym_b_return_address); - i64 level = eval_const_int(p, pp_materialize_loc(p->pp, p->cur.loc)); + i64 level = eval_const_int(p, pp_materialize_loc(p->pp, p_cur(p)->loc)); expect_punct(p, ')', "')' after __builtin_return_address/__builtin_frame_address"); if (level < 0) @@ -1683,7 +1683,7 @@ static int try_parse_builtin_call(Parser* p) { } if (name == p->sym_a_always_lock_free || name == p->sym_a_is_lock_free) { - i64 size = eval_const_int(p, pp_materialize_loc(p->pp, p->cur.loc)); + i64 size = eval_const_int(p, pp_materialize_loc(p->pp, p_cur(p)->loc)); expect_punct(p, ',', "',' in atomic lock-free builtin"); parse_assign_expr(p); to_rvalue(p); @@ -1733,7 +1733,7 @@ static int try_parse_builtin_call(Parser* p) { coerce_top_to_type(p, val_ty); expect_punct(p, ',', "',' in __atomic_compare_exchange_n"); - (void)eval_const_int(p, pp_materialize_loc(p->pp, p->cur.loc)); /* weak */ + (void)eval_const_int(p, pp_materialize_loc(p->pp, p_cur(p)->loc)); /* weak */ expect_punct(p, ',', "',' in __atomic_compare_exchange_n"); MemOrder succ = parse_atomic_mem_order(p); expect_punct(p, ',', "',' in __atomic_compare_exchange_n"); @@ -1823,7 +1823,7 @@ static int try_parse_builtin_call(Parser* p) { * ============================================================ */ static void parse_primary(Parser* p) { - Tok t = p->cur; + Tok t = *p_cur(p); if (t.kind == TOK_NUM) { i64 v = parse_int_literal(p, &t); const Type* lty = int_literal_type(p, &t); @@ -1858,7 +1858,7 @@ static void parse_primary(Parser* p) { /* try_parse_builtin_call may rewrite the current ident in-place * (e.g. __builtin_memcpy → memcpy) and return 0, asking us to * resume normal lookup with the rewritten name. */ - t = p->cur; + t = *p_cur(p); /* C99 §6.4.2.2: `__func__` inside a function-body acts as * static const char __func__[] = "<function-name>"; * GCC also exposes `__FUNCTION__` and `__PRETTY_FUNCTION__` with @@ -2016,7 +2016,7 @@ static void parse_postfix(Parser* p) { parse_primary(p); vla_bounds = p->last_pushed_vla_bounds; for (;;) { - Tok t = p->cur; + Tok t = *p_cur(p); if (is_punct(&t, P_INC)) { c_const_guard_note_at( p, pp_materialize_loc(p->pp, t.loc), @@ -2061,7 +2061,7 @@ static void parse_postfix(Parser* p) { } advance(p); /* '(' */ u32 nargs = 0; - if (!is_punct(&p->cur, ')')) { + if (!is_punct(p_cur(p), ')')) { for (;;) { const Type* param_ty = (nargs < fn_type->fn.nparams) ? fn_type->fn.params[nargs] : NULL; @@ -2153,11 +2153,11 @@ static void parse_postfix(Parser* p) { perr(p, "request for member in something that is not a struct or union"); } - if (p->cur.kind != TOK_IDENT || - ident_kw_inline(p, tok_ident(&p->cur)) != KW_NONE) { + if (p_cur(p)->kind != TOK_IDENT || + ident_kw_inline(p, tok_ident(p_cur(p))) != KW_NONE) { perr(p, "expected member name after '.'"); } - mname = tok_ident(&p->cur); + mname = tok_ident(p_cur(p)); advance(p); lt = type_unqual(p->pool, lt); if (!find_record_member_path(p, lt, mname, &mty, &off, &bf_off, &bf_w, @@ -2184,11 +2184,11 @@ static void parse_postfix(Parser* p) { if (!rec_ty || (rec_ty->kind != TY_STRUCT && rec_ty->kind != TY_UNION)) { perr(p, "'->' on pointer to non-struct/union"); } - if (p->cur.kind != TOK_IDENT || - ident_kw_inline(p, tok_ident(&p->cur)) != KW_NONE) { + if (p_cur(p)->kind != TOK_IDENT || + ident_kw_inline(p, tok_ident(p_cur(p))) != KW_NONE) { perr(p, "expected member name after '->'"); } - mname = tok_ident(&p->cur); + mname = tok_ident(p_cur(p)); advance(p); if (!find_record_member_path(p, rec_ty, mname, &mty, &off, &bf_off, &bf_w, &bf_ss)) @@ -2202,7 +2202,7 @@ static void parse_postfix(Parser* p) { } void parse_unary(Parser* p) { - Tok t = p->cur; + Tok t = *p_cur(p); if (is_punct(&t, '(')) { Tok n = peek1(p); if (starts_type_name(p, &n)) { @@ -2211,7 +2211,7 @@ void parse_unary(Parser* p) { advance(p); /* '(' */ dst = parse_type_name(p); expect_punct(p, ')', "')' after type-name"); - if (is_punct(&p->cur, '{')) { + if (is_punct(p_cur(p), '{')) { FrameSlotDesc fsd; FrameSlot slot; const Type* lit_ty = dst; @@ -2229,10 +2229,10 @@ void parse_unary(Parser* p) { c_cg_push_local_typed(p, slot, lit_ty); return; } - if (c_const_guard_active(p) && p->cur.kind == TOK_FLT) { + if (c_const_guard_active(p) && p_cur(p)->kind == TOK_FLT) { const Type* tu = type_unqual(p->pool, dst); if (tu && type_is_int(tu)) { - double fv = parse_float_literal(p, &p->cur); + double fv = parse_float_literal(p, p_cur(p)); advance(p); c_cg_push_int(p, (i64)fv, tu); return; @@ -2299,12 +2299,12 @@ void parse_unary(Parser* p) { p, pp_materialize_loc(p->pp, t.loc), "address constant is not an integer constant expression"); advance(p); /* '&&' */ - if (p->cur.kind != TOK_IDENT || - ident_kw_inline(p, tok_ident(&p->cur)) != KW_NONE) { + if (p_cur(p)->kind != TOK_IDENT || + ident_kw_inline(p, tok_ident(p_cur(p))) != KW_NONE) { perr(p, "expected label name after '&&'"); } - name = tok_ident(&p->cur); - loc = pp_materialize_loc(p->pp, p->cur.loc); + name = tok_ident(p_cur(p)); + loc = pp_materialize_loc(p->pp, p_cur(p)->loc); advance(p); c_cg_push_label_addr(p, take_label_addr(p, name, loc)); return; @@ -2361,7 +2361,7 @@ void parse_unary(Parser* p) { const Type* ty = NULL; FrameSlot vla_slot = FRAME_SLOT_NONE; advance(p); - if (is_punct(&p->cur, '(')) { + if (is_punct(p_cur(p), '(')) { Tok n = peek1(p); if (starts_type_name(p, &n)) { advance(p); @@ -2422,7 +2422,7 @@ void parse_unary(Parser* p) { for (;;) { const Type* assoc_ty = NULL; int is_default = 0; - if (is_kw(p, &p->cur, KW_DEFAULT)) { + if (is_kw(p, p_cur(p), KW_DEFAULT)) { advance(p); is_default = 1; if (saw_default) perr(p, "_Generic has duplicate default association"); @@ -2462,9 +2462,9 @@ void parse_unary(Parser* p) { Tok* buf = arena_array(p->pool->arena, Tok, cap); u32 len = 0; int paren_depth = 0, brack_depth = 0, brace_depth = 0; - while (p->cur.kind != TOK_EOF) { + while (p_cur(p)->kind != TOK_EOF) { if (paren_depth == 0 && brack_depth == 0 && brace_depth == 0) { - if (is_punct(&p->cur, ',') || is_punct(&p->cur, ')')) break; + if (is_punct(p_cur(p), ',') || is_punct(p_cur(p), ')')) break; } if (len == cap) { u32 new_cap = cap * 2; @@ -2474,18 +2474,18 @@ void parse_unary(Parser* p) { buf = nv; cap = new_cap; } - buf[len++] = p->cur; - if (is_punct(&p->cur, '(')) + buf[len++] = *p_cur(p); + if (is_punct(p_cur(p), '(')) ++paren_depth; - else if (is_punct(&p->cur, ')')) + else if (is_punct(p_cur(p), ')')) --paren_depth; - else if (is_punct(&p->cur, '[')) + else if (is_punct(p_cur(p), '[')) ++brack_depth; - else if (is_punct(&p->cur, ']')) + else if (is_punct(p_cur(p), ']')) --brack_depth; - else if (is_punct(&p->cur, '{')) + else if (is_punct(p_cur(p), '{')) ++brace_depth; - else if (is_punct(&p->cur, '}')) + else if (is_punct(p_cur(p), '}')) --brace_depth; advance(p); } @@ -2507,21 +2507,21 @@ void parse_unary(Parser* p) { int paren_depth = 0; int brack_depth = 0; int brace_depth = 0; - while (p->cur.kind != TOK_EOF) { + while (p_cur(p)->kind != TOK_EOF) { if (paren_depth == 0 && brack_depth == 0 && brace_depth == 0) { - if (is_punct(&p->cur, ',') || is_punct(&p->cur, ')')) break; + if (is_punct(p_cur(p), ',') || is_punct(p_cur(p), ')')) break; } - if (is_punct(&p->cur, '(')) + if (is_punct(p_cur(p), '(')) ++paren_depth; - else if (is_punct(&p->cur, ')')) + else if (is_punct(p_cur(p), ')')) --paren_depth; - else if (is_punct(&p->cur, '[')) + else if (is_punct(p_cur(p), '[')) ++brack_depth; - else if (is_punct(&p->cur, ']')) + else if (is_punct(p_cur(p), ']')) --brack_depth; - else if (is_punct(&p->cur, '{')) + else if (is_punct(p_cur(p), '{')) ++brace_depth; - else if (is_punct(&p->cur, '}')) + else if (is_punct(p_cur(p), '}')) --brace_depth; advance(p); } @@ -2529,20 +2529,18 @@ void parse_unary(Parser* p) { if (!accept_punct(p, ',')) break; } if (!emitted && default_buf) { + /* Whole-ring save/restore (POD) plus the replay quintuple; the + * replay-source switch resets the ring. */ + ParserInput save_input = p->input; Tok* save_replay = p->replay; u32 save_cap = p->replay_cap; u32 save_len = p->replay_len; u32 save_pos = p->replay_pos; u8 save_active = p->replay_active; - Tok save_cur = p->cur; - int save_has_next = p->has_next; p->replay = default_buf; p->replay_cap = default_len; p->replay_len = default_len; - p->replay_pos = 1; - p->replay_active = 1; - p->cur = default_buf[0]; - p->has_next = 0; + parser_replay_begin(p); parse_assign_expr(p); emitted = 1; p->replay = save_replay; @@ -2550,8 +2548,7 @@ void parse_unary(Parser* p) { p->replay_len = save_len; p->replay_pos = save_pos; p->replay_active = save_active; - p->cur = save_cur; - p->has_next = save_has_next; + p->input = save_input; } expect_punct(p, ')', "')' after _Generic"); if (!emitted) { @@ -2563,7 +2560,7 @@ void parse_unary(Parser* p) { const Type* ty; advance(p); expect_punct(p, '(', "'('"); - if (starts_type_name(p, &p->cur)) { + if (starts_type_name(p, p_cur(p))) { ty = parse_type_name(p); } else { c_const_guard_not_eval_push(p); @@ -2672,7 +2669,7 @@ static BinOp int_div_rem_binop(BinOp op, const Type* common) { static void parse_mul(Parser* p) { parse_unary(p); for (;;) { - Tok t = p->cur; + Tok t = *p_cur(p); SrcLoc op_loc; BinOp bop; if (is_punct(&t, '*')) { @@ -2788,7 +2785,7 @@ static void emit_add_or_sub(Parser* p, BinOp bop) { static void parse_add(Parser* p) { parse_mul(p); for (;;) { - Tok t = p->cur; + Tok t = *p_cur(p); BinOp bop; if (is_punct(&t, '+')) { bop = BO_IADD; @@ -2808,7 +2805,7 @@ static void parse_add(Parser* p) { static void parse_shift(Parser* p) { parse_add(p); for (;;) { - Tok t = p->cur; + Tok t = *p_cur(p); SrcLoc op_loc; BinOp bop; if (is_punct(&t, P_SHL)) { @@ -2847,7 +2844,7 @@ static void parse_shift(Parser* p) { static void parse_rel(Parser* p) { parse_shift(p); for (;;) { - Tok t = p->cur; + Tok t = *p_cur(p); CmpOp cop; if (is_punct(&t, '<')) { cop = CMP_LT_S; @@ -2908,7 +2905,7 @@ static void parse_rel(Parser* p) { static void parse_eq(Parser* p) { parse_rel(p); for (;;) { - Tok t = p->cur; + Tok t = *p_cur(p); CmpOp cop; if (is_punct(&t, P_EQ)) { cop = CMP_EQ; @@ -2951,7 +2948,7 @@ static void parse_eq(Parser* p) { static void parse_band(Parser* p) { parse_eq(p); - while (is_punct(&p->cur, '&')) { + while (is_punct(p_cur(p), '&')) { advance(p); to_rvalue(p); parse_eq(p); @@ -2967,7 +2964,7 @@ static void parse_band(Parser* p) { static void parse_bxor(Parser* p) { parse_band(p); - while (is_punct(&p->cur, '^')) { + while (is_punct(p_cur(p), '^')) { advance(p); to_rvalue(p); parse_band(p); @@ -2983,7 +2980,7 @@ static void parse_bxor(Parser* p) { static void parse_bor(Parser* p) { parse_bxor(p); - while (is_punct(&p->cur, '|')) { + while (is_punct(p_cur(p), '|')) { advance(p); to_rvalue(p); parse_bxor(p); @@ -3016,7 +3013,7 @@ static void ll_store_const(Parser* p, FrameSlot tmp, const Type* ty, i64 v) { static void parse_land(Parser* p) { parse_bor(p); - while (is_punct(&p->cur, P_AND)) { + while (is_punct(p_cur(p), P_AND)) { CGLabel L_false = c_cg_label_new(p); CGLabel L_end = c_cg_label_new(p); const Type* result_ty = ty_int(p); @@ -3062,7 +3059,7 @@ static void parse_land(Parser* p) { static void parse_lor(Parser* p) { parse_land(p); - while (is_punct(&p->cur, P_OR)) { + while (is_punct(p_cur(p), P_OR)) { CGLabel L_true = c_cg_label_new(p); CGLabel L_end = c_cg_label_new(p); const Type* result_ty = ty_int(p); @@ -3108,7 +3105,7 @@ static void parse_lor(Parser* p) { static void parse_ternary(Parser* p) { parse_lor(p); - if (!is_punct(&p->cur, '?')) return; + if (!is_punct(p_cur(p), '?')) return; CGLabel L_else = c_cg_label_new(p); CGLabel L_then = c_cg_label_new(p); CGLabel L_end = c_cg_label_new(p); @@ -3246,7 +3243,7 @@ static void parse_ternary(Parser* p) { void parse_assign_expr(Parser* p) { parse_ternary(p); - Tok t = p->cur; + Tok t = *p_cur(p); SrcLoc op_loc = pp_materialize_loc(p->pp, t.loc); BinOp compound; int is_simple_assign; @@ -3381,7 +3378,7 @@ void parse_assign_expr(Parser* p) { void parse_expr(Parser* p) { parse_assign_expr(p); - while (is_punct(&p->cur, ',')) { + while (is_punct(p_cur(p), ',')) { c_const_guard_note(p, "comma operator in integer constant expression"); advance(p); c_cg_drop(p); diff --git a/lang/c/parse/parse_init.c b/lang/c/parse/parse_init.c @@ -35,11 +35,11 @@ int is_char_kind(const Type* ty) { return ty->kind == TY_CHAR || ty->kind == TY_SCHAR || ty->kind == TY_UCHAR; } -/* Decode the string token at p->cur without advancing. Returns a heap- +/* Decode the current string token without advancing. Returns a heap- * allocated byte buffer (caller frees) and writes length (including NUL) * to *nlen_out. */ static u8* peek_string_bytes(Parser* p, size_t* nlen_out) { - Tok t = p->cur; + Tok t = *p_cur(p); if (t.kind != TOK_STR) perr(p, "internal: peek_string_bytes on non-string"); return decode_string_literal(p, &t, nlen_out); } @@ -73,10 +73,7 @@ static void init_aggregate_remainder(Parser* p, FrameSlot slot, static void replay_recorded_initializer_expr(Parser* p) { if (p->replay_len == 0) perr(p, "internal: empty initializer expression replay"); - p->cur = p->replay[0]; - p->replay_pos = 1; - p->replay_active = 1; - p->has_next = 0; + parser_replay_begin(p); } static void record_initializer_expr_for_replay(Parser* p) { @@ -96,25 +93,25 @@ static void record_initializer_expr_for_replay(Parser* p) { buf = nb; cap = new_cap; } - buf[len++] = p->cur; + buf[len++] = *p_cur(p); - if (p->cur.kind == TOK_EOF) break; + if (p_cur(p)->kind == TOK_EOF) break; if (paren_depth == 0 && brack_depth == 0 && brace_depth == 0 && - (is_punct(&p->cur, ',') || is_punct(&p->cur, '}'))) { + (is_punct(p_cur(p), ',') || is_punct(p_cur(p), '}'))) { break; } - if (is_punct(&p->cur, '(')) + if (is_punct(p_cur(p), '(')) ++paren_depth; - else if (is_punct(&p->cur, ')')) + else if (is_punct(p_cur(p), ')')) --paren_depth; - else if (is_punct(&p->cur, '[')) + else if (is_punct(p_cur(p), '[')) ++brack_depth; - else if (is_punct(&p->cur, ']')) + else if (is_punct(p_cur(p), ']')) --brack_depth; - else if (is_punct(&p->cur, '{')) + else if (is_punct(p_cur(p), '{')) ++brace_depth; - else if (is_punct(&p->cur, '}')) + else if (is_punct(p_cur(p), '}')) --brace_depth; advance(p); @@ -134,8 +131,8 @@ static int try_init_aggregate_from_expr(Parser* p, FrameSlot slot, int compatible; if (!ty || (ty->kind != TY_STRUCT && ty->kind != TY_UNION)) return 0; - if (is_punct(&p->cur, '{') || is_punct(&p->cur, '.') || - is_punct(&p->cur, '[')) { + if (is_punct(p_cur(p), '{') || is_punct(p_cur(p), '.') || + is_punct(p_cur(p), '[')) { return 0; } @@ -380,10 +377,10 @@ static void parse_designator_chain(Parser* p, const Type* outer_ty, InitDesignatorCont cont; memset(&cont, 0, sizeof cont); for (;;) { - if (is_punct(&p->cur, '[')) { + if (is_punct(p_cur(p), '[')) { i64 idx; u32 esz; - SrcLoc cloc = tok_loc_init(p, &p->cur); + SrcLoc cloc = tok_loc_init(p, p_cur(p)); const Type* parent_ty = cur_ty; u32 parent_off = cur_off; advance(p); @@ -403,7 +400,7 @@ static void parse_designator_chain(Parser* p, const Type* outer_ty, cont.next_index = (u32)idx + 1u; if (first) *top_index_out = (u32)idx; first = 0; - } else if (is_punct(&p->cur, '.')) { + } else if (is_punct(p_cur(p), '.')) { Sym fname; const Type* fty; u32 foff; @@ -414,11 +411,11 @@ static void parse_designator_chain(Parser* p, const Type* outer_ty, const Type* parent_ty = cur_ty; u32 parent_off = cur_off; advance(p); - if (p->cur.kind != TOK_IDENT || - ident_kw_inline(p, tok_ident(&p->cur)) != KW_NONE) { + if (p_cur(p)->kind != TOK_IDENT || + ident_kw_inline(p, tok_ident(p_cur(p))) != KW_NONE) { perr(p, "expected field name after '.'"); } - fname = tok_ident(&p->cur); + fname = tok_ident(p_cur(p)); advance(p); if (!cur_ty || (cur_ty->kind != TY_STRUCT && cur_ty->kind != TY_UNION)) { perr(p, "field designator on non-record type"); @@ -504,11 +501,11 @@ static u32 init_struct_fields(Parser* p, FrameSlot slot, const Type* arr_ty, * count) terminates it. */ for (;;) { if (braced) { - if (is_punct(&p->cur, '}') || p->cur.kind == TOK_EOF) break; + if (is_punct(p_cur(p), '}') || p_cur(p)->kind == TOK_EOF) break; } else if (i >= ty->rec.nfields) { break; } - if (braced && is_punct(&p->cur, '.')) { + if (braced && is_punct(p_cur(p), '.')) { const Type* sub_ty; u32 sub_off; u32 top_idx = 0; @@ -534,7 +531,7 @@ static u32 init_struct_fields(Parser* p, FrameSlot slot, const Type* arr_ty, u32 top_off = offset + L->fields[top_idx].offset; if (designator_continues_inside(p, ty, offset, top_f->type, top_off, &cont) && - accept_punct(p, ',') && !is_punct(&p->cur, '}')) { + accept_punct(p, ',') && !is_punct(p_cur(p), '}')) { init_aggregate_remainder(p, slot, arr_ty, cont.parent_offset, cont.parent_ty, cont.next_index); } @@ -559,7 +556,7 @@ static u32 init_struct_fields(Parser* p, FrameSlot slot, const Type* arr_ty, ++i; break; } - if (is_punct(&p->cur, '}')) { + if (is_punct(p_cur(p), '}')) { ++i; break; } @@ -594,7 +591,7 @@ static void init_aggregate_remainder(Parser* p, FrameSlot slot, init_at(p, slot, arr_ty, offset + i * esz, ty->arr.elem); if (i + 1u >= ty->arr.count) return; if (!accept_punct(p, ',')) break; - if (is_punct(&p->cur, '}')) break; + if (is_punct(p_cur(p), '}')) break; } for (++i; i < ty->arr.count; ++i) { zero_init_at(p, slot, arr_ty, offset + i * esz, ty->arr.elem); @@ -608,7 +605,7 @@ static void init_aggregate_remainder(Parser* p, FrameSlot slot, init_field_at(p, slot, arr_ty, offset, ty, i); if (i + 1u >= ty->rec.nfields) return; if (!accept_punct(p, ',')) break; - if (is_punct(&p->cur, '}')) break; + if (is_punct(p_cur(p), '}')) break; } for (++i; i < ty->rec.nfields; ++i) { const Field* f = &ty->rec.fields[i]; @@ -634,12 +631,12 @@ void init_at(Parser* p, FrameSlot slot, const Type* arr_ty, u32 offset, if (ty->kind == TY_ARRAY) { const Type* elem_ty = ty->arr.elem; u32 esz = c_abi_sizeof(p->abi, p->pool, elem_ty); - if (p->cur.kind == TOK_STR && - string_literal_initializes_array(p, elem_ty, &p->cur)) { + if (p_cur(p)->kind == TOK_STR && + string_literal_initializes_array(p, elem_ty, p_cur(p))) { init_string_at(p, slot, arr_ty, offset, elem_ty, ty->arr.count); return; } - if (is_punct(&p->cur, '{') && peek1(p).kind == TOK_STR) { + if (is_punct(p_cur(p), '{') && peek1(p).kind == TOK_STR) { Tok str = peek1(p); if (string_literal_initializes_array(p, elem_ty, &str)) { advance(p); @@ -649,7 +646,7 @@ void init_at(Parser* p, FrameSlot slot, const Type* arr_ty, u32 offset, return; } } - if (!is_punct(&p->cur, '{')) { + if (!is_punct(p_cur(p), '{')) { init_aggregate_remainder(p, slot, arr_ty, offset, ty, 0); return; } @@ -657,9 +654,9 @@ void init_at(Parser* p, FrameSlot slot, const Type* arr_ty, u32 offset, { u32 i = 0; u32 zero_lo = 0; - if (!is_punct(&p->cur, '}')) { + if (!is_punct(p_cur(p), '}')) { for (;;) { - if (is_punct(&p->cur, '[')) { + if (is_punct(p_cur(p), '[')) { const Type* sub_ty; u32 sub_off; u32 top_idx = 0; @@ -673,7 +670,7 @@ void init_at(Parser* p, FrameSlot slot, const Type* arr_ty, u32 offset, init_at(p, slot, arr_ty, sub_off, sub_ty); if (designator_continues_inside(p, ty, offset, elem_ty, offset + top_idx * esz, &cont) && - accept_punct(p, ',') && !is_punct(&p->cur, '}')) { + accept_punct(p, ',') && !is_punct(p_cur(p), '}')) { init_aggregate_remainder(p, slot, arr_ty, cont.parent_offset, cont.parent_ty, cont.next_index); } @@ -688,7 +685,7 @@ void init_at(Parser* p, FrameSlot slot, const Type* arr_ty, u32 offset, if (zero_lo < i) zero_lo = i; } if (!accept_punct(p, ',')) break; - if (is_punct(&p->cur, '}')) break; + if (is_punct(p_cur(p), '}')) break; } } expect_punct(p, '}', "'}' after array initializer"); @@ -702,7 +699,7 @@ void init_at(Parser* p, FrameSlot slot, const Type* arr_ty, u32 offset, return; } if (ty->kind == TY_STRUCT) { - if (!is_punct(&p->cur, '{')) { + if (!is_punct(p_cur(p), '{')) { if (try_init_aggregate_from_expr(p, slot, arr_ty, offset, ty)) return; init_aggregate_remainder(p, slot, arr_ty, offset, ty, 0); return; @@ -723,7 +720,7 @@ void init_at(Parser* p, FrameSlot slot, const Type* arr_ty, u32 offset, if (had_brace) expect_punct(p, '}', "'}'"); return; } - if (had_brace && is_punct(&p->cur, '.')) { + if (had_brace && is_punct(p_cur(p), '.')) { const Type* sub_ty; u32 sub_off; u32 top_idx = 0; @@ -847,13 +844,13 @@ static double parse_static_float_primary(Parser* p) { expect_punct(p, ')', "')' in floating constant expression"); return v; } - if (p->cur.kind == TOK_FLT) { - v = parse_float_literal(p, &p->cur); + if (p_cur(p)->kind == TOK_FLT) { + v = parse_float_literal(p, p_cur(p)); advance(p); return v; } - if (p->cur.kind == TOK_NUM) { - v = (double)parse_int_literal(p, &p->cur); + if (p_cur(p)->kind == TOK_NUM) { + v = (double)parse_int_literal(p, p_cur(p)); advance(p); return v; } @@ -1065,7 +1062,7 @@ static CStaticConst parse_static_compound_literal_after_type(Parser* p, SrcLoc loc) { CStaticConst r; memset(&r, 0, sizeof r); - if (!is_punct(&p->cur, '{')) { + if (!is_punct(p_cur(p), '{')) { perr(p, "expected compound literal initializer in static initializer"); } r.kind = C_STATIC_CONST_ADDR; @@ -1120,7 +1117,7 @@ static void check_static_integer_initializer_range(Parser* p, const Type* ty, } static CConstInt parse_null_pointer_constant(Parser* p, SrcLoc loc) { - if (is_punct(&p->cur, '(')) { + if (is_punct(p_cur(p), '(')) { Tok n = peek1(p); if (starts_type_name(p, &n)) { const Type* cast_ty; @@ -1151,7 +1148,7 @@ static CConstInt parse_null_pointer_constant(Parser* p, SrcLoc loc) { /* Try to parse the current expression as a static initializer address * constant. Leaves non-address expressions untouched. */ static int try_parse_static_address_const(Parser* p, CStaticConst* out) { - Tok t = p->cur; + Tok t = *p_cur(p); Sym name = 0; int saw_amp = 0; i64 element_addend = 0; @@ -1175,7 +1172,7 @@ static int try_parse_static_address_const(Parser* p, CStaticConst* out) { if (is_punct(&t, '&')) { saw_amp = 1; advance(p); - if (is_punct(&p->cur, '(')) { + if (is_punct(p_cur(p), '(')) { Tok n = peek1(p); if (starts_type_name(p, &n)) { const Type* lit_ty; @@ -1187,11 +1184,11 @@ static int try_parse_static_address_const(Parser* p, CStaticConst* out) { return 1; } } - if (p->cur.kind != TOK_IDENT || - ident_kw_inline(p, tok_ident(&p->cur)) != KW_NONE) { + if (p_cur(p)->kind != TOK_IDENT || + ident_kw_inline(p, tok_ident(p_cur(p))) != KW_NONE) { perr(p, "expected identifier after '&' in static initializer"); } - name = tok_ident(&p->cur); + name = tok_ident(p_cur(p)); advance(p); } else if (t.kind == TOK_IDENT && ident_kw_inline(p, tok_ident(&t)) == KW_NONE) { @@ -1206,10 +1203,10 @@ static int try_parse_static_address_const(Parser* p, CStaticConst* out) { } tgt = e->v.sym; tgt_ty = e->type; - if (saw_amp && is_punct(&p->cur, '[')) { + if (saw_amp && is_punct(p_cur(p), '[')) { SrcLoc cloc; advance(p); - cloc = tok_loc_init(p, &p->cur); + cloc = tok_loc_init(p, p_cur(p)); element_addend = eval_const_int(p, cloc); expect_punct(p, ']', "']' after array-subscript constant"); if (tgt_ty && tgt_ty->kind == TY_ARRAY) { @@ -1219,12 +1216,12 @@ static int try_parse_static_address_const(Parser* p, CStaticConst* out) { byte_addend += element_addend; } } - while (is_punct(&p->cur, '+') || is_punct(&p->cur, '-')) { - int neg = is_punct(&p->cur, '-'); + while (is_punct(p_cur(p), '+') || is_punct(p_cur(p), '-')) { + int neg = is_punct(p_cur(p), '-'); SrcLoc cloc; i64 v; advance(p); - cloc = tok_loc_init(p, &p->cur); + cloc = tok_loc_init(p, p_cur(p)); v = eval_const_int(p, cloc); if (neg) v = -v; if (tgt_ty && tgt_ty->kind == TY_ARRAY) { @@ -1249,25 +1246,25 @@ static CStaticConst parse_static_const(Parser* p, const Type* ty, SrcLoc loc) { memset(&r, 0, sizeof r); r.kind = C_STATIC_CONST_INT; if (ty && ty->kind == TY_PTR) { - if (is_punct(&p->cur, P_AND)) { + if (is_punct(p_cur(p), P_AND)) { /* GNU labels-as-values: `&&label` in a static pointer initializer, * e.g. a direct-threaded dispatch table `static void *tab[] = {...}`. */ Sym lname; SrcLoc lloc; advance(p); /* '&&' */ - if (p->cur.kind != TOK_IDENT || - ident_kw_inline(p, tok_ident(&p->cur)) != KW_NONE) { + if (p_cur(p)->kind != TOK_IDENT || + ident_kw_inline(p, tok_ident(p_cur(p))) != KW_NONE) { perr(p, "expected label name after '&&' in static initializer"); } - lname = tok_ident(&p->cur); - lloc = tok_loc_init(p, &p->cur); + lname = tok_ident(p_cur(p)); + lloc = tok_loc_init(p, p_cur(p)); advance(p); r.kind = C_STATIC_CONST_LABEL_ADDR; r.label = take_label_addr(p, lname, lloc); r.addend = 0; return r; } - if (is_punct(&p->cur, '(')) { + if (is_punct(p_cur(p), '(')) { Tok n = peek1(p); /* Grouping parens around the pointer initializer, e.g. `("str")`, * `(&x)`, or `((expr))`. A `(type-name)` is a cast or compound literal @@ -1280,7 +1277,7 @@ static CStaticConst parse_static_const(Parser* p, const Type* ty, SrcLoc loc) { return r; } } - if (is_punct(&p->cur, '(')) { + if (is_punct(p_cur(p), '(')) { Tok n = peek1(p); if (starts_type_name(p, &n)) { const Type* cast_ty; @@ -1289,7 +1286,7 @@ static CStaticConst parse_static_const(Parser* p, const Type* ty, SrcLoc loc) { cast_ty = parse_type_name(p); cast_unqual = type_unqual(p->pool, cast_ty); expect_punct(p, ')', "')' after cast or compound literal type-name"); - if (is_punct(&p->cur, '{')) { + if (is_punct(p_cur(p), '{')) { const Type* lit_unqual = type_unqual(p->pool, cast_ty); if (!lit_unqual || lit_unqual->kind != TY_ARRAY) { perr(p, @@ -1303,9 +1300,9 @@ static CStaticConst parse_static_const(Parser* p, const Type* ty, SrcLoc loc) { perr(p, "invalid cast in null pointer constant"); } if (cast_unqual->kind == TY_PTR && - (p->cur.kind == TOK_STR || is_punct(&p->cur, '&') || - (p->cur.kind == TOK_IDENT && - ident_kw_inline(p, tok_ident(&p->cur)) == KW_NONE)) && + (p_cur(p)->kind == TOK_STR || is_punct(p_cur(p), '&') || + (p_cur(p)->kind == TOK_IDENT && + ident_kw_inline(p, tok_ident(p_cur(p))) == KW_NONE)) && try_parse_static_address_const(p, &r)) { return r; } @@ -1338,7 +1335,7 @@ static CStaticConst parse_static_const(Parser* p, const Type* ty, SrcLoc loc) { static void parse_static_bitfield_at(Parser* p, u8* buf, u32 buflen, u32 rec_offset, const ABIFieldLayout* fl, const Type* field_ty) { - SrcLoc cloc = tok_loc_init(p, &p->cur); + SrcLoc cloc = tok_loc_init(p, p_cur(p)); CStaticConst parsed = parse_static_const(p, field_ty, cloc); u32 storage_off = rec_offset + fl->offset; u32 storage_size = fl->storage_size; @@ -1374,7 +1371,7 @@ static void parse_static_aggregate_remainder(Parser* p, u8* buf, u32 buflen, parse_static_init_at(p, buf, buflen, offset + i * esz, elem); if (i + 1u >= ty->arr.count) return; if (!accept_punct(p, ',')) break; - if (is_punct(&p->cur, '}')) break; + if (is_punct(p_cur(p), '}')) break; } return; } @@ -1395,7 +1392,7 @@ static void parse_static_aggregate_remainder(Parser* p, u8* buf, u32 buflen, } if (i + 1u >= ty->rec.nfields) return; if (!accept_punct(p, ',')) break; - if (is_punct(&p->cur, '}')) break; + if (is_punct(p_cur(p), '}')) break; } return; } @@ -1412,7 +1409,7 @@ void parse_static_init_at(Parser* p, u8* buf, u32 buflen, u32 offset, * own handling (parse_static_const / eval_const), where a compound literal * can instead yield an address or value. */ if ((ty->kind == TY_STRUCT || ty->kind == TY_UNION || ty->kind == TY_ARRAY) && - is_punct(&p->cur, '(')) { + is_punct(p_cur(p), '(')) { Tok n = peek1(p); if (starts_type_name(p, &n)) { advance(p); @@ -1430,12 +1427,12 @@ void parse_static_init_at(Parser* p, u8* buf, u32 buflen, u32 offset, u32 esz = c_abi_sizeof(p->abi, p->pool, elem); u32 i = 0; int had_brace; - if (p->cur.kind == TOK_STR && - string_literal_initializes_array(p, elem, &p->cur)) { + if (p_cur(p)->kind == TOK_STR && + string_literal_initializes_array(p, elem, p_cur(p))) { parse_static_string_at(p, buf, buflen, offset, elem, ty->arr.count); return; } - if (is_punct(&p->cur, '{') && peek1(p).kind == TOK_STR) { + if (is_punct(p_cur(p), '{') && peek1(p).kind == TOK_STR) { Tok str = peek1(p); if (string_literal_initializes_array(p, elem, &str)) { advance(p); @@ -1450,9 +1447,9 @@ void parse_static_init_at(Parser* p, u8* buf, u32 buflen, u32 offset, parse_static_aggregate_remainder(p, buf, buflen, offset, ty, 0); return; } - if (!is_punct(&p->cur, '}')) { + if (!is_punct(p_cur(p), '}')) { for (;;) { - if (is_punct(&p->cur, '[')) { + if (is_punct(p_cur(p), '[')) { const Type* sub_ty; u32 sub_off; u32 top_idx = 0; @@ -1462,7 +1459,7 @@ void parse_static_init_at(Parser* p, u8* buf, u32 buflen, u32 offset, parse_static_init_at(p, buf, buflen, sub_off, sub_ty); if (designator_continues_inside(p, ty, offset, elem, offset + top_idx * esz, &cont) && - accept_punct(p, ',') && !is_punct(&p->cur, '}')) { + accept_punct(p, ',') && !is_punct(p_cur(p), '}')) { parse_static_aggregate_remainder(p, buf, buflen, cont.parent_offset, cont.parent_ty, cont.next_index); } @@ -1475,7 +1472,7 @@ void parse_static_init_at(Parser* p, u8* buf, u32 buflen, u32 offset, ++i; } if (!accept_punct(p, ',')) break; - if (is_punct(&p->cur, '}')) break; + if (is_punct(p_cur(p), '}')) break; } } expect_punct(p, '}', "'}' after array initializer"); @@ -1492,9 +1489,9 @@ void parse_static_init_at(Parser* p, u8* buf, u32 buflen, u32 offset, /* Designators may re-target any field regardless of the running position * `i`, so the loop is bounded by '}'/EOF; `i` only drives positional * placement (and is range-checked before use). */ - while (!is_punct(&p->cur, '}') && p->cur.kind != TOK_EOF) { + while (!is_punct(p_cur(p), '}') && p_cur(p)->kind != TOK_EOF) { const Field* f; - if (is_punct(&p->cur, '.')) { + if (is_punct(p_cur(p), '.')) { const Type* sub_ty; u32 sub_off; u32 top_idx = 0; @@ -1507,7 +1504,7 @@ void parse_static_init_at(Parser* p, u8* buf, u32 buflen, u32 offset, u32 top_off = offset + L->fields[top_idx].offset; if (designator_continues_inside(p, ty, offset, top_f->type, top_off, &cont) && - accept_punct(p, ',') && !is_punct(&p->cur, '}')) { + accept_punct(p, ',') && !is_punct(p_cur(p), '}')) { parse_static_aggregate_remainder(p, buf, buflen, cont.parent_offset, cont.parent_ty, cont.next_index); } @@ -1540,7 +1537,7 @@ void parse_static_init_at(Parser* p, u8* buf, u32 buflen, u32 offset, if (had_brace) expect_punct(p, '}', "'}' after union initializer"); return; } - if (had_brace && is_punct(&p->cur, '.')) { + if (had_brace && is_punct(p_cur(p), '.')) { const Type* sub_ty; u32 sub_off; u32 top_idx = 0; @@ -1566,7 +1563,7 @@ void parse_static_init_at(Parser* p, u8* buf, u32 buflen, u32 offset, /* Scalar / pointer. */ { int had_brace = accept_punct(p, '{'); - SrcLoc cloc = tok_loc_init(p, &p->cur); + SrcLoc cloc = tok_loc_init(p, p_cur(p)); u32 sz = c_abi_sizeof(p->abi, p->pool, ty); CStaticConst cv; if (offset + sz > buflen) perr(p, "initializer overflows object"); diff --git a/lang/c/parse/parse_priv.h b/lang/c/parse/parse_priv.h @@ -234,6 +234,37 @@ struct GotoLabel { }; /* ============================================================ + * Parser input ring + * ============================================================ */ + +/* The parser consumes pp output through a fixed 3-cell ring (see + * doc/plan/FRONTEND-SHAPE.md "Parser Input Ring"). cells[cur] is the current + * token (depth 0); the two trailing slots provide LL(2) lookahead headroom. The + * C parser is strictly LL(1) today (only depths 0/1 are read), so the depth-2 + * slot stays unfilled until something calls parser_peek(p, 2). No VLAs: the + * lookahead window is fixed; variable replay uses the parser arena. Cells are + * always lexeme view. */ +typedef struct ParserInput { + CFeCell cells[3]; /* fixed cur + LL(2) lookahead ring; no VLA */ + u8 cur; /* index of the current token in cells[] */ + u8 nvalid; /* number of valid slots from cur, 0..3 */ + CFeCell pending; /* string-literal fusion / one-token pushback */ + u8 has_pending; +} ParserInput; + +/* Ring accessors. parser_ring_idx maps a depth (0 == current) to a physical + * slot; parser_cur borrows the current cell. */ +static inline u8 parser_ring_idx(const ParserInput* in, u32 d) { + return (u8)((in->cur + d) % 3u); +} +static inline CFeCell* parser_cur(ParserInput* in) { + return &in->cells[in->cur]; +} +static inline const CFeCell* parser_cur_const(const ParserInput* in) { + return &in->cells[in->cur]; +} + +/* ============================================================ * Parser context * ============================================================ */ @@ -247,12 +278,7 @@ typedef struct Parser { u8 default_visibility; /* SymVis */ u8 auto_var_init; /* KitAutoVarInit: implicit init for uninit locals */ - Tok cur; - Tok next; - int has_next; - - Tok pending; - int has_pending; + ParserInput input; Sym kw_sym[KW_COUNT]; KwTab kw_map; /* keyword/alias Sym -> CKw; built once, see ident_kw_inline */ @@ -406,6 +432,13 @@ typedef struct Parser { u32 static_relocs_cap; } Parser; +/* Borrowed pointer to the current token cell (depth 0). Valid until the next + * advance or replay-source switch. */ +static inline CFeCell* p_cur(Parser* p) { return parser_cur(&p->input); } +static inline const CFeCell* p_cur_const(const Parser* p) { + return parser_cur_const(&p->input); +} + /* ============================================================ * DeclSpecs and TypeSpecAccum * ============================================================ */ @@ -443,6 +476,13 @@ typedef struct TypeSpecAccum { * ============================================================ */ _Noreturn void perr(Parser* p, const char* fmt, ...); + +void parser_advance(Parser* p); +void parser_fill_to(Parser* p, u32 depth); /* cold path: fills through depth */ +/* Borrowed pointer to the cell at lookahead `depth` (0 == current); LL(2) + * headroom. Valid until the next advance or replay-source switch. */ +const CFeCell* parser_peek(Parser* p, u32 depth); + void advance(Parser* p); Tok peek1(Parser* p); void expect_punct(Parser* p, u32 punct, const char* what); @@ -650,4 +690,7 @@ FrameSlot make_local_aligned(Parser* p, Sym name, const Type* type, SrcLoc loc, Sym mint_static_local_sym(Parser* p, Sym orig); void record_braced_block(Parser* p); void replay_rewind(Parser* p); +/* Switch the input source to the parser's replay buffer (replay[0..]); resets + * the ring. Caller sets replay/replay_cap/replay_len first. */ +void parser_replay_begin(Parser* p); u32 count_recorded_top_level_items(const Tok* vec, u32 len); diff --git a/lang/c/parse/parse_stmt.c b/lang/c/parse/parse_stmt.c @@ -16,7 +16,7 @@ static SrcLoc tok_loc_stmt(Parser* p, const Tok* t) { } static int accept_kw_stmt(Parser* p, CKw k) { - if (!is_kw(p, &p->cur, k)) return 0; + if (!is_kw(p, p_cur(p), k)) return 0; advance(p); return 1; } @@ -143,7 +143,7 @@ static void parse_for_stmt(Parser* p) { } c_cg_label_place(p, L_top); - if (!is_punct(&p->cur, ';')) { + if (!is_punct(p_cur(p), ';')) { parse_expr(p); to_rvalue(p); if (!c_type_is_scalar(c_cg_top_type(p))) { @@ -157,7 +157,7 @@ static void parse_for_stmt(Parser* p) { CGLabel L_body = c_cg_label_new(p); c_cg_jump(p, L_body); c_cg_label_place(p, L_step); - if (!is_punct(&p->cur, ')')) { + if (!is_punct(p_cur(p), ')')) { parse_expr(p); c_cg_drop(p); } @@ -230,7 +230,7 @@ static void parse_do_stmt(Parser* p) { p->cur_break = saved_break; p->cur_continue = saved_continue; c_cg_label_place(p, L_cond); - if (!is_kw(p, &p->cur, KW_WHILE)) perr(p, "expected 'while' after do-body"); + if (!is_kw(p, p_cur(p), KW_WHILE)) perr(p, "expected 'while' after do-body"); advance(p); /* while */ expect_punct(p, '(', "'('"); parse_expr(p); @@ -320,16 +320,16 @@ static void parse_goto_stmt(Parser* p) { Sym name; SrcLoc loc; GotoLabel* gl; - if (is_punct(&p->cur, '*')) { + if (is_punct(p_cur(p), '*')) { parse_computed_goto(p); return; } - if (p->cur.kind != TOK_IDENT || - ident_kw_inline(p, tok_ident(&p->cur)) != KW_NONE) { + if (p_cur(p)->kind != TOK_IDENT || + ident_kw_inline(p, tok_ident(p_cur(p))) != KW_NONE) { perr(p, "expected label name after 'goto'"); } - name = tok_ident(&p->cur); - loc = tok_loc_stmt(p, &p->cur); + name = tok_ident(p_cur(p)); + loc = tok_loc_stmt(p, p_cur(p)); advance(p); expect_punct(p, ';', "';' after goto"); gl = label_get_or_create(p, name, loc); @@ -344,8 +344,8 @@ static void parse_goto_stmt(Parser* p) { } static void parse_label_stmt(Parser* p) { - Sym name = tok_ident(&p->cur); - SrcLoc loc = tok_loc_stmt(p, &p->cur); + Sym name = tok_ident(p_cur(p)); + SrcLoc loc = tok_loc_stmt(p, p_cur(p)); GotoLabel* gl; advance(p); /* IDENT */ advance(p); /* ':' */ @@ -364,7 +364,7 @@ static void parse_case_stmt(Parser* p) { i64 v; CGLabel L; CaseEntry* ce; - SrcLoc loc = tok_loc_stmt(p, &p->cur); + SrcLoc loc = tok_loc_stmt(p, p_cur(p)); if (!p->cur_switch) perr(p, "'case' label not in switch statement"); v = eval_const_int(p, loc); for (ce = p->cur_switch->cases; ce; ce = ce->next) { @@ -533,19 +533,19 @@ static void parse_switch_stmt(Parser* p) { } void parse_static_assert(Parser* p) { - SrcLoc loc = tok_loc_stmt(p, &p->cur); + SrcLoc loc = tok_loc_stmt(p, p_cur(p)); i64 v; if (!accept_kw_stmt(p, KW_STATIC_ASSERT)) { perr(p, "expected _Static_assert"); } expect_punct(p, '(', "'(' after _Static_assert"); - v = eval_const_int(p, tok_loc_stmt(p, &p->cur)); + v = eval_const_int(p, tok_loc_stmt(p, p_cur(p))); expect_punct(p, ',', "',' separating _Static_assert args"); - if (p->cur.kind != TOK_STR) { + if (p_cur(p)->kind != TOK_STR) { perr(p, "expected string literal as _Static_assert message"); } { - Tok msg = p->cur; + Tok msg = *p_cur(p); advance(p); expect_punct(p, ')', "')' after _Static_assert"); expect_punct(p, ';', "';' after _Static_assert"); @@ -587,12 +587,12 @@ static void asm_out_value_push(Parser* p, const AsmOutLValue* lv) { static Sym parse_asm_operand_name(Parser* p) { Sym name = 0; - if (!is_punct(&p->cur, '[')) return 0; + if (!is_punct(p_cur(p), '[')) return 0; advance(p); - if (p->cur.kind != TOK_IDENT) { + if (p_cur(p)->kind != TOK_IDENT) { perr(p, "expected identifier inside '[name]' on asm operand"); } - name = tok_ident(&p->cur); + name = tok_ident(p_cur(p)); advance(p); expect_punct(p, ']', "']' after asm operand name"); return name; @@ -603,11 +603,11 @@ static const char* parse_asm_str(Parser* p, const char* what) { size_t nlen = 0; Sym s; Tok t; - if (p->cur.kind != TOK_STR) { + if (p_cur(p)->kind != TOK_STR) { perr(p, "expected string literal in %.*s", KIT_SLICE_ARG(kit_slice_cstr(what))); } - t = p->cur; + t = *p_cur(p); advance(p); bytes = decode_string_literal(p, &t, &nlen); if (nlen > 0) nlen -= 1; @@ -620,7 +620,7 @@ static const char* parse_asm_str(Parser* p, const char* what) { /* GNU local register variables: when an asm operand is exactly a bare reference * to a `register T x __asm__("reg")` local, return that register name (else 0). - * Called with p->cur positioned at the first token of the operand expression, + * Called with the current token positioned at the first token of the operand expression, * so it only peeks — it must not consume. The operand has to be a lone * identifier (the canonical idiom); anything more complex is not a * hard-register operand under GCC's rules either. The name is carried opaquely @@ -630,10 +630,10 @@ static const char* parse_asm_str(Parser* p, const char* what) { static Sym asm_operand_pinned_reg(Parser* p, FrameSlot* slot_out) { Tok nxt; SymEntry* e; - if (p->cur.kind != TOK_IDENT) return 0; + if (p_cur(p)->kind != TOK_IDENT) return 0; nxt = peek1(p); if (!is_punct(&nxt, ')')) return 0; - e = scope_lookup(p, tok_ident(&p->cur)); + e = scope_lookup(p, tok_ident(p_cur(p))); if (!e || e->kind != SEK_LOCAL) return 0; if (e->reg_asm_name && slot_out) *slot_out = e->v.slot; return e->reg_asm_name; @@ -648,7 +648,7 @@ static void parse_asm_stmt(Parser* p) { u32 nout = 0, nin = 0, nclob = 0; u32 cap_out = 0, cap_in = 0, cap_clob = 0; int saw_goto = 0; - SrcLoc loc = tok_loc_stmt(p, &p->cur); + SrcLoc loc = tok_loc_stmt(p, p_cur(p)); for (;;) { if (accept_kw_stmt(p, KW_VOLATILE)) @@ -661,7 +661,7 @@ static void parse_asm_stmt(Parser* p) { tmpl = parse_asm_str(p, "asm template"); if (accept_punct(p, ':')) { - if (!is_punct(&p->cur, ':') && !is_punct(&p->cur, ')')) { + if (!is_punct(p_cur(p), ':') && !is_punct(p_cur(p), ')')) { cap_out = 4; outs = (AsmConstraint*)arena_array(p->pool->arena, AsmConstraint, cap_out); @@ -732,7 +732,7 @@ static void parse_asm_stmt(Parser* p) { } if (accept_punct(p, ':')) { - if (!is_punct(&p->cur, ':') && !is_punct(&p->cur, ')')) { + if (!is_punct(p_cur(p), ':') && !is_punct(p_cur(p), ')')) { cap_in = 4; ins = (AsmConstraint*)arena_array(p->pool->arena, AsmConstraint, cap_in); @@ -762,7 +762,7 @@ static void parse_asm_stmt(Parser* p) { } if (accept_punct(p, ':')) { - if (!is_punct(&p->cur, ':') && !is_punct(&p->cur, ')')) { + if (!is_punct(p_cur(p), ':') && !is_punct(p_cur(p), ')')) { cap_clob = 4; clobbers = (Sym*)arena_array(p->pool->arena, Sym, cap_clob); for (;;) { @@ -783,9 +783,9 @@ static void parse_asm_stmt(Parser* p) { } if (accept_punct(p, ':')) { - if (!is_punct(&p->cur, ')')) { + if (!is_punct(p_cur(p), ')')) { for (;;) { - if (p->cur.kind != TOK_IDENT) { + if (p_cur(p)->kind != TOK_IDENT) { perr(p, "expected label identifier in asm-goto label list"); } advance(p); @@ -854,18 +854,18 @@ static void parse_asm_stmt(Parser* p) { void parse_compound_stmt(Parser* p) { expect_punct(p, '{', "'{'"); scope_push(p); - while (!is_punct(&p->cur, '}') && p->cur.kind != TOK_EOF) { - if (p->cur.kind == TOK_NEWLINE || is_pp_hash(&p->cur)) { + while (!is_punct(p_cur(p), '}') && p_cur(p)->kind != TOK_EOF) { + if (p_cur(p)->kind == TOK_NEWLINE || is_pp_hash(p_cur(p))) { advance(p); continue; } - if (is_kw(p, &p->cur, KW_STATIC_ASSERT)) { + if (is_kw(p, p_cur(p), KW_STATIC_ASSERT)) { parse_static_assert(p); continue; } { DeclSpecs specs; - Tok save_tok = p->cur; + Tok save_tok = *p_cur(p); (void)save_tok; if (parse_decl_specs(p, &specs)) { parse_local_decl(p, &specs); @@ -883,79 +883,79 @@ void parse_compound_stmt(Parser* p) { } void parse_stmt(Parser* p) { - c_cg_set_loc(p, tok_loc_stmt(p, &p->cur)); - if (p->cur.kind == TOK_IDENT && - ident_kw_inline(p, tok_ident(&p->cur)) == KW_NONE) { + c_cg_set_loc(p, tok_loc_stmt(p, p_cur(p))); + if (p_cur(p)->kind == TOK_IDENT && + ident_kw_inline(p, tok_ident(p_cur(p))) == KW_NONE) { Tok n = peek1(p); if (is_punct(&n, ':')) { parse_label_stmt(p); return; } } - if (is_punct(&p->cur, '{')) { + if (is_punct(p_cur(p), '{')) { parse_compound_stmt(p); return; } - if (is_punct(&p->cur, ';')) { + if (is_punct(p_cur(p), ';')) { advance(p); return; } - if (is_kw(p, &p->cur, KW_IF)) { + if (is_kw(p, p_cur(p), KW_IF)) { advance(p); parse_if_stmt(p); return; } - if (is_kw(p, &p->cur, KW_WHILE)) { + if (is_kw(p, p_cur(p), KW_WHILE)) { advance(p); parse_while_stmt(p); return; } - if (is_kw(p, &p->cur, KW_FOR)) { + if (is_kw(p, p_cur(p), KW_FOR)) { advance(p); parse_for_stmt(p); return; } - if (is_kw(p, &p->cur, KW_DO)) { + if (is_kw(p, p_cur(p), KW_DO)) { advance(p); parse_do_stmt(p); return; } - if (is_kw(p, &p->cur, KW_RETURN)) { + if (is_kw(p, p_cur(p), KW_RETURN)) { advance(p); parse_return_stmt(p); return; } - if (is_kw(p, &p->cur, KW_BREAK)) { + if (is_kw(p, p_cur(p), KW_BREAK)) { advance(p); parse_break_stmt(p); return; } - if (is_kw(p, &p->cur, KW_CONTINUE)) { + if (is_kw(p, p_cur(p), KW_CONTINUE)) { advance(p); parse_continue_stmt(p); return; } - if (is_kw(p, &p->cur, KW_GOTO)) { + if (is_kw(p, p_cur(p), KW_GOTO)) { advance(p); parse_goto_stmt(p); return; } - if (is_kw(p, &p->cur, KW_SWITCH)) { + if (is_kw(p, p_cur(p), KW_SWITCH)) { advance(p); parse_switch_stmt(p); return; } - if (is_kw(p, &p->cur, KW_CASE)) { + if (is_kw(p, p_cur(p), KW_CASE)) { advance(p); parse_case_stmt(p); return; } - if (is_kw(p, &p->cur, KW_DEFAULT)) { + if (is_kw(p, p_cur(p), KW_DEFAULT)) { advance(p); parse_default_stmt(p); return; } - if (is_kw(p, &p->cur, KW_ASM) || is_kw(p, &p->cur, KW_BUILTIN_ASM)) { + if (is_kw(p, p_cur(p), KW_ASM) || is_kw(p, p_cur(p), KW_BUILTIN_ASM)) { advance(p); parse_asm_stmt(p); return; diff --git a/lang/c/parse/parse_type.c b/lang/c/parse/parse_type.c @@ -76,7 +76,7 @@ static void attr_canon_range(const char* s, size_t len, const char** out_p, size_t* out_len); static int accept_kw(Parser* p, CKw k) { - if (is_kw(p, &p->cur, k)) { + if (is_kw(p, p_cur(p), k)) { advance(p); return 1; } @@ -111,18 +111,20 @@ static const Type* attrs_apply_type_mode(Parser* p, const Type* base, } int starts_attr(const Parser* p) { - return p->cur.kind == TOK_IDENT && tok_ident(&p->cur) == p->sym_attribute; + return p_cur_const(p)->kind == TOK_IDENT && + tok_ident(p_cur_const(p)) == p->sym_attribute; } static int starts_asm_label(const Parser* p) { - return is_kw(p, &p->cur, KW_ASM) || is_kw(p, &p->cur, KW_BUILTIN_ASM); + return is_kw(p, p_cur_const(p), KW_ASM) || + is_kw(p, p_cur_const(p), KW_BUILTIN_ASM); } static Sym parse_asm_label(Parser* p) { Sym label = 0; advance(p); /* asm / __asm / __asm__ */ expect_punct(p, '(', "'(' after asm label"); - if (p->cur.kind != TOK_STR) { + if (p_cur(p)->kind != TOK_STR) { perr(p, "expected string literal in asm label"); } /* Capture the label string for the declarator currently being parsed. For a @@ -130,7 +132,7 @@ static Sym parse_asm_label(Parser* p) { * variable binds to. Other asm labels (symbol renames) are still effectively * ignored by callers that do not consume DeclaratorInfo.asm_label. */ { - Tok t = p->cur; + Tok t = *p_cur(p); size_t nlen = 0; u8* bytes = decode_string_literal(p, &t, &nlen); u32 ilen = (nlen > 0) ? (u32)(nlen - 1) : 0; @@ -141,7 +143,7 @@ static Sym parse_asm_label(Parser* p) { } do { advance(p); - } while (p->cur.kind == TOK_STR); + } while (p_cur(p)->kind == TOK_STR); expect_punct(p, ')', "')' after asm label"); return label; } @@ -216,16 +218,16 @@ static AttrKind classify_attr(Parser* p, Sym name, AttrArgShape* shape_out) { static void skip_balanced_parens(Parser* p) { int depth; - if (!is_punct(&p->cur, '(')) perr(p, "internal: skip_balanced_parens"); + if (!is_punct(p_cur(p), '(')) perr(p, "internal: skip_balanced_parens"); depth = 1; advance(p); while (depth > 0) { - if (p->cur.kind == TOK_EOF) { + if (p_cur(p)->kind == TOK_EOF) { perr(p, "unexpected EOF inside attribute arguments"); } - if (is_punct(&p->cur, '(')) + if (is_punct(p_cur(p), '(')) ++depth; - else if (is_punct(&p->cur, ')')) { + else if (is_punct(p_cur(p), ')')) { --depth; if (depth == 0) { advance(p); @@ -238,7 +240,7 @@ static void skip_balanced_parens(Parser* p) { static void parse_attr_args(Parser* p, Attr* a, AttrArgShape shape, const char* attr_diag_name) { - if (!is_punct(&p->cur, '(')) { + if (!is_punct(p_cur(p), '(')) { if (shape == AS_NONE || shape == AS_OPTIONAL || shape == AS_INT_OPT || shape == AS_OPAQUE) { return; @@ -263,7 +265,7 @@ static void parse_attr_args(Parser* p, Attr* a, AttrArgShape shape, case AS_INT_OPT: { SrcLoc loc; advance(p); /* '(' */ - if (is_punct(&p->cur, ')')) { + if (is_punct(p_cur(p), ')')) { if (shape == AS_INT) { perr(p, "attribute '%.*s' expects an integer argument", KIT_SLICE_ARG(kit_slice_cstr(attr_diag_name))); @@ -271,7 +273,7 @@ static void parse_attr_args(Parser* p, Attr* a, AttrArgShape shape, advance(p); return; } - loc = tok_loc(p, &p->cur); + loc = tok_loc(p, p_cur(p)); a->v.i = eval_const_int(p, loc); if (a->kind == ATTR_ALIGNED && a->v.i > 0 && (((u64)a->v.i & ((u64)a->v.i - 1u)) != 0)) { @@ -283,12 +285,12 @@ static void parse_attr_args(Parser* p, Attr* a, AttrArgShape shape, } case AS_STRING: { advance(p); /* '(' */ - if (p->cur.kind != TOK_STR) { + if (p_cur(p)->kind != TOK_STR) { perr(p, "attribute '%.*s' expects a string literal", KIT_SLICE_ARG(kit_slice_cstr(attr_diag_name))); } { - Tok t = p->cur; + Tok t = *p_cur(p); size_t nlen = 0; u8* bytes = decode_string_literal(p, &t, &nlen); u32 ilen = (nlen > 0) ? (u32)(nlen - 1) : 0; @@ -304,11 +306,11 @@ static void parse_attr_args(Parser* p, Attr* a, AttrArgShape shape, } case AS_IDENT: { advance(p); /* '(' */ - if (p->cur.kind != TOK_IDENT) { + if (p_cur(p)->kind != TOK_IDENT) { perr(p, "attribute '%.*s' expects an identifier", KIT_SLICE_ARG(kit_slice_cstr(attr_diag_name))); } - a->v.sym = tok_ident(&p->cur); + a->v.sym = tok_ident(p_cur(p)); a->nargs = 1; advance(p); expect_punct(p, ')', "')' after attribute identifier argument"); @@ -318,15 +320,15 @@ static void parse_attr_args(Parser* p, Attr* a, AttrArgShape shape, SrcLoc mloc, nloc; i64 mv, nv; advance(p); /* '(' */ - if (p->cur.kind != TOK_IDENT) { + if (p_cur(p)->kind != TOK_IDENT) { perr(p, "attribute 'format' expects (archetype, m, n)"); } advance(p); expect_punct(p, ',', "',' after format archetype"); - mloc = tok_loc(p, &p->cur); + mloc = tok_loc(p, p_cur(p)); mv = eval_const_int(p, mloc); expect_punct(p, ',', "',' after format string-index"); - nloc = tok_loc(p, &p->cur); + nloc = tok_loc(p, p_cur(p)); nv = eval_const_int(p, nloc); if (mv < 0 || mv > 0xFFFF || nv < 0 || nv > 0xFFFF) { perr(p, "attribute 'format' indices out of range"); @@ -349,7 +351,7 @@ Attr* parse_attribute_spec_list(Parser* p) { Attr* head = NULL; Attr* tail = NULL; while (starts_attr(p)) { - SrcLoc kw_loc = tok_loc(p, &p->cur); + SrcLoc kw_loc = tok_loc(p, p_cur(p)); advance(p); /* __attribute__ */ expect_punct(p, '(', "'(' after __attribute__"); expect_punct(p, '(', "'((' after __attribute__"); @@ -363,15 +365,15 @@ Attr* parse_attribute_spec_list(Parser* p) { size_t canon_len; while (accept_punct(p, ',')) { /* skip */ } - if (is_punct(&p->cur, ')')) break; - if (p->cur.kind != TOK_IDENT) { + if (is_punct(p_cur(p), ')')) break; + if (p_cur(p)->kind != TOK_IDENT) { perr(p, "expected attribute name"); } - aname = tok_ident(&p->cur); + aname = tok_ident(p_cur(p)); a = arena_new(p->pool->arena, Attr); if (!a) perr(p, "out of memory in parse_attribute_spec_list"); memset(a, 0, sizeof *a); - a->loc = tok_loc(p, &p->cur); + a->loc = tok_loc(p, p_cur(p)); a->name = aname; a->kind = (u16)classify_attr(p, aname, &shape); advance(p); @@ -608,9 +610,9 @@ int parse_decl_specs(Parser* p, DeclSpecs* out) { out->vla_byte_slot = FRAME_SLOT_NONE; out->vla_bounds = NULL; out->attrs = NULL; - loc = tok_loc(p, &p->cur); + loc = tok_loc(p, p_cur(p)); for (;;) { - Tok t = p->cur; + Tok t = *p_cur(p); /* Classify the token's keyword identity exactly once per iteration; the * decl-spec dispatch below compares against this instead of re-deciding * keyword-ness per candidate (was ~26 is_kw probes/token). */ @@ -779,11 +781,11 @@ int parse_decl_specs(Parser* p, DeclSpecs* out) { u32 a = 0; advance(p); /* `_Alignas` */ expect_punct(p, '(', "'(' after _Alignas"); - if (starts_type_name(p, &p->cur)) { + if (starts_type_name(p, p_cur(p))) { const Type* tn = parse_type_name(p); a = c_abi_alignof(p->abi, p->pool, tn); } else { - i64 v = eval_const_int(p, tok_loc(p, &p->cur)); + i64 v = eval_const_int(p, tok_loc(p, p_cur(p))); if (v < 0) perr(p, "_Alignas requires a non-negative alignment"); a = (u32)v; } @@ -955,12 +957,12 @@ static void parse_member_decls(Parser* p, TypeRecordBuilder* b) { MemberNameSeen* names = NULL; u32 field_count = 0; int saw_flexible = 0; - while (!is_punct(&p->cur, '}') && p->cur.kind != TOK_EOF) { + while (!is_punct(p_cur(p), '}') && p_cur(p)->kind != TOK_EOF) { DeclSpecs specs; if (!parse_decl_specs(p, &specs)) { perr(p, "expected member declaration"); } - if (is_punct(&p->cur, ';')) { + if (is_punct(p_cur(p), ';')) { if (specs.type && (specs.type->kind == TY_STRUCT || specs.type->kind == TY_UNION)) { Field f; @@ -977,11 +979,11 @@ static void parse_member_decls(Parser* p, TypeRecordBuilder* b) { } for (;;) { Sym mname = 0; - SrcLoc mloc = tok_loc(p, &p->cur); + SrcLoc mloc = tok_loc(p, p_cur(p)); const Type* mty; Field f; memset(&f, 0, sizeof f); - if (is_punct(&p->cur, ':')) { + if (is_punct(p_cur(p), ':')) { advance(p); if (!type_is_int(specs.type)) perr(p, "bit-field has non-integer type"); i64 w = eval_const_int(p, mloc); @@ -1046,13 +1048,13 @@ const Type* parse_struct_or_union(Parser* p, TypeKind kind, TagDeclKind tdk = (kind == TY_STRUCT) ? TAG_STRUCT : TAG_UNION; Attr* rec_attrs = NULL; parse_attrs_into(p, &rec_attrs); - tag_loc = tok_loc(p, &p->cur); - if (p->cur.kind == TOK_IDENT && - ident_kw_inline(p, tok_ident(&p->cur)) == KW_NONE) { - tag_name = tok_ident(&p->cur); + tag_loc = tok_loc(p, p_cur(p)); + if (p_cur(p)->kind == TOK_IDENT && + ident_kw_inline(p, tok_ident(p_cur(p))) == KW_NONE) { + tag_name = tok_ident(p_cur(p)); advance(p); } - int has_body = is_punct(&p->cur, '{'); + int has_body = is_punct(p_cur(p), '{'); if (!has_body && tag_name == 0) { perr(p, "expected tag name or '{' after struct/union"); } @@ -1141,10 +1143,10 @@ const Type* parse_enum(Parser* p, Attr** anon_attrs_out) { SrcLoc tag_loc; Attr* rec_attrs = NULL; parse_attrs_into(p, &rec_attrs); - tag_loc = tok_loc(p, &p->cur); - if (p->cur.kind == TOK_IDENT && - ident_kw_inline(p, tok_ident(&p->cur)) == KW_NONE) { - tag_name = tok_ident(&p->cur); + tag_loc = tok_loc(p, p_cur(p)); + if (p_cur(p)->kind == TOK_IDENT && + ident_kw_inline(p, tok_ident(p_cur(p))) == KW_NONE) { + tag_name = tok_ident(p_cur(p)); advance(p); } /* C23 §6.7.2.2: an optional fixed underlying type — `enum [tag] : T` — @@ -1157,7 +1159,7 @@ const Type* parse_enum(Parser* p, Attr** anon_attrs_out) { underlying = parse_type_name(p); has_fixed_type = 1; } - int has_body = is_punct(&p->cur, '{'); + int has_body = is_punct(p_cur(p), '{'); if (!has_body && tag_name == 0) { perr(p, "expected tag name or '{' after enum"); } @@ -1197,13 +1199,13 @@ const Type* parse_enum(Parser* p, Attr** anon_attrs_out) { u32 nconsts = 0, consts_cap = 0; for (;;) { Sym name; - SrcLoc nloc = tok_loc(p, &p->cur); + SrcLoc nloc = tok_loc(p, p_cur(p)); SymEntry* e; - if (p->cur.kind != TOK_IDENT || - ident_kw_inline(p, tok_ident(&p->cur)) != KW_NONE) { + if (p_cur(p)->kind != TOK_IDENT || + ident_kw_inline(p, tok_ident(p_cur(p))) != KW_NONE) { perr(p, "expected enumerator name"); } - name = tok_ident(&p->cur); + name = tok_ident(p_cur(p)); advance(p); i64 val = next_val; if (accept_punct(p, '=')) { @@ -1228,7 +1230,7 @@ const Type* parse_enum(Parser* p, Attr** anon_attrs_out) { nconsts++; } if (!accept_punct(p, ',')) break; - if (is_punct(&p->cur, '}')) break; + if (is_punct(p_cur(p), '}')) break; } expect_punct(p, '}', "'}' after enumerator list"); ((Type*)et)->enm.consts = consts; @@ -1379,7 +1381,7 @@ static void parse_param_array_bound(Parser* p, DeclSuffix* out) { return; } while (depth > 0) { - Tok t = p->cur; + Tok t = *p_cur(p); if (t.kind == TOK_EOF) { perr(p, "unexpected EOF in parameter array bound"); } @@ -1441,7 +1443,7 @@ int parse_decl_suffix(Parser* p, DeclSuffix* out) { return 1; } { - Tok t = p->cur; + Tok t = *p_cur(p); /* A VLA is a block-scope-only feature (§6.7.6.2¶4): at file scope every * declared array bound must be an integer constant expression. Route all * file-scope bounds through eval_const_int below, so a non-constant bound @@ -1463,7 +1465,7 @@ int parse_decl_suffix(Parser* p, DeclSuffix* out) { } } if (is_const_start) { - SrcLoc cloc = tok_loc(p, &p->cur); + SrcLoc cloc = tok_loc(p, p_cur(p)); i64 v = eval_const_int(p, cloc); if (v < 0) perr(p, "negative array size"); out->count = (u32)v; @@ -1591,7 +1593,7 @@ const Type* parse_declarator_full_info(Parser* p, const Type* base, DeclSuffix inner_suffs[8]; int n_inner_suffs = 0; - if (is_punct(&p->cur, '(')) { + if (is_punct(p_cur(p), '(')) { Tok n = peek1(p); int is_inner = 0; if (is_punct(&n, '*')) { @@ -1632,12 +1634,12 @@ const Type* parse_declarator_full_info(Parser* p, const Type* base, } inner_quals[nptrs_inner++] = q; } - if (p->cur.kind == TOK_IDENT && - ident_kw_inline(p, tok_ident(&p->cur)) == KW_NONE) { - name = tok_ident(&p->cur); - nloc = tok_loc(p, &p->cur); + if (p_cur(p)->kind == TOK_IDENT && + ident_kw_inline(p, tok_ident(p_cur(p))) == KW_NONE) { + name = tok_ident(p_cur(p)); + nloc = tok_loc(p, p_cur(p)); advance(p); - } else if (is_punct(&p->cur, '(')) { + } else if (is_punct(p_cur(p), '(')) { Tok nn = peek1(p); if (!is_punct(&nn, '*')) { if (!allow_abstract) perr(p, "expected declarator name"); @@ -1672,10 +1674,10 @@ const Type* parse_declarator_full_info(Parser* p, const Type* base, } nested_quals[nptrs_nested++] = q; } - if (p->cur.kind == TOK_IDENT && - ident_kw_inline(p, tok_ident(&p->cur)) == KW_NONE) { - name = tok_ident(&p->cur); - nloc = tok_loc(p, &p->cur); + if (p_cur(p)->kind == TOK_IDENT && + ident_kw_inline(p, tok_ident(p_cur(p))) == KW_NONE) { + name = tok_ident(p_cur(p)); + nloc = tok_loc(p, p_cur(p)); advance(p); } else if (!allow_abstract) { perr(p, "expected declarator name"); @@ -1697,10 +1699,10 @@ const Type* parse_declarator_full_info(Parser* p, const Type* base, } if (!has_inner_parens) { - if (p->cur.kind == TOK_IDENT && - ident_kw_inline(p, tok_ident(&p->cur)) == KW_NONE) { - name = tok_ident(&p->cur); - nloc = tok_loc(p, &p->cur); + if (p_cur(p)->kind == TOK_IDENT && + ident_kw_inline(p, tok_ident(p_cur(p))) == KW_NONE) { + name = tok_ident(p_cur(p)); + nloc = tok_loc(p, p_cur(p)); advance(p); } else if (!allow_abstract) { perr(p, "expected declarator name"); @@ -1719,7 +1721,7 @@ const Type* parse_declarator_full_info(Parser* p, const Type* base, parse_attrs_and_asm_into(p, attrs_out, &local_attrs, &asm_label); } base = attrs_apply_type_mode(p, base, attrs_out ? *attrs_out : local_attrs); - if (nsuffs == 8 && (is_punct(&p->cur, '[') || is_punct(&p->cur, '('))) { + if (nsuffs == 8 && (is_punct(p_cur(p), '[') || is_punct(p_cur(p), '('))) { perr(p, "too many declarator suffixes (raise the cap if needed)"); } if (n_inner_suffs > 0 && inner_suffs[0].kind == DS_FUNC) { @@ -1775,9 +1777,9 @@ const Type* complete_incomplete_array(Parser* p, const Type* ty) { const Type* elem; if (!ty || ty->kind != TY_ARRAY || !ty->arr.incomplete) return ty; elem = ty->arr.elem; - if (p->cur.kind == TOK_STR && - string_literal_initializes_array(p, elem, &p->cur)) { - Tok t = p->cur; + if (p_cur(p)->kind == TOK_STR && + string_literal_initializes_array(p, elem, p_cur(p))) { + Tok t = *p_cur(p); size_t n = 0; u8* bytes = decode_string_literal(p, &t, &n); u32 elem_size = c_abi_sizeof(p->abi, p->pool, elem); @@ -1786,7 +1788,7 @@ const Type* complete_incomplete_array(Parser* p, const Type* ty) { return type_array(p->pool, elem, elem_size ? (u32)(n / elem_size) : 0, /*incomplete=*/0); } - if (is_punct(&p->cur, '{')) { + if (is_punct(p_cur(p), '{')) { u32 cnt; record_braced_block(p); cnt = count_recorded_top_level_items(p->replay, p->replay_len);