Skip to content

Commit

Permalink
Merge branch 'feature/function-calls' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
danielzsh committed Nov 11, 2020
2 parents baa4f4a + 8ba8fec commit 893532e
Show file tree
Hide file tree
Showing 9 changed files with 349 additions and 190 deletions.
39 changes: 39 additions & 0 deletions Interpreter/Stack.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#pragma once
#include <string>
#include <variant>
#include <map>
#include <vector>
enum class ARType {
PROGRAM,
FUNCTION
};
using value = std::variant<int, double, std::string>;
class ActivationRecord {
public:
std::string name;
ARType type;
int nesting_level;
std::map<std::string, value> members;
ActivationRecord(ARType type, int nesting_level, std::string name = "") {
this->name = name;
this->type = type;
this->nesting_level = nesting_level;
this->members = members;
}
value& operator [] (std::string index) {
return members[index];
}
};
class CallStack {
public:
std::vector<ActivationRecord> records;
void push(ActivationRecord& ar) {
records.push_back(ar);
}
void pop() {
records.pop_back();
}
ActivationRecord& peek() {
return records.back();
}
};
153 changes: 153 additions & 0 deletions Interpreter/SymbolTable.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
#pragma once
#include <string>
#include <iostream>
#include <map>
#include "../Parser/astnodes.h"
#include "./Symbols.h"
class ScopedSymbolTable {
private:
std::string scope_name;
public:
int scope_level;
ScopedSymbolTable* enclosingScope = NULL;
std::map<std::string, Symbol*> symbols;
ScopedSymbolTable(std::string name, int level) {
define(new BuiltinTypeSymbol("int"));
define(new BuiltinTypeSymbol("real"));
define(new BuiltinTypeSymbol("string"));
scope_name = name;
scope_level = level;
}
void define(Symbol* symbol) {
// std::// cout << "Define: " << symbol->print() << std::endl;
symbols[symbol->name] = symbol;
}
Symbol* lookup(std::string name) {
// std::// cout << "Lookup: " << name << "\n";
if (symbols.count(name)) {
return symbols[name];
}
else {
if (enclosingScope != NULL) return enclosingScope->lookup(name);
else return new Symbol();
}
}
std::string print() {
std::string rep("");
rep += "SCOPE (SCOPED SYMBOL TABLE)\n==================\n";
rep += "Scope name: " + scope_name + "\n";
rep += "Scope level: " + std::to_string(scope_level) + "\n";
rep += "Contents:\n...................\n";
for (auto pair : symbols) {
rep += pair.first + ": " + pair.second->print() + "\n";
}
rep += "====================\n";
return rep;
}
};
class SymbolTableBuilder {
public:
ScopedSymbolTable symtab;
ScopedSymbolTable& currentScope;
std::map<std::string, std::string> types;
SymbolTableBuilder(std::string name, int level) : symtab("global", 1), currentScope(symtab) {
}
void visit(AstNode* node) {
if (node->print() == "Program") visit_Program(*static_cast<Program*>(node));
else if (node->print() == "FunctionDecl") visit_ProcedureDecl(*static_cast<FunctionDecl*>(node));
else if (node->print() == "FunctionCall") visit_FunctionCall(*static_cast<FunctionCall*>(node));
else if (node->print() == "Block") visit_Block(*static_cast<Block*>(node));
else if (node->print() == "UnOp") visit_UnOp(*static_cast<UnOp*>(node));
else if (node->print() == "Var") visit_Var(*static_cast<Var*>(node));
else if (node->print() == "BinOp") return visit_BinOp(*static_cast<BinOp*>(node));
else if (node->print() == "Assign") visit_Assign(*static_cast<class Assign*>(node));
}
void visit_FunctionCall(FunctionCall& functionCall) {
if (functionCall.params.size() != static_cast<ProcedureSymbol*>(symtab.lookup(functionCall.proc_name))->params.size()) {
std::string error("Function call parameters do not match function parameters.");
throw error;
}
for (AstNode* param : functionCall.params) {
visit(param);
}
ProcedureSymbol procSymbol = *static_cast<ProcedureSymbol*>(symtab.lookup(functionCall.proc_name));
functionCall.procSymbol = procSymbol;
}
void visit_Program(Program program) {
// // cout << "Enter scope: GLOBAL\n";
ScopedSymbolTable globalScope("global", 1);
currentScope = globalScope;
visit_Block(program.block);
// // cout << currentScope.print();
// // cout << "Leave scope: GLOBAL\n";
}
void visit_ProcedureDecl(FunctionDecl proc) {
ProcedureSymbol* proc_symbol = new ProcedureSymbol(proc.name);
currentScope.define(proc_symbol);
// // cout << "Enter scope: " << proc.name << endl;
ScopedSymbolTable proc_scope(proc.name, currentScope.scope_level + 1);
ScopedSymbolTable* enclosing = new ScopedSymbolTable(currentScope);
proc_scope.enclosingScope = enclosing;
currentScope = proc_scope;
for (VarDecl param : proc.params) {
BuiltinTypeSymbol* type = static_cast<BuiltinTypeSymbol*>(currentScope.lookup(param.type.type));
std::string param_name = param.var.value;
Symbol* var = new VarSymbol(param_name, type);
currentScope.define(var);
VarSymbol var_symbol(param_name, type);
proc_symbol->params.push_back(var_symbol);
types[param_name] = param.type.type;
}
visit_Block(proc.block);
// // cout << currentScope.print();
currentScope = *proc_scope.enclosingScope;
proc_symbol->blockAst = *new Block(proc.block);
}
void visit_Block(Block block) {
for (VarDecl decl : block.declarations) {
visit_VarDecl(decl);
}
for (FunctionDecl* decl : block.procedures) {
visit(decl);
}
for (AstNode* node : block.children) {
visit(node);
}
}
void visit_UnOp(UnOp unOp) {
visit(unOp.expr);
}
void visit_BinOp(BinOp binOp) {
visit(binOp.left);
visit(binOp.right);
}
void visit_Assign(class Assign assign) {
std::string var_name = assign.var.value;
Symbol* var_symbol = currentScope.lookup(var_name);
if (var_symbol->name == "") {
std::string error = "Error: variable not defined: " + var_name;
throw error;
}
visit(assign.right);
}
void visit_Var(Var var) {
std::string var_name = var.value;
Symbol* var_symbol = currentScope.lookup(var_name);
if (var_symbol->name == "") {
std::string error = "Error: variable not defined: " + var_name;
throw error;
}
}
void visit_VarDecl(VarDecl varDecl) {
std::string type_name = varDecl.type.type;
BuiltinTypeSymbol* type_symbol = static_cast<BuiltinTypeSymbol*>(currentScope.lookup(type_name));
std::string var_name = varDecl.var.value;
if (currentScope.lookup(var_name)->name != "") {
std::string error("Multiple definition of variable " + var_name);
throw error;
}
VarSymbol* var = new VarSymbol(var_name, type_symbol);
currentScope.define(var);
types[var_name] = type_name;
}
};
142 changes: 0 additions & 142 deletions Interpreter/Symbols.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
#pragma once
#include <string>
#include <iostream>
#include <map>
#include "../Parser/astnodes.h"
class Symbol
{
private:
Expand Down Expand Up @@ -34,142 +31,3 @@ class VarSymbol : public Symbol
private:

};
class ProcedureSymbol : public Symbol {
public:
std::vector<VarSymbol> params;
ProcedureSymbol(std::string name, std::vector<VarSymbol> p) : Symbol(name), params(p) {
}
ProcedureSymbol(std::string name) : Symbol(name) {
}
};
class ScopedSymbolTable {
private:
std::string scope_name;
public:
int scope_level;
ScopedSymbolTable* enclosingScope = NULL;
std::map<std::string, Symbol*> symbols;
ScopedSymbolTable(std::string name, int level) {
define(new BuiltinTypeSymbol("int"));
define(new BuiltinTypeSymbol("real"));
define(new BuiltinTypeSymbol("string"));
scope_name = name;
scope_level = level;
}
void define(Symbol* symbol) {
// std::cout << "Define: " << symbol->print() << std::endl;
symbols[symbol->name] = symbol;
}
Symbol* lookup(std::string name) {
// std::cout << "Lookup: " << name << "\n";
if (symbols.count(name)) {
return symbols[name];
}
else {
if (enclosingScope != NULL) return enclosingScope->lookup(name);
else return new Symbol();
}
}
std::string print() {
std::string rep("");
rep += "SCOPE (SCOPED SYMBOL TABLE)\n==================\n";
rep += "Scope name: " + scope_name + "\n";
rep += "Scope level: " + std::to_string(scope_level) + "\n";
rep += "Contents:\n...................\n";
for (auto pair : symbols) {
rep += pair.first + ": " + pair.second->print() + "\n";
}
rep += "====================\n";
return rep;
}
};
class SymbolTableBuilder {
public:
ScopedSymbolTable symtab;
ScopedSymbolTable& currentScope;
SymbolTableBuilder(std::string name, int level) : symtab("global", 1), currentScope(symtab) {
}
void visit(AstNode * node) {
if (node->print() == "Program") visit_Program(*static_cast<Program*>(node));
else if (node->print() == "ProcedureDecl") visit_ProcedureDecl(*static_cast<ProcedureDecl*>(node));
else if (node->print() == "Block") visit_Block(*static_cast<Block*>(node));
else if (node->print() == "UnOp") visit_UnOp(*static_cast<UnOp*>(node));
else if (node->print() == "Var") visit_Var(*static_cast<Var*>(node));
else if (node->print() == "BinOp") return visit_BinOp(*static_cast<BinOp*>(node));
else if (node->print() == "Assign") visit_Assign(*static_cast<class Assign*>(node));
}
void visit_Program(Program program) {
// cout << "Enter scope: GLOBAL\n";
ScopedSymbolTable globalScope("global", 1);
currentScope = globalScope;
visit_Block(program.block);
// cout << currentScope.print();
// cout << "Leave scope: GLOBAL\n";
}
void visit_ProcedureDecl(ProcedureDecl proc) {
ProcedureSymbol* proc_symbol = new ProcedureSymbol(proc.name);
currentScope.define(proc_symbol);
// cout << "Enter scope: " << proc.name << endl;
ScopedSymbolTable proc_scope(proc.name, currentScope.scope_level + 1);
ScopedSymbolTable* enclosing = new ScopedSymbolTable(currentScope);
proc_scope.enclosingScope = enclosing;
currentScope = proc_scope;
for (VarDecl param : proc.params) {
BuiltinTypeSymbol* type = static_cast<BuiltinTypeSymbol*>(currentScope.lookup(param.type.type));
std::string param_name = param.var.value;
Symbol* var = new VarSymbol(param_name, type);
currentScope.define(var);
VarSymbol var_symbol(param_name, type);
proc_symbol->params.push_back(var_symbol);
}
visit_Block(proc.block);
// cout << currentScope.print();
currentScope = *proc_scope.enclosingScope;
}
void visit_Block(Block block) {
for (VarDecl decl : block.declarations) {
visit_VarDecl(decl);
}
for (ProcedureDecl* decl : block.procedures) {
visit(decl);
}
for (AstNode* node : block.children) {
visit(node);
}
}
void visit_UnOp(UnOp unOp) {
visit(unOp.expr);
}
void visit_BinOp(BinOp binOp) {
visit(binOp.left);
visit(binOp.right);
}
void visit_Assign(class Assign assign) {
std::string var_name = assign.var.value;
Symbol* var_symbol = currentScope.lookup(var_name);
if (var_symbol->name == "") {
std::string error = "Error: variable not defined: " + var_name;
throw error;
}
visit(assign.right);
}
void visit_Var(Var var) {
std::string var_name = var.value;
Symbol* var_symbol = currentScope.lookup(var_name);
if (var_symbol->name == "") {
std::string error = "Error: variable not defined: " + var_name;
throw error;
}
}
void visit_VarDecl(VarDecl varDecl) {
std::string type_name = varDecl.type.type;
BuiltinTypeSymbol* type_symbol = static_cast<BuiltinTypeSymbol*>(currentScope.lookup(type_name));
std::string var_name = varDecl.var.value;
if (currentScope.lookup(var_name)->name != "") {
std::string error("Multiple definition of variable " + var_name);
throw error;
}
VarSymbol* var = new VarSymbol(var_name, type_symbol);
currentScope.define(var);
}
};
Loading

0 comments on commit 893532e

Please sign in to comment.