practice/java/BasicInterpreter/src/InterpreterAlpha/InterpreterAlpha.java

394 lines
12 KiB
Java

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<String, Symbol> _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<String, String> 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<String, String> 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();
}
}