From a608d32f4638e91d0299551287682a55bd21070a Mon Sep 17 00:00:00 2001 From: Mariano Riefolo Date: Thu, 27 Jun 2024 15:37:07 +0200 Subject: [PATCH] Representing code chapter --- src/lox/AstPrinter.java | 42 +++++++++++++++++ src/lox/Expr.java | 68 +++++++++++++++++++++++++++ src/tool/GenerateAst.java | 96 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 206 insertions(+) create mode 100644 src/lox/AstPrinter.java create mode 100644 src/lox/Expr.java create mode 100644 src/tool/GenerateAst.java diff --git a/src/lox/AstPrinter.java b/src/lox/AstPrinter.java new file mode 100644 index 0000000..ecb07d3 --- /dev/null +++ b/src/lox/AstPrinter.java @@ -0,0 +1,42 @@ +package lox; + +public class AstPrinter implements Expr.Visitor { + String print(Expr expr) { + return expr.accept(this); + } + + @Override + public String visitBinaryExpr(Expr.Binary expr) { + return parethesize(expr.operator.lexeme, + expr.left, expr.right); + } + + @Override + public String visitGroupingExpr(Expr.Grouping expr) { + return parethesize("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 parethesize(expr.operator.lexeme, expr.right); + } + + private String parethesize(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(); + } +} diff --git a/src/lox/Expr.java b/src/lox/Expr.java new file mode 100644 index 0000000..e6edfcf --- /dev/null +++ b/src/lox/Expr.java @@ -0,0 +1,68 @@ +package lox; + +import java.util.List; + +abstract class Expr { + interface Visitor { + 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 accept(Visitor 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 accept(Visitor visitor) { + return visitor.visitGroupingExpr(this); + } + + final Expr expression; + } + static class Literal extends Expr { + Literal(Object value) { + this.value = value; + } + + @Override + R accept(Visitor 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 accept(Visitor visitor) { + return visitor.visitUnaryExpr(this); + } + + final Token operator; + final Expr right; + } + + abstract R accept(Visitor visitor); +} diff --git a/src/tool/GenerateAst.java b/src/tool/GenerateAst.java new file mode 100644 index 0000000..4f67c43 --- /dev/null +++ b/src/tool/GenerateAst.java @@ -0,0 +1,96 @@ +package tool; + +import java.io.FileNotFoundException; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.util.Arrays; +import java.util.List; + +public class GenerateAst { + public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException { + if (args.length != 1) { + System.err.println("Usage: generate_ast "); + 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 types) throws FileNotFoundException, UnsupportedEncodingException { + String path = outputDir + "/" + baseName + ".java"; + PrintWriter writer = new PrintWriter(path, "UTF-8"); + + writer.println("package lox;"); + writer.println(); + writer.println("import java.util.List;"); + writer.println(); + writer.println("abstract class " + baseName + " {"); + + defineVisitor(writer, baseName, types); + + + for (String type : types) { + String className = type.split(":")[0].trim(); + String fields = type.split(":")[1].trim(); + defineType(writer, baseName, className, fields); + } + + writer.println(); + writer.println("\tabstract R accept(Visitor visitor);"); + + writer.println("}"); + writer.close(); + } + + private static void defineVisitor( + PrintWriter writer, String baseName, List types) { + writer.println("\tinterface Visitor {"); + + for (String type : types) { + String typeName = type.split(":")[0].trim(); + writer.println("\t\tR visit" + typeName + baseName + "(" + + typeName + " " + baseName.toLowerCase() + ");"); + + } + + writer.println("\t}"); + } + + private static void defineType( + PrintWriter writer, String baseName, + String className, String fieldList) { + writer.println("\tstatic class " + className + " extends " + baseName + " {"); + + writer.println("\t\t" + className + "(" + fieldList + ") {"); + + String[] fields = fieldList.split(", "); + for (String field : fields) { + String name = field.split(" ")[1]; + writer.println("\t\t\tthis." + name + " = " + name + ";"); + } + + writer.println("\t\t}"); + + writer.println(); + writer.println("\t\t@Override"); + writer.println("\t\t R accept(Visitor visitor) {"); + writer.println("\t\t\treturn visitor.visit" + + className + baseName + "(this);"); + writer.println("\t\t}"); + + + writer.println(); + for (String field : fields) { + writer.println("\t\tfinal " + field + ";"); + } + + writer.println("\t}"); + } + +} \ No newline at end of file