400 lines
14 KiB
C++
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 {};
|
|
} |