Initial language with three binary operators
expr → expr "=" expr [Assignment]
expr → expr "-" expr [Subtraction]
expr → expr "÷" expr [Division]
expr → NUMBER | IDENTIFIER | "(" expr ")"
x = 1 - 2 ÷ 3
= = ÷ ÷ -
/ \ / \ / \ / \ / \
x - x ÷ - 3 = 3 = ÷
/ \ / \ / \ / \ / \ / \
1 ÷ - 3 = 2 x - x 1 2 3
/ \ / \ / \ / \
2 3 1 2 x 1 1 2
Provide names for each level
expr → assign | term | factor | primary
assign → expr "=" expr
term → expr "-" expr
factor → expr "÷" expr
primary → NUMBER | IDENTIFIER | "(" expr ")"
x = 1 - 2 ÷ 3
= = ÷ ÷ -
/ \ / \ / \ / \ / \
x - x ÷ - 3 = 3 = ÷
/ \ / \ / \ / \ / \ / \
1 ÷ - 3 = 2 x - x 1 2 3
/ \ / \ / \ / \
2 3 1 2 x 1 1 2
Precedence solved, but still ambiguous
expr → assign
assign → assign "=" assign | term [Lowest Precedence]
term → term "-" term | factor [Middle Precedence]
factor → factor "÷" factor | primary [Highest Precedence]
primary → NUMBER | IDENTIFIER | "(" expr ")"
x = 1 - 2 - 3
= =
/ \ / \
x - x -
/ \ / \
1 - - 3
/ \ / \
2 3 1 2
Unambiguous, but at most one occurrence of each operator)
expr → assign
assign → term "=" term | term [Lowest Precedence]
term → factor "-" factor | factor [Middle Precedence]
factor → primary "÷" primary | primary [Highest Precedence]
primary → NUMBER | IDENTIFIER | "(" expr ")"
x = 1 - 2 - 3
=
/ \
x -
/ \
1 ???
Unambiguous, full language
expr → assign
assign → term "=" assign | term [Right Associative]
term → term "-" factor | factor [Left Associative]
factor → factor "÷" primary | primary [Left Associative]
primary → NUMBER | IDENTIFIER | "(" expr ")"
x = y = 1 - 2 - 3
=
/ \
x =
/ \
y -
/ \
- 3
/ \
1 2
Removing left recursion (removing connection between grammar and parse tree for left associative operators)
expr → assign
assign → term ("=" assign)?
term → factor ("-" factor)*
factor → primary ("÷" primary)*
primary → NUMBER | IDENTIFIER | "(" expr ")"
x = y = 1 - 2 - 3
=
/ \
x =
/ \
y -
/ \
- 3
/ \
1 2
As code
private Expr expression() {
return assign();
}
/* lowest precedence, right associative */
private Expr assign() {
Expr expr = term();
if (match(EQUAL)) {
Token operator = previous();
Expr right = assign();
expr = new Expr.Binary(expr, operator, right);
}
return expr;
}
/* middle precedence, left associative */
private Expr term() {
Expr expr = factor();
while (match(DIVIDE)) {
Token operator = previous();
Expr right = factor();
expr = new Expr.Binary(expr, operator, right);
}
return expr;
}
/* highest precedence, left associative */
private Expr factor() {
Expr expr = primary();
while (match(DIVIDE)) {
Token operator = previous();
Expr right = primary();
expr = new Expr.Binary(expr, operator, right);
}
return expr;
}
private Expr primary() {
if (match(FALSE)) return new Expr.Literal(false);
if (match(TRUE)) return new Expr.Literal(true);
if (match(NIL)) return new Expr.Literal(null);
if (match(NUMBER, STRING)) {
return new Expr.Literal(previous().literal);
}
if (match(LEFT_PAREN)) {
Expr expr = expression();
consume(RIGHT_PAREN, "Expect ')' after expression.");
return new Expr.Grouping(expr);
}
throw error(peek(), "Expect expression.");
}