kit

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

internal.h (23045B)


      1 #ifndef KIT_GRAM_INTERNAL_H
      2 #define KIT_GRAM_INTERNAL_H
      3 
      4 #include <ctype.h>
      5 #include <limits.h>
      6 #include <setjmp.h>
      7 #include <stdarg.h>
      8 #include <stdbool.h>
      9 #include <stddef.h>
     10 #include <stdint.h>
     11 #include <stdio.h>
     12 #include <stdlib.h>
     13 #include <string.h>
     14 
     15 #include <kit/gram.h>
     16 #include <kit/support/gram_lex_tables.h>
     17 #include <kit/support/gram_parse_tables.h>
     18 #include <kit/gram_unicode.h>
     19 
     20 #define diag_vset kit_gram_diag_vset
     21 #define diag_set kit_gram_diag_set
     22 #define die_oom kit_gram_die_oom
     23 #define xmalloc kit_gram_xmalloc
     24 #define xrealloc kit_gram_xrealloc
     25 #define xcalloc kit_gram_xcalloc
     26 #define xfree kit_gram_xfree
     27 #define mem_release kit_gram_mem_release
     28 #define scratch_enter kit_gram_scratch_enter
     29 #define scratch_leave kit_gram_scratch_leave
     30 #define scratch_release kit_gram_scratch_release
     31 #define xstrndup kit_gram_xstrndup
     32 #define xstrdup kit_gram_xstrdup
     33 #define xasprintf kit_gram_xasprintf
     34 #define buf_init kit_gram_buf_init
     35 #define buf_init_writer kit_gram_buf_init_writer
     36 #define buf_reserve kit_gram_buf_reserve
     37 #define buf_appendn kit_gram_buf_appendn
     38 #define buf_append kit_gram_buf_append
     39 #define buf_append_uint kit_gram_buf_append_uint
     40 #define buf_take kit_gram_buf_take
     41 #define str_from_owned kit_gram_str_from_owned
     42 #define str_dup_len kit_gram_str_dup_len
     43 #define str_dup_c kit_gram_str_dup_c
     44 #define str_eq kit_gram_str_eq
     45 #define str_eq_c kit_gram_str_eq_c
     46 #define str_to_c kit_gram_str_to_c
     47 #define intern_len kit_gram_intern_len
     48 #define intern_c kit_gram_intern_c
     49 #define name_index_find kit_gram_name_index_find
     50 #define name_index_put kit_gram_name_index_put
     51 #define ast_seq_new kit_gram_ast_seq_new
     52 #define ast_alt_new kit_gram_ast_alt_new
     53 #define ast_node_new kit_gram_ast_node_new
     54 #define ast_lex_seq_new kit_gram_ast_lex_seq_new
     55 #define ast_lex_alt_new kit_gram_ast_lex_alt_new
     56 #define ast_lex_node_new kit_gram_ast_lex_node_new
     57 #define ast_seq_append kit_gram_ast_seq_append
     58 #define ast_alt_append kit_gram_ast_alt_append
     59 #define ast_lex_seq_append kit_gram_ast_lex_seq_append
     60 #define ast_lex_alt_append kit_gram_ast_lex_alt_append
     61 #define hex_val kit_gram_hex_val
     62 #define is_c_ident_str kit_gram_is_c_ident_str
     63 #define is_rule_name kit_gram_is_rule_name
     64 #define is_token_name kit_gram_is_token_name
     65 #define intset_contains kit_gram_intset_contains
     66 #define intset_add kit_gram_intset_add
     67 #define intset_union kit_gram_intset_union
     68 #define intset_copy kit_gram_intset_copy
     69 #define intset_sorted kit_gram_intset_sorted
     70 #define intset_equal kit_gram_intset_equal
     71 #define intset_intersection_min kit_gram_intset_intersection_min
     72 #define c_string_str kit_gram_c_string_str
     73 
     74 typedef struct GramgenContext GramgenContext;
     75 typedef struct ScalarSetCacheEntry ScalarSetCacheEntry;
     76 
     77 typedef struct {
     78   const char* path;
     79   uint32_t line, col;
     80 } Loc;
     81 
     82 /* Pending diagnostic, captured into the GramgenContext and flushed to the
     83  * caller's KitContext.diag sink at the public-API boundary. (Replaces the
     84  * upstream gramgen_diagnostic out-param; kit routes diagnostics through
     85  * KitContext.diag.) */
     86 typedef struct {
     87   const char* path;
     88   uint32_t line, col;
     89   char message[512];
     90 } GramDiag;
     91 
     92 typedef struct {
     93   char* s;
     94   size_t len;
     95 } Str;
     96 
     97 typedef struct {
     98   GramgenContext* ctx;
     99   char* s;
    100   size_t len, cap;
    101   KitWriter* writer;       /* streaming sink; NULL => accumulate into `s` */
    102   const char* write_path;  /* for the "codegen write failed" diagnostic   */
    103 } Buf;
    104 
    105 /* Bump-allocated arena block. Allocations within a block are a pointer bump;
    106  * each carries a 16-byte size header so the most-recent allocation can be freed
    107  * (LIFO rewind) and realloc can grow in place. Non-LIFO frees are no-ops and
    108  * the space is reclaimed when the whole arena is released. */
    109 typedef struct ArenaBlock {
    110   struct ArenaBlock* next;
    111   size_t cap;  /* usable bytes in the data area */
    112   size_t used; /* bytes consumed so far          */
    113 } ArenaBlock;
    114 
    115 /* Tracked block for the freeing (list) allocator. Used for the scratch region
    116  * so a phase with large, simultaneously-live intermediates (the UTF-8 lexer
    117  * build) frees incrementally and keeps peak memory low — a bump arena can only
    118  * reclaim at the end, which would balloon mid-build peak. */
    119 typedef struct MemBlock {
    120   void* ptr;
    121   size_t size;
    122   struct MemBlock* next;
    123 } MemBlock;
    124 
    125 typedef struct InternEntry {
    126   char* s;
    127   size_t len;
    128   uint64_t hash;
    129   struct InternEntry* next;
    130 } InternEntry;
    131 
    132 /* A region allocator in one of two modes. MEM_BUMP (the permanent arena) bumps
    133  * a pointer and frees everything at once. MEM_LIST (the scratch region) tracks
    134  * each allocation so individual frees reclaim immediately, bounding peak. */
    135 typedef enum { MEM_BUMP, MEM_LIST } MemKind;
    136 typedef struct {
    137   KitHeap* heap;
    138   MemKind kind;
    139   ArenaBlock* head; /* MEM_BUMP: first block (for release) */
    140   ArenaBlock* cur;  /* MEM_BUMP: active bump block          */
    141   MemBlock* blocks; /* MEM_LIST: tracked allocations        */
    142 } GramgenMem;
    143 
    144 struct GramgenContext {
    145   GramgenMem mem;     /* permanent arena: owned by the compiled object   */
    146   GramgenMem scratch; /* transient arena: released after a scoped phase  */
    147   GramgenMem* active; /* arena that x* allocate from (NULL => &mem)       */
    148   InternEntry** intern_buckets;
    149   size_t intern_nbuckets, intern_count;
    150   ScalarSetCacheEntry* scalar_set_cache;
    151   int* union_tmp; /* reused scratch for intset_union merges (perm)    */
    152   size_t union_tmp_cap;
    153   const KitContext* kit; /* caller context: heap + diag sink              */
    154   GramDiag* diag;        /* -> diag_storage; populated then flushed to kit */
    155   GramDiag diag_storage;
    156   jmp_buf jmp;
    157   int can_jump;
    158 };
    159 
    160 typedef enum { AST_NAME, AST_LITERAL, AST_GROUP, AST_OPT, AST_REP } AstNodeKind;
    161 /* LEX_ANCHOR (edge anchor), LEX_REPEAT (counted/`+` quantifier), and LEX_NAME
    162  * (`%def` fragment reference) are front-end-only kinds: the anchor-extraction
    163  * and desugaring passes strip/expand/inline them on the lex AST before NFA
    164  * construction, so the byte and scalar pipelines never encounter them. */
    165 typedef enum {
    166   LEX_LITERAL,
    167   LEX_CLASS,
    168   LEX_PROP,
    169   LEX_ANY,
    170   LEX_GROUP,
    171   LEX_OPT,
    172   LEX_REP,
    173   LEX_ANCHOR,
    174   LEX_REPEAT,
    175   LEX_NAME
    176 } AstLexNodeKind;
    177 typedef enum { PRATT_NAME, PRATT_LITERAL } PrattAtomKind;
    178 /* LEX_LINE_DEF is a `%def` fragment definition: inlined and dropped during
    179  * desugaring, it never becomes a recognizer. LEX_LINE_KEYWORDS is a `%keywords`
    180  * block: its entries are extracted literals, never DFA recognizers. */
    181 typedef enum {
    182   LEX_LINE_TOKEN,
    183   LEX_LINE_SKIP,
    184   LEX_LINE_DEF,
    185   LEX_LINE_KEYWORDS
    186 } LexLineKind;
    187 
    188 /* Counted-repetition bound cap. `A{n,m}` bodies are unrolled into NFA states,
    189  * so both bounds are capped; overflow is a located error. */
    190 #define KIT_GRAM_MAX_REPEAT 255
    191 
    192 #define KIT_GRAM_HASH_OFFSET_BASIS 1469598103934665603ull
    193 #define KIT_GRAM_HASH_PRIME 1099511628211ull
    194 #define GROW_CAP(cap, init) ((cap) ? (cap) * 2 : (init))
    195 
    196 typedef struct AstNode AstNode;
    197 typedef struct AstSeq AstSeq;
    198 typedef struct AstAlt AstAlt;
    199 typedef struct AstLexNode AstLexNode;
    200 typedef struct AstLexSeq AstLexSeq;
    201 typedef struct AstLexAlt AstLexAlt;
    202 
    203 struct AstSeq {
    204   GramgenContext* ctx;
    205   AstNode** items;
    206   size_t nitems, cap;
    207   Loc loc;
    208 };
    209 
    210 struct AstAlt {
    211   GramgenContext* ctx;
    212   AstSeq** seqs;
    213   size_t nseqs, cap;
    214   Loc loc;
    215 };
    216 
    217 struct AstNode {
    218   AstNodeKind kind;
    219   Loc loc;
    220   Str value;
    221   AstAlt* alts;
    222 };
    223 
    224 struct AstLexSeq {
    225   GramgenContext* ctx;
    226   AstLexNode** items;
    227   size_t nitems, cap;
    228   Loc loc;
    229 };
    230 
    231 struct AstLexAlt {
    232   GramgenContext* ctx;
    233   AstLexSeq** seqs;
    234   size_t nseqs, cap;
    235   Loc loc;
    236 };
    237 
    238 struct AstLexNode {
    239   AstLexNodeKind kind;
    240   Loc loc;
    241   Str value;
    242   Str scalar_value;
    243   AstLexAlt* alts;
    244 };
    245 
    246 typedef struct {
    247   PrattAtomKind kind;
    248   Loc loc;
    249   Str value;
    250 } AstPrattAtom;
    251 
    252 typedef struct {
    253   GramgenContext* ctx;
    254   char* kind;
    255   Loc loc;
    256   AstPrattAtom** atoms;
    257   size_t natoms, cap;
    258 } AstPrattLine;
    259 
    260 typedef struct {
    261   GramgenContext* ctx;
    262   AstPrattLine** lines;
    263   size_t nlines, cap;
    264 } AstPrattSpec;
    265 
    266 typedef struct {
    267   char* name;
    268   Loc loc;
    269   AstAlt* alts;
    270   AstPrattSpec* pratt;
    271 } AstRule;
    272 
    273 typedef struct {
    274   Str literal;
    275   char* name;
    276   Loc loc;
    277   int used;
    278 } TokenDecl;
    279 
    280 /* One %keywords entry. A token name, a literal, or both; the missing side is
    281  * resolved by the builder (string -> auto-named token; bare name -> its %token
    282  * literal). */
    283 typedef struct {
    284   char* name;  /* token name, or NULL for the string-only form */
    285   Str literal; /* literal bytes when has_literal                */
    286   int has_literal;
    287   Loc loc;
    288 } AstKwEntry;
    289 
    290 typedef struct {
    291   LexLineKind kind;
    292   char* name; /* token/skip/def name; the host name for KEYWORDS */
    293   Loc loc;
    294   AstLexAlt* alts; /* NULL for a KEYWORDS line                        */
    295   AstKwEntry* kw_entries;
    296   size_t nkw_entries;
    297 } AstLexLine;
    298 
    299 typedef struct {
    300   GramgenContext* ctx;
    301   char* name;
    302   Loc loc;
    303   KitGramLexInputMode mode;
    304   AstLexLine** lines;
    305   size_t nlines, cap;
    306 } AstLexBlock;
    307 
    308 typedef struct {
    309   GramgenContext* ctx;
    310   AstRule** rules;
    311   size_t nrules, cap_rules;
    312   TokenDecl** token_decls;
    313   size_t ntoken_decls, cap_token_decls;
    314   AstLexBlock** lex_blocks;
    315   size_t nlex_blocks, cap_lex_blocks;
    316 } ParsedGrammar;
    317 
    318 typedef struct {
    319   int* v;
    320   size_t n, cap;
    321 } IntSet;
    322 
    323 typedef struct {
    324   const char** keys;
    325   int* values;
    326   size_t n, cap;
    327 } NameIndexMap;
    328 
    329 typedef enum { SYM_TERM, SYM_RULE, SYM_REP, SYM_OPT } SymKind;
    330 
    331 typedef struct Sym Sym;
    332 struct Sym {
    333   SymKind kind;
    334   Loc loc;
    335   int value;
    336   Sym* sub;
    337   int set_index;
    338   int sub_array_id;
    339 };
    340 
    341 typedef struct {
    342   Sym* syms;
    343   size_t nsyms, cap;
    344   Loc loc;
    345   IntSet first;
    346   int nullable;
    347 } Prod;
    348 
    349 typedef struct {
    350   char* role;
    351   int tok;        /* prefix/postfix/infix op; ternary op1; circumfix open */
    352   int tok2;       /* ternary op2; circumfix close (0 for unary/binary)    */
    353   int inner_rule; /* circumfix inner rule index (-1 otherwise)            */
    354   int prod;
    355   int lbp, rbp;
    356   Loc loc;
    357   char* enum_name;
    358 } PrattOp;
    359 
    360 typedef struct {
    361   int primary_rule;
    362   int primary_prod;
    363   PrattOp* ops;
    364   size_t nops, cap;
    365 } PrattInfo;
    366 
    367 typedef struct {
    368   char* name;
    369   Str display;
    370   Loc loc;
    371 } TokenDef;
    372 
    373 typedef struct {
    374   char* name;
    375   Loc loc;
    376   int public_rule;
    377   int index;
    378   Prod* prods;
    379   size_t nprods, cap_prods;
    380   PrattInfo* pratt;
    381   IntSet first, follow;
    382   int nullable;
    383   int empty_prod;
    384 } Rule;
    385 
    386 typedef struct {
    387   char* name;
    388   Loc loc;
    389   AstLexAlt* alts;
    390   int tok;
    391   int skip;
    392   int seq;
    393   int has_literal_key;
    394   Str literal_key;
    395   int start_anchor; /* KitGramLexAnchor */
    396   int end_anchor;   /* KitGramLexAnchor */
    397 } LexRecognizer;
    398 
    399 /* One extracted literal: its bytes and the token kind to rewrite to. */
    400 typedef struct {
    401   Str literal;
    402   int tok;
    403 } LexKeyword;
    404 
    405 /* All literals extracted under one host kind, addressed by a minimal perfect
    406  * hash. `slots` holds nslots keywords placed at their hash positions and
    407  * `seeds` holds the CHD bucket displacements. Mirrors the runtime
    408  * KitGramLexKeywordTable. */
    409 typedef struct {
    410   int host;          /* host token kind whose lexemes are looked up */
    411   LexKeyword* slots; /* nslots entries; keyword i at its perfect slot */
    412   size_t nslots;
    413   uint32_t* seeds; /* nseeds CHD displacements */
    414   size_t nseeds;
    415   size_t min_len;
    416   size_t max_len;
    417 } LexKeywordTable;
    418 
    419 /* A declared %keywords entry, resolved to (lexeme, token) plus its host name
    420  * and owning lexer. Collected before parser rules so a parser literal matching
    421  * a keyword resolves to its token without creating a DFA recognizer. */
    422 typedef struct {
    423   Str literal;
    424   int tok;
    425   char* host;  /* host token name; resolved to a kind in prepare_lexer */
    426   char* group; /* lexer (lex-block) name this keyword belongs to       */
    427   Loc loc;
    428 } KeywordBinding;
    429 
    430 typedef struct {
    431   char* name;
    432   Loc loc;
    433   LexRecognizer* recognizers;
    434   size_t nrecognizers;
    435   KitGramLexInputMode input;
    436   uint8_t class_of[256];
    437   uint16_t nclasses;
    438   uint16_t* trans;
    439   uint16_t nstates;
    440   uint16_t* accept;
    441   /* End-of-match context accepts (zero-width `\z`/`$` edges). NULL when no end
    442    * anchors. start_text/start_line are alternate start states for the start-of-
    443    * match context (`\A`/`^`); 0 when no start anchors (state 0 serves all). */
    444   uint16_t* accept_text;
    445   uint16_t* accept_line;
    446   uint16_t start_text;
    447   uint16_t start_line;
    448   /* Automatic keyword extraction: literals moved out of the DFA, grouped by
    449    * host kind (sorted by host, then lexeme). Empty when nothing was extracted.
    450    */
    451   LexKeywordTable* keyword_tables;
    452   size_t nkeyword_tables;
    453   /* ---- Token-machine (%machine) fields; NULL/0 for byte/scalar lexers. ----
    454    * A token machine is a regular language over an abstract symbol alphabet,
    455    * compiled codegen-only (it never materializes an KitGramLexGrammar).
    456    * class_of[] above is byte-only and unused here; the symbol->class map is
    457    * sym_class_of (uint16, NSYM-wide, no 256 cap), and `accept`/`trans` carry
    458    * the atom DFA directly (no UTF-8 lowering). Each recognizer is a named rule;
    459    * the accept id is the winning rule's source-order index (the kind report).
    460    */
    461   int is_machine;
    462   uint16_t* sym_class_of; /* nsym symbol -> class id                       */
    463   uint16_t nsym;          /* number of alphabet symbols                    */
    464   char** sym_names;       /* nsym symbol names, by id (first-use order)    */
    465   uint8_t* live;          /* per state: an accepting state still reachable */
    466 } LexDFA;
    467 
    468 typedef struct {
    469   GramgenContext* ctx;
    470   ParsedGrammar* pg;
    471   Rule* rules;
    472   size_t nrules, cap_rules;
    473   size_t public_count;
    474   TokenDef* tokens;
    475   size_t ntokens, cap_tokens;
    476   NameIndexMap token_index;
    477   NameIndexMap rule_index;
    478   /* O(1) lookups keyed by interned-pointer identity (every name/literal is
    479    * interned to a canonical pointer, so pointer identity == byte identity).
    480    * literal_* key on the literal's interned bytes; decl_name on a token
    481    * declaration's name. They replace what were linear scans over these lists.
    482    */
    483   NameIndexMap literal_decl_index; /* interned literal -> token_decls index */
    484   NameIndexMap decl_name_index;    /* token decl name  -> token_decls index */
    485   NameIndexMap kw_literal_index;   /* interned literal -> kw_bindings index  */
    486   NameIndexMap literal_rec_index;  /* interned literal -> literal_recs index */
    487   LexRecognizer* literal_recs;
    488   size_t nliteral_recs, cap_literal_recs;
    489   KeywordBinding* kw_bindings; /* declared %keywords entries (all lexers) */
    490   size_t nkw_bindings, cap_kw_bindings;
    491   LexDFA* lex_dfa; /* main lexer, when present */
    492   LexDFA* lex_dfas;
    493   size_t nlex_dfas, cap_lex_dfas;
    494   /* Token machines (%machine blocks). Kept separate from lex_dfas so they never
    495    * enter the byte/scalar KitGramLexGrammar emission or the TOK_* enum. */
    496   LexDFA* machines;
    497   size_t nmachines, cap_machines;
    498   IntSet* sets;
    499   size_t nsets, cap_sets;
    500   Sym** wrapper_syms;
    501   size_t nwrapper_syms, cap_wrapper_syms;
    502   int rec_seq;
    503   int multiline;        /* bake newline-aware ^/$ into emitted lexers */
    504   int lexer_standalone; /* emit a self-contained tokenizer + match API,
    505                            table-free (re2c-style scanner, no runtime link) */
    506   int fold_keywords;    /* standalone: fold %keywords into the DFA instead of
    507                            the default minimal-perfect-hash lookup */
    508   int position_lazy;    /* standalone: omit per-token line/col (emit 0) */
    509   int parser_codegen; /* also emit a recursive-descent parser (experimental) */
    510   int parser_recover; /* emit RD error-recovery machinery (opt-in) */
    511   /* Interned Pratt role/kind tokens. line->kind and op->role are interned, so
    512    * classification compares against these by pointer identity rather than
    513    * strcmp. Interned once in the compile context and carried on the builder,
    514    * so codegen (a separate context) compares against them too. */
    515   struct {
    516     char *primary, *prefix, *postfix, *infixl, *infixr, *infix, *ternary,
    517         *circumfix;
    518   } role;
    519 } Builder;
    520 
    521 typedef struct {
    522   uint32_t lo, hi;
    523 } ScalarRange;
    524 
    525 #define UNICODE_MAX_SCALAR 0x10FFFFu
    526 #define UNICODE_SURROGATE_FIRST 0xD800u
    527 #define UNICODE_SURROGATE_LAST 0xDFFFu
    528 
    529 typedef struct {
    530   GramgenContext* ctx;
    531   ScalarRange* v;
    532   size_t n, cap;
    533 } ScalarSet;
    534 
    535 struct ScalarSetCacheEntry {
    536   char* key;
    537   size_t key_len;
    538   uint64_t hash;
    539   ScalarSet set;
    540   ScalarSetCacheEntry* next;
    541 };
    542 
    543 /* Shared NFA->DFA core (subset construction, minimization, canonical relabel)
    544  * used by both the byte and scalar lexer pipelines. */
    545 #include "lex_dfa.h"
    546 
    547 /* Alphabet-neutral range-set NFA + atom partition + determinization, shared by
    548  * the utf8 scalar pipeline and the token-alphabet (%machine) pipeline. */
    549 #include "lex_range.h"
    550 
    551 void diag_vset(GramgenContext* ctx, Loc loc, const char* fmt, va_list ap);
    552 void diag_set(GramgenContext* ctx, Loc loc, const char* fmt, ...);
    553 void die_oom(GramgenContext* ctx);
    554 
    555 void* xmalloc(GramgenContext* ctx, size_t n);
    556 void* xrealloc(GramgenContext* ctx, void* p, size_t n);
    557 void* xcalloc(GramgenContext* ctx, size_t n, size_t size);
    558 void xfree(GramgenContext* ctx, void* p);
    559 void mem_release(GramgenMem* m);
    560 void scratch_enter(GramgenContext* ctx); /* route x* to the scratch arena   */
    561 void scratch_leave(GramgenContext* ctx); /* route x* back to the perm arena  */
    562 void scratch_release(GramgenContext* ctx); /* free everything in the scratch */
    563 char* xstrndup(GramgenContext* ctx, const char* s, size_t n);
    564 char* xstrdup(GramgenContext* ctx, const char* s);
    565 char* xasprintf(GramgenContext* ctx, const char* fmt, ...);
    566 
    567 void buf_init(GramgenContext* ctx, Buf* b);
    568 void buf_init_writer(GramgenContext* ctx, Buf* b, KitWriter* writer,
    569                      const char* path);
    570 void buf_reserve(Buf* b, size_t add);
    571 void buf_appendn(Buf* b, const char* s, size_t n);
    572 void buf_append(Buf* b, const char* s);
    573 void buf_append_uint(Buf* b, unsigned v);
    574 char* buf_take(Buf* b);
    575 
    576 Str str_from_owned(char* s, size_t len);
    577 Str str_dup_len(GramgenContext* ctx, const char* s, size_t len);
    578 Str str_dup_c(GramgenContext* ctx, const char* s);
    579 int str_eq(Str a, Str b);
    580 int str_eq_c(Str a, const char* b);
    581 char* str_to_c(GramgenContext* ctx, Str s);
    582 char* intern_len(GramgenContext* ctx, const char* s, size_t len);
    583 char* intern_c(GramgenContext* ctx, const char* s);
    584 int name_index_find(const NameIndexMap* map, const char* key, int* out);
    585 void name_index_put(GramgenContext* ctx, NameIndexMap* map, const char* key,
    586                     int value);
    587 
    588 AstSeq* ast_seq_new(GramgenContext* ctx, Loc loc);
    589 AstAlt* ast_alt_new(GramgenContext* ctx, Loc loc);
    590 AstNode* ast_node_new(GramgenContext* ctx, AstNodeKind kind, Loc loc);
    591 AstLexSeq* ast_lex_seq_new(GramgenContext* ctx, Loc loc);
    592 AstLexAlt* ast_lex_alt_new(GramgenContext* ctx, Loc loc);
    593 AstLexNode* ast_lex_node_new(GramgenContext* ctx, AstLexNodeKind kind, Loc loc);
    594 void ast_seq_append(AstSeq* seq, AstNode* node);
    595 void ast_alt_append(AstAlt* alt, AstSeq* seq);
    596 void ast_lex_seq_append(AstLexSeq* seq, AstLexNode* node);
    597 void ast_lex_alt_append(AstLexAlt* alt, AstLexSeq* seq);
    598 
    599 void kit_gram_error(GramgenContext* ctx, Loc loc, const char* fmt, ...);
    600 int hex_val(int c);
    601 int is_c_ident_str(Str s);
    602 int is_rule_name(const char* name);
    603 int is_token_name(const char* name);
    604 
    605 int intset_contains(const IntSet* s, int v);
    606 int intset_add(GramgenContext* ctx, IntSet* s, int v);
    607 int intset_union(GramgenContext* ctx, IntSet* dst, const IntSet* src);
    608 IntSet intset_copy(GramgenContext* ctx, const IntSet* src);
    609 int* intset_sorted(GramgenContext* ctx, const IntSet* s);
    610 int intset_equal(const IntSet* a, const IntSet* b);
    611 int intset_intersection_min(const IntSet* a, const IntSet* b);
    612 
    613 char* c_string_str(GramgenContext* ctx, Str s);
    614 char* kit_gram_pratt_prod_enum_name(GramgenContext* ctx, Builder* b,
    615                                    const char* rule_name, const char* role,
    616                                    int tok);
    617 
    618 Builder* kit_gram_builder_new(GramgenContext* ctx, ParsedGrammar* pg);
    619 Builder* kit_gram_builder_build(Builder* b);
    620 void kit_gram_prepare_lexer(Builder* b);
    621 int kit_gram_token_for_ident(Builder* b, const char* name, Loc loc);
    622 int kit_gram_next_rec_seq(Builder* b);
    623 
    624 /* Token-alphabet (%machine) compile: desugared `recognizers` (each a named
    625  * rule) over an abstract symbol alphabet -> a codegen-only token-machine
    626  * LexDFA. Fills is_machine/sym_class_of/nsym/sym_names/live plus the shared
    627  * atom DFA tables (nclasses/trans/nstates/accept). `sets` are the machine's
    628  * %def lines (LEX_LINE_DEF): a %def whose body is a set doubles as a named
    629  * symbol set that a `[ … ]` may reference by lowercase name; resolved and
    630  * inlined into the bracket text up front. gen/kit_gram_lex_tokens.c. */
    631 LexDFA* kit_gram_compile_machine(GramgenContext* ctx, const char* name,
    632                                 LexRecognizer* recognizers, size_t nrecognizers,
    633                                 AstLexLine** sets, size_t nsets, Loc loc);
    634 
    635 /* Parse a %machine `[ A B ]` / `[^ A B ]` set node into interned member names;
    636  * shared by the NFA leaves and the sampler. *complement set for `[^ … ]`.
    637  * Members must be UPPERCASE symbol names: lowercase set references are resolved
    638  * and inlined into the bracket text before this runs (see
    639  * kit_gram_compile_machine), so reaching one here is a grammar/internal error.
    640  */
    641 char* const* kit_gram_machine_class_names(GramgenContext* ctx, Str raw, Loc loc,
    642                                          size_t* nout, int* complement);
    643 
    644 /* In-memory AST-directed sampler for a token machine: generate one valid trace
    645  * of rule `which` into out[0..cap) as symbol-name pointers (into m->sym_names);
    646  * *n is the produced length (may exceed cap if truncated). Deterministic for a
    647  * given *seed (advanced on return). Returns KIT_GRAM_GEN_DONE, or KIT_GRAM_GEN_LIMIT if
    648  * max_tokens was hit. Matches the emitted gen_* sampler bit-for-bit. */
    649 KitGramGenStatus kit_gram_machine_sample(GramgenContext* ctx, const LexDFA* m,
    650                                        size_t which, uint64_t* seed,
    651                                        double stop_prob, size_t max_repeat,
    652                                        size_t max_tokens, const char** out,
    653                                        size_t cap, size_t* n);
    654 
    655 ScalarSet kit_gram_scalar_set_universe(GramgenContext* ctx);
    656 void kit_gram_scalar_set_require_nonempty(GramgenContext* ctx,
    657                                          const ScalarSet* set, Loc loc);
    658 ScalarSet kit_gram_unicode_char_class_set(GramgenContext* ctx, Str raw, Loc loc);
    659 ScalarSet kit_gram_unicode_prop_atom_set(GramgenContext* ctx, Str raw, Loc loc);
    660 
    661 #ifndef KIT_GRAM_NO_UNICODE
    662 /* utf8 lexer pipeline entry point (gen/kit_gram_lex_scalar.c); the byte driver
    663  * in gen/kit_gram_lex_byte.c calls this for %lex :utf8 grammars. */
    664 void kit_gram_compile_lexer_utf8(
    665     GramgenContext* ctx, Loc loc, LexRecognizer* recognizers,
    666     const size_t* compile_indices, size_t ncompile, uint8_t class_of[256],
    667     uint16_t* nclasses_out, uint16_t** trans_out, uint16_t* nstates_out,
    668     uint16_t** accept_out, uint16_t** accept_text_out,
    669     uint16_t** accept_line_out, uint16_t* start_text_out,
    670     uint16_t* start_line_out);
    671 #endif
    672 
    673 #endif /* KIT_GRAM_INTERNAL_H */