0307-Nand-实现类

news/2025/10/31 16:15:42/文章来源:https://www.cnblogs.com/jiangbo4444/p/19180343

环境

  • Time 2023-07-11
  • Java 17

前言

说明

参考:

  • https://craftinginterpreters.com/contents.html
  • https://github.com/GuoYaxiang/craftinginterpreters_zh
  • https://space.bilibili.com/44550904

目标

接上一节,面向对象语言中的类。

GenerateAst

package com.jiangbo.tool;import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;public class GenerateAst {public static void main(String[] args) throws IOException {// 根据实际情况,修改成对应的代码路径String outputDir = "C:\\work\\workspace\\demo\\src\\main\\java\\com\\jiangbo\\lox";defineAst(outputDir, "Expr", Arrays.asList("Assign   : Token name, Expr value","Binary   : Expr left, Token operator, Expr right","Call     : Expr callee, Token paren, List<Expr> arguments","Get      : Expr object, Token name","Grouping : Expr expression","Literal  : Object value","Logical  : Expr left, Token operator, Expr right","Set      : Expr object, Token name, Expr value","This     : Token keyword","Unary    : Token operator, Expr right","Variable : Token name"));defineAst(outputDir, "Stmt", Arrays.asList("Block      : List<Stmt> statements","Class      : Token name, List<Stmt.Function> methods","Expression : Expr expression","Function   : Token name, List<Token> params," +" List<Stmt> body","If         : Expr condition, Stmt thenBranch," +" Stmt elseBranch","Print      : Expr expression","Return     : Token keyword, Expr value","Var        : Token name, Expr initializer","While      : Expr condition, Stmt body"));}private static void defineAst(String outputDir, String baseName, List<String> types)throws IOException {String path = outputDir + "/" + baseName + ".java";PrintWriter writer = new PrintWriter(path, StandardCharsets.UTF_8);writer.println("package com.jiangbo.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);}// The base accept() method.writer.println();writer.println("  abstract <R> R accept(Visitor<R> visitor);");writer.println("}");writer.close();}private static void defineVisitor(PrintWriter writer, String baseName, List<String> types) {writer.println("  interface Visitor<R> {");for (String type : types) {String typeName = type.split(":")[0].trim();writer.println("    R visit" + typeName + baseName + "(" +typeName + " " + baseName.toLowerCase() + ");");}writer.println("  }");}private static void defineType(PrintWriter writer, String baseName,String className, String fieldList) {writer.println("  static class " + className + " extends " +baseName + " {");// Constructor.writer.println("    " + className + "(" + fieldList + ") {");// Store parameters in fields.String[] fields = fieldList.split(", ");for (String field : fields) {String name = field.split(" ")[1];writer.println("      this." + name + " = " + name + ";");}writer.println("    }");// Visitor pattern.writer.println();writer.println("    @Override");writer.println("    <R> R accept(Visitor<R> visitor) {");writer.println("      return visitor.visit" +className + baseName + "(this);");writer.println("    }");// Fields.writer.println();for (String field : fields) {writer.println("    final " + field + ";");}writer.println("  }");}
}

LoxClass

package com.jiangbo.lox;import java.util.List;
import java.util.Map;class LoxClass implements LoxCallable {final String name;private final Map<String, LoxFunction> methods;LoxClass(String name, Map<String, LoxFunction> methods) {this.name = name;this.methods = methods;}LoxFunction findMethod(String name) {if (methods.containsKey(name)) {return methods.get(name);}return null;}@Overridepublic Object call(Interpreter interpreter,List<Object> arguments) {LoxInstance instance = new LoxInstance(this);LoxFunction initializer = findMethod("init");if (initializer != null) {initializer.bind(instance).call(interpreter, arguments);}return instance;}@Overridepublic int arity() {LoxFunction initializer = findMethod("init");if (initializer == null) return 0;return initializer.arity();}@Overridepublic String toString() {return name;}
}

LoxFunction

package com.jiangbo.lox;import java.util.List;class LoxFunction implements LoxCallable {private final Stmt.Function declaration;private final Environment closure;private final boolean isInitializer;LoxFunction(Stmt.Function declaration, Environment closure, boolean isInitializer) {this.isInitializer = isInitializer;this.closure = closure;this.declaration = declaration;}LoxFunction bind(LoxInstance instance) {Environment environment = new Environment(closure);environment.define("this", instance);return new LoxFunction(declaration, environment, isInitializer);}@Overridepublic int arity() {return declaration.params.size();}@Overridepublic Object call(Interpreter interpreter,List<Object> arguments) {Environment environment = new Environment(closure);for (int i = 0; i < declaration.params.size(); i++) {environment.define(declaration.params.get(i).lexeme,arguments.get(i));}try {interpreter.executeBlock(declaration.body, environment);} catch (Return returnValue) {if (isInitializer) return closure.getAt(0, "this");return returnValue.value;}if (isInitializer) return closure.getAt(0, "this");return null;}@Overridepublic String toString() {return "<fn " + declaration.name.lexeme + ">";}
}

LoxInstance

package com.jiangbo.lox;import java.util.HashMap;
import java.util.Map;class LoxInstance {private LoxClass klass;private final Map<String, Object> fields = new HashMap<>();LoxInstance(LoxClass klass) {this.klass = klass;}Object get(Token name) {if (fields.containsKey(name.lexeme)) {return fields.get(name.lexeme);}LoxFunction method = klass.findMethod(name.lexeme);if (method != null) return method.bind(this);throw new RuntimeError(name,"Undefined property '" + name.lexeme + "'.");}void set(Token name, Object value) {fields.put(name.lexeme, value);}@Overridepublic String toString() {return klass.name + " instance";}
}

Interpreter

package com.jiangbo.lox;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;class Interpreter implements Expr.Visitor<Object>,Stmt.Visitor<Void> {final Environment globals = new Environment();private Environment environment = globals;private final Map<Expr, Integer> locals = new HashMap<>();Interpreter() {globals.define("clock", new LoxCallable() {@Overridepublic int arity() { return 0; }@Overridepublic Object call(Interpreter interpreter, List<Object> arguments) {return (double)System.currentTimeMillis() / 1000.0;}@Overridepublic String toString() { return "<native fn>"; }});}void interpret(List<Stmt> statements) {try {for (Stmt statement : statements) {execute(statement);}} catch (RuntimeError error) {Lox.runtimeError(error);}}private void execute(Stmt stmt) {stmt.accept(this);}void resolve(Expr expr, int depth) {locals.put(expr, depth);}@Overridepublic Void visitBlockStmt(Stmt.Block stmt) {executeBlock(stmt.statements, new Environment(environment));return null;}@Overridepublic Void visitClassStmt(Stmt.Class stmt) {environment.define(stmt.name.lexeme, null);Map<String, LoxFunction> methods = new HashMap<>();for (Stmt.Function method : stmt.methods) {LoxFunction function = new LoxFunction(method, environment,method.name.lexeme.equals("init"));methods.put(method.name.lexeme, function);}LoxClass klass = new LoxClass(stmt.name.lexeme, methods);environment.assign(stmt.name, klass);return null;}void executeBlock(List<Stmt> statements,Environment environment) {Environment previous = this.environment;try {this.environment = environment;for (Stmt statement : statements) {execute(statement);}} finally {this.environment = previous;}}@Overridepublic Object visitLiteralExpr(Expr.Literal expr) {return expr.value;}@Overridepublic Object visitLogicalExpr(Expr.Logical expr) {Object left = evaluate(expr.left);if (expr.operator.type == TokenType.OR) {if (isTruthy(left)) return left;} else {if (!isTruthy(left)) return left;}return evaluate(expr.right);}@Overridepublic Object visitSetExpr(Expr.Set expr) {Object object = evaluate(expr.object);if (!(object instanceof LoxInstance)) {throw new RuntimeError(expr.name,"Only instances have fields.");}Object value = evaluate(expr.value);((LoxInstance)object).set(expr.name, value);return value;}@Overridepublic Object visitThisExpr(Expr.This expr) {return lookUpVariable(expr.keyword, expr);}@Overridepublic Object visitGroupingExpr(Expr.Grouping expr) {return evaluate(expr.expression);}@Overridepublic Void visitVarStmt(Stmt.Var stmt) {Object value = null;if (stmt.initializer != null) {value = evaluate(stmt.initializer);}environment.define(stmt.name.lexeme, value);return null;}@Overridepublic Void visitWhileStmt(Stmt.While stmt) {while (isTruthy(evaluate(stmt.condition))) {execute(stmt.body);}return null;}@Overridepublic Object visitAssignExpr(Expr.Assign expr) {Object value = evaluate(expr.value);Integer distance = locals.get(expr);if (distance != null) {environment.assignAt(distance, expr.name, value);} else {globals.assign(expr.name, value);}return value;}@Overridepublic Object visitVariableExpr(Expr.Variable expr) {return lookUpVariable(expr.name, expr);}private Object lookUpVariable(Token name, Expr expr) {Integer distance = locals.get(expr);if (distance != null) {return environment.getAt(distance, name.lexeme);} else {return globals.get(name);}}@Overridepublic Object visitUnaryExpr(Expr.Unary expr) {Object right = evaluate(expr.right);checkNumberOperand(expr.operator, right);return switch (expr.operator.type) {case BANG -> !isTruthy(right);case MINUS -> -(double) right;default -> null;};}@Overridepublic Object visitBinaryExpr(Expr.Binary expr) {Object left = evaluate(expr.left);Object right = evaluate(expr.right);switch (expr.operator.type) {case GREATER:checkNumberOperands(expr.operator, left, right);return (double) left > (double) right;case GREATER_EQUAL:checkNumberOperands(expr.operator, left, right);return (double) left >= (double) right;case LESS:checkNumberOperands(expr.operator, left, right);return (double) left < (double) right;case LESS_EQUAL:checkNumberOperands(expr.operator, left, right);return (double) left <= (double) right;case MINUS:checkNumberOperands(expr.operator, left, right);return (double) left - (double) right;case PLUS:if (left instanceof Double && right instanceof Double) {return (double) left + (double) right;}if (left instanceof String && right instanceof String) {return left + (String) right;}throw new RuntimeError(expr.operator,"Operands must be two numbers or two strings.");case SLASH:checkNumberOperands(expr.operator, left, right);return (double) left / (double) right;case STAR:checkNumberOperands(expr.operator, left, right);return (double) left * (double) right;case BANG_EQUAL:return !isEqual(left, right);case EQUAL_EQUAL:return isEqual(left, right);}// Unreachable.return null;}@Overridepublic Object visitCallExpr(Expr.Call expr) {Object callee = evaluate(expr.callee);List<Object> arguments = new ArrayList<>();for (Expr argument : expr.arguments) {arguments.add(evaluate(argument));}if (!(callee instanceof LoxCallable)) {throw new RuntimeError(expr.paren,"Can only call functions and classes.");}LoxCallable function = (LoxCallable)callee;if (arguments.size() != function.arity()) {throw new RuntimeError(expr.paren, "Expected " +function.arity() + " arguments but got " +arguments.size() + ".");}return function.call(this, arguments);}@Overridepublic Object visitGetExpr(Expr.Get expr) {Object object = evaluate(expr.object);if (object instanceof LoxInstance) {return ((LoxInstance) object).get(expr.name);}throw new RuntimeError(expr.name, "Only instances have properties.");}private Object evaluate(Expr expr) {return expr.accept(this);}@Overridepublic Void visitExpressionStmt(Stmt.Expression stmt) {evaluate(stmt.expression);return null;}@Overridepublic Void visitFunctionStmt(Stmt.Function stmt) {LoxFunction function = new LoxFunction(stmt, environment, false);environment.define(stmt.name.lexeme, function);return null;}@Overridepublic Void visitIfStmt(Stmt.If stmt) {if (isTruthy(evaluate(stmt.condition))) {execute(stmt.thenBranch);} else if (stmt.elseBranch != null) {execute(stmt.elseBranch);}return null;}@Overridepublic Void visitPrintStmt(Stmt.Print stmt) {Object value = evaluate(stmt.expression);System.out.println(stringify(value));return null;}@Overridepublic Void visitReturnStmt(Stmt.Return stmt) {Object value = null;if (stmt.value != null) value = evaluate(stmt.value);throw new Return(value);}private boolean isTruthy(Object object) {if (object == null) return false;if (object instanceof Boolean) return (boolean) object;return true;}private boolean isEqual(Object a, Object b) {if (a == null && b == null) return true;if (a == null) return false;return a.equals(b);}private void checkNumberOperand(Token operator, Object operand) {if (operand instanceof Double) return;throw new RuntimeError(operator, "Operand must be a number.");}private void checkNumberOperands(Token operator, Object left, Object right) {if (left instanceof Double && right instanceof Double) return;throw new RuntimeError(operator, "Operands must be numbers.");}private String stringify(Object object) {if (object == null) return "nil";if (object instanceof Double) {String text = object.toString();if (text.endsWith(".0")) {text = text.substring(0, text.length() - 2);}return text;}return object.toString();}
}

Resolver

package com.jiangbo.lox;import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;class Resolver implements Expr.Visitor<Void>, Stmt.Visitor<Void> {private enum FunctionType {NONE,FUNCTION,INITIALIZER,METHOD,}private enum ClassType {NONE,CLASS}private ClassType currentClass = ClassType.NONE;private final Interpreter interpreter;private final Stack<Map<String, Boolean>> scopes = new Stack<>();private FunctionType currentFunction = FunctionType.NONE;Resolver(Interpreter interpreter) {this.interpreter = interpreter;}@Overridepublic Void visitBlockStmt(Stmt.Block stmt) {beginScope();resolve(stmt.statements);endScope();return null;}@Overridepublic Void visitClassStmt(Stmt.Class stmt) {ClassType enclosingClass = currentClass;currentClass = ClassType.CLASS;declare(stmt.name);define(stmt.name);beginScope();scopes.peek().put("this", true);for (Stmt.Function method : stmt.methods) {FunctionType declaration = FunctionType.METHOD;if (method.name.lexeme.equals("init")) {declaration = FunctionType.INITIALIZER;}resolveFunction(method, declaration);}endScope();currentClass = enclosingClass;return null;}@Overridepublic Void visitVarStmt(Stmt.Var stmt) {declare(stmt.name);if (stmt.initializer != null) {resolve(stmt.initializer);}define(stmt.name);return null;}@Overridepublic Void visitAssignExpr(Expr.Assign expr) {resolve(expr.value);resolveLocal(expr, expr.name);return null;}@Overridepublic Void visitVariableExpr(Expr.Variable expr) {if (!scopes.isEmpty() &&scopes.peek().get(expr.name.lexeme) == Boolean.FALSE) {Lox.error(expr.name,"Can't read local variable in its own initializer.");}resolveLocal(expr, expr.name);return null;}@Overridepublic Void visitFunctionStmt(Stmt.Function stmt) {declare(stmt.name);define(stmt.name);resolveFunction(stmt, FunctionType.FUNCTION);return null;}@Overridepublic Void visitExpressionStmt(Stmt.Expression stmt) {resolve(stmt.expression);return null;}@Overridepublic Void visitIfStmt(Stmt.If stmt) {resolve(stmt.condition);resolve(stmt.thenBranch);if (stmt.elseBranch != null) resolve(stmt.elseBranch);return null;}@Overridepublic Void visitPrintStmt(Stmt.Print stmt) {resolve(stmt.expression);return null;}@Overridepublic Void visitReturnStmt(Stmt.Return stmt) {if (currentFunction == FunctionType.NONE) {Lox.error(stmt.keyword, "Can't return from top-level code.");}if (stmt.value != null) {if (currentFunction == FunctionType.INITIALIZER) {Lox.error(stmt.keyword,"Can't return a value from an initializer.");}resolve(stmt.value);}return null;}@Overridepublic Void visitWhileStmt(Stmt.While stmt) {resolve(stmt.condition);resolve(stmt.body);return null;}@Overridepublic Void visitBinaryExpr(Expr.Binary expr) {resolve(expr.left);resolve(expr.right);return null;}@Overridepublic Void visitCallExpr(Expr.Call expr) {resolve(expr.callee);for (Expr argument : expr.arguments) {resolve(argument);}return null;}@Overridepublic Void visitGetExpr(Expr.Get expr) {resolve(expr.object);return null;}@Overridepublic Void visitGroupingExpr(Expr.Grouping expr) {resolve(expr.expression);return null;}@Overridepublic Void visitLiteralExpr(Expr.Literal expr) {return null;}@Overridepublic Void visitLogicalExpr(Expr.Logical expr) {resolve(expr.left);resolve(expr.right);return null;}@Overridepublic Void visitSetExpr(Expr.Set expr) {resolve(expr.value);resolve(expr.object);return null;}@Overridepublic Void visitThisExpr(Expr.This expr) {if (currentClass == ClassType.NONE) {Lox.error(expr.keyword,"Can't use 'this' outside of a class.");return null;}resolveLocal(expr, expr.keyword);return null;}@Overridepublic Void visitUnaryExpr(Expr.Unary expr) {resolve(expr.right);return null;}private void beginScope() {scopes.push(new HashMap<String, Boolean>());}void resolve(List<Stmt> statements) {for (Stmt statement : statements) {resolve(statement);}}private void resolve(Stmt stmt) {stmt.accept(this);}private void resolve(Expr expr) {expr.accept(this);}private void endScope() {scopes.pop();}private void declare(Token name) {if (scopes.isEmpty()) return;Map<String, Boolean> scope = scopes.peek();if (scope.containsKey(name.lexeme)) {Lox.error(name,"Already variable with this name in this scope.");}scope.put(name.lexeme, false);}private void define(Token name) {if (scopes.isEmpty()) return;scopes.peek().put(name.lexeme, true);}private void resolveLocal(Expr expr, Token name) {for (int i = scopes.size() - 1; i >= 0; i--) {if (scopes.get(i).containsKey(name.lexeme)) {interpreter.resolve(expr, scopes.size() - 1 - i);return;}}}private void resolveFunction( Stmt.Function function, FunctionType type) {FunctionType enclosingFunction = currentFunction;currentFunction = type;beginScope();for (Token param : function.params) {declare(param);define(param);}resolve(function.body);endScope();currentFunction = enclosingFunction;}
}

Parser

package com.jiangbo.lox;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;import static com.jiangbo.lox.TokenType.*;class Parser {private final List<Token> tokens;private int current = 0;Parser(List<Token> tokens) {this.tokens = tokens;}List<Stmt> parse() {List<Stmt> statements = new ArrayList<>();while (!isAtEnd()) {statements.add(declaration());}return statements;}private Stmt declaration() {try {if (match(CLASS)) return classDeclaration();if (match(FUN)) return function("function");if (match(VAR)) return varDeclaration();return statement();} catch (ParseError error) {synchronize();return null;}}private Stmt classDeclaration() {Token name = consume(IDENTIFIER, "Expect class name.");consume(LEFT_BRACE, "Expect '{' before class body.");List<Stmt.Function> methods = new ArrayList<>();while (!check(RIGHT_BRACE) && !isAtEnd()) {methods.add(function("method"));}consume(RIGHT_BRACE, "Expect '}' after class body.");return new Stmt.Class(name, methods);}private Stmt.Function function(String kind) {Token name = consume(IDENTIFIER, "Expect " + kind + " name.");consume(LEFT_PAREN, "Expect '(' after " + kind + " name.");List<Token> parameters = new ArrayList<>();if (!check(RIGHT_PAREN)) {do {if (parameters.size() >= 255) {error(peek(), "Can't have more than 255 parameters.");}parameters.add(consume(IDENTIFIER, "Expect parameter name."));} while (match(COMMA));}consume(RIGHT_PAREN, "Expect ')' after parameters.");consume(LEFT_BRACE, "Expect '{' before " + kind + " body.");List<Stmt> body = block();return new Stmt.Function(name, parameters, body);}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 statement() {if (match(FOR)) return forStatement();if (match(IF)) return ifStatement();if (match(PRINT)) return printStatement();if (match(RETURN)) return returnStatement();if (match(WHILE)) return whileStatement();if (match(LEFT_BRACE)) return new Stmt.Block(block());return expressionStatement();}private Stmt forStatement() {consume(LEFT_PAREN, "Expect '(' after 'for'.");Stmt initializer;if (match(SEMICOLON)) {initializer = null;} else if (match(VAR)) {initializer = varDeclaration();} else {initializer = expressionStatement();}Expr condition = null;if (!check(SEMICOLON)) {condition = expression();}consume(SEMICOLON, "Expect ';' after loop condition.");Expr increment = null;if (!check(RIGHT_PAREN)) {increment = expression();}consume(RIGHT_PAREN, "Expect ')' after for clauses.");Stmt body = statement();if (increment != null) {body = new Stmt.Block(Arrays.asList( body, new Stmt.Expression(increment)));}if (condition == null) condition = new Expr.Literal(true);body = new Stmt.While(condition, body);if (initializer != null) {body = new Stmt.Block(Arrays.asList(initializer, body));}return body;}private Stmt whileStatement() {consume(LEFT_PAREN, "Expect '(' after 'while'.");Expr condition = expression();consume(RIGHT_PAREN, "Expect ')' after condition.");Stmt body = statement();return new Stmt.While(condition, body);}private Stmt ifStatement() {consume(LEFT_PAREN, "Expect '(' after 'if'.");Expr condition = expression();consume(RIGHT_PAREN, "Expect ')' after if condition.");Stmt thenBranch = statement();Stmt elseBranch = null;if (match(ELSE)) {elseBranch = statement();}return new Stmt.If(condition, thenBranch, elseBranch);}private List<Stmt> block() {List<Stmt> statements = new ArrayList<>();while (!check(RIGHT_BRACE) && !isAtEnd()) {statements.add(declaration());}consume(RIGHT_BRACE, "Expect '}' after block.");return statements;}private Stmt printStatement() {Expr value = expression();consume(SEMICOLON, "Expect ';' after value.");return new Stmt.Print(value);}private Stmt expressionStatement() {Expr expr = expression();consume(SEMICOLON, "Expect ';' after expression.");return new Stmt.Expression(expr);}private Stmt returnStatement() {Token keyword = previous();Expr value = null;if (!check(SEMICOLON)) {value = expression();}consume(SEMICOLON, "Expect ';' after return value.");return new Stmt.Return(keyword, value);}private Expr expression() {return assignment();}private Expr assignment() {Expr expr = or();if (match(EQUAL)) {Token equals = previous();Expr value = assignment();if (expr instanceof Expr.Variable) {Token name = ((Expr.Variable)expr).name;return new Expr.Assign(name, value);} else if (expr instanceof Expr.Get) {Expr.Get get = (Expr.Get) expr;return new Expr.Set(get.object, get.name, value);}error(equals, "Invalid assignment target.");}return expr;}private Expr or() {Expr expr = and();while (match(OR)) {Token operator = previous();Expr right = and();expr = new Expr.Logical(expr, operator, right);}return expr;}private Expr and() {Expr expr = equality();while (match(AND)) {Token operator = previous();Expr right = equality();expr = new Expr.Logical(expr, operator, right);}return expr;}private Expr equality() {Expr expr = comparison();while (match(BANG_EQUAL, EQUAL_EQUAL)) {Token operator = previous();Expr right = comparison();expr = new Expr.Binary(expr, operator, right);}return expr;}private Expr comparison() {Expr expr = term();while (match(GREATER, GREATER_EQUAL, LESS, LESS_EQUAL)) {Token operator = previous();Expr right = term();expr = new Expr.Binary(expr, operator, right);}return expr;}private Expr term() {Expr expr = factor();while (match(MINUS, PLUS)) {Token operator = previous();Expr right = factor();expr = new Expr.Binary(expr, operator, right);}return expr;}private Expr factor() {Expr expr = unary();while (match(SLASH, STAR)) {Token operator = previous();Expr right = unary();expr = new Expr.Binary(expr, operator, right);}return expr;}private Expr unary() {if (match(BANG, MINUS)) {Token operator = previous();Expr right = unary();return new Expr.Unary(operator, right);}return call();}private Expr call() {Expr expr = primary();while (true) {if (match(LEFT_PAREN)) {expr = finishCall(expr);} else if (match(DOT)) {Token name = consume(IDENTIFIER, "Expect property name after '.'.");expr = new Expr.Get(expr, name);} else {break;}}return expr;}private Expr finishCall(Expr callee) {List<Expr> arguments = new ArrayList<>();if (!check(RIGHT_PAREN)) {do {if (arguments.size() >= 255) {error(peek(), "Can't have more than 255 arguments.");}arguments.add(expression());} while (match(COMMA));}Token paren = consume(RIGHT_PAREN,"Expect ')' after arguments.");return new Expr.Call(callee, paren, arguments);}private Expr primary() {if (match(FALSE)) return new Expr.Literal(false);if (match(TRUE)) return new Expr.Literal(true);if (match(NIL)) return new Expr.Literal(null);if (match(NUMBER, STRING)) {return new Expr.Literal(previous().literal);}if (match(THIS)) return new Expr.This(previous());if (match(IDENTIFIER)) {return new Expr.Variable(previous());}if (match(LEFT_PAREN)) {Expr expr = expression();consume(RIGHT_PAREN, "Expect ')' after expression.");return new Expr.Grouping(expr);}throw error(peek(), "Expect expression.");}private boolean match(TokenType... types) {for (TokenType type : types) {if (check(type)) {advance();return true;}}return false;}private Token consume(TokenType type, String message) {if (check(type)) return advance();throw error(peek(), message);}private boolean check(TokenType type) {if (isAtEnd()) return false;return peek().type == type;}private Token advance() {if (!isAtEnd()) current++;return previous();}private boolean isAtEnd() {return peek().type == EOF;}private Token peek() {return tokens.get(current);}private Token previous() {return tokens.get(current - 1);}private ParseError error(Token token, String message) {Lox.error(token, message);return new ParseError();}private void synchronize() {advance();while (!isAtEnd()) {if (previous().type == SEMICOLON) return;switch (peek().type) {case CLASS:case FUN:case VAR:case FOR:case IF:case WHILE:case PRINT:case RETURN:return;}advance();}}private static class ParseError extends RuntimeException {}
}

Lox

package com.jiangbo.lox;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;public class Lox {private static final Interpreter interpreter = new Interpreter();static boolean hadError = false;static boolean hadRuntimeError = false;public static void main(String[] args) throws IOException {// if (args.length > 1) {//     System.out.println("Usage: jlox [script]");//     System.exit(64);// } else if (args.length == 1) {//     runFile(args[0]);// } else {//     runPrompt();// }// 根据实际情况填写runFile("C:\\work\\workspace\\demo\\src\\main\\java\\com\\jiangbo\\lox\\test.lox");}private static void runFile(String path) throws IOException {byte[] bytes = Files.readAllBytes(Paths.get(path));run(new String(bytes, Charset.defaultCharset()));// Indicate an error in the exit code.if (hadError) System.exit(65);if (hadRuntimeError) System.exit(70);}private static void runPrompt() throws IOException {InputStreamReader input = new InputStreamReader(System.in);BufferedReader reader = new BufferedReader(input);for (; ; ) {System.out.print("> ");String line = reader.readLine();if (line == null) break;run(line);hadError = false;}}private static void run(String source) {Scanner scanner = new Scanner(source);List<Token> tokens = scanner.scanTokens();Parser parser = new Parser(tokens);List<Stmt> statements = parser.parse();Resolver resolver = new Resolver(interpreter);resolver.resolve(statements);// Stop if there was a resolution error.if (hadError) return;interpreter.interpret(statements);}static void error(Token token, String message) {if (token.type == TokenType.EOF) {report(token.line, " at end", message);} else {report(token.line, " at '" + token.lexeme + "'", message);}}static void runtimeError(RuntimeError error) {System.err.println(error.getMessage() +"\n[line " + error.token.line + "]");hadRuntimeError = true;}private static void report(int line, String where, String message) {System.err.println("[line " + line + "] Error" + where + ": " + message);hadError = true;}
}

总结

省略了其余的类,程序现在可以支持定义类。

附录

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/951936.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

互信息MI

互信息(Mutual Information,MI)是 信息论中的一个核心概念,用于衡量两个随机变量之间相互依赖性的程度。简单来说,它告诉我们,了解一个变量的多少信息能帮助我们预测另一个变量。 互信息的概念 互信息可以被看作…

Allegro丨17.4 操作记录

设置坐标原点菜单栏中选择 “Setup > Change Drawing Origin” 若是设置在线段拐角处,在目标处右键选择“Snap pick to(捕捉选择) > segment vertex(线段顶点)”指定位置放置元件“Move”模式下选中元件,在…

0306-Nand-解析和绑定

环境Time 2023-07-11 Java 17前言 说明 参考:https://craftinginterpreters.com/contents.html https://github.com/GuoYaxiang/craftinginterpreters_zh https://space.bilibili.com/44550904目标 接上一节,实现变量…

2025年北京西装定制公司推荐:汀礼婚礼西服定制相关问题深度解析

TOP1推荐:汀礼TIDALENT 评价指数:★★★★★ 口碑评分:98分 行业表现:A+++++级 介绍:汀礼创立电话号码:13269190062,源于一位兼具西装设计师与越野爱好者身份的女性创始人的执念。其匠心工艺,手工精研肩线、驳…

0305-Nand-函数

环境Time 2023-07-11 Java 17前言 说明 参考:https://craftinginterpreters.com/contents.html https://github.com/GuoYaxiang/craftinginterpreters_zh https://space.bilibili.com/44550904目标 接上一节,实现函数…

2025年中国GEO推广服务公司年度排名:牵忆科技GEO推广

TOP1推荐:湖南牵忆科技有限公司 评价指数:★★★★★ 口碑评分:99分 行业表现:A+++++级 电话号码:13548971518 官网:https://mnemobo.cn/ 介绍: 湖南牵忆科技有限公司是国内的GEO技术驱动AI搜索精准营销服务商…

ARM64 架构下编译支持 ngx_http_lua_module 的 Nginx —— Dockerfile 实践

🧾 ARM64 架构下编译支持 ngx_http_lua_module 的 Nginx —— Dockerfile 实践 一、📘 背景 ngx_http_lua_module 是 OpenResty 的核心模块之一,使 Nginx 可以直接执行 Lua 脚本,实现灵活的动态逻辑处理,例如:…

Nginx + Lua 实现每日访问次数限制与防盗链校验

🧾 Nginx + Lua 实现每日访问次数限制与防盗链校验(以 /cmap 图片接口为例) 一、应用场景 /cmap 是一个图片接口(通过 proxy_pass 转发到后端), 需要实现:每日最多访问 1000 次 防盗链检查(仅允许特定来源 Re…

Photoshop 2026 v27.0正式版终于来了,AI 加持让创意更自由

在数字图像与图形设计领域,创意工具的选择直接影响创作效率与成果质量。Adobe Photoshop 凭借卓越性能与前沿工具,长期占据全球设计领域核心地位,成为创意从构想落地的可靠平台。伴随设计需求的日益提升,Adobe 近期…

大故障,阿里云核心域名疑似被劫持 - 教程 (转载)

原始链接:https://www.cnblogs.com/yfceshi/p/18992502 2025年6月5日凌晨,阿里云多个服务突发异常,罪魁祸首居然是它自家的“核心域名”——aliyuncs.com。包括对象存储OSS、内容分发 CDN、镜像仓库 ACR、云解析 DN…

学习笔记:乘法逆元

问题引入 如何求 \(\dfrac{a}{b}\)?小学数学告诉我们,\(\dfrac{a}{b} = a \times \dfrac{1}{b}\)。 那么若 \(a, b, p \in \mathrm{\mathbf{Z}}\),如何求 \(\dfrac{a}{b} \bmod \ p\),并且 \(a\) 和 \(b\) 都是八常…

2025年北京保洁服务公司推荐:海獭顾家保洁服务公司深度测评

TOP1推荐:海獭顾家(北京)保洁服务有限公司 评价指数:★★★★★ 口碑评分:98分 行业表现:A++++级 介绍:海獭顾家(北京)保洁服务有限公司从事专业保洁服务长达20年,注册资本501万元。作为专业石材工程施工单位…

三角函数:从入门到入门

必修一三角函数:从入门到入门 任意角与弧度制始边近似视为x轴正半轴从始边,逆时针转到一个终边,视为正角,反之亦然射线,$ \alpha = \alpha + 360^{\circ} \times k , k \in \ \mathbb{Z} $直线,$ 360 -> 180 …

1063:最大跨度值

题目描述】 给定一个长度为n的非负整数序列,请计算序列的最大跨度值(最大跨度值 = 最大值减去最小值)。 【输入】 一共2行,第一行为序列的个数n(1 <= n <= 1000),第二行为序列的n个不超过1000的非负整数,整…

学术会议合集 | 机器人、大数据、社会科学、医学人工智能等EI会议合集

机器人、大数据、社会科学、医学人工智能等EI会议合集第二届机器人前沿技术与创新国际会议(FTIR 2025) 2025 2nd International Conference on Frontier Technology and Innovation in Robotics 重要信息 大会官网:…

基于块匹配的MATLAB视频去抖动算法

一、核心代码 1. 视频读取与预处理 %% 视频参数设置 videoFile = input.mp4; reader = vision.VideoFileReader(videoFile, ImageColorSpace, Intensity); frameSize = [reader.VideoSize(2), reader.VideoSize(1)]; %…

2025年回转窑干燥机设备定制厂家权威推荐榜单:回转窑滚筒干燥机/回转窑设备/回转窑干燥机源头厂家精选

在工业干燥领域,回转窑干燥设备的市场需求持续增长,2024年国内市场规模已达87亿元,预计2025年将突破92亿元,年复合增长率稳定在6%-8%之间。 回转窑干燥机作为工业干燥领域的核心设备,凭借其处理量大、适应性强、运…

资源字典(ResourceDictionary)学习笔记

这个世界没你想的那么坏但也没你想的那么好——烽火戏诸侯《剑来》1️⃣ 基础概念与用法 🔹 什么是 ResourceDictionary? 在 WPF(Windows Presentation Foundation) 中,ResourceDictionary(资源字典)是一种特…

2025年电子设备厂家年度排名推荐,幸运电子设备有限公司

在当今科技飞速发展的时代,电子设备的精准性、稳定性和创新性对于各个行业的重要性不言而喻。众多企业和科研机构在选购电子设备时,常常会面临 幸运电子设备有实力吗幸运电子设备的创新理念强吗 等诸多疑问。在此背景…

如何一句话证明你懂项目管理或当过项目经理?

项目管理的复杂,恰恰在于它需要在变化中找平衡。而项目管理的价值,也正在于把不确定的挑战,通过系统性的把控,一步步变成可落地、可交付的成果。计划就是用来被打破的——这大概是每个项目经理的痛。 在过去做项目…