Ver código fonte

Statement syntax trees

runningwater 2 anos atrás
pai
commit
287ce38073

+ 18 - 2
README.md

@@ -31,7 +31,7 @@
 - **Binary expressions.** The infix arithmetic(+,-,*,/) and logic operators (==, !=, <, <=,>,>=)
 - **Parentheses.** A pair of ( and ) wrapped around and expression.
 
-    - Syntax tree
+    - Syntax tree - Expression
 
       ```
       expression     → literal
@@ -66,4 +66,20 @@ unary          → ( "!" | "-" ) unary
                | primary ;
 primary        → NUMBER | STRING | "true" | "false" | "nil"
                | "(" expression ")" ;
-```
+```
+
+- Syntax tree - Statement
+
+```
+program        → statement* EOF ;
+
+statement      → exprStmt
+               | printStmt ;
+
+exprStmt       → expression ";" ;
+printStmt      → "print" expression ";" ;
+```
+
+ A program is a list of statements followed by the special "end of file" token.
+ The mandatory end token ensures the parse consumes the entire input and don't
+ silently ignore erroneous unconsumed tokens at the end of a script.

+ 47 - 29
src/main/java/com/craftinginterpreters/lox/AstPrinter.java

@@ -2,45 +2,63 @@
  * All right reserved.*/
 package com.craftinginterpreters.lox;
 
+import java.util.List;
+
 /**
  * @author simon
  * @date 2023-06-05 13:19
  * @desc
  */
-public class AstPrinter implements Expr.Visitor<String> {
-    String print(Expr expr) {
-        return expr.accept(this);
+public class AstPrinter implements Expr.Visitor<String>, Stmt.Visitor<String> {
+  String print(List<Stmt> statements) {
+    StringBuilder builder = new StringBuilder();
+    for (Stmt statement : statements) {
+      builder.append("\n    ");
+      builder.append(statement.accept(this));
+      builder.append("\n");
     }
+    return builder.toString();
+  }
 
-    @Override
-    public String visitBinaryExpr(Expr.Binary expr) {
-        return parenthesize(expr.operator.lexeme, expr.left, expr.right);
-    }
+  @Override
+  public String visitExpressionStmt(Stmt.Expression stmt) {
+    return stmt.expression.accept(this);
+  }
 
-    @Override
-    public String visitGroupingExpr(Expr.Grouping expr) {
-        return parenthesize("group", expr.expression);
-    }
+  @Override
+  public String visitPrintStmt(Stmt.Print stmt) {
+    return parenthesize("print", stmt.expression);
+  }
 
-    @Override
-    public String visitLiteralExpr(Expr.Literal expr) {
-        if (expr.value == null) return "nil";
-        return expr.value.toString();
-    }
+  @Override
+  public String visitBinaryExpr(Expr.Binary expr) {
+    return parenthesize(expr.operator.lexeme, expr.left, expr.right);
+  }
 
-    @Override
-    public String visitUnaryExpr(Expr.Unary expr) {
-        return parenthesize(expr.operator.lexeme, expr.right);
-    }
+  @Override
+  public String visitGroupingExpr(Expr.Grouping expr) {
+    return parenthesize("group", expr.expression);
+  }
+
+  @Override
+  public String visitLiteralExpr(Expr.Literal expr) {
+    if (expr.value == null) return "nil";
+    return expr.value.toString();
+  }
+
+  @Override
+  public String visitUnaryExpr(Expr.Unary expr) {
+    return parenthesize(expr.operator.lexeme, expr.right);
+  }
 
-    private String parenthesize(String name, Expr... exprs) {
-        StringBuilder builder = new StringBuilder();
-        builder.append("(").append(name);
-        for (Expr expr : exprs) {
-            builder.append(" ");
-            builder.append(expr.accept(this));
-        }
-        builder.append(")");
-        return builder.toString();
+  private String parenthesize(String name, Expr... exprs) {
+    StringBuilder builder = new StringBuilder();
+    builder.append("(").append(name);
+    for (Expr expr : exprs) {
+      builder.append(" ");
+      builder.append(expr.accept(this));
     }
+    builder.append(")");
+    return builder.toString();
+  }
 }

+ 26 - 5
src/main/java/com/craftinginterpreters/lox/Interpreter.java

@@ -2,26 +2,33 @@
  * All right reserved.*/
 package com.craftinginterpreters.lox;
 
+import java.util.List;
+
 /**
  * @author simon
  * @date 2023-06-07 12:20
  * @desc
  */
-public class Interpreter implements Expr.Visitor<Object> {
+public class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
   /**
    * public API
    *
-   * @param expression
+   * @param statements statements
    */
-  void interpret(Expr expression) {
+  void interpret(List<Stmt> statements) {
     try {
-      Object value = evaluate(expression);
-      System.out.println(stringify(value));
+      for (Stmt statement : statements) {
+        execute(statement);
+      }
     } catch (RuntimeError error) {
       Lox.runtimeError(error);
     }
   }
 
+  private void execute(Stmt stmt) {
+    stmt.accept(this);
+  }
+
   @Override
   public Object visitBinaryExpr(Expr.Binary expr) {
     Object left = evaluate(expr.left);
@@ -96,6 +103,20 @@ public class Interpreter implements Expr.Visitor<Object> {
     };
   }
 
+  @Override
+  public Void visitExpressionStmt(Stmt.Expression stmt) {
+    Object value = evaluate(stmt.expression);
+    System.out.println("  " + stringify(value));
+    return null;
+  }
+
+  @Override
+  public Void visitPrintStmt(Stmt.Print stmt) {
+    Object value = evaluate(stmt.expression);
+    System.out.println("  " + stringify(value));
+    return null;
+  }
+
   private Object evaluate(Expr expr) {
     return expr.accept(this);
   }

+ 3 - 3
src/main/java/com/craftinginterpreters/lox/Lox.java

@@ -71,13 +71,13 @@ public class Lox {
     //    System.out.println(token);
     // }
     Parser parser = new Parser(tokens);
-    Expr expression = parser.parse();
+    List<Stmt> statements = parser.parse();
 
     // Stop if there was a syntax error.
     if (hadError) return;
 
-    System.out.println("  ...AST: " + new AstPrinter().print(expression));
-    interpreter.interpret(expression);
+    System.out.println("  ...AST: " + new AstPrinter().print(statements));
+    interpreter.interpret(statements);
   }
 
   /**

+ 26 - 5
src/main/java/com/craftinginterpreters/lox/Parser.java

@@ -4,6 +4,7 @@ package com.craftinginterpreters.lox;
 
 import static com.craftinginterpreters.lox.TokenType.*;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -31,12 +32,32 @@ public class Parser {
     this.tokens = tokens;
   }
 
-  Expr parse() {
-    try {
-      return expression();
-    } catch (ParseError e) {
-      return null;
+  List<Stmt> parse() {
+    List<Stmt> statements = new ArrayList<>();
+    while (!isAtEnd()) {
+      statements.add(statement());
     }
+    return statements;
+  }
+
+  // statement  → exprStmt | printStmt ;
+  private Stmt statement() {
+    if (match(PRINT)) return printStatement();
+    return expressionStatement();
+  }
+
+  // exprStmt  → expression ";" ;
+  private Stmt expressionStatement() {
+    Expr expr = expression();
+    consume(SEMICOLON, "Expect ';' after expression.");
+    return new Stmt.Expression(expr);
+  }
+
+  // printStmt → "print" expression ";" ;
+  private Stmt printStatement() {
+    Expr value = expression();
+    consume(SEMICOLON, "Expect ';' after value.");
+    return new Stmt.Print(value);
   }
 
   // expression  → equality ;

+ 41 - 0
src/main/java/com/craftinginterpreters/lox/Stmt.java

@@ -0,0 +1,41 @@
+package com.craftinginterpreters.lox;
+
+/**
+ * @author GenerateAst
+ * @date 2023-06-09 11:18
+ */
+abstract class Stmt {
+    interface Visitor<R> {
+        R visitExpressionStmt(Expression stmt);
+
+        R visitPrintStmt(Print stmt);
+
+    }
+
+    static class Expression extends Stmt {
+        Expression(Expr expression) {
+            this.expression = expression;
+        }
+
+        @Override
+        <R> R accept(Visitor<R> visitor) {
+            return visitor.visitExpressionStmt(this);
+        }
+
+        final Expr expression;
+    }
+    static class Print extends Stmt {
+        Print(Expr expression) {
+            this.expression = expression;
+        }
+
+        @Override
+        <R> R accept(Visitor<R> visitor) {
+            return visitor.visitPrintStmt(this);
+        }
+
+        final Expr expression;
+    }
+
+    abstract <R> R accept(Visitor<R> visitor);
+}

+ 9 - 5
src/main/java/com/craftinginterpreters/tool/GenerateAst.java

@@ -42,11 +42,15 @@ public class GenerateAst {
             System.exit(64);
         }
         String outputDir = args[0];
-        defineAst(outputDir, "Expr", Arrays.asList(
-                "Binary   : Expr left, Token operator, Expr right",
-                "Grouping : Expr expression",
-                "Literal  : Object value",
-                "Unary    : Token operator, Expr right"
+//        defineAst(outputDir, "Expr", Arrays.asList(
+//                "Binary   : Expr left, Token operator, Expr right",
+//                "Grouping : Expr expression",
+//                "Literal  : Object value",
+//                "Unary    : Token operator, Expr right"
+//        ));
+        defineAst(outputDir, "Stmt", Arrays.asList(
+                "Expression  : Expr expression",
+                "Print       : Expr expression"
         ));
     }