runningwater преди 2 години
родител
ревизия
11f87c94bc

+ 27 - 2
README.md

@@ -1,5 +1,5 @@
 
-Lox
+## Lox
 ```c
  // Your first Lox program!
  print "Hello, world!";
@@ -21,4 +21,29 @@ Lox
 - Control Flow
 - Functions
 - Closures
-- Classes
+- Classes
+
+## A Grammar for Lox expressions
+
+- **Literals**. Numbers,strings,Booleans, and nil
+- **Unary expressions.** A prefix ! to perform a logical not, and - to negate a number.
+- **Binary expressions.** The infix arithmetic(+,-,*,/) and logic operators (==, !=, <, <=,>,>=)
+- **Parentheses.** A pair of ( and ) wrapped around and expression.
+
+  - Syntax tree
+  
+    ```
+    expression     → literal
+    | unary
+    | binary
+    | grouping ;
+  
+    literal        → NUMBER | STRING | "true" | "false" | "nil" ;
+    grouping       → "(" expression ")" ;
+    unary          → ( "-" | "!" ) expression ;
+    binary         → expression operator expression ;
+    operator       → "==" | "!=" | "<" | "<=" | ">" | ">="
+    | "+"  | "-"  | "*" | "/" ;
+  
+    ```
+

+ 46 - 0
src/main/java/com/craftinginterpreters/lox/AstPrinter.java

@@ -0,0 +1,46 @@
+/* Copyright (C) 2019-2023 Hangzhou HSH Co. Ltd.
+ * All right reserved.*/
+package com.craftinginterpreters.lox;
+
+/**
+ * @author simon
+ * @date 2023-06-05 13:19
+ * @desc
+ */
+public class AstPrinter implements Expr.Visitor<String> {
+    String print(Expr expr) {
+        return expr.accept(this);
+    }
+
+    @Override
+    public String visitBinaryExpr(Expr.Binary expr) {
+        return parenthesize(expr.operator.lexeme, expr.left, 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();
+    }
+}

+ 75 - 0
src/main/java/com/craftinginterpreters/lox/Expr.java

@@ -0,0 +1,75 @@
+package com.craftinginterpreters.lox;
+
+/**
+ * @author GenerateAst
+ * @date 2023-06-05 13:42
+ */
+abstract class Expr {
+    interface Visitor<R> {
+        R visitBinaryExpr(Binary expr);
+
+        R visitGroupingExpr(Grouping expr);
+
+        R visitLiteralExpr(Literal expr);
+
+        R visitUnaryExpr(Unary expr);
+
+    }
+
+    static class Binary extends Expr {
+        Binary(Expr left, Token operator, Expr right) {
+            this.left = left;
+            this.operator = operator;
+            this.right = right;
+        }
+
+        @Override
+        <R> R accept(Visitor<R> visitor) {
+            return visitor.visitBinaryExpr(this);
+        }
+
+        final Expr left;
+        final  Token operator;
+        final  Expr right;
+    }
+    static class Grouping extends Expr {
+        Grouping(Expr expression) {
+            this.expression = expression;
+        }
+
+        @Override
+        <R> R accept(Visitor<R> visitor) {
+            return visitor.visitGroupingExpr(this);
+        }
+
+        final Expr expression;
+    }
+    static class Literal extends Expr {
+        Literal(Object value) {
+            this.value = value;
+        }
+
+        @Override
+        <R> R accept(Visitor<R> visitor) {
+            return visitor.visitLiteralExpr(this);
+        }
+
+        final Object value;
+    }
+    static class Unary extends Expr {
+        Unary(Token operator, Expr right) {
+            this.operator = operator;
+            this.right = right;
+        }
+
+        @Override
+        <R> R accept(Visitor<R> visitor) {
+            return visitor.visitUnaryExpr(this);
+        }
+
+        final Token operator;
+        final  Expr right;
+    }
+
+    abstract <R> R accept(Visitor<R> visitor);
+}

+ 1 - 1
src/main/java/com/craftinginterpreters/lox/Scanner.java

@@ -177,7 +177,7 @@ public class Scanner {
     /**
      * consumes the next character in the source file and returns it
      *
-     * @return
+     * @return character
      */
     private char advance() {
         return source.charAt(current++);

+ 130 - 0
src/main/java/com/craftinginterpreters/tool/GenerateAst.java

@@ -0,0 +1,130 @@
+/* Copyright (C) 2019-2023 Hangzhou HSH Co. Ltd.
+ * All right reserved.*/
+package com.craftinginterpreters.tool;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+
+
+/**
+ * @author simon
+ * @date 2023-06-05 10:53
+ * @desc <code>
+ * expression     → literal
+ * | unary
+ * | binary
+ * | grouping ;
+ * <p>
+ * literal        → NUMBER | STRING | "true" | "false" | "nil" ;
+ * <p>
+ * grouping       → "(" expression ")" ;
+ *
+ * <p>
+ * unary          → ( "-" | "!" ) expression ;
+ * <p>
+ * binary         → expression operator expression ;
+ * <p>
+ * operator       → "==" | "!=" | "<" | "<=" | ">" | ">="
+ * | "+"  | "-"  | "*" | "/" ;
+ * </code>
+ */
+public class GenerateAst {
+    private static final String space = "    ";
+
+    public static void main(String[] args) throws IOException {
+        if (args.length != 1) {
+            System.err.println("Usage: generate_ast <output directory>");
+            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"
+        ));
+    }
+
+    private static void defineAst(String outputDir, String baseName, List<String> types)
+            throws IOException {
+        String path = outputDir + File.separator + baseName + ".java";
+        PrintWriter writer = new PrintWriter(path, StandardCharsets.UTF_8);
+        SimpleDateFormat matter = new SimpleDateFormat("yyyy-MM-dd HH:mm");
+        writer.println("package com.craftinginterpreters.lox;");
+        writer.println();
+        //writer.println("import java.util.List;");
+        //writer.println();
+        writer.println("/**");
+        writer.println(" * @author GenerateAst");
+        writer.println(" * @date " + matter.format(new Date()));
+        writer.println(" */");
+        writer.println("abstract class " + baseName + " {");
+
+        defineVisitor(writer, baseName, types);
+
+        // The AST classes
+        for (String type : types) {
+            String className = type.split(":")[0].trim();
+            String fields = type.split(":")[1].trim();
+            defineType(writer, baseName, className, fields);
+        } // End for
+
+        // The base accept() method
+        writer.println();
+        writer.println(space + "abstract <R> R accept(Visitor<R> visitor);");
+
+        writer.println("}");
+        writer.close();
+    }
+
+    private static void defineVisitor(PrintWriter writer, String baseName, List<String> types) {
+        writer.println(space + "interface Visitor<R> {");
+
+        for (String type : types) {
+            String typeName = type.split(":")[0].trim();
+            writer.println(space + space + "R visit" + typeName + baseName + "(" +
+                    typeName + " " + baseName.toLowerCase() + ");");
+            writer.println();
+        }
+
+        writer.println(space + "}");
+        writer.println();
+    }
+
+    private static void defineType(
+            PrintWriter writer, String baseName,
+            String className, String fieldList) {
+        writer.println(space + "static class " + className + " extends " + baseName + " {");
+
+        // Constructor.
+        writer.println(space + space + className + "(" + fieldList + ") {");
+        // Store parameters in fields
+        String[] fields = fieldList.split(",");
+        for (String field : fields) {
+            String name = field.trim().split(" ")[1];
+            writer.println(space + space + space + "this." + name + " = " + name + ";");
+        }
+        writer.println(space + space + "}");
+
+        // Visitor pattern.
+        writer.println();
+        writer.println(space + space + "@Override");
+        writer.println(space + space + "<R> R accept(Visitor<R> visitor) {");
+        writer.println(space + space + space + "return visitor.visit" + className + baseName + "(this);");
+        writer.println(space + space + "}");
+
+        // Fields
+        writer.println();
+        for (String field : fields) {
+            writer.println(space + space + "final " + field + ";");
+        }
+
+        writer.println("    }");
+    }
+}

+ 19 - 0
src/test/java/com/craftinginterpreters/lox/AstPrinterTest.java

@@ -0,0 +1,19 @@
+package com.craftinginterpreters.lox;
+
+import org.junit.Test;
+
+/* Copyright (C) 2019-2023 Hangzhou HSH Co. Ltd.
+ * All right reserved.*/
+public class AstPrinterTest {
+
+    @Test
+    public void print() {
+        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));
+    }
+}