json_frontend.ebnf (2185B)
1 // JSON front end: the realistic JSON grammar (RFC 8259) with the two sub-lexers 2 // a real frontend uses to turn leaf lexemes into values. The parser yields whole 3 // NUMBER / STRING tokens; the value-channel actions then point a sub-lexer at the 4 // token's own bytes to decode it — NUMBER via the `number` sub-lexer (classify 5 // int vs float, read the integer value), STRING via the `strescape` sub-lexer 6 // (unescape into raw UTF-8). Driven by test/realistic/test_json_frontend.c, which 7 // reaches the sub-lexers through gramgen_lexer_grammar_at / gramgen_find_lexer. 8 // 9 // The main lexer + parser are the ordinary JSON grammar, written with inline 10 // string literals ("[", "true", ...) exactly like test/realistic/json.ebnf — the 11 // `strescape` sub-lexer's catch-all SCHARS = [^"\\]+ does NOT shadow them, because 12 // parser literals are scoped to the parser-feeding (main) lexer and never 13 // injected into a sub-lexer. 14 %lex { 15 %skip WS = [ \t\r\n] [ \t\r\n]*; 16 17 // string = quote ( unescaped | '\' escape )* quote 18 STRING = "\"" ( [^"\\] | "\\" ( ["\\/bfnrt] | "u" [0-9A-Fa-f] [0-9A-Fa-f] [0-9A-Fa-f] [0-9A-Fa-f] ) )* "\""; 19 20 // number = -? int frac? exp? (no leading zeros, per the spec) 21 NUMBER = "-"? ( "0" | [1-9] [0-9]* ) ( "." [0-9]+ )? ( [eE] [+\-]? [0-9]+ )?; 22 } 23 24 // NUMBER payload -> sign / integer / fraction / exponent parts. 25 %lex number { 26 %def digit = [0-9]; 27 NSIGN = "-"; 28 NINT = digit+; 29 NFRAC = "." digit+; 30 NEXP = [eE] [+\-]? digit+; 31 } 32 33 // STRING payload -> quotes, literal runs, and one escape atom per escape. The 34 // catch-all SCHARS would have collided with the parser's "[" / "true" / ... if 35 // parser literals were shared across lexers — they are not. 36 %lex strescape { 37 SQUOTE = "\""; 38 SESC = "\\" ( ["\\/bfnrt] | "u" [0-9A-Fa-f] [0-9A-Fa-f] [0-9A-Fa-f] [0-9A-Fa-f] ); 39 SCHARS = [^"\\]+; 40 } 41 42 %token TRUE = "true"; 43 %token FALSE = "false"; 44 %token NULL = "null"; 45 46 value = object | array | STRING | NUMBER | "true" | "false" | "null"; 47 48 object = "{" members? "}"; 49 members = member member_tail*; 50 member_tail = "," member; 51 member = STRING ":" value; 52 53 array = "[" elements? "]"; 54 elements = value element_tail*; 55 element_tail = "," value;