c-repl/src/interpreter.cpp
2023-12-08 15:29:30 +01:00

400 lines
14 KiB
C++

#include <vector>
#include <string>
#include <iostream>
#include "include/parser.h"
#include "include/interpreter.h"
#include "include/memory.h"
using namespace std;
bool bool_cast(EvalResult value) {
if (holds_alternative<int>(value)) {
return get<int>(value) != 0;
}
else if (holds_alternative<double>(value)) {
return get<double>(value) != 0;
}
else {
throw;
}
}
int int_cast(EvalResult value) {
if (holds_alternative<int>(value)) {
return get<int>(value);
} else if (holds_alternative<double>(value)) {
return int(get<double>(value));
}
else {
throw;
}
}
double double_cast(EvalResult value) {
if (holds_alternative<int>(value)) {
return double(get<int>(value));
}
else if (holds_alternative<double>(value)) {
return get<double>(value);
}
else {
throw;
}
}
EvalResult eval(Node &ast, Memory &memory) {
if (holds_alternative<InnerNode>(ast)) {
InnerNode node = get<InnerNode>(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<double>(e1) || holds_alternative<double>(e2)) {
double d1 = double_cast(e1);
double d2 = double_cast(e2);
return d1 + d2;
}
else {
int i1 = get<int>(e1);
int i2 = get<int>(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<double>(e1) || holds_alternative<double>(e2)) {
double d1 = double_cast(e1);
double d2 = double_cast(e2);
return d1 - d2;
}
else {
int i1 = get<int>(e1);
int i2 = get<int>(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<double>(e1) || holds_alternative<double>(e2)) {
double d1 = double_cast(e1);
double d2 = double_cast(e2);
return d1 * d2;
}
else {
int i1 = get<int>(e1);
int i2 = get<int>(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<double>(e1) || holds_alternative<double>(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<int>(e1);
int i2 = get<int>(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<int>(e1);
int i2 = get<int>(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<int>(e1)) {
return +get<int>(e1);
}
else if (holds_alternative<double>(e1)) {
return +get<double>(e1);
}
} break;
case NodeType::UnaryMinus: {
EvalResult e1 = eval(node.children[0], memory);
if (holds_alternative<int>(e1)) {
return -get<int>(e1);
}
else if (holds_alternative<double>(e1)) {
return -get<double>(e1);
}
} break;
case NodeType::Declaration: {
Token typeTok = get<Token>(node.children[0]);
Token identifierTok = get<Token>(node.children[1]);
Type type = get<Type>(typeTok.data);
string identifier = get<string>(identifierTok.data);
memory.declare(identifier, type);
return {};
} break;
case NodeType::AssignedDeclaration: {
Token typeTok = get<Token>(node.children[0]);
Token identifierTok = get<Token>(node.children[1]);
Type type = get<Type>(typeTok.data);
string identifier = get<string>(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<Token>(node.children[0]);
string identifier = get<string>(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<Token>(node.children[0]);
string identifier = get<string>(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<int>(var.value) + 1);
return var.value;
}
else {
return var.value;
}
}
case NodeType::RIncr: {
Token identifierTok = get<Token>(node.children[0]);
string identifier = get<string>(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<int>(var.value);
memory.update(identifier, oldVal + 1);
return oldVal;
}
else {
return var.value;
}
}
case NodeType::LDecr: {
Token identifierTok = get<Token>(node.children[0]);
string identifier = get<string>(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<int>(var.value) - 1);
return var.value;
}
else {
return var.value;
}
}
case NodeType::RDecr: {
Token identifierTok = get<Token>(node.children[0]);
string identifier = get<string>(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<int>(var.value);
memory.update(identifier, oldVal - 1);
return oldVal;
}
else {
return var.value;
}
}
default: {
throw RuntimeError("Not Implemented", node.pos);
}
}
}
else {
Token token = get<Token>(ast);
switch (token.type) {
case TokenType::Litteral: {
if (holds_alternative<int>(token.data)) {
return get<int>(token.data);
} else if (holds_alternative<double>(token.data)) {
return get<double>(token.data);
}
else {
throw;
}
} break;
case TokenType::Identifier: {
string identifier = get<string>(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 {};
}