From b1cd274a39bbdadf5185f32baa3032849b249ec5 Mon Sep 17 00:00:00 2001 From: David Ashby Date: Sun, 19 Sep 2021 14:13:47 -0400 Subject: [PATCH] global variables --- src/lox/ASTPrinter.java | 5 +++++ src/lox/Environment.java | 19 +++++++++++++++++++ src/lox/Expr.java | 16 ++++++++++++++-- src/lox/Interpreter.java | 17 +++++++++++++++++ src/lox/Parser.java | 37 ++++++++++++++++++++++++++++--------- src/lox/Scanner.java | 4 +--- src/lox/Stmt.java | 17 ++++++++++++++++- src/tool/GenerateAST.java | 12 ++++++++---- 8 files changed, 108 insertions(+), 19 deletions(-) create mode 100644 src/lox/Environment.java diff --git a/src/lox/ASTPrinter.java b/src/lox/ASTPrinter.java index 9ea4b64..6b23528 100644 --- a/src/lox/ASTPrinter.java +++ b/src/lox/ASTPrinter.java @@ -28,6 +28,11 @@ class ASTPrinter implements Expr.Visitor { return parenthesize(expr.operator.lexeme, expr.right); } + @Override + public String visitVariableExpr(Expr.Variable expr) { + return expr.name.toString(); + } + private String parenthesize(String name, Expr... exprs) { StringBuilder builder = new StringBuilder(); diff --git a/src/lox/Environment.java b/src/lox/Environment.java new file mode 100644 index 0000000..188efdd --- /dev/null +++ b/src/lox/Environment.java @@ -0,0 +1,19 @@ +package lox; + +import java.util.HashMap; +import java.util.Map; + +class Environment { + private final Map values = new HashMap<>(); + + void define(String name, Object value) { + values.put(name, value); + } + + Object get(Token name) { + if (values.containsKey(name.lexeme)) { + return values.get(name.lexeme); + } + throw new RuntimeError(name, "Undefined variable '" + name.lexeme + "'."); + } +} diff --git a/src/lox/Expr.java b/src/lox/Expr.java index 5337c91..a1c9fb0 100644 --- a/src/lox/Expr.java +++ b/src/lox/Expr.java @@ -1,13 +1,12 @@ 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); + R visitVariableExpr(Variable expr); } static class Binary extends Expr { @@ -68,5 +67,18 @@ abstract class Expr { final Expr right; } + static class Variable extends Expr { + Variable(Token name) { + this.name = name; + } + + @Override + R accept(Visitor visitor) { + return visitor.visitVariableExpr(this); + } + + final Token name; + } + abstract R accept(Visitor visitor); } diff --git a/src/lox/Interpreter.java b/src/lox/Interpreter.java index b58a855..ae0e43b 100644 --- a/src/lox/Interpreter.java +++ b/src/lox/Interpreter.java @@ -3,6 +3,8 @@ package lox; import java.util.List; class Interpreter implements Expr.Visitor, Stmt.Visitor { + private Environment environment = new Environment(); + void interpret(List statements) { try { for (Stmt statement : statements) { @@ -82,6 +84,11 @@ class Interpreter implements Expr.Visitor, Stmt.Visitor { return null; } + @Override + public Object visitVariableExpr(Expr.Variable expr) { + return environment.get(expr.name); + } + @Override public Void visitExpressionStmt(Stmt.Expression stmt) { evaluate(stmt.expression); @@ -95,6 +102,16 @@ class Interpreter implements Expr.Visitor, Stmt.Visitor { return null; } + @Override + public Void visitVarStmt(Stmt.Var stmt) { + Object value = null; + if (stmt.initializer != null) { + value = evaluate(stmt.initializer); + } + environment.define(stmt.name.lexeme, value); + return null; + } + private void checkNumberOperand(Token operator, Object operand) { if (operand instanceof Double) { return; diff --git a/src/lox/Parser.java b/src/lox/Parser.java index d298955..bb081ec 100644 --- a/src/lox/Parser.java +++ b/src/lox/Parser.java @@ -18,11 +18,34 @@ class Parser { List parse() { List statements = new ArrayList<>(); while (!isAtEnd()) { - statements.add(statement()); + statements.add(declaration()); } return statements; } + private Stmt declaration() { + try { + if (match(VAR)) { + return varDeclaration(); + } + return statement(); + } catch (ParseError error) { + synchronize(); + return null; + } + } + + private Stmt varDeclaration() { + Token name = consume(IDENTIFIER, "Expect variable name."); + + Expr initializer = null; + if (match(EQUAL)) { + initializer = expression(); + } + consume(SEMICOLON, "Expect semicolon."); + return new Stmt.Var(name, initializer); + } + private Stmt statement() { if (match(PRINT)) { return printStatement(); @@ -113,6 +136,9 @@ class Parser { consume(RIGHT_PAREN, "Expect ')' after expression."); return new Expr.Grouping(expr); } + if (match(IDENTIFIER)) { + return new Expr.Variable(previous()); + } throw error(peek(), "Expected expression."); } @@ -172,14 +198,7 @@ class Parser { return; } switch (peek().type) { - case CLASS: - case FOR: - case FUN: - case IF: - case PRINT: - case RETURN: - case VAR: - case WHILE: + case CLASS, FOR, FUN, IF, PRINT, RETURN, VAR, WHILE: return; } } diff --git a/src/lox/Scanner.java b/src/lox/Scanner.java index 10ed93d..e0aed03 100644 --- a/src/lox/Scanner.java +++ b/src/lox/Scanner.java @@ -106,9 +106,7 @@ class Scanner { addToken(SLASH); } break; - case ' ': - case '\r': - case '\t': + case ' ', '\r', '\t': break; // skip whitespace case '\n': line++; diff --git a/src/lox/Stmt.java b/src/lox/Stmt.java index 2f5d407..1be8253 100644 --- a/src/lox/Stmt.java +++ b/src/lox/Stmt.java @@ -3,7 +3,7 @@ package lox; abstract class Stmt { interface Visitor { R visitExpressionStmt(Expression stmt); - + R visitVarStmt(Var stmt); R visitPrintStmt(Print stmt); } @@ -20,6 +20,21 @@ abstract class Stmt { final Expr expression; } + static class Var extends Stmt { + Var(Token name, Expr initializer) { + this.name = name; + this.initializer = initializer; + } + + @Override + R accept(Visitor visitor) { + return visitor.visitVarStmt(this); + } + + final Token name; + final Expr initializer; + } + static class Print extends Stmt { Print(Expr expression) { this.expression = expression; diff --git a/src/tool/GenerateAST.java b/src/tool/GenerateAST.java index 5a701cf..1dc6937 100644 --- a/src/tool/GenerateAST.java +++ b/src/tool/GenerateAST.java @@ -20,12 +20,16 @@ public class GenerateAST { "Binary : Expr left, Token operator, Expr right", "Grouping : Expr expression", "Literal : Object value", - "Unary : Token operator, Expr right")); + "Unary : Token operator, Expr right", + "Variable : Token name")); defineAST( outputDir, "Stmt", - Arrays.asList("Expression : Expr expression", "Print : Expr expression")); + Arrays.asList( + "Expression : Expr expression", + "Var : Token name, Expr initializer", + "Print : Expr expression")); } private static void defineAST(String outputDir, String baseName, List types) @@ -35,8 +39,8 @@ public class GenerateAST { writer.println("package lox;"); writer.println(); - writer.println("import java.util.List;"); - writer.println(); + // writer.println("import java.util.List;"); + // writer.println(); writer.println("abstract class " + baseName + " {"); defineVisitor(writer, baseName, types);