#include #include #include #include "include/parser.h" #include "include/interpreter.h" #include "include/memory.h" using namespace std; bool bool_cast(EvalResult value) { if (holds_alternative(value)) { return get(value) != 0; } else if (holds_alternative(value)) { return get(value) != 0; } else { throw; } } int int_cast(EvalResult value) { if (holds_alternative(value)) { return get(value); } else if (holds_alternative(value)) { return int(get(value)); } else { throw; } } double double_cast(EvalResult value) { if (holds_alternative(value)) { return double(get(value)); } else if (holds_alternative(value)) { return get(value); } else { throw; } } EvalResult eval(Node &ast, Memory &memory) { if (holds_alternative(ast)) { InnerNode node = get(ast); switch (node.type) { case NodeType::Prog: eval(node.children[0], memory); return eval(node.children[1], memory); break; case NodeType::Epsilon: return {}; break; case NodeType::If: { int cond = bool_cast(eval(node.children[0], memory)); if (cond) { eval(node.children[1], memory); } return {}; } break; case NodeType::IfElse: { int cond = bool_cast(eval(node.children[0], memory)); if (cond) { eval(node.children[1], memory); } else { eval(node.children[2], memory); } return {}; } break; case NodeType::While: { while (true) { int cond = bool_cast(eval(node.children[0], memory)); if (!cond) break; eval(node.children[1], memory); } return {}; } break; case NodeType::For: { memory.add_scope(ScopeType::For); eval(node.children[0], memory); while (true) { int cond = bool_cast(eval(node.children[1], memory)); if (!cond) break; eval(node.children[3], memory); eval(node.children[2], memory); } memory.remove_scope(); return {}; } break; case NodeType::Bloc: { memory.add_scope(ScopeType::Block); eval(node.children[0], memory); memory.remove_scope(); return {}; } break; case NodeType::Eq: { EvalResult e1 = eval(node.children[0], memory); EvalResult e2 = eval(node.children[1], memory); return e1 == e2; } break; case NodeType::Neq: { EvalResult e1 = eval(node.children[0], memory); EvalResult e2 = eval(node.children[1], memory); return e1 != e2; } break; case NodeType::Lor: { EvalResult e1 = eval(node.children[0], memory); EvalResult e2 = eval(node.children[1], memory); return bool_cast(e1) || bool_cast(e2); } break; case NodeType::Land: { EvalResult e1 = eval(node.children[0], memory); EvalResult e2 = eval(node.children[1], memory); return bool_cast(e1) && bool_cast(e2); } break; case NodeType::Neg: { EvalResult e1 = eval(node.children[0], memory); return !bool_cast(e1); } break; case NodeType::Lt: { EvalResult e1 = eval(node.children[0], memory); EvalResult e2 = eval(node.children[1], memory); return e1 < e2; } break; case NodeType::Gt: { EvalResult e1 = eval(node.children[0], memory); EvalResult e2 = eval(node.children[1], memory); return e1 > e2; } break; case NodeType::Leq: { EvalResult e1 = eval(node.children[0], memory); EvalResult e2 = eval(node.children[1], memory); return e1 <= e2; } break; case NodeType::Geq: { EvalResult e1 = eval(node.children[0], memory); EvalResult e2 = eval(node.children[1], memory); return e1 >= e2; } break; case NodeType::Plus: { EvalResult e1 = eval(node.children[0], memory); EvalResult e2 = eval(node.children[1], memory); if (holds_alternative(e1) || holds_alternative(e2)) { double d1 = double_cast(e1); double d2 = double_cast(e2); return d1 + d2; } else { int i1 = get(e1); int i2 = get(e2); return i1 + i2; } } break; case NodeType::Minus: { EvalResult e1 = eval(node.children[0], memory); EvalResult e2 = eval(node.children[1], memory); if (holds_alternative(e1) || holds_alternative(e2)) { double d1 = double_cast(e1); double d2 = double_cast(e2); return d1 - d2; } else { int i1 = get(e1); int i2 = get(e2); return i1 - i2; } } break; case NodeType::Mult: { EvalResult e1 = eval(node.children[0], memory); EvalResult e2 = eval(node.children[1], memory); if (holds_alternative(e1) || holds_alternative(e2)) { double d1 = double_cast(e1); double d2 = double_cast(e2); return d1 * d2; } else { int i1 = get(e1); int i2 = get(e2); return i1 * i2; } } break; case NodeType::Div: { EvalResult e1 = eval(node.children[0], memory); EvalResult e2 = eval(node.children[1], memory); if (holds_alternative(e1) || holds_alternative(e2)) { double d1 = double_cast(e1); double d2 = double_cast(e2); if (d2 == 0) throw RuntimeError("Division by 0", node.pos); return d1 / d2; } else { int i1 = get(e1); int i2 = get(e2); if (i2 == 0) throw RuntimeError("Division by 0", node.pos); return i1 / i2; } } break; case NodeType::Mod: { EvalResult e1 = eval(node.children[0], memory); EvalResult e2 = eval(node.children[1], memory); int i1 = get(e1); int i2 = get(e2); if (i2 == 0) throw RuntimeError("Modulo by 0", node.pos); return i1 % i2; } break; case NodeType::UnaryPlus: { EvalResult e1 = eval(node.children[0], memory); if (holds_alternative(e1)) { return +get(e1); } else if (holds_alternative(e1)) { return +get(e1); } } break; case NodeType::UnaryMinus: { EvalResult e1 = eval(node.children[0], memory); if (holds_alternative(e1)) { return -get(e1); } else if (holds_alternative(e1)) { return -get(e1); } } break; case NodeType::Declaration: { Token typeTok = get(node.children[0]); Token identifierTok = get(node.children[1]); Type type = get(typeTok.data); string identifier = get(identifierTok.data); memory.declare(identifier, type); return {}; } break; case NodeType::AssignedDeclaration: { Token typeTok = get(node.children[0]); Token identifierTok = get(node.children[1]); Type type = get(typeTok.data); string identifier = get(identifierTok.data); EvalResult value = eval(node.children[2], memory); memory.declare(identifier, type); if (type == Type::Int) { memory.update(identifier, int_cast(value)); } else if (type == Type::Double) { memory.update(identifier, double_cast(value)); } return value; } break; case NodeType::Assignment: { Token identifierTok = get(node.children[0]); string identifier = get(identifierTok.data); EvalResult value = eval(node.children[1], memory); Type type = memory.get(identifier).type; if (type == Type::Int) { memory.update(identifier, int_cast(value)); } else if (type == Type::Double) { memory.update(identifier, double_cast(value)); } return value; } break; case NodeType::LIncr: { Token identifierTok = get(node.children[0]); string identifier = get(identifierTok.data); MemoryVar& var = memory.get(identifier); if (!var.initialized) { throw RuntimeError("Accessing uninitialized identifier \""+identifier+"\"", identifierTok.pos); } else if (var.type == Type::Int) { memory.update(identifier, get(var.value) + 1); return var.value; } else { return var.value; } } case NodeType::RIncr: { Token identifierTok = get(node.children[0]); string identifier = get(identifierTok.data); MemoryVar& var = memory.get(identifier); if (!var.initialized) { throw RuntimeError("Accessing uninitialized identifier \""+identifier+"\"", identifierTok.pos); } else if (var.type == Type::Int) { int oldVal = get(var.value); memory.update(identifier, oldVal + 1); return oldVal; } else { return var.value; } } case NodeType::LDecr: { Token identifierTok = get(node.children[0]); string identifier = get(identifierTok.data); MemoryVar& var = memory.get(identifier); if (!var.initialized) { throw RuntimeError("Accessing uninitialized identifier \""+identifier+"\"", identifierTok.pos); } else if (var.type == Type::Int) { memory.update(identifier, get(var.value) - 1); return var.value; } else { return var.value; } } case NodeType::RDecr: { Token identifierTok = get(node.children[0]); string identifier = get(identifierTok.data); MemoryVar& var = memory.get(identifier); if (!var.initialized) { throw RuntimeError("Accessing uninitialized identifier \""+identifier+"\"", identifierTok.pos); } else if (var.type == Type::Int) { int oldVal = get(var.value); memory.update(identifier, oldVal - 1); return oldVal; } else { return var.value; } } default: { throw RuntimeError("Not Implemented", node.pos); } } } else { Token token = get(ast); switch (token.type) { case TokenType::Litteral: { if (holds_alternative(token.data)) { return get(token.data); } else if (holds_alternative(token.data)) { return get(token.data); } else { throw; } } break; case TokenType::Identifier: { string identifier = get(token.data); MemoryVar& var = memory.get(identifier); if (!var.initialized) throw RuntimeError("Accessing uninitialized identifier \""+identifier+"\"", token.pos); return var.value; } break; default: throw; break; } } return {}; }