Following along with the Crafting Interpreters book.
expression -> litral | unary | binary | grouping ;
literal -> NUMBER | STRING | "true" | "false" | "nil" ;
grouping -> "(" expression ")" ;
unary -> ( "-" | "!" ) expression ;
binary -> expression operator expression ;
operator -> "==" | "!=" | "<" | "<=" | "+" | "-" | "*" | "/" ;
Quoted strings are exact terminals.1 Single lexeme whose text representation may vary are CAPITALIZED. Lowercase words are non-terminals.2
This grammar allows the production of strings like (4 + 9) / !1 == nil, but it's "ambiguous". The binary rule allows nesting in both ways, which allows you to generate the same string but with a different syntax tree. Take the string 6 / 3 - 1 for example. You can produce it by:
- Starting with expression, picking
binary - For the left
expression, pickingNUMBER, and using 6 - For the
operator, pick/ - For the right
expression, pickbinaryagain. - In the nested
binarypick3 - 1
But you can also produce the same string in another way:
- Begin with expresssion, pick
binary - For the right
expressionpickNUMBERand use 1 - For the
operatorpick- - For the left
expressionpickbinary - Then in the nested
binarypick6 / 3
The string is the same, but the generated syntax tree is different. In other words there are no rules for precedence or associativity. We will apply the same precedence rules C, going from lowest to highest.
| Name | Operators | Associates |
|---|---|---|
| Equality | == != | Left |
| Comparison | > >= < <= | Left |
| Term | - + | Left |
| Factor | / * | Left |
| Unary | ! - | Right |
We will define a separate rule for each level of precedence. Each rule below matches expressions at its precedence level or higher. For example a term can match 4 + 6, but also 3 * 2 / 6. The final primary rule covers the highest-precedence - literals and expressions inside parenthesis.
expression -> equality
equality -> comparison ( ( "==" | "!=" ) comparison )* ;
comparison -> term ( ( ">" | "<" | ">=" | "<=" ) term )* ;
term -> factor ( ( "+" | "-" ) factor )* ;
factor -> unary ( ( "*" | "/" ) unary )* ;
unary -> ( "!" | "-" ) unary | primary ;
primary -> NUMBER | STRING | "true" | "false" | "nil" | "(" expression ")" ;
