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.");
}