dangling_else.ebnf (940B)
1 // RED FIXTURE — does not compile; preserved on purpose. 2 // 3 // The textbook dangling-else, written the natural way: `else` is optional and 4 // binds to the nearest `if`. Every hand-written recursive-descent parser does 5 // this with a greedy "if there's an else, take it" shift. LL(1) predict-set 6 // analysis can't express that preference, so this is a hard conflict here — an 7 // inherent LL(1) limitation, not a generator bug. (Keywords go through 8 // %keywords so the conflict isn't masked by the shadowed-literal check.) 9 // 10 // Observed diagnostic (now a precise, in-file location pointing at `else_part?`): 11 // red/dangling_else.ebnf:19:33: error: LL(1) conflict in optional in rule 12 // stmt: token 'ELSE' can start the body or follow the optional 13 %lex { 14 %skip WS = [ \t\r\n]+; 15 IDENT = [A-Za-z_] [A-Za-z0-9_]*; 16 %keywords IDENT { IF="if"; ELSE="else"; } 17 } 18 19 stmt = "if" IDENT stmt else_part? | IDENT ";"; 20 else_part = "else" stmt;