From 80ad509e6c11cad6c79bbb5afd53812858ca6b3b Mon Sep 17 00:00:00 2001 From: adnanioricce Date: Tue, 3 Sep 2024 08:47:49 -0300 Subject: [PATCH] [Chapter6&Parsing] - Implementing the first part of the parser --- run.sh | 4 +- src/com/lox/AstPrinter.java | 20 ++--- src/com/lox/Lox.java | 18 ++++- src/com/lox/Parser.java | 154 ++++++++++++++++++++++++++++++++++++ 4 files changed, 180 insertions(+), 16 deletions(-) create mode 100644 src/com/lox/Parser.java diff --git a/run.sh b/run.sh index cf90732..c2fd907 100755 --- a/run.sh +++ b/run.sh @@ -7,6 +7,6 @@ javac -d out src/com/tool/*.java # Run Lox interpreter java -cp out com.lox.Lox # Run Lox ast print printer -java -cp out com.lox.AstPrinter +# java -cp out com.lox.AstPrinter # Run Lox tool -java -cp out com.tool.GenerateAst \ No newline at end of file +# java -cp out com.tool.GenerateAst \ No newline at end of file diff --git a/src/com/lox/AstPrinter.java b/src/com/lox/AstPrinter.java index 594f847..a8f84fc 100644 --- a/src/com/lox/AstPrinter.java +++ b/src/com/lox/AstPrinter.java @@ -37,16 +37,16 @@ class AstPrinter implements Expr.Visitor { return builder.toString(); } - public static void main(String[] args) { - Expr expression = new Expr.Binary( - new Expr.Unary( - new Token(TokenType.MINUS, "-", null, 1), - new Expr.Literal(123)), - new Token(TokenType.STAR, "*", null, 1), - new Expr.Grouping( - new Expr.Literal(45.67))); + // public static void main(String[] args) { + // Expr expression = new Expr.Binary( + // new Expr.Unary( + // new Token(TokenType.MINUS, "-", null, 1), + // new Expr.Literal(123)), + // new Token(TokenType.STAR, "*", null, 1), + // new Expr.Grouping( + // new Expr.Literal(45.67))); - System.out.println(new AstPrinter().print(expression)); - } + // System.out.println(new AstPrinter().print(expression)); + // } } \ No newline at end of file diff --git a/src/com/lox/Lox.java b/src/com/lox/Lox.java index c53c0d9..b3af507 100644 --- a/src/com/lox/Lox.java +++ b/src/com/lox/Lox.java @@ -24,11 +24,13 @@ public class Lox { private static void run(String source) { Scanner scanner = new Scanner(source); List 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)); } static void error(int line, String message) { report(line, "", message); @@ -41,6 +43,14 @@ public class Lox { hadError = true; } + 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); + } + } + private static void runFile(String path) throws IOException { byte[] bytes = Files.readAllBytes(Paths.get(path)); diff --git a/src/com/lox/Parser.java b/src/com/lox/Parser.java new file mode 100644 index 0000000..30511eb --- /dev/null +++ b/src/com/lox/Parser.java @@ -0,0 +1,154 @@ +package com.lox; + +import java.util.List; + +import static com.lox.TokenType.*; + +class Parser { + private static class ParseError extends RuntimeException {} + private final List tokens; + private int current = 0; + + Parser(List tokens) { + this.tokens = tokens; + } + 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(); + } + } + +} \ No newline at end of file