summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Tom Willemse2020-11-11 21:07:49 -0800
committerGravatar Tom Willemse2020-11-11 21:07:49 -0800
commita78fe97f60c2ad39d3d6335c1d058bd8ee4921bb (patch)
treebee881d28f01db046e01813e2066e23c47d3cc88
parent09600801287ee5f219c4389688f81ec3b5ab5404 (diff)
downloadcrafting-interpreters-a78fe97f60c2ad39d3d6335c1d058bd8ee4921bb.tar.gz
crafting-interpreters-a78fe97f60c2ad39d3d6335c1d058bd8ee4921bb.zip
Add the Parser
-rw-r--r--src/com/craftinginterpreters/lox/CMakeLists.txt1
-rw-r--r--src/com/craftinginterpreters/lox/Lox.java24
-rw-r--r--src/com/craftinginterpreters/lox/Parser.java178
3 files changed, 197 insertions, 6 deletions
diff --git a/src/com/craftinginterpreters/lox/CMakeLists.txt b/src/com/craftinginterpreters/lox/CMakeLists.txt
index d2807e6..c326c88 100644
--- a/src/com/craftinginterpreters/lox/CMakeLists.txt
+++ b/src/com/craftinginterpreters/lox/CMakeLists.txt
@@ -13,4 +13,5 @@ add_jar(Lox
Scanner.java
${EXPR_JAVA_FILENAME}
AstPrinter.java
+ Parser.java
ENTRY_POINT com/craftinginterpreters/lox/Lox)
diff --git a/src/com/craftinginterpreters/lox/Lox.java b/src/com/craftinginterpreters/lox/Lox.java
index 51d72c7..586442d 100644
--- a/src/com/craftinginterpreters/lox/Lox.java
+++ b/src/com/craftinginterpreters/lox/Lox.java
@@ -27,7 +27,8 @@ public class Lox {
run(new String(bytes, Charset.defaultCharset()));
// Indicate an error in the exit code.
- if (hadError) System.exit(65);
+ if (hadError)
+ System.exit(65);
}
private static void runPrompt() throws IOException {
@@ -37,7 +38,8 @@ public class Lox {
for (;;) {
System.out.print("> ");
String line = reader.readLine();
- if (line == null) break;
+ if (line == null)
+ break;
run(line);
hadError = false;
}
@@ -46,11 +48,13 @@ public class Lox {
private static void run(String source) {
Scanner scanner = new Scanner(source);
List<Token> tokens = scanner.scanTokens();
+ Parser parser = new Parser(tokens);
+ Expr expression = parser.parse();
- // For now, just print the tokens.
- for (Token token : tokens) {
- System.out.println(token);
- }
+ // Stop if there was a syntax error
+ if (hadError) return;
+
+ System.out.println(new AstPrinter().print(expression));
}
public static void error(int line, String message) {
@@ -61,4 +65,12 @@ public class Lox {
System.err.println("[line " + line + "] Error" + where + ": " + message);
hadError = true;
}
+
+ public static void error(Token token, String message) {
+ if (token.type == TokenType.EOF) {
+ report(token.line, " at end", message);
+ } else {
+ report(token.line, " at '" + token.lexeme + "'", message);
+ }
+ }
}
diff --git a/src/com/craftinginterpreters/lox/Parser.java b/src/com/craftinginterpreters/lox/Parser.java
new file mode 100644
index 0000000..c5e50e0
--- /dev/null
+++ b/src/com/craftinginterpreters/lox/Parser.java
@@ -0,0 +1,178 @@
+package com.craftinginterpreters.lox;
+
+import static com.craftinginterpreters.lox.TokenType.*;
+
+import java.util.List;
+
+class Parser {
+ private static class ParseError extends RuntimeException {
+ }
+
+ private final List<Token> tokens;
+ private int current = 0;
+
+ Parser(List<Token> tokens) {
+ this.tokens = tokens;
+ }
+
+ public Expr parse() {
+ try {
+ return expression();
+ } catch (ParseError error) {
+ return null;
+ }
+ }
+
+ private Expr expression() {
+ return equality();
+ }
+
+ private Expr equality() {
+ Expr expr = comparison();
+
+ while (match(BANG_EQUAL, EQUAL_EQUAL)) {
+ Token operator = previous();
+ Expr right = comparison();
+ expr = new Expr.Binary(expr, operator, right);
+ }
+
+ return expr;
+ }
+
+ private Expr comparison() {
+ Expr expr = term();
+
+ while (match(GREATER, GREATER_EQUAL, LESS, LESS_EQUAL)) {
+ Token operator = previous();
+ Expr right = term();
+ expr = new Expr.Binary(expr, operator, right);
+ }
+
+ return expr;
+ }
+
+ private Expr term() {
+ Expr expr = factor();
+
+ while (match(MINUS, PLUS)) {
+ Token operator = previous();
+ Expr right = factor();
+ expr = new Expr.Binary(expr, operator, right);
+ }
+
+ return expr;
+ }
+
+ private Expr factor() {
+ Expr expr = unary();
+
+ while (match(SLASH, STAR)) {
+ Token operator = previous();
+ Expr right = unary();
+ expr = new Expr.Binary(expr, operator, right);
+ }
+
+ return expr;
+ }
+
+ private Expr unary() {
+ if (match(BANG, MINUS)) {
+ Token operator = previous();
+ Expr right = unary();
+ return new Expr.Unary(operator, right);
+ }
+
+ return primary();
+ }
+
+ 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.");
+ }
+
+ private boolean match(TokenType... types) {
+ for (TokenType type : types) {
+ if (check(type)) {
+ advance();
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private Token consume(TokenType type, String message) {
+ if (check(type))
+ return advance();
+
+ throw error(peek(), message);
+ }
+
+ private boolean check(TokenType type) {
+ if (isAtEnd())
+ return false;
+ return peek().type == type;
+ }
+
+ private Token advance() {
+ if (!isAtEnd())
+ current++;
+ return previous();
+ }
+
+ private boolean isAtEnd() {
+ return peek().type == EOF;
+ }
+
+ private Token peek() {
+ return tokens.get(current);
+ }
+
+ private Token previous() {
+ return tokens.get(current - 1);
+ }
+
+ private ParseError error(Token token, String message) {
+ Lox.error(token, message);
+ return new ParseError();
+ }
+
+ private void synchronize() {
+ advance();
+
+ while (!isAtEnd()) {
+ if (previous().type == SEMICOLON)
+ return;
+
+ switch (peek().type) {
+ case CLASS:
+ case FUN:
+ case VAR:
+ case FOR:
+ case IF:
+ case WHILE:
+ case PRINT:
+ case RETURN:
+ return;
+ }
+
+ advance();
+ }
+ }
+}