Skip to content

Commit

Permalink
Merge pull request #6 from dantheking-crypto/develop
Browse files Browse the repository at this point in the history
Added type checking
  • Loading branch information
danielzsh authored Oct 7, 2020
2 parents a8c1b13 + 524e60b commit a3020b3
Show file tree
Hide file tree
Showing 6 changed files with 303 additions and 45 deletions.
107 changes: 107 additions & 0 deletions Interpreter/Symbols.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
#pragma once
#include <string>
#include <iostream>
#include <map>
#include "../Parser/astnodes.h"
class Symbol
{
private:
public:
Symbol(std::string n = "", Symbol* t = NULL) {
name = n;
type = t;
}
std::string name;
Symbol* type;
std::string print() {
if (type == NULL) return name;
return "<" + name + ":" + type->print() + ">";
}
};
class BuiltinTypeSymbol : public Symbol {
public:
BuiltinTypeSymbol(std::string n) : Symbol(n) {

}
};
class VarSymbol : public Symbol
{
public:
VarSymbol(std::string n, BuiltinTypeSymbol* t) : Symbol(n, t) {

}

private:

};
class SymbolTable {
public:
std::map<std::string, Symbol*> symbols;
SymbolTable() {
define(new BuiltinTypeSymbol("int"));
define(new BuiltinTypeSymbol("real"));
}
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 {
return new Symbol();
}
}
};
class SymbolTableBuilder {
public:
SymbolTable symtab;
void visit(AstNode * node) {
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_Block(Block block) {
for (VarDecl decl : block.declarations) {
visit_VarDecl(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 = symtab.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 = symtab.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*>(symtab.lookup(type_name));
std::string var_name = varDecl.var.value;
VarSymbol* var = new VarSymbol(var_name, type_symbol);
symtab.define(var);
}
};
194 changes: 159 additions & 35 deletions Interpreter/interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,72 +2,196 @@
#include "../Parser/parser.h"
#include <map>
#include <string>
#include <cmath>
#include "Symbols.h"
#include <typeinfo>
class Interpreter
{
private:
Parser parser;
SymbolTable symTab;
public:
std::map<std::string, double> GLOBAL_SCOPE;
union val
{
int i;
double d;
};
std::map<std::string,val> GLOBAL_SCOPE;
Interpreter(std::string input) : parser(input) {

}
~Interpreter() {}
void visit(AstNode* node) {
if (node->print() == "Block") visit_Block(*static_cast<Block*>(node));
else if (node->print() == "Assign") visit_Assign(*static_cast<class Assign*>(node));
else if (node->print() == "NoOp") visit_NoOp();
template<class T>
T visit(AstNode* node) {
if (typeid(T) == typeid(void)) {
if (node->print() == "Block") visit_Block(*static_cast<Block*>(node));
else if (node->print() == "Assign") visit_Assign(*static_cast<class Assign*>(node));
else if (node->print() == "NoOp") visit_NoOp();
else {
std::string error = "Error: void operation not recognized";
throw error;
}
}
else if (typeid(T) == typeid(int) || typeid(T) == typeid(double)) {
if (node->print() == "BinOp") {
BinOp binOp = *static_cast<BinOp*>(node);
return visit_BinOp<T>(binOp);
}
else if (node->print() == "Num") {
return visit_Num<T>(*static_cast<Num*>(node));
}
else if (node->print() == "UnOp") {
return visit_UnOp<T>(*static_cast<UnOp*>(node));
}
else if (node->print() == "Var") {
return visit_Var<T>(*static_cast<Var*>(node));
}
else {
std::string error = "Error: not recognized";
throw error;
}
}
else {
std::string error = "Error: not recognized";
std::string error("Type not recognized");
throw error;
}
}
double visit_Real(AstNode* node) {
if (node->print() == "Num") return visit_Num(*static_cast<Num*>(node));
else if (node->print() == "UnOp") return visit_UnOp(*static_cast<UnOp*>(node));
else if (node->print() == "Var") return visit_Var(*static_cast<Var*>(node));
else if (node->print() == "BinOp") return visit_BinOp(*static_cast<BinOp*>(node));
template <class T>
T visit_BinOp(BinOp binOp) {
if (typeid(T) == typeid(int))
{
if (binOp.op.type == Div) {
std::string error = "Error: Float division and int are incompatible types";
throw error;
}
else if (binOp.op.type == Plus) {
return (T)(visit<int>(binOp.left) + visit<int>(binOp.right));
}
else if (binOp.op.type == Minus) {
return (T)(visit<int>(binOp.left) - visit<int>(binOp.right));
}
else if (binOp.op.type == Times) return (T)(visit<int>(binOp.left) * visit<int>(binOp.right));
else if (binOp.op.type == IntDiv) return (T)(visit<int>(binOp.left) / visit<int>(binOp.right));
else {
std::string error("Error: BinOp operation not recognized.");
throw error;
}
}
else if (typeid(T) == typeid(double)) {
if (binOp.op.type == Plus) {
return (T)(visit<double>(binOp.left) + visit<double>(binOp.right));
}
else if (binOp.op.type == Minus) {
return (T)(visit<int>(binOp.left) - visit<int>(binOp.right));
}
else if (binOp.op.type == Times) return (T)(visit<double>(binOp.left) * visit<double>(binOp.right));
else if (binOp.op.type == IntDiv) return (T)(visit<int>(binOp.left) / visit<int>(binOp.right));
else if (binOp.op.type == Div) {
return (T)(visit<double>(binOp.left) / visit<double>(binOp.right));
}
else {
std::string error("Error: BinOp operation not recognized.");
throw error;
}
}
else {
std::string error = "Error: not recognized";
std::string error("Type not recognized");
throw error;
}
}
double visit_Num(Num num) {
return num.value;
template<class T>
T visit_Num(Num num) {
if (typeid(T) == typeid(void)) {
return (T)(1);
}
if (typeid(T) == typeid(int)) {
if (ceil(num.value) == num.value) return (T)num.value;
else {
std::string error = "Error: Wanted int but got double";
throw error;
}
}
else return (T)num.value;

}
double visit_BinOp(BinOp binOp) {
if (binOp.op.type == Plus) return visit_Real(binOp.left) + visit_Real(binOp.right);
else if (binOp.op.type == Minus) return visit_Real(binOp.left) - visit_Real(binOp.right);
else if (binOp.op.type == Times) return visit_Real(binOp.left) * visit_Real(binOp.right);
else if (binOp.op.type == Div) return (double)(visit_Real(binOp.left) / (double)visit_Real(binOp.right));
else if (binOp.op.type == IntDiv) return (int)(visit_Real(binOp.left) / visit_Real(binOp.right));
else {
std::string error("Error: BinOp operation not recognized.");
template <class T>
T visit_UnOp(UnOp unOp) {
if (typeid(T) == typeid(void)) {
std::string error = "void unOp? srsly";
throw error;
}
}
double visit_UnOp(UnOp unOp) {
TokenType op = unOp.op.type;
if (op == Plus) return visit_Real(unOp.expr);
else return 0 - visit_Real(unOp.expr);
if (typeid(T) == typeid(int)) {
if (op == Plus) return (T)(visit<int>(unOp.expr));
else return (T)(0 - visit<int>(unOp.expr));
}
if (typeid(T) == typeid(double)) {
if (op == Plus) return (T)(visit<double>(unOp.expr));
else return (T)(0 - visit<double>(unOp.expr));
}
else {
std::string error("Type not recognized");
throw error;
}
}
void visit_Block(Block block) {
for (AstNode* child : block.children) {
visit(child);
visit<void>(child);
}
}
void visit_Assign(class Assign assign) {
string var_name = assign.var.value;
GLOBAL_SCOPE[var_name] = visit_Real(assign.right);
}
double visit_Var(Var var) {
if (GLOBAL_SCOPE.find(var.value) != GLOBAL_SCOPE.end()) return GLOBAL_SCOPE[var.value];
std::string var_name = assign.var.value;
std::string type = symTab.lookup(var_name)->type->name;
cout << type << endl;
if (type == "int") {
GLOBAL_SCOPE[var_name].i = visit<int>(assign.right);
return;
}
else if (type == "real") {
GLOBAL_SCOPE[var_name].d = visit<double>(assign.right);
return;
}
else {
std::string error = "Error: variable not found";
std::string error("Var type not supported");
throw error;
}
}
template<class T>
T visit_Var(Var var) {
if (GLOBAL_SCOPE.find(var.value) != GLOBAL_SCOPE.end()) {
if (typeid(T) == typeid(int)) {
std::string type = symTab.lookup(var.value)->type->name;
if (type == "int") return (T)GLOBAL_SCOPE[var.value].i;
else {
std::string error("Wanted integer, got " + type);
throw error;
}
}
else if (typeid(T) == typeid(double)) {
std::string type = symTab.lookup(var.value)->type->name;
if (type == "real") return (T)GLOBAL_SCOPE[var.value].d;
else {
std::string error("Wanted real, got " + type);
throw error;
}
}
else {
std::string error("Var type invalid");
throw error;
}
}
else return (T)0;
}
SymbolTable getSymTab() {
return symTab;
}
void visit_NoOp() {}
void interpret() {
Block block = parser.parseProgram();
SymbolTableBuilder symtabBuilder;
symtabBuilder.visit(&block);
std::cout << "Finished building symtab...\n";
symTab = symtabBuilder.symtab;
visit_Block(block);
}
private:
Parser parser;
};
3 changes: 2 additions & 1 deletion Lexer/Lexer.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ class Lexer {
{"int", INT},
{"real", REAL},
{"vars", VARS},
{"program", PROGRAM}
{"program", PROGRAM},
{"func", FUNCTION}
};
public:
Lexer(string inputPass) {
Expand Down
1 change: 1 addition & 0 deletions Lexer/tokens.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ enum TokenType {
REAL,
VARS,
PROGRAM,
FUNCTION,
// Miscellaneous
Colon,
Comma
Expand Down
Loading

0 comments on commit a3020b3

Please sign in to comment.