kit

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

meta.ebnf (6343B)


      1 // gramgen EBNF source language.
      2 //
      3 // A file is a stream of declarations and rules. Whitespace and line comments
      4 // `// ...` are ignored by the gramgen lexer. Block comments are not supported.
      5 // Terminals are token kinds. They may be produced by a generated lexer or
      6 // supplied externally by the embedder. Uppercase NAME values refer to named
      7 // token kinds, and STRING literals refer to literal token kinds. Rule names
      8 // must start with a lowercase letter.
      9 
     10 // Literal declarations choose emitted token enum names. When a generated lexer
     11 // is emitted, each literal also contributes an exact-match recognizer.
     12 %token TOKEN_DECL = "%token";
     13 %token EMPTY_DECL = "%empty";
     14 %token PRATT_DECL = "%pratt";
     15 %token LEX_DECL = "%lex";
     16 %token SKIP_DECL = "%skip";
     17 %token DEF_DECL = "%def";
     18 %token KEYWORDS_DECL = "%keywords";
     19 %token COLON = ":";
     20 // `%machine NAME { ... }` declares a regular language over an abstract token
     21 // alphabet (codegen-only verifier + sampler).
     22 %token MACHINE_DECL = "%machine";
     23 
     24 %lex {
     25   %skip WS = [ \t\r\n] [ \t\r\n]*;
     26   %skip LINE_COMMENT = "//" [^\n]*;
     27 
     28   NAME = [A-Za-z_] [A-Za-z0-9_]*;
     29   STRING = "\"" ( "\\" [^\n] | [^"\\\n] )* "\"";
     30   UNICODE_PROP = "\\" [pP] "{" [^}\n] [^}\n]* "}";
     31   CHAR_CLASS = "[" "^"? ( "\\" [^\n] | [^\]\\\n] ) ( "\\" [^\n] | [^\]\\\n] )* "]";
     32   // Tier-1 edge anchors: \A/\z (text) and ^/$ (line). Recorded as
     33   // per-recognizer flags during lowering; mid-pattern uses are rejected.
     34   ANCHOR = "\\A" | "\\z" | "^" | "$";
     35   // ASCII shorthand classes \d \w \s and their complements \D \W \S, usable
     36   // standalone and inside `[...]`. Expanded to character classes during lowering.
     37   SHORTHAND = "\\" [dDwWsS];
     38   // Counted-repetition suffix `{n}` `{n,}` `{n,m}` `{,m}`; the bounds are
     39   // hand-parsed and validated (cap, ordering) during lowering.
     40   REPEAT = "{" [0-9,] [0-9,]* "}";
     41 }
     42 
     43 grammar = item*;
     44 item    = decl | rule | pratt_rule | lex_block | machine_block;
     45 
     46 decl    = token_decl;
     47 token_decl = "%token" NAME "=" STRING ";";
     48 
     49 rule    = NAME "=" alt ";";
     50 
     51 // Rules are LL(1): alternatives are separated by `|`, and each alternative is
     52 // a sequence of factors. `%empty` is the explicit empty alternative.
     53 alt     = seq alt_tail*;
     54 alt_tail = "|" seq;
     55 seq     = "%empty"
     56         | factor*;
     57 
     58 // A factor is a primary item plus optional quantifier sugar. `?` is
     59 // zero-or-one and `*` is zero-or-more.
     60 factor  = primary quant?;
     61 primary = NAME
     62         | STRING
     63         | "(" alt ")";
     64 
     65 quant   = "?" | "*";
     66 
     67 // Pratt declarations are optional expression parsers. `%pratt NAME { ... }`
     68 // declares a named parser rule whose body is an operator table instead of LL(1)
     69 // alternatives. A `primary RULE;` line names the LL(1) leaf parser, and each
     70 // operator line names a role followed by one or more token names or literals.
     71 pratt_rule = "%pratt" NAME "{" pratt_line* "}";
     72 pratt_line = NAME pratt_atom pratt_atom* ";";
     73 pratt_atom = NAME | STRING;
     74 
     75 // Lexer declarations are optional. `%lex { ... }` groups generated DFA
     76 // recognizers in one block. `TOKEN = pattern;` binds an uppercase token.
     77 // Tokens without a rule may still be supplied externally and pushed directly to
     78 // the parser. `%skip NAME = pattern;` recognizes input that is consumed but not
     79 // emitted to the parser.
     80 //
     81 // `%lex :utf8 { ... }` keeps generated DFA tables byte-oriented, but marks the
     82 // runtime input model as UTF-8 for scalar-position tracking and encoding
     83 // diagnostics.
     84 //
     85 // Patterns are regex-like but not slash-delimited. They support alternation,
     86 // concatenation, grouping, string literals, character classes, and `.` as a
     87 // wildcard. Postfix quantifiers are `?`, `*`, `+`, and counted `{n}` `{n,}`
     88 // `{n,m}` `{,m}` (capped; lazy forms like `*?` are an error). The ASCII
     89 // shorthands `\d \w \s` and complements `\D \W \S` work standalone and inside
     90 // `[...]`, in both byte and utf8 mode. `%def name = pattern;` declares an
     91 // inlined, acyclic fragment (lowercase name) scoped to its `%lex`/`%machine`
     92 // block and referenced by name in other patterns in the same block; fragments
     93 // are never tokens. All of these lower to the primitive pattern forms during a
     94 // desugaring pass before NFA construction.
     95 //
     96 // Character classes are lexical primitives, not parsed by this grammar:
     97 // `[A-Z_]`, `[^"\n]`, or `[A-Za-z0-9_]`. `^` negates only immediately after
     98 // `[`. In byte mode ranges are written as `a-z`; a literal `-`, `]`, `^`, or
     99 // `\` must be escaped inside the class. In UTF-8 mode the generator parses
    100 // Unicode scalar escapes, `\p{...}`/`\P{...}`, and class algebra inside the
    101 // bracketed primitive. Empty classes are invalid.
    102 lex_block = "%lex" lex_name lex_mode "{" lex_line* "}";
    103 // `%machine NAME { ... }` is a token-alphabet lexer block: the same lex_line
    104 // productions, compiled over an abstract symbol alphabet (UPPERCASE leaves are
    105 // symbols, `[ A B ]` is a symbol set). Codegen-only verifier + sampler.
    106 machine_block = "%machine" NAME "{" lex_line* "}";
    107 lex_name = NAME | %empty;
    108 lex_mode = ":" NAME | %empty;
    109 lex_line = lex_rule | skip_rule | def_rule | keywords_block;
    110 lex_rule = NAME "=" lex_alt ";";
    111 skip_rule = "%skip" NAME "=" lex_alt ";";
    112 // `%def name = pattern;` declares an inlined pattern fragment (lowercase name).
    113 // Fragments are scoped to their `%lex`/`%machine` block, acyclic, and never
    114 // become tokens (a reference to another block's %def is an "unknown fragment").
    115 // In a %machine a %def whose body is a set (`[ A B ]`, a union `a | b`, or a
    116 // class with set algebra) doubles as a named symbol set referenced inside
    117 // `[ … ]`.
    118 def_rule = "%def" NAME "=" lex_alt ";";
    119 // `%keywords HOST { ... }` lists string-literal tokens that the more general
    120 // recognizer HOST shadows; they are kept out of the DFA and recovered by a
    121 // lexeme lookup. Each entry names a token, a literal string, or both.
    122 keywords_block = "%keywords" NAME "{" kw_entry* "}";
    123 kw_entry = NAME kw_value? ";" | STRING ";";
    124 kw_value = "=" STRING;
    125 lex_alt = lex_seq lex_alt_tail*;
    126 lex_alt_tail = "|" lex_seq;
    127 lex_seq = lex_factor lex_factor*;
    128 // Lexer quantifiers extend the parser's `? *` with `+` and counted `{...}`.
    129 lex_factor = lex_primary lex_quant?;
    130 lex_quant = "?" | "*" | "+" | REPEAT;
    131 lex_primary = STRING
    132             | CHAR_CLASS
    133             | UNICODE_PROP
    134             | SHORTHAND
    135             | "."
    136             | NAME
    137             | "(" lex_alt ")"
    138             | ANCHOR;