kit

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

clike.ebnf (2337B)


      1 // C-like kitchen sink: declarations, functions, statements, and a Pratt
      2 // expression grammar with the usual C precedence ladder.
      3 //
      4 // Two natural forms had to be left-factored by hand to satisfy LL(1); both are
      5 // preserved untouched as red fixtures under test/realistic/red/ so the friction
      6 // stays visible:
      7 //   * dangling-else  -> red/dangling_else.ebnf   (LL(1) optional conflict)
      8 //   * IDENT vs call  -> red/ident_call.ebnf      (FIRST/FIRST conflict)
      9 // Here `if` requires an `else` (sidesteps dangling-else) and a name/call is
     10 // left-factored through `call_tail`.
     11 //
     12 // Keywords go through a %keywords block (host = IDENT). Declaring them with bare
     13 // %token *before* IDENT also works; writing the %lex block first and the keyword
     14 // %tokens after is now a hard error (the keyword would be shadowed by IDENT) —
     15 // see red/keyword_shadow.ebnf.
     16 %lex {
     17   %skip WS    = [ \t\r\n]+;
     18   %skip LINE  = "//" [^\n]*;
     19   %skip BLOCK = "/*" ( [^*] | "*" [^/] )* "*/";
     20 
     21   IDENT  = [A-Za-z_] [A-Za-z0-9_]*;
     22   INT    = "0" [xX] [0-9A-Fa-f]+ | [0-9]+;
     23   FLOAT  = [0-9]+ "." [0-9]* ( [eE] [+\-]? [0-9]+ )?;
     24   CHAR   = "'" ( [^'\\] | "\\" . ) "'";
     25   STRING = "\"" ( [^"\\] | "\\" . )* "\"";
     26 
     27   %keywords IDENT {
     28     IF="if"; ELSE="else"; WHILE="while"; RETURN="return";
     29     INT_T="int"; VOID="void";
     30   }
     31 }
     32 
     33 program   = decl*;
     34 decl      = type IDENT decl_tail;
     35 decl_tail = "(" params? ")" block      // function definition
     36           | ";"                         // global declaration
     37           | "=" expr ";";               // global initializer
     38 type      = "int" | "void";
     39 params    = param param_tail*;
     40 param_tail = "," param;
     41 param     = type IDENT;
     42 
     43 block     = "{" stmt* "}";
     44 stmt      = block
     45           | "if" "(" expr ")" stmt else_part
     46           | "while" "(" expr ")" stmt
     47           | "return" expr? ";"
     48           | type IDENT var_init? ";"
     49           | expr ";";
     50 else_part = "else" stmt;
     51 var_init  = "=" expr;
     52 
     53 %pratt expr {
     54   primary  primary;
     55   infixr   "=";                  // assignment: loosest, right-associative
     56   infixl   "||";
     57   infixl   "&&";
     58   infixl   "==" "!=";
     59   infixl   "<" ">" "<=" ">=";
     60   infixl   "+" "-";
     61   infixl   "*" "/" "%";
     62   prefix   "-" "!";
     63 }
     64 primary   = INT | FLOAT | STRING | CHAR | "(" expr ")" | IDENT call_tail;
     65 call_tail = "(" args? ")" | %empty;
     66 args      = expr arg_tail*;
     67 arg_tail  = "," expr;