package InterpreterAlpha; import java.io.FileWriter; import java.io.IOException; import java.nio.file.*; import java.util.HashMap; import java.util.Map; ////////////////////////////////////////////////////////////////// // // // AST visitors // // // ////////////////////////////////////////////////////////////////// class NodeVisitor { String visit(AST node) throws Exception { if (node instanceof Block) return visit_Block((Block) node); else if (node instanceof Program) return visit_Program((Program) node); else if (node instanceof BinOp) return visit_BinOp((BinOp) node); else if (node instanceof Num) return visit_Num((Num) node); else if (node instanceof UnaryOp) return visit_UnaryOp((UnaryOp) node); else if (node instanceof Compound) return visit_Compound((Compound) node); else if (node instanceof NoOp) return visit_NoOp((NoOp) node); else if (node instanceof VarDecl) return visit_VarDecl((VarDecl) node); else if (node instanceof Assign) return visit_Assign((Assign) node); else if (node instanceof Var) return visit_Var((Var) node); else if (node instanceof Type) return visit_Type((Type) node); else if (node instanceof ForStatement) return visit_for((ForStatement) node); else throw new Exception("No visit function for the type of node!"); } String visit_Type(Type node) throws Exception { return ""; } String visit_for(ForStatement node) throws Exception { return ""; } String visit_Block(Block node) throws Exception { return ""; } String visit_Program(Program node) throws Exception { return ""; } String visit_BinOp(BinOp node) throws Exception { return ""; } String visit_Num(Num node) throws Exception { return ""; } String visit_UnaryOp(UnaryOp node) throws Exception { return ""; } String visit_Compound(Compound node) throws Exception { return ""; } String visit_NoOp(NoOp node) throws Exception { return ""; } String visit_VarDecl(VarDecl node) throws Exception { return ""; } String visit_Assign(Assign node) throws Exception { return ""; } String visit_Var(Var node) throws Exception { return ""; } } /////////////////////////////////////////////////////////////////////////////// // // // SYMBOL and SYMBOL TABLE // // // /////////////////////////////////////////////////////////////////////////////// class Symbol { String name; TokenType type; // INTEGER | REAL static public FileWriter resultFile; static { try { FileWriter deletedFile = new FileWriter("result.txt", false); deletedFile.write(""); deletedFile.close(); resultFile = new FileWriter("result.txt", true); } catch (IOException e) { System.out.println("File doesn't exist!"); } } // built-in type Symbol(String name) { this.name = name; if (name.equals("INTEGER")) this.type = TokenType.INTEGER; else this.type = TokenType.REAL; } // variable Symbol(String name, TokenType type) { this.name = name; this.type = type; } void printSym() throws Exception { } } class VarSymbol extends Symbol { VarSymbol(String name, TokenType type) { super(name, type); } @Override void printSym() throws Exception { Symbol.resultFile.append("<" + this.name + " : " + this.type + ">"); } } class BuiltinTypeSymbol extends Symbol { BuiltinTypeSymbol(String name) { super(name); } @Override void printSym() throws Exception { Symbol.resultFile.append(this.name); } } // map of (symbol_name, symbol) class SymbolTable { Map _symbols; SymbolTable() { this._symbols = new HashMap<>(); this.initBuiltins(); } private void initBuiltins() { this.define(new BuiltinTypeSymbol("INTEGER")); this.define(new BuiltinTypeSymbol("REAL")); } void define(Symbol symbol) { this._symbols.put(symbol.name, symbol); } // return an instance of Symbol class or a null objects Symbol lookup(String name) { return this._symbols.get(name); } } class SymbolTableBuilder extends NodeVisitor { SymbolTable symtab; SymbolTableBuilder() { this.symtab = new SymbolTable(); } void printTable() throws Exception { for (String name : symtab._symbols.keySet()) { symtab._symbols.get(name).printSym(); Symbol.resultFile.append("; "); } Symbol.resultFile.append("\n\n"); } @Override String visit_Block(Block node) throws Exception { for (VarDecl declaration : node.declaration) this.visit(declaration); this.visit(node.compound_statement); return ""; } @Override String visit_Program(Program node) throws Exception { this.visit(node.block); return ""; } @Override String visit_BinOp(BinOp node) throws Exception { this.visit(node.left); this.visit(node.right); return ""; } @Override String visit_UnaryOp(UnaryOp node) throws Exception { this.visit(node.expr); return ""; } @Override String visit_Compound(Compound node) throws Exception { for (AST child : node.children) this.visit(child); return ""; } @Override String visit_VarDecl(VarDecl node) throws Exception { String type_name = node.type_node.value; Symbol type_symbol = this.symtab.lookup(type_name); String var_name = node.var_node.value; VarSymbol var_symbol = new VarSymbol(var_name, type_symbol.type); this.symtab.define(var_symbol); return ""; } @Override String visit_Assign(Assign node) throws Exception { String var_name = node.left.value; Symbol var_symbol = this.symtab.lookup(var_name); if (var_symbol == null) throw new Exception("No var_name declaration for " + var_name); this.visit(node.right); return ""; } @Override String visit_Var(Var node) throws Exception { String var_name = node.value; Symbol var_symbol = this.symtab.lookup(var_name); if (var_symbol == null) throw new Exception("No var_name declaration for " + var_name); return ""; } } ///////////////////////////////////////////////////////////////////////////////////// // // // INTERPRETER // // // ///////////////////////////////////////////////////////////////////////////////////// public class InterpreterAlpha extends NodeVisitor { // store table of (var_name; var_value) Map GLOBAL_SCOPE; AST tree; InterpreterAlpha(AST tree) { this.tree = tree; GLOBAL_SCOPE = new HashMap<>(); } void interpret() throws Exception { AST tree = this.tree; if (tree == null) { throw new Exception("Have no tree to trace!"); } this.visit(tree); printTab(GLOBAL_SCOPE); } void printTab(Map scope) throws Exception { for (String key : scope.keySet()) Symbol.resultFile.append(key + " = " + scope.get(key) + "\n"); } @Override String visit_Program(Program node) throws Exception { return this.visit(node.block); } @Override String visit_for(ForStatement node) throws Exception { String val = GLOBAL_SCOPE.getOrDefault(node.variable.value, null); if (val == null) throw new Exception("No variable found in for_loop!"); else { int end_point = Integer.parseInt(val); for (int tmp = 1; tmp <= end_point; tmp++) { for (AST nod : node.statements) this.visit(nod); } } return ""; } @Override String visit_Block(Block node) throws Exception { for (AST declaration : node.declaration) this.visit(declaration); this.visit(node.compound_statement); return ""; } @Override String visit_BinOp(BinOp node) throws Exception { switch (node.op.type) { case PLUS: return Double.toString(Double.parseDouble(this.visit(node.left)) + Double.parseDouble(this.visit(node.right))); case MINUS: return Double.toString(Double.parseDouble(this.visit(node.left)) - Double.parseDouble(this.visit(node.right))); case MUL: return Double.toString(Double.parseDouble(this.visit(node.left)) * Double.parseDouble(this.visit(node.right))); case FLOAT_DIV: return Double.toString(Double.parseDouble(this.visit(node.left)) / Double.parseDouble(this.visit(node.right))); case INTEGER_DIV: return Integer.toString((int) Double.parseDouble(this.visit(node.left)) / (int) Double.parseDouble(this.visit(node.right))); default: throw new Exception("Incorrect binary operator!"); } } @Override String visit_Num(Num node) throws Exception { return node.value; } @Override String visit_UnaryOp(UnaryOp node) throws Exception { switch (node.op.type) { case PLUS: return Double.toString(+Double.parseDouble(this.visit(((UnaryOp) node).expr))); case MINUS: return Double.toString(-Double.parseDouble(this.visit(((UnaryOp) node).expr))); default: throw new Exception("Incorrect unary operator!"); } } @Override String visit_Compound(Compound node) throws Exception { for (AST child : node.children) this.visit(child); return ""; } @Override String visit_Assign(Assign node) throws Exception { String var_name = node.left.value; GLOBAL_SCOPE.put(var_name, this.visit(node.right)); return ""; } @Override String visit_Var(Var node) throws Exception { String var_name = node.value; String val = this.GLOBAL_SCOPE.get(var_name); if (val != null) return val; else throw new Exception("Variable has no value!"); } public static void main(String[] args) throws Exception { String str = Files.readString(Paths.get("Program.txt")); if (str.equals("")) { throw new Exception("Please input text into Program.txt"); } Lexer lexer = new Lexer(str); Parser parser = new Parser(lexer); AST tree = parser.parse(); SymbolTableBuilder symtab = new SymbolTableBuilder(); symtab.visit(tree); symtab.printTable(); InterpreterAlpha interpreter = new InterpreterAlpha(tree); interpreter.interpret(); Symbol.resultFile.close(); } }