kit

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

commit 76f33b88a9245f1f03ef8d8eb7b5406ae06663a2
parent 142c5027b04c79c1acca25563a1fe678d670e31a
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Mon, 15 Jun 2026 17:32:21 -0700

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

The 3-cell ring regressed -c by +31.7M instructions on the parse phase
(+4.5%; +0.96% total -c) on the sqlite amalgamation, for no functional
gain: the parser is strictly LL(1) and the LL(2) headroom the ring bought
is unused (the semantic-tagging overlay it was shaped for was dropped).
Every consumed token paid the ring's %3 modulo + indexed cells[cur] load
instead of the old direct cur/next fields.

Keeps the Phase 1 macro-availability rewrite (-15M lex+pp) and the
type-generic overflow builtins (142c5027) intact; restores lang/c/parse to
the pre-ring cur/next/pending model.

This reverts commit 26b3a235.

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, 373 insertions(+), 442 deletions(-)

diff --git a/lang/c/parse/parse.c b/lang/c/parse/parse.c @@ -2,8 +2,7 @@ * * Contains: * - kw_names[] table (used by parse_c to intern keywords) - * - Diagnostics/token helpers (perr, advance, peek1) over the input ring - * (parser_advance, parser_fill_to, parser_peek; see parse_priv.h) + * - Diagnostics/token helpers (perr, advance, peek1, fetch_tok, ...) * - Scope/tag operations * - Type helpers (ty_int, ty_size_t) * - Local-variable slot allocation (make_local, make_local_aligned) @@ -16,7 +15,6 @@ * 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> @@ -87,7 +85,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(p)); + SrcLoc loc = tok_loc(p, &p->cur); va_start(ap, fmt); compiler_panicv(p->c, loc, fmt, ap); } @@ -106,16 +104,13 @@ 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 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); +/* 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); u16 fused_enc; - KitSlice a_sl = pp_text_slice(p->pp, dst); - KitSlice b_sl = pp_text_slice(p->pp, b); + KitSlice a_sl = pp_text_slice(p->pp, &a); + 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; @@ -126,6 +121,7 @@ static void fuse_string_lits_into(Parser* p, CFeCell* dst, const CFeCell* 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, @@ -133,8 +129,8 @@ static void fuse_string_lits_into(Parser* p, CFeCell* dst, const CFeCell* b) { "encoding prefixes"); } fused_enc = ae ? ae : be; - apfx = str_prefix_len(dst->flags); - bpfx = str_prefix_len(b->flags); + apfx = str_prefix_len(a.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"); @@ -160,82 +156,61 @@ static void fuse_string_lits_into(Parser* p, CFeCell* dst, const CFeCell* b) { k += b_content_len; } buf[k++] = '"'; - dst->text = + out = a; + out.text = text_sym_ref(kit_sym_intern(p->pool->c, (KitSlice){.s = buf, .len = k})); - dst->flags = (u16)((dst->flags & ~STR_ENC_MASK) | fused_enc); + out.flags = (u16)((a.flags & ~STR_ENC_MASK) | fused_enc); h->free(h, buf, 0); + return out; } -/* 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; +/* 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; } else { - pp_next_parse(p->pp, slot); + pp_next_parse(p->pp, &t); } - if (slot->kind != TOK_STR) return; + if (t.kind != TOK_STR) return t; for (;;) { - CFeCell n; - /* A replay run records lexeme cells with adjacent strings already fused, so - * fusion only ever pulls follow-on cells from pp. */ + Tok n; pp_next_parse(p->pp, &n); if (n.kind != TOK_STR) { - p->input.pending = n; - p->input.has_pending = 1; - return; + p->pending = n; + p->has_pending = 1; + return t; } - fuse_string_lits_into(p, slot, &n); + t = fuse_string_lits(p, t, n); } } -/* 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++; +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); } - 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) { - parser_fill_to(p, 1); - return p->input.cells[parser_ring_idx(&p->input, 1)]; + 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; } void expect_punct(Parser* p, u32 punct, const char* what) { @@ -245,7 +220,7 @@ void expect_punct(Parser* p, u32 punct, const char* what) { } int accept_punct(Parser* p, u32 punct) { - if (is_punct(p_cur(p), punct)) { + if (is_punct(&p->cur, punct)) { advance(p); return 1; } @@ -256,7 +231,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(p), '{')) perr(p, "internal: record on non-'{'"); + if (!is_punct(&p->cur, '{')) perr(p, "internal: record on non-'{'"); p->replay_len = 0; for (;;) { if (p->replay_len == p->replay_cap) { @@ -269,36 +244,28 @@ void record_braced_block(Parser* p) { p->replay = nv; p->replay_cap = new_cap; } - p->replay[p->replay_len++] = *p_cur(p); - if (is_punct(p_cur(p), '{')) { + p->replay[p->replay_len++] = p->cur; + if (is_punct(&p->cur, '{')) { ++depth; - } else if (is_punct(p_cur(p), '}')) { + } else if (is_punct(&p->cur, '}')) { --depth; if (depth == 0) break; - } else if (p_cur(p)->kind == TOK_EOF) { + } else if (p->cur.kind == TOK_EOF) { perr(p, "unexpected end of file in initializer"); } advance(p); } } -/* 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; +/* 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]; 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; @@ -722,10 +689,9 @@ static int type_array_depth(const Type* ty) { static void eval_param_vla_count(Parser* p, const ParamVLABoundExpr* expr, FrameSlot slot) { - /* 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_cur = p->cur; + Tok save_next = p->next; + int save_has_next = p->has_next; Tok* save_replay = p->replay; u32 save_cap = p->replay_cap; u32 save_len = p->replay_len; @@ -741,19 +707,25 @@ 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; - parser_replay_begin(p); + p->replay_pos = 1; + p->replay_active = 1; parse_assign_expr(p); to_rvalue(p); - if (p_cur(p)->kind != TOK_EOF) { + if (p->cur.kind != TOK_EOF) { perr(p, "unexpected token in VLA parameter bound"); } store_top_to_size_slot(p, slot); - p->input = save_input; + p->cur = save_cur; + p->next = save_next; + p->has_next = save_has_next; p->replay = save_replay; p->replay_cap = save_cap; p->replay_len = save_len; @@ -849,7 +821,7 @@ static void parse_init_declarator(Parser* p, const DeclSpecs* specs) { /*is_member=*/0); if (specs->storage == DS_TYPEDEF) { - if (is_punct(p_cur(p), '=')) { + if (is_punct(&p->cur, '=')) { perr(p, "typedef declarator cannot have initializer"); } { @@ -880,7 +852,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(p), '=')) { + if (is_punct(&p->cur, '=')) { perr(p, "function declarator cannot have initializer"); } (void)declare_function(p, name, var_ty, specs, loc, NULL, dinfo.asm_label, @@ -1009,7 +981,7 @@ static void parse_init_declarator(Parser* p, const DeclSpecs* specs) { } /* Non-VLA local. */ { - int has_init = is_punct(p_cur(p), '='); + int has_init = is_punct(&p->cur, '='); FrameSlot s; if (has_init && var_ty && var_ty->kind == TY_ARRAY && var_ty->arr.incomplete) { @@ -1038,7 +1010,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(p), '{')) { + !is_punct(&p->cur, '{')) { 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 || @@ -1098,10 +1070,10 @@ void parse_param_list(Parser* p, ParamInfo** infos_out, u16* nparams_out, *infos_out = NULL; *nparams_out = 0; - if (is_punct(p_cur(p), ')')) { + if (is_punct(&p->cur, ')')) { return; } - if (is_kw(p, p_cur(p), KW_VOID)) { + if (is_kw(p, &p->cur, KW_VOID)) { Tok n2 = peek1(p); if (is_punct(&n2, ')')) { advance(p); /* `void` */ @@ -1410,7 +1382,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(p), '=')) { + if (is_punct(&p->cur, '=')) { perr(p, "typedef declarator cannot have initializer"); } { @@ -1450,7 +1422,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(p), '{')) { + if (is_punct(&p->cur, '{')) { int suppress_body_codegen = specs.storage == DS_EXTERN && ((specs.flags | fn_decl_flags) & DF_INLINE); if (fent->defined) perr(p, "redefinition of function"); @@ -1503,7 +1475,7 @@ static void parse_external_decl(Parser* p) { /* Global object declaration. */ for (;;) { - int has_init = is_punct(p_cur(p), '='); + int has_init = is_punct(&p->cur, '='); int is_pure_extern = (specs.storage == DS_EXTERN || specs.storage == DS_REGISTER) && !has_init; @@ -1607,7 +1579,7 @@ static void parse_file_scope_asm(Parser* p) { size_t nbytes; advance(p); /* asm / __asm__ */ for (;;) { - if (is_kw(p, p_cur(p), + if (is_kw(p, &p->cur, KW_VOLATILE)) { /* matches `volatile` and `__volatile__` */ advance(p); continue; @@ -1615,10 +1587,10 @@ static void parse_file_scope_asm(Parser* p) { break; } expect_punct(p, '(', "'(' after file-scope asm"); - if (p_cur(p)->kind != TOK_STR) { + if (p->cur.kind != TOK_STR) { perr(p, "expected string literal in file-scope asm"); } - bytes = decode_string_literal(p, p_cur(p), &nbytes); + bytes = decode_string_literal(p, &p->cur, &nbytes); advance(p); expect_punct(p, ')', "')' after file-scope asm"); expect_punct(p, ';', "';' after file-scope asm"); @@ -1630,16 +1602,16 @@ static void parse_file_scope_asm(Parser* p) { } static void parse_translation_unit(Parser* p) { - while (p_cur(p)->kind != TOK_EOF) { - if (p_cur(p)->kind == TOK_NEWLINE || is_pp_hash(p_cur(p))) { + while (p->cur.kind != TOK_EOF) { + if (p->cur.kind == TOK_NEWLINE || is_pp_hash(&p->cur)) { advance(p); continue; } - if (is_kw(p, p_cur(p), KW_STATIC_ASSERT)) { + if (is_kw(p, &p->cur, KW_STATIC_ASSERT)) { parse_static_assert(p); continue; } - if (is_kw(p, p_cur(p), KW_ASM) || is_kw(p, p_cur(p), KW_BUILTIN_ASM)) { + if (is_kw(p, &p->cur, KW_ASM) || is_kw(p, &p->cur, KW_BUILTIN_ASM)) { parse_file_scope_asm(p); continue; } @@ -1830,9 +1802,7 @@ void parse_c(Compiler* c, Pool* pool, Pp* pp, DeclTable* decls, CG* cg, p.scope = scope_new(&p, NULL); - /* 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); + p.cur = fetch_tok(&p); 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(p)->loc), message); + c_const_guard_note_at(p, pp_materialize_loc(p->pp, p->cur.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(p)->kind == TOK_NUM) { - return (MemOrder)eval_const_int(p, pp_materialize_loc(p->pp, p_cur(p)->loc)); + if (p->cur.kind == TOK_NUM) { + return (MemOrder)eval_const_int(p, pp_materialize_loc(p->pp, p->cur.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(p)->kind != TOK_IDENT || - ident_kw_inline(p, tok_ident(p_cur(p))) != KW_NONE) { + if (p->cur.kind != TOK_IDENT || + ident_kw_inline(p, tok_ident(&p->cur)) != 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(p)); + Sym mname = tok_ident(&p->cur); 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(p), '.')) { + if (is_punct(&p->cur, '.')) { advance(p); - if (p_cur(p)->kind != TOK_IDENT || - ident_kw_inline(p, tok_ident(p_cur(p))) != KW_NONE) { + if (p->cur.kind != TOK_IDENT || + ident_kw_inline(p, tok_ident(&p->cur)) != KW_NONE) { perr(p, "expected member name after '.'"); } continue; } - if (is_punct(p_cur(p), '[')) { + if (is_punct(&p->cur, '[')) { advance(p); - i64 idx = eval_const_int(p, pp_materialize_loc(p->pp, p_cur(p)->loc)); + i64 idx = eval_const_int(p, pp_materialize_loc(p->pp, p->cur.loc)); expect_punct(p, ']', "']' in __builtin_offsetof"); if (cur->kind != TY_ARRAY) { perr(p, "__builtin_offsetof '[' on non-array"); @@ -1525,8 +1525,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(p)); - SrcLoc loc = pp_materialize_loc(p->pp, p_cur(p)->loc); + Sym name = tok_ident(&p->cur); + SrcLoc loc = pp_materialize_loc(p->pp, p->cur.loc); if (c_const_guard_active(p) && name != p->sym_b_offsetof && name != p->sym_b_constant_p) { @@ -1638,7 +1638,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(p)->loc)); + i64 level = eval_const_int(p, pp_materialize_loc(p->pp, p->cur.loc)); expect_punct(p, ')', "')' after __builtin_return_address/__builtin_frame_address"); if (level < 0) @@ -1753,7 +1753,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(p)->loc)); + i64 size = eval_const_int(p, pp_materialize_loc(p->pp, p->cur.loc)); expect_punct(p, ',', "',' in atomic lock-free builtin"); parse_assign_expr(p); to_rvalue(p); @@ -1803,7 +1803,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(p)->loc)); /* weak */ + (void)eval_const_int(p, pp_materialize_loc(p->pp, p->cur.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"); @@ -1893,7 +1893,7 @@ static int try_parse_builtin_call(Parser* p) { * ============================================================ */ static void parse_primary(Parser* p) { - Tok t = *p_cur(p); + Tok t = p->cur; if (t.kind == TOK_NUM) { i64 v = parse_int_literal(p, &t); const Type* lty = int_literal_type(p, &t); @@ -1928,7 +1928,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(p); + t = p->cur; /* 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 @@ -2086,7 +2086,7 @@ static void parse_postfix(Parser* p) { parse_primary(p); vla_bounds = p->last_pushed_vla_bounds; for (;;) { - Tok t = *p_cur(p); + Tok t = p->cur; if (is_punct(&t, P_INC)) { c_const_guard_note_at( p, pp_materialize_loc(p->pp, t.loc), @@ -2131,7 +2131,7 @@ static void parse_postfix(Parser* p) { } advance(p); /* '(' */ u32 nargs = 0; - if (!is_punct(p_cur(p), ')')) { + if (!is_punct(&p->cur, ')')) { for (;;) { const Type* param_ty = (nargs < fn_type->fn.nparams) ? fn_type->fn.params[nargs] : NULL; @@ -2223,11 +2223,11 @@ static void parse_postfix(Parser* p) { perr(p, "request for member in something that is not a struct or union"); } - if (p_cur(p)->kind != TOK_IDENT || - ident_kw_inline(p, tok_ident(p_cur(p))) != KW_NONE) { + if (p->cur.kind != TOK_IDENT || + ident_kw_inline(p, tok_ident(&p->cur)) != KW_NONE) { perr(p, "expected member name after '.'"); } - mname = tok_ident(p_cur(p)); + mname = tok_ident(&p->cur); advance(p); lt = type_unqual(p->pool, lt); if (!find_record_member_path(p, lt, mname, &mty, &off, &bf_off, &bf_w, @@ -2254,11 +2254,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(p)->kind != TOK_IDENT || - ident_kw_inline(p, tok_ident(p_cur(p))) != KW_NONE) { + if (p->cur.kind != TOK_IDENT || + ident_kw_inline(p, tok_ident(&p->cur)) != KW_NONE) { perr(p, "expected member name after '->'"); } - mname = tok_ident(p_cur(p)); + mname = tok_ident(&p->cur); advance(p); if (!find_record_member_path(p, rec_ty, mname, &mty, &off, &bf_off, &bf_w, &bf_ss)) @@ -2272,7 +2272,7 @@ static void parse_postfix(Parser* p) { } void parse_unary(Parser* p) { - Tok t = *p_cur(p); + Tok t = p->cur; if (is_punct(&t, '(')) { Tok n = peek1(p); if (starts_type_name(p, &n)) { @@ -2281,7 +2281,7 @@ void parse_unary(Parser* p) { advance(p); /* '(' */ dst = parse_type_name(p); expect_punct(p, ')', "')' after type-name"); - if (is_punct(p_cur(p), '{')) { + if (is_punct(&p->cur, '{')) { FrameSlotDesc fsd; FrameSlot slot; const Type* lit_ty = dst; @@ -2299,10 +2299,10 @@ void parse_unary(Parser* p) { c_cg_push_local_typed(p, slot, lit_ty); return; } - if (c_const_guard_active(p) && p_cur(p)->kind == TOK_FLT) { + if (c_const_guard_active(p) && p->cur.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(p)); + double fv = parse_float_literal(p, &p->cur); advance(p); c_cg_push_int(p, (i64)fv, tu); return; @@ -2369,12 +2369,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(p)->kind != TOK_IDENT || - ident_kw_inline(p, tok_ident(p_cur(p))) != KW_NONE) { + if (p->cur.kind != TOK_IDENT || + ident_kw_inline(p, tok_ident(&p->cur)) != KW_NONE) { perr(p, "expected label name after '&&'"); } - name = tok_ident(p_cur(p)); - loc = pp_materialize_loc(p->pp, p_cur(p)->loc); + name = tok_ident(&p->cur); + loc = pp_materialize_loc(p->pp, p->cur.loc); advance(p); c_cg_push_label_addr(p, take_label_addr(p, name, loc)); return; @@ -2431,7 +2431,7 @@ void parse_unary(Parser* p) { const Type* ty = NULL; FrameSlot vla_slot = FRAME_SLOT_NONE; advance(p); - if (is_punct(p_cur(p), '(')) { + if (is_punct(&p->cur, '(')) { Tok n = peek1(p); if (starts_type_name(p, &n)) { advance(p); @@ -2492,7 +2492,7 @@ void parse_unary(Parser* p) { for (;;) { const Type* assoc_ty = NULL; int is_default = 0; - if (is_kw(p, p_cur(p), KW_DEFAULT)) { + if (is_kw(p, &p->cur, KW_DEFAULT)) { advance(p); is_default = 1; if (saw_default) perr(p, "_Generic has duplicate default association"); @@ -2532,9 +2532,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(p)->kind != TOK_EOF) { + while (p->cur.kind != TOK_EOF) { if (paren_depth == 0 && brack_depth == 0 && brace_depth == 0) { - if (is_punct(p_cur(p), ',') || is_punct(p_cur(p), ')')) break; + if (is_punct(&p->cur, ',') || is_punct(&p->cur, ')')) break; } if (len == cap) { u32 new_cap = cap * 2; @@ -2544,18 +2544,18 @@ void parse_unary(Parser* p) { buf = nv; cap = new_cap; } - buf[len++] = *p_cur(p); - if (is_punct(p_cur(p), '(')) + buf[len++] = p->cur; + if (is_punct(&p->cur, '(')) ++paren_depth; - else if (is_punct(p_cur(p), ')')) + else if (is_punct(&p->cur, ')')) --paren_depth; - else if (is_punct(p_cur(p), '[')) + else if (is_punct(&p->cur, '[')) ++brack_depth; - else if (is_punct(p_cur(p), ']')) + else if (is_punct(&p->cur, ']')) --brack_depth; - else if (is_punct(p_cur(p), '{')) + else if (is_punct(&p->cur, '{')) ++brace_depth; - else if (is_punct(p_cur(p), '}')) + else if (is_punct(&p->cur, '}')) --brace_depth; advance(p); } @@ -2577,21 +2577,21 @@ void parse_unary(Parser* p) { int paren_depth = 0; int brack_depth = 0; int brace_depth = 0; - while (p_cur(p)->kind != TOK_EOF) { + while (p->cur.kind != TOK_EOF) { if (paren_depth == 0 && brack_depth == 0 && brace_depth == 0) { - if (is_punct(p_cur(p), ',') || is_punct(p_cur(p), ')')) break; + if (is_punct(&p->cur, ',') || is_punct(&p->cur, ')')) break; } - if (is_punct(p_cur(p), '(')) + if (is_punct(&p->cur, '(')) ++paren_depth; - else if (is_punct(p_cur(p), ')')) + else if (is_punct(&p->cur, ')')) --paren_depth; - else if (is_punct(p_cur(p), '[')) + else if (is_punct(&p->cur, '[')) ++brack_depth; - else if (is_punct(p_cur(p), ']')) + else if (is_punct(&p->cur, ']')) --brack_depth; - else if (is_punct(p_cur(p), '{')) + else if (is_punct(&p->cur, '{')) ++brace_depth; - else if (is_punct(p_cur(p), '}')) + else if (is_punct(&p->cur, '}')) --brace_depth; advance(p); } @@ -2599,18 +2599,20 @@ 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; - parser_replay_begin(p); + p->replay_pos = 1; + p->replay_active = 1; + p->cur = default_buf[0]; + p->has_next = 0; parse_assign_expr(p); emitted = 1; p->replay = save_replay; @@ -2618,7 +2620,8 @@ void parse_unary(Parser* p) { p->replay_len = save_len; p->replay_pos = save_pos; p->replay_active = save_active; - p->input = save_input; + p->cur = save_cur; + p->has_next = save_has_next; } expect_punct(p, ')', "')' after _Generic"); if (!emitted) { @@ -2630,7 +2633,7 @@ void parse_unary(Parser* p) { const Type* ty; advance(p); expect_punct(p, '(', "'('"); - if (starts_type_name(p, p_cur(p))) { + if (starts_type_name(p, &p->cur)) { ty = parse_type_name(p); } else { c_const_guard_not_eval_push(p); @@ -2739,7 +2742,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(p); + Tok t = p->cur; SrcLoc op_loc; BinOp bop; if (is_punct(&t, '*')) { @@ -2855,7 +2858,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(p); + Tok t = p->cur; BinOp bop; if (is_punct(&t, '+')) { bop = BO_IADD; @@ -2875,7 +2878,7 @@ static void parse_add(Parser* p) { static void parse_shift(Parser* p) { parse_add(p); for (;;) { - Tok t = *p_cur(p); + Tok t = p->cur; SrcLoc op_loc; BinOp bop; if (is_punct(&t, P_SHL)) { @@ -2914,7 +2917,7 @@ static void parse_shift(Parser* p) { static void parse_rel(Parser* p) { parse_shift(p); for (;;) { - Tok t = *p_cur(p); + Tok t = p->cur; CmpOp cop; if (is_punct(&t, '<')) { cop = CMP_LT_S; @@ -2975,7 +2978,7 @@ static void parse_rel(Parser* p) { static void parse_eq(Parser* p) { parse_rel(p); for (;;) { - Tok t = *p_cur(p); + Tok t = p->cur; CmpOp cop; if (is_punct(&t, P_EQ)) { cop = CMP_EQ; @@ -3018,7 +3021,7 @@ static void parse_eq(Parser* p) { static void parse_band(Parser* p) { parse_eq(p); - while (is_punct(p_cur(p), '&')) { + while (is_punct(&p->cur, '&')) { advance(p); to_rvalue(p); parse_eq(p); @@ -3034,7 +3037,7 @@ static void parse_band(Parser* p) { static void parse_bxor(Parser* p) { parse_band(p); - while (is_punct(p_cur(p), '^')) { + while (is_punct(&p->cur, '^')) { advance(p); to_rvalue(p); parse_band(p); @@ -3050,7 +3053,7 @@ static void parse_bxor(Parser* p) { static void parse_bor(Parser* p) { parse_bxor(p); - while (is_punct(p_cur(p), '|')) { + while (is_punct(&p->cur, '|')) { advance(p); to_rvalue(p); parse_bxor(p); @@ -3083,7 +3086,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), P_AND)) { + while (is_punct(&p->cur, 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); @@ -3129,7 +3132,7 @@ static void parse_land(Parser* p) { static void parse_lor(Parser* p) { parse_land(p); - while (is_punct(p_cur(p), P_OR)) { + while (is_punct(&p->cur, 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); @@ -3175,7 +3178,7 @@ static void parse_lor(Parser* p) { static void parse_ternary(Parser* p) { parse_lor(p); - if (!is_punct(p_cur(p), '?')) return; + if (!is_punct(&p->cur, '?')) 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); @@ -3313,7 +3316,7 @@ static void parse_ternary(Parser* p) { void parse_assign_expr(Parser* p) { parse_ternary(p); - Tok t = *p_cur(p); + Tok t = p->cur; SrcLoc op_loc = pp_materialize_loc(p->pp, t.loc); BinOp compound; int is_simple_assign; @@ -3448,7 +3451,7 @@ void parse_assign_expr(Parser* p) { void parse_expr(Parser* p) { parse_assign_expr(p); - while (is_punct(p_cur(p), ',')) { + while (is_punct(&p->cur, ',')) { 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 current string token without advancing. Returns a heap- +/* Decode the string token at p->cur 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(p); + Tok t = p->cur; if (t.kind != TOK_STR) perr(p, "internal: peek_string_bytes on non-string"); return decode_string_literal(p, &t, nlen_out); } @@ -73,7 +73,10 @@ 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"); - parser_replay_begin(p); + p->cur = p->replay[0]; + p->replay_pos = 1; + p->replay_active = 1; + p->has_next = 0; } static void record_initializer_expr_for_replay(Parser* p) { @@ -93,25 +96,25 @@ static void record_initializer_expr_for_replay(Parser* p) { buf = nb; cap = new_cap; } - buf[len++] = *p_cur(p); + buf[len++] = p->cur; - if (p_cur(p)->kind == TOK_EOF) break; + if (p->cur.kind == TOK_EOF) break; if (paren_depth == 0 && brack_depth == 0 && brace_depth == 0 && - (is_punct(p_cur(p), ',') || is_punct(p_cur(p), '}'))) { + (is_punct(&p->cur, ',') || is_punct(&p->cur, '}'))) { break; } - if (is_punct(p_cur(p), '(')) + if (is_punct(&p->cur, '(')) ++paren_depth; - else if (is_punct(p_cur(p), ')')) + else if (is_punct(&p->cur, ')')) --paren_depth; - else if (is_punct(p_cur(p), '[')) + else if (is_punct(&p->cur, '[')) ++brack_depth; - else if (is_punct(p_cur(p), ']')) + else if (is_punct(&p->cur, ']')) --brack_depth; - else if (is_punct(p_cur(p), '{')) + else if (is_punct(&p->cur, '{')) ++brace_depth; - else if (is_punct(p_cur(p), '}')) + else if (is_punct(&p->cur, '}')) --brace_depth; advance(p); @@ -131,8 +134,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(p), '{') || is_punct(p_cur(p), '.') || - is_punct(p_cur(p), '[')) { + if (is_punct(&p->cur, '{') || is_punct(&p->cur, '.') || + is_punct(&p->cur, '[')) { return 0; } @@ -377,10 +380,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(p), '[')) { + if (is_punct(&p->cur, '[')) { i64 idx; u32 esz; - SrcLoc cloc = tok_loc_init(p, p_cur(p)); + SrcLoc cloc = tok_loc_init(p, &p->cur); const Type* parent_ty = cur_ty; u32 parent_off = cur_off; advance(p); @@ -400,7 +403,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(p), '.')) { + } else if (is_punct(&p->cur, '.')) { Sym fname; const Type* fty; u32 foff; @@ -411,11 +414,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(p)->kind != TOK_IDENT || - ident_kw_inline(p, tok_ident(p_cur(p))) != KW_NONE) { + if (p->cur.kind != TOK_IDENT || + ident_kw_inline(p, tok_ident(&p->cur)) != KW_NONE) { perr(p, "expected field name after '.'"); } - fname = tok_ident(p_cur(p)); + fname = tok_ident(&p->cur); advance(p); if (!cur_ty || (cur_ty->kind != TY_STRUCT && cur_ty->kind != TY_UNION)) { perr(p, "field designator on non-record type"); @@ -501,11 +504,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), '}') || p_cur(p)->kind == TOK_EOF) break; + if (is_punct(&p->cur, '}') || p->cur.kind == TOK_EOF) break; } else if (i >= ty->rec.nfields) { break; } - if (braced && is_punct(p_cur(p), '.')) { + if (braced && is_punct(&p->cur, '.')) { const Type* sub_ty; u32 sub_off; u32 top_idx = 0; @@ -531,7 +534,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(p), '}')) { + accept_punct(p, ',') && !is_punct(&p->cur, '}')) { init_aggregate_remainder(p, slot, arr_ty, cont.parent_offset, cont.parent_ty, cont.next_index); } @@ -556,7 +559,7 @@ static u32 init_struct_fields(Parser* p, FrameSlot slot, const Type* arr_ty, ++i; break; } - if (is_punct(p_cur(p), '}')) { + if (is_punct(&p->cur, '}')) { ++i; break; } @@ -591,7 +594,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(p), '}')) break; + if (is_punct(&p->cur, '}')) break; } for (++i; i < ty->arr.count; ++i) { zero_init_at(p, slot, arr_ty, offset + i * esz, ty->arr.elem); @@ -605,7 +608,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(p), '}')) break; + if (is_punct(&p->cur, '}')) break; } for (++i; i < ty->rec.nfields; ++i) { const Field* f = &ty->rec.fields[i]; @@ -631,12 +634,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(p)->kind == TOK_STR && - string_literal_initializes_array(p, elem_ty, p_cur(p))) { + if (p->cur.kind == TOK_STR && + string_literal_initializes_array(p, elem_ty, &p->cur)) { init_string_at(p, slot, arr_ty, offset, elem_ty, ty->arr.count); return; } - if (is_punct(p_cur(p), '{') && peek1(p).kind == TOK_STR) { + if (is_punct(&p->cur, '{') && peek1(p).kind == TOK_STR) { Tok str = peek1(p); if (string_literal_initializes_array(p, elem_ty, &str)) { advance(p); @@ -646,7 +649,7 @@ void init_at(Parser* p, FrameSlot slot, const Type* arr_ty, u32 offset, return; } } - if (!is_punct(p_cur(p), '{')) { + if (!is_punct(&p->cur, '{')) { init_aggregate_remainder(p, slot, arr_ty, offset, ty, 0); return; } @@ -654,9 +657,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(p), '}')) { + if (!is_punct(&p->cur, '}')) { for (;;) { - if (is_punct(p_cur(p), '[')) { + if (is_punct(&p->cur, '[')) { const Type* sub_ty; u32 sub_off; u32 top_idx = 0; @@ -670,7 +673,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(p), '}')) { + accept_punct(p, ',') && !is_punct(&p->cur, '}')) { init_aggregate_remainder(p, slot, arr_ty, cont.parent_offset, cont.parent_ty, cont.next_index); } @@ -685,7 +688,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(p), '}')) break; + if (is_punct(&p->cur, '}')) break; } } expect_punct(p, '}', "'}' after array initializer"); @@ -699,7 +702,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(p), '{')) { + if (!is_punct(&p->cur, '{')) { if (try_init_aggregate_from_expr(p, slot, arr_ty, offset, ty)) return; init_aggregate_remainder(p, slot, arr_ty, offset, ty, 0); return; @@ -720,7 +723,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(p), '.')) { + if (had_brace && is_punct(&p->cur, '.')) { const Type* sub_ty; u32 sub_off; u32 top_idx = 0; @@ -844,13 +847,13 @@ static double parse_static_float_primary(Parser* p) { expect_punct(p, ')', "')' in floating constant expression"); return v; } - if (p_cur(p)->kind == TOK_FLT) { - v = parse_float_literal(p, p_cur(p)); + if (p->cur.kind == TOK_FLT) { + v = parse_float_literal(p, &p->cur); advance(p); return v; } - if (p_cur(p)->kind == TOK_NUM) { - v = (double)parse_int_literal(p, p_cur(p)); + if (p->cur.kind == TOK_NUM) { + v = (double)parse_int_literal(p, &p->cur); advance(p); return v; } @@ -1062,7 +1065,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(p), '{')) { + if (!is_punct(&p->cur, '{')) { perr(p, "expected compound literal initializer in static initializer"); } r.kind = C_STATIC_CONST_ADDR; @@ -1117,7 +1120,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(p), '(')) { + if (is_punct(&p->cur, '(')) { Tok n = peek1(p); if (starts_type_name(p, &n)) { const Type* cast_ty; @@ -1148,7 +1151,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(p); + Tok t = p->cur; Sym name = 0; int saw_amp = 0; i64 element_addend = 0; @@ -1172,7 +1175,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(p), '(')) { + if (is_punct(&p->cur, '(')) { Tok n = peek1(p); if (starts_type_name(p, &n)) { const Type* lit_ty; @@ -1184,11 +1187,11 @@ static int try_parse_static_address_const(Parser* p, CStaticConst* out) { return 1; } } - if (p_cur(p)->kind != TOK_IDENT || - ident_kw_inline(p, tok_ident(p_cur(p))) != KW_NONE) { + if (p->cur.kind != TOK_IDENT || + ident_kw_inline(p, tok_ident(&p->cur)) != KW_NONE) { perr(p, "expected identifier after '&' in static initializer"); } - name = tok_ident(p_cur(p)); + name = tok_ident(&p->cur); advance(p); } else if (t.kind == TOK_IDENT && ident_kw_inline(p, tok_ident(&t)) == KW_NONE) { @@ -1203,10 +1206,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(p), '[')) { + if (saw_amp && is_punct(&p->cur, '[')) { SrcLoc cloc; advance(p); - cloc = tok_loc_init(p, p_cur(p)); + cloc = tok_loc_init(p, &p->cur); element_addend = eval_const_int(p, cloc); expect_punct(p, ']', "']' after array-subscript constant"); if (tgt_ty && tgt_ty->kind == TY_ARRAY) { @@ -1216,12 +1219,12 @@ static int try_parse_static_address_const(Parser* p, CStaticConst* out) { byte_addend += element_addend; } } - while (is_punct(p_cur(p), '+') || is_punct(p_cur(p), '-')) { - int neg = is_punct(p_cur(p), '-'); + while (is_punct(&p->cur, '+') || is_punct(&p->cur, '-')) { + int neg = is_punct(&p->cur, '-'); SrcLoc cloc; i64 v; advance(p); - cloc = tok_loc_init(p, p_cur(p)); + cloc = tok_loc_init(p, &p->cur); v = eval_const_int(p, cloc); if (neg) v = -v; if (tgt_ty && tgt_ty->kind == TY_ARRAY) { @@ -1246,25 +1249,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), P_AND)) { + if (is_punct(&p->cur, 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(p)->kind != TOK_IDENT || - ident_kw_inline(p, tok_ident(p_cur(p))) != KW_NONE) { + if (p->cur.kind != TOK_IDENT || + ident_kw_inline(p, tok_ident(&p->cur)) != KW_NONE) { perr(p, "expected label name after '&&' in static initializer"); } - lname = tok_ident(p_cur(p)); - lloc = tok_loc_init(p, p_cur(p)); + lname = tok_ident(&p->cur); + lloc = tok_loc_init(p, &p->cur); 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(p), '(')) { + if (is_punct(&p->cur, '(')) { 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 @@ -1277,7 +1280,7 @@ static CStaticConst parse_static_const(Parser* p, const Type* ty, SrcLoc loc) { return r; } } - if (is_punct(p_cur(p), '(')) { + if (is_punct(&p->cur, '(')) { Tok n = peek1(p); if (starts_type_name(p, &n)) { const Type* cast_ty; @@ -1286,7 +1289,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(p), '{')) { + if (is_punct(&p->cur, '{')) { const Type* lit_unqual = type_unqual(p->pool, cast_ty); if (!lit_unqual || lit_unqual->kind != TY_ARRAY) { perr(p, @@ -1300,9 +1303,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(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)) && + (p->cur.kind == TOK_STR || is_punct(&p->cur, '&') || + (p->cur.kind == TOK_IDENT && + ident_kw_inline(p, tok_ident(&p->cur)) == KW_NONE)) && try_parse_static_address_const(p, &r)) { return r; } @@ -1335,7 +1338,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(p)); + SrcLoc cloc = tok_loc_init(p, &p->cur); CStaticConst parsed = parse_static_const(p, field_ty, cloc); u32 storage_off = rec_offset + fl->offset; u32 storage_size = fl->storage_size; @@ -1371,7 +1374,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(p), '}')) break; + if (is_punct(&p->cur, '}')) break; } return; } @@ -1392,7 +1395,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(p), '}')) break; + if (is_punct(&p->cur, '}')) break; } return; } @@ -1409,7 +1412,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(p), '(')) { + is_punct(&p->cur, '(')) { Tok n = peek1(p); if (starts_type_name(p, &n)) { advance(p); @@ -1427,12 +1430,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(p)->kind == TOK_STR && - string_literal_initializes_array(p, elem, p_cur(p))) { + if (p->cur.kind == TOK_STR && + string_literal_initializes_array(p, elem, &p->cur)) { parse_static_string_at(p, buf, buflen, offset, elem, ty->arr.count); return; } - if (is_punct(p_cur(p), '{') && peek1(p).kind == TOK_STR) { + if (is_punct(&p->cur, '{') && peek1(p).kind == TOK_STR) { Tok str = peek1(p); if (string_literal_initializes_array(p, elem, &str)) { advance(p); @@ -1447,9 +1450,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(p), '}')) { + if (!is_punct(&p->cur, '}')) { for (;;) { - if (is_punct(p_cur(p), '[')) { + if (is_punct(&p->cur, '[')) { const Type* sub_ty; u32 sub_off; u32 top_idx = 0; @@ -1459,7 +1462,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(p), '}')) { + accept_punct(p, ',') && !is_punct(&p->cur, '}')) { parse_static_aggregate_remainder(p, buf, buflen, cont.parent_offset, cont.parent_ty, cont.next_index); } @@ -1472,7 +1475,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(p), '}')) break; + if (is_punct(&p->cur, '}')) break; } } expect_punct(p, '}', "'}' after array initializer"); @@ -1489,9 +1492,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), '}') && p_cur(p)->kind != TOK_EOF) { + while (!is_punct(&p->cur, '}') && p->cur.kind != TOK_EOF) { const Field* f; - if (is_punct(p_cur(p), '.')) { + if (is_punct(&p->cur, '.')) { const Type* sub_ty; u32 sub_off; u32 top_idx = 0; @@ -1504,7 +1507,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(p), '}')) { + accept_punct(p, ',') && !is_punct(&p->cur, '}')) { parse_static_aggregate_remainder(p, buf, buflen, cont.parent_offset, cont.parent_ty, cont.next_index); } @@ -1537,7 +1540,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(p), '.')) { + if (had_brace && is_punct(&p->cur, '.')) { const Type* sub_ty; u32 sub_off; u32 top_idx = 0; @@ -1563,7 +1566,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(p)); + SrcLoc cloc = tok_loc_init(p, &p->cur); 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,37 +234,6 @@ 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 * ============================================================ */ @@ -278,7 +247,12 @@ typedef struct Parser { u8 default_visibility; /* SymVis */ u8 auto_var_init; /* KitAutoVarInit: implicit init for uninit locals */ - ParserInput input; + Tok cur; + Tok next; + int has_next; + + Tok pending; + int has_pending; Sym kw_sym[KW_COUNT]; KwTab kw_map; /* keyword/alias Sym -> CKw; built once, see ident_kw_inline */ @@ -432,13 +406,6 @@ 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 * ============================================================ */ @@ -476,13 +443,6 @@ 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); @@ -690,7 +650,4 @@ 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(p), k)) return 0; + if (!is_kw(p, &p->cur, 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(p), ';')) { + if (!is_punct(&p->cur, ';')) { 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(p), ')')) { + if (!is_punct(&p->cur, ')')) { 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(p), KW_WHILE)) perr(p, "expected 'while' after do-body"); + if (!is_kw(p, &p->cur, 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(p), '*')) { + if (is_punct(&p->cur, '*')) { parse_computed_goto(p); return; } - if (p_cur(p)->kind != TOK_IDENT || - ident_kw_inline(p, tok_ident(p_cur(p))) != KW_NONE) { + if (p->cur.kind != TOK_IDENT || + ident_kw_inline(p, tok_ident(&p->cur)) != KW_NONE) { perr(p, "expected label name after 'goto'"); } - name = tok_ident(p_cur(p)); - loc = tok_loc_stmt(p, p_cur(p)); + name = tok_ident(&p->cur); + loc = tok_loc_stmt(p, &p->cur); 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(p)); - SrcLoc loc = tok_loc_stmt(p, p_cur(p)); + Sym name = tok_ident(&p->cur); + SrcLoc loc = tok_loc_stmt(p, &p->cur); 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(p)); + SrcLoc loc = tok_loc_stmt(p, &p->cur); 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(p)); + SrcLoc loc = tok_loc_stmt(p, &p->cur); 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(p))); + v = eval_const_int(p, tok_loc_stmt(p, &p->cur)); expect_punct(p, ',', "',' separating _Static_assert args"); - if (p_cur(p)->kind != TOK_STR) { + if (p->cur.kind != TOK_STR) { perr(p, "expected string literal as _Static_assert message"); } { - Tok msg = *p_cur(p); + Tok msg = p->cur; 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(p), '[')) return 0; + if (!is_punct(&p->cur, '[')) return 0; advance(p); - if (p_cur(p)->kind != TOK_IDENT) { + if (p->cur.kind != TOK_IDENT) { perr(p, "expected identifier inside '[name]' on asm operand"); } - name = tok_ident(p_cur(p)); + name = tok_ident(&p->cur); 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(p)->kind != TOK_STR) { + if (p->cur.kind != TOK_STR) { perr(p, "expected string literal in %.*s", KIT_SLICE_ARG(kit_slice_cstr(what))); } - t = *p_cur(p); + t = p->cur; 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 the current token positioned at the first token of the operand expression, + * Called with p->cur 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(p)->kind != TOK_IDENT) return 0; + if (p->cur.kind != TOK_IDENT) return 0; nxt = peek1(p); if (!is_punct(&nxt, ')')) return 0; - e = scope_lookup(p, tok_ident(p_cur(p))); + e = scope_lookup(p, tok_ident(&p->cur)); 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(p)); + SrcLoc loc = tok_loc_stmt(p, &p->cur); 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(p), ':') && !is_punct(p_cur(p), ')')) { + if (!is_punct(&p->cur, ':') && !is_punct(&p->cur, ')')) { 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(p), ':') && !is_punct(p_cur(p), ')')) { + if (!is_punct(&p->cur, ':') && !is_punct(&p->cur, ')')) { 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(p), ':') && !is_punct(p_cur(p), ')')) { + if (!is_punct(&p->cur, ':') && !is_punct(&p->cur, ')')) { 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(p), ')')) { + if (!is_punct(&p->cur, ')')) { for (;;) { - if (p_cur(p)->kind != TOK_IDENT) { + if (p->cur.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), '}') && p_cur(p)->kind != TOK_EOF) { - if (p_cur(p)->kind == TOK_NEWLINE || is_pp_hash(p_cur(p))) { + while (!is_punct(&p->cur, '}') && p->cur.kind != TOK_EOF) { + if (p->cur.kind == TOK_NEWLINE || is_pp_hash(&p->cur)) { advance(p); continue; } - if (is_kw(p, p_cur(p), KW_STATIC_ASSERT)) { + if (is_kw(p, &p->cur, KW_STATIC_ASSERT)) { parse_static_assert(p); continue; } { DeclSpecs specs; - Tok save_tok = *p_cur(p); + Tok save_tok = p->cur; (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(p))); - if (p_cur(p)->kind == TOK_IDENT && - ident_kw_inline(p, tok_ident(p_cur(p))) == KW_NONE) { + 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) { Tok n = peek1(p); if (is_punct(&n, ':')) { parse_label_stmt(p); return; } } - if (is_punct(p_cur(p), '{')) { + if (is_punct(&p->cur, '{')) { parse_compound_stmt(p); return; } - if (is_punct(p_cur(p), ';')) { + if (is_punct(&p->cur, ';')) { advance(p); return; } - if (is_kw(p, p_cur(p), KW_IF)) { + if (is_kw(p, &p->cur, KW_IF)) { advance(p); parse_if_stmt(p); return; } - if (is_kw(p, p_cur(p), KW_WHILE)) { + if (is_kw(p, &p->cur, KW_WHILE)) { advance(p); parse_while_stmt(p); return; } - if (is_kw(p, p_cur(p), KW_FOR)) { + if (is_kw(p, &p->cur, KW_FOR)) { advance(p); parse_for_stmt(p); return; } - if (is_kw(p, p_cur(p), KW_DO)) { + if (is_kw(p, &p->cur, KW_DO)) { advance(p); parse_do_stmt(p); return; } - if (is_kw(p, p_cur(p), KW_RETURN)) { + if (is_kw(p, &p->cur, KW_RETURN)) { advance(p); parse_return_stmt(p); return; } - if (is_kw(p, p_cur(p), KW_BREAK)) { + if (is_kw(p, &p->cur, KW_BREAK)) { advance(p); parse_break_stmt(p); return; } - if (is_kw(p, p_cur(p), KW_CONTINUE)) { + if (is_kw(p, &p->cur, KW_CONTINUE)) { advance(p); parse_continue_stmt(p); return; } - if (is_kw(p, p_cur(p), KW_GOTO)) { + if (is_kw(p, &p->cur, KW_GOTO)) { advance(p); parse_goto_stmt(p); return; } - if (is_kw(p, p_cur(p), KW_SWITCH)) { + if (is_kw(p, &p->cur, KW_SWITCH)) { advance(p); parse_switch_stmt(p); return; } - if (is_kw(p, p_cur(p), KW_CASE)) { + if (is_kw(p, &p->cur, KW_CASE)) { advance(p); parse_case_stmt(p); return; } - if (is_kw(p, p_cur(p), KW_DEFAULT)) { + if (is_kw(p, &p->cur, KW_DEFAULT)) { advance(p); parse_default_stmt(p); return; } - if (is_kw(p, p_cur(p), KW_ASM) || is_kw(p, p_cur(p), KW_BUILTIN_ASM)) { + if (is_kw(p, &p->cur, KW_ASM) || is_kw(p, &p->cur, 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(p), k)) { + if (is_kw(p, &p->cur, k)) { advance(p); return 1; } @@ -111,20 +111,18 @@ static const Type* attrs_apply_type_mode(Parser* p, const Type* base, } int starts_attr(const Parser* p) { - return p_cur_const(p)->kind == TOK_IDENT && - tok_ident(p_cur_const(p)) == p->sym_attribute; + return p->cur.kind == TOK_IDENT && tok_ident(&p->cur) == p->sym_attribute; } static int starts_asm_label(const Parser* p) { - return is_kw(p, p_cur_const(p), KW_ASM) || - is_kw(p, p_cur_const(p), KW_BUILTIN_ASM); + return is_kw(p, &p->cur, KW_ASM) || is_kw(p, &p->cur, 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(p)->kind != TOK_STR) { + if (p->cur.kind != TOK_STR) { perr(p, "expected string literal in asm label"); } /* Capture the label string for the declarator currently being parsed. For a @@ -132,7 +130,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(p); + Tok t = p->cur; size_t nlen = 0; u8* bytes = decode_string_literal(p, &t, &nlen); u32 ilen = (nlen > 0) ? (u32)(nlen - 1) : 0; @@ -143,7 +141,7 @@ static Sym parse_asm_label(Parser* p) { } do { advance(p); - } while (p_cur(p)->kind == TOK_STR); + } while (p->cur.kind == TOK_STR); expect_punct(p, ')', "')' after asm label"); return label; } @@ -218,16 +216,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(p), '(')) perr(p, "internal: skip_balanced_parens"); + if (!is_punct(&p->cur, '(')) perr(p, "internal: skip_balanced_parens"); depth = 1; advance(p); while (depth > 0) { - if (p_cur(p)->kind == TOK_EOF) { + if (p->cur.kind == TOK_EOF) { perr(p, "unexpected EOF inside attribute arguments"); } - if (is_punct(p_cur(p), '(')) + if (is_punct(&p->cur, '(')) ++depth; - else if (is_punct(p_cur(p), ')')) { + else if (is_punct(&p->cur, ')')) { --depth; if (depth == 0) { advance(p); @@ -240,7 +238,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(p), '(')) { + if (!is_punct(&p->cur, '(')) { if (shape == AS_NONE || shape == AS_OPTIONAL || shape == AS_INT_OPT || shape == AS_OPAQUE) { return; @@ -265,7 +263,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(p), ')')) { + if (is_punct(&p->cur, ')')) { if (shape == AS_INT) { perr(p, "attribute '%.*s' expects an integer argument", KIT_SLICE_ARG(kit_slice_cstr(attr_diag_name))); @@ -273,7 +271,7 @@ static void parse_attr_args(Parser* p, Attr* a, AttrArgShape shape, advance(p); return; } - loc = tok_loc(p, p_cur(p)); + loc = tok_loc(p, &p->cur); 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)) { @@ -285,12 +283,12 @@ static void parse_attr_args(Parser* p, Attr* a, AttrArgShape shape, } case AS_STRING: { advance(p); /* '(' */ - if (p_cur(p)->kind != TOK_STR) { + if (p->cur.kind != TOK_STR) { perr(p, "attribute '%.*s' expects a string literal", KIT_SLICE_ARG(kit_slice_cstr(attr_diag_name))); } { - Tok t = *p_cur(p); + Tok t = p->cur; size_t nlen = 0; u8* bytes = decode_string_literal(p, &t, &nlen); u32 ilen = (nlen > 0) ? (u32)(nlen - 1) : 0; @@ -306,11 +304,11 @@ static void parse_attr_args(Parser* p, Attr* a, AttrArgShape shape, } case AS_IDENT: { advance(p); /* '(' */ - if (p_cur(p)->kind != TOK_IDENT) { + if (p->cur.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(p)); + a->v.sym = tok_ident(&p->cur); a->nargs = 1; advance(p); expect_punct(p, ')', "')' after attribute identifier argument"); @@ -320,15 +318,15 @@ static void parse_attr_args(Parser* p, Attr* a, AttrArgShape shape, SrcLoc mloc, nloc; i64 mv, nv; advance(p); /* '(' */ - if (p_cur(p)->kind != TOK_IDENT) { + if (p->cur.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(p)); + mloc = tok_loc(p, &p->cur); mv = eval_const_int(p, mloc); expect_punct(p, ',', "',' after format string-index"); - nloc = tok_loc(p, p_cur(p)); + nloc = tok_loc(p, &p->cur); nv = eval_const_int(p, nloc); if (mv < 0 || mv > 0xFFFF || nv < 0 || nv > 0xFFFF) { perr(p, "attribute 'format' indices out of range"); @@ -351,7 +349,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(p)); + SrcLoc kw_loc = tok_loc(p, &p->cur); advance(p); /* __attribute__ */ expect_punct(p, '(', "'(' after __attribute__"); expect_punct(p, '(', "'((' after __attribute__"); @@ -365,15 +363,15 @@ Attr* parse_attribute_spec_list(Parser* p) { size_t canon_len; while (accept_punct(p, ',')) { /* skip */ } - if (is_punct(p_cur(p), ')')) break; - if (p_cur(p)->kind != TOK_IDENT) { + if (is_punct(&p->cur, ')')) break; + if (p->cur.kind != TOK_IDENT) { perr(p, "expected attribute name"); } - aname = tok_ident(p_cur(p)); + aname = tok_ident(&p->cur); 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(p)); + a->loc = tok_loc(p, &p->cur); a->name = aname; a->kind = (u16)classify_attr(p, aname, &shape); advance(p); @@ -610,9 +608,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(p)); + loc = tok_loc(p, &p->cur); for (;;) { - Tok t = *p_cur(p); + Tok t = p->cur; /* 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). */ @@ -781,11 +779,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(p))) { + if (starts_type_name(p, &p->cur)) { 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(p))); + i64 v = eval_const_int(p, tok_loc(p, &p->cur)); if (v < 0) perr(p, "_Alignas requires a non-negative alignment"); a = (u32)v; } @@ -957,12 +955,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), '}') && p_cur(p)->kind != TOK_EOF) { + while (!is_punct(&p->cur, '}') && p->cur.kind != TOK_EOF) { DeclSpecs specs; if (!parse_decl_specs(p, &specs)) { perr(p, "expected member declaration"); } - if (is_punct(p_cur(p), ';')) { + if (is_punct(&p->cur, ';')) { if (specs.type && (specs.type->kind == TY_STRUCT || specs.type->kind == TY_UNION)) { Field f; @@ -979,11 +977,11 @@ static void parse_member_decls(Parser* p, TypeRecordBuilder* b) { } for (;;) { Sym mname = 0; - SrcLoc mloc = tok_loc(p, p_cur(p)); + SrcLoc mloc = tok_loc(p, &p->cur); const Type* mty; Field f; memset(&f, 0, sizeof f); - if (is_punct(p_cur(p), ':')) { + if (is_punct(&p->cur, ':')) { advance(p); if (!type_is_int(specs.type)) perr(p, "bit-field has non-integer type"); i64 w = eval_const_int(p, mloc); @@ -1048,13 +1046,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(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)); + 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); advance(p); } - int has_body = is_punct(p_cur(p), '{'); + int has_body = is_punct(&p->cur, '{'); if (!has_body && tag_name == 0) { perr(p, "expected tag name or '{' after struct/union"); } @@ -1143,10 +1141,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(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)); + 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); advance(p); } /* C23 §6.7.2.2: an optional fixed underlying type — `enum [tag] : T` — @@ -1159,7 +1157,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(p), '{'); + int has_body = is_punct(&p->cur, '{'); if (!has_body && tag_name == 0) { perr(p, "expected tag name or '{' after enum"); } @@ -1199,13 +1197,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(p)); + SrcLoc nloc = tok_loc(p, &p->cur); SymEntry* e; - if (p_cur(p)->kind != TOK_IDENT || - ident_kw_inline(p, tok_ident(p_cur(p))) != KW_NONE) { + if (p->cur.kind != TOK_IDENT || + ident_kw_inline(p, tok_ident(&p->cur)) != KW_NONE) { perr(p, "expected enumerator name"); } - name = tok_ident(p_cur(p)); + name = tok_ident(&p->cur); advance(p); i64 val = next_val; if (accept_punct(p, '=')) { @@ -1230,7 +1228,7 @@ const Type* parse_enum(Parser* p, Attr** anon_attrs_out) { nconsts++; } if (!accept_punct(p, ',')) break; - if (is_punct(p_cur(p), '}')) break; + if (is_punct(&p->cur, '}')) break; } expect_punct(p, '}', "'}' after enumerator list"); ((Type*)et)->enm.consts = consts; @@ -1381,7 +1379,7 @@ static void parse_param_array_bound(Parser* p, DeclSuffix* out) { return; } while (depth > 0) { - Tok t = *p_cur(p); + Tok t = p->cur; if (t.kind == TOK_EOF) { perr(p, "unexpected EOF in parameter array bound"); } @@ -1443,7 +1441,7 @@ int parse_decl_suffix(Parser* p, DeclSuffix* out) { return 1; } { - Tok t = *p_cur(p); + Tok t = p->cur; /* 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 @@ -1465,7 +1463,7 @@ int parse_decl_suffix(Parser* p, DeclSuffix* out) { } } if (is_const_start) { - SrcLoc cloc = tok_loc(p, p_cur(p)); + SrcLoc cloc = tok_loc(p, &p->cur); i64 v = eval_const_int(p, cloc); if (v < 0) perr(p, "negative array size"); out->count = (u32)v; @@ -1593,7 +1591,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(p), '(')) { + if (is_punct(&p->cur, '(')) { Tok n = peek1(p); int is_inner = 0; if (is_punct(&n, '*')) { @@ -1634,12 +1632,12 @@ const Type* parse_declarator_full_info(Parser* p, const Type* base, } inner_quals[nptrs_inner++] = q; } - 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)); + 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); advance(p); - } else if (is_punct(p_cur(p), '(')) { + } else if (is_punct(&p->cur, '(')) { Tok nn = peek1(p); if (!is_punct(&nn, '*')) { if (!allow_abstract) perr(p, "expected declarator name"); @@ -1674,10 +1672,10 @@ const Type* parse_declarator_full_info(Parser* p, const Type* base, } nested_quals[nptrs_nested++] = q; } - 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)); + 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); advance(p); } else if (!allow_abstract) { perr(p, "expected declarator name"); @@ -1699,10 +1697,10 @@ const Type* parse_declarator_full_info(Parser* p, const Type* base, } if (!has_inner_parens) { - 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)); + 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); advance(p); } else if (!allow_abstract) { perr(p, "expected declarator name"); @@ -1721,7 +1719,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(p), '[') || is_punct(p_cur(p), '('))) { + if (nsuffs == 8 && (is_punct(&p->cur, '[') || is_punct(&p->cur, '('))) { perr(p, "too many declarator suffixes (raise the cap if needed)"); } if (n_inner_suffs > 0 && inner_suffs[0].kind == DS_FUNC) { @@ -1777,9 +1775,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(p)->kind == TOK_STR && - string_literal_initializes_array(p, elem, p_cur(p))) { - Tok t = *p_cur(p); + if (p->cur.kind == TOK_STR && + string_literal_initializes_array(p, elem, &p->cur)) { + Tok t = p->cur; size_t n = 0; u8* bytes = decode_string_literal(p, &t, &n); u32 elem_size = c_abi_sizeof(p->abi, p->pool, elem); @@ -1788,7 +1786,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(p), '{')) { + if (is_punct(&p->cur, '{')) { u32 cnt; record_braced_block(p); cnt = count_recorded_top_level_items(p->replay, p->replay_len);