|
|
@@ -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(" }");
|
|
|
+ }
|
|
|
+}
|