Chapter 8: Add variable declarations
This commit is contained in:
parent
8019f6aa41
commit
899ecea236
6 changed files with 95 additions and 6 deletions
|
@ -3,7 +3,7 @@ package com.craftinginterpreters.lox;
|
|||
/**
|
||||
* AstPrinter
|
||||
*/
|
||||
class AstPrinter implements Expr.Visitor<String> {
|
||||
class AstPrinter implements Expr.Visitor<String>, Stmt.Visitor<String> {
|
||||
String print(Expr expr) {
|
||||
return expr.accept(this);
|
||||
}
|
||||
|
@ -30,6 +30,26 @@ class AstPrinter implements Expr.Visitor<String> {
|
|||
return parenthesize(expr.operator.lexeme, expr.right);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String visitVariableExpr(Expr.Variable expr) {
|
||||
return expr.name.lexeme;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String visitVarStmt(Stmt.Var statement) {
|
||||
return parenthesize("define " + statement.name.lexeme + " = ", statement.initializer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String visitPrintStmt(Stmt.Print statement) {
|
||||
return parenthesize("print", statement.expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String visitExpressionStmt(Stmt.Expression expression) {
|
||||
return expression.expression.accept(this);
|
||||
}
|
||||
|
||||
private String parenthesize(String name, Expr... exprs) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ set(GENERATED_JAVA_FILENAMES
|
|||
|
||||
add_custom_command(OUTPUT ${GENERATED_JAVA_FILENAMES}
|
||||
COMMAND java -jar ${GENERATE_AST_JAR} ${CMAKE_CURRENT_BINARY_DIR}
|
||||
DEPENDS GenerateAst)
|
||||
DEPENDS GenerateAst ${GENERATE_AST_JAR})
|
||||
|
||||
add_jar(Lox
|
||||
Lox.java
|
||||
|
@ -19,4 +19,5 @@ add_jar(Lox
|
|||
Parser.java
|
||||
Interpreter.java
|
||||
RuntimeError.java
|
||||
Environment.java
|
||||
ENTRY_POINT com/craftinginterpreters/lox/Lox)
|
||||
|
|
20
src/com/craftinginterpreters/lox/Environment.java
Normal file
20
src/com/craftinginterpreters/lox/Environment.java
Normal file
|
@ -0,0 +1,20 @@
|
|||
package com.craftinginterpreters.lox;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
class Environment {
|
||||
private final Map<String, Object> values = new HashMap<>();
|
||||
|
||||
Object get(Token name) {
|
||||
if (values.containsKey(name.lexeme)) {
|
||||
return values.get(name.lexeme);
|
||||
}
|
||||
|
||||
throw new RuntimeError(name, "Undefined variable '" + name.lexeme + "'.");
|
||||
}
|
||||
|
||||
void define(String name, Object value) {
|
||||
values.put(name, value);
|
||||
}
|
||||
}
|
|
@ -3,6 +3,8 @@ package com.craftinginterpreters.lox;
|
|||
import java.util.List;
|
||||
|
||||
class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
|
||||
private Environment environment = new Environment();
|
||||
|
||||
@Override
|
||||
public Object visitLiteralExpr(Expr.Literal expr) {
|
||||
return expr.value;
|
||||
|
@ -24,6 +26,11 @@ class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitVariableExpr(Expr.Variable expr) {
|
||||
return environment.get(expr.name);
|
||||
}
|
||||
|
||||
private void checkNumberOperand(Token operator, Object operand) {
|
||||
if (operand instanceof Double)
|
||||
return;
|
||||
|
@ -95,6 +102,17 @@ class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
|
|||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitBinaryExpr(Expr.Binary expr) {
|
||||
Object left = evaluate(expr.left);
|
||||
|
|
|
@ -20,7 +20,7 @@ class Parser {
|
|||
List<Stmt> statements = new ArrayList<>();
|
||||
|
||||
while (!isAtEnd()) {
|
||||
statements.add(statement());
|
||||
statements.add(declaration());
|
||||
}
|
||||
|
||||
return statements;
|
||||
|
@ -30,6 +30,18 @@ class Parser {
|
|||
return equality();
|
||||
}
|
||||
|
||||
private Stmt declaration() {
|
||||
try {
|
||||
if (match(VAR))
|
||||
return varDeclaration();
|
||||
|
||||
return statement();
|
||||
} catch (ParseError error) {
|
||||
synchronize();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Stmt statement() {
|
||||
if (match(PRINT))
|
||||
return printStatement();
|
||||
|
@ -43,6 +55,18 @@ class Parser {
|
|||
return new Stmt.Print(value);
|
||||
}
|
||||
|
||||
private Stmt varDeclaration() {
|
||||
Token name = consume(IDENTIFIER, "Expect variable name.");
|
||||
|
||||
Expr initializer = null;
|
||||
if (match(EQUAL)) {
|
||||
initializer = expression();
|
||||
}
|
||||
|
||||
consume(SEMICOLON, "Expect ';' after variable declaration.");
|
||||
return new Stmt.Var(name, initializer);
|
||||
}
|
||||
|
||||
private Stmt expressionStatement() {
|
||||
Expr expr = expression();
|
||||
consume(SEMICOLON, "Expect ';' after expression.");
|
||||
|
@ -119,6 +143,10 @@ class Parser {
|
|||
return new Expr.Literal(previous().literal);
|
||||
}
|
||||
|
||||
if (match(IDENTIFIER)) {
|
||||
return new Expr.Variable(previous());
|
||||
}
|
||||
|
||||
if (match(LEFT_PAREN)) {
|
||||
Expr expr = expression();
|
||||
consume(RIGHT_PAREN, "Expect ')' after expression.");
|
||||
|
|
|
@ -14,9 +14,11 @@ public class GenerateAst {
|
|||
|
||||
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, "Stmt", Arrays.asList("Expression : Expr expression", "Print : Expr expression"));
|
||||
defineAst(outputDir, "Expr",
|
||||
Arrays.asList("Binary : Expr left, Token operator, Expr right", "Grouping : Expr expression",
|
||||
"Literal : Object value", "Unary : Token operator, Expr right", "Variable : Token name"));
|
||||
defineAst(outputDir, "Stmt", Arrays.asList("Expression : Expr expression", "Print : Expr expression",
|
||||
"Var : Token name, Expr initializer"));
|
||||
}
|
||||
|
||||
private static void defineAst(String outputDir, String baseName, List<String> types) throws IOException {
|
||||
|
|
Loading…
Reference in a new issue