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
|
* AstPrinter
|
||||||
*/
|
*/
|
||||||
class AstPrinter implements Expr.Visitor<String> {
|
class AstPrinter implements Expr.Visitor<String>, Stmt.Visitor<String> {
|
||||||
String print(Expr expr) {
|
String print(Expr expr) {
|
||||||
return expr.accept(this);
|
return expr.accept(this);
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,26 @@ class AstPrinter implements Expr.Visitor<String> {
|
||||||
return parenthesize(expr.operator.lexeme, expr.right);
|
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) {
|
private String parenthesize(String name, Expr... exprs) {
|
||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ set(GENERATED_JAVA_FILENAMES
|
||||||
|
|
||||||
add_custom_command(OUTPUT ${GENERATED_JAVA_FILENAMES}
|
add_custom_command(OUTPUT ${GENERATED_JAVA_FILENAMES}
|
||||||
COMMAND java -jar ${GENERATE_AST_JAR} ${CMAKE_CURRENT_BINARY_DIR}
|
COMMAND java -jar ${GENERATE_AST_JAR} ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
DEPENDS GenerateAst)
|
DEPENDS GenerateAst ${GENERATE_AST_JAR})
|
||||||
|
|
||||||
add_jar(Lox
|
add_jar(Lox
|
||||||
Lox.java
|
Lox.java
|
||||||
|
@ -19,4 +19,5 @@ add_jar(Lox
|
||||||
Parser.java
|
Parser.java
|
||||||
Interpreter.java
|
Interpreter.java
|
||||||
RuntimeError.java
|
RuntimeError.java
|
||||||
|
Environment.java
|
||||||
ENTRY_POINT com/craftinginterpreters/lox/Lox)
|
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;
|
import java.util.List;
|
||||||
|
|
||||||
class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
|
class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
|
||||||
|
private Environment environment = new Environment();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object visitLiteralExpr(Expr.Literal expr) {
|
public Object visitLiteralExpr(Expr.Literal expr) {
|
||||||
return expr.value;
|
return expr.value;
|
||||||
|
@ -24,6 +26,11 @@ class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object visitVariableExpr(Expr.Variable expr) {
|
||||||
|
return environment.get(expr.name);
|
||||||
|
}
|
||||||
|
|
||||||
private void checkNumberOperand(Token operator, Object operand) {
|
private void checkNumberOperand(Token operator, Object operand) {
|
||||||
if (operand instanceof Double)
|
if (operand instanceof Double)
|
||||||
return;
|
return;
|
||||||
|
@ -95,6 +102,17 @@ class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
|
||||||
return null;
|
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
|
@Override
|
||||||
public Object visitBinaryExpr(Expr.Binary expr) {
|
public Object visitBinaryExpr(Expr.Binary expr) {
|
||||||
Object left = evaluate(expr.left);
|
Object left = evaluate(expr.left);
|
||||||
|
|
|
@ -20,7 +20,7 @@ class Parser {
|
||||||
List<Stmt> statements = new ArrayList<>();
|
List<Stmt> statements = new ArrayList<>();
|
||||||
|
|
||||||
while (!isAtEnd()) {
|
while (!isAtEnd()) {
|
||||||
statements.add(statement());
|
statements.add(declaration());
|
||||||
}
|
}
|
||||||
|
|
||||||
return statements;
|
return statements;
|
||||||
|
@ -30,6 +30,18 @@ class Parser {
|
||||||
return equality();
|
return equality();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Stmt declaration() {
|
||||||
|
try {
|
||||||
|
if (match(VAR))
|
||||||
|
return varDeclaration();
|
||||||
|
|
||||||
|
return statement();
|
||||||
|
} catch (ParseError error) {
|
||||||
|
synchronize();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Stmt statement() {
|
private Stmt statement() {
|
||||||
if (match(PRINT))
|
if (match(PRINT))
|
||||||
return printStatement();
|
return printStatement();
|
||||||
|
@ -43,6 +55,18 @@ class Parser {
|
||||||
return new Stmt.Print(value);
|
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() {
|
private Stmt expressionStatement() {
|
||||||
Expr expr = expression();
|
Expr expr = expression();
|
||||||
consume(SEMICOLON, "Expect ';' after expression.");
|
consume(SEMICOLON, "Expect ';' after expression.");
|
||||||
|
@ -119,6 +143,10 @@ class Parser {
|
||||||
return new Expr.Literal(previous().literal);
|
return new Expr.Literal(previous().literal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (match(IDENTIFIER)) {
|
||||||
|
return new Expr.Variable(previous());
|
||||||
|
}
|
||||||
|
|
||||||
if (match(LEFT_PAREN)) {
|
if (match(LEFT_PAREN)) {
|
||||||
Expr expr = expression();
|
Expr expr = expression();
|
||||||
consume(RIGHT_PAREN, "Expect ')' after expression.");
|
consume(RIGHT_PAREN, "Expect ')' after expression.");
|
||||||
|
|
|
@ -14,9 +14,11 @@ public class GenerateAst {
|
||||||
|
|
||||||
String outputDir = args[0];
|
String outputDir = args[0];
|
||||||
|
|
||||||
defineAst(outputDir, "Expr", Arrays.asList("Binary : Expr left, Token operator, Expr right",
|
defineAst(outputDir, "Expr",
|
||||||
"Grouping : Expr expression", "Literal : Object value", "Unary : Token operator, Expr right"));
|
Arrays.asList("Binary : Expr left, Token operator, Expr right", "Grouping : Expr expression",
|
||||||
defineAst(outputDir, "Stmt", Arrays.asList("Expression : Expr expression", "Print : 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 {
|
private static void defineAst(String outputDir, String baseName, List<String> types) throws IOException {
|
||||||
|
|
Loading…
Reference in a new issue