Flex.and.Bison.Examples/examples/example.09/eval.cpp
Source: Flex.and.Bison.Examples/examples/example.09/eval.cpp
/*
GNU flex & bison test program
created by Jared Bruni
http://github.com/lostjared
*/
#include"syntax-tree.hpp"
#include<sstream>
#include<cmath>
using namespace ast;
namespace ast {
int grabParam(std::vector<Symbol> &values, AST *node);
Symbol eval(AST *node) {
Symbol s;
unsigned int eval_node_type = node->node_type;
switch(eval_node_type) {
case '+': {
Symbol s1 = eval(node->left), s2 = eval(node->right);
s.type = s1.type;
if((s1.type == Symbol_Type::CONSTANT_NUMERIC || s1.type == Symbol_Type::NUMERIC) && (s2.type == Symbol_Type::CONSTANT_NUMERIC || s2.type == Symbol_Type::NUMERIC)) {
s.dvalue = s1.dvalue + s2.dvalue;
}
else if((s1.type == Symbol_Type::CONSTANT_STRING || s1.type == Symbol_Type::STRING) && (s2.type == Symbol_Type::CONSTANT_STRING || s2.type == Symbol_Type::STRING)) {
s.value = s1.value+s2.value;
}
else if((s1.type == Symbol_Type::CONSTANT_STRING || s1.type == Symbol_Type::STRING) && (s2.type == Symbol_Type::CONSTANT_NUMERIC || s2.type == Symbol_Type::NUMERIC)){
std::ostringstream stream;
stream << s1.value << s2.dvalue;
s.value = stream.str();
} else if((s1.type == Symbol_Type::NUMERIC || s1.type == Symbol_Type::CONSTANT_NUMERIC) && (s2.type == Symbol_Type::STRING || s2.type == Symbol_Type::CONSTANT_STRING)) {
throw SymbolException("Invalid argument to expression, plus operator for Numeric requires Numeric");
}
return s;
}
break;
case '-': {
Symbol s1 = eval(node->left), s2 = eval(node->right);
s.dvalue = s1.dvalue - s2.dvalue;
s.type = s1.type;
return s;
}
break;
case '*': {
Symbol s1 = eval(node->left), s2 = eval(node->right);
s.dvalue = s1.dvalue * s2.dvalue;
s.type = s1.type;
return s;
}
break;
case '/': {
Symbol s1 = eval(node->left), s2 = eval(node->right);
if(s2.dvalue == 0)
throw ast::DivideByZero();
s.dvalue = s1.dvalue / s2.dvalue;
s.type = s1.type;
return s;
}
break;
case 'M': {
Symbol v = eval(node->left);
v.dvalue = -v.dvalue;
return v;
}
break;
case '$':
return *node->sym;
break;
case 'S':
return *node->sym;
break;
case 'N': {
if(!sym_table.exisits(node->sym->name)) {
sym_table.insertTop(node->sym->name, *node->sym);
}
auto item = sym_table.searchStack(node->sym->name);
item->value.name = item->id;
return item->value;
}
break;
case '=': {
Symbol v = eval(node->left);
if(!sym_table.exisits(node->sym->name)) {
if(v.type == Symbol_Type::CONSTANT_NUMERIC || v.type == Symbol_Type::NUMERIC)
v.type = Symbol_Type::NUMERIC;
else if(v.type == Symbol_Type::CONSTANT_STRING || v.type == Symbol_Type::STRING)
v.type = Symbol_Type::STRING;
v.name = node->sym->name;
sym_table.insertTop(node->sym->name, v);
} else {
auto n = sym_table.searchStack(node->sym->name);
if(v.type == Symbol_Type::CONSTANT_NUMERIC || v.type == Symbol_Type::NUMERIC) {
v.type = Symbol_Type::NUMERIC;
}
else if(v.type == Symbol_Type::CONSTANT_STRING || v.type == Symbol_Type::STRING) {
v.type = Symbol_Type::STRING;
}
v.name = node->sym->name;
n->value = v;
}
return v;
}
break;
case 'f':
if(node != nullptr && node->sym != nullptr) {
#ifdef DEBUG_INFO
std::cout <<"CALL: " << node->sym->name << "\n";
#endif
std::vector<Symbol> symbols;
int counter = grabParam(symbols,node);
#ifdef DEBUG_INFO
std::cout << "Parameters: " << counter << " {\n";
for(int j = 0; j < counter; ++j) {
std::cout << j << ": \t" << symbols[j] << "\n";
}
std::cout << "}\n";
#endif
// call function here
if(sym_table.exisits(node->sym->name)) {
auto func = sym_table.searchStack(node->sym->name);
if(func->value.type == Symbol_Type::FUNCTION)
return func->value.function.func(symbols);
else
std::cerr << "Expected function found: " << func->value.type << "\n";
} else {
std::cerr << "Function: " << node->sym->name << " not found!\n";
}
return Symbol(counter);
}
break;
case 'F': {
if(node->sym != nullptr) {
unsigned int fn_type = node->sym->function.fn;
switch(fn_type) {
case FN_INPUT_STRING: {
std::string in_str;
std::getline(std::cin, in_str);
return Symbol(in_str);
}
break;
case FN_INPUT_NUMBER: {
double val = 0;
std::cin >> val;
return Symbol(val);
}
break;
case FN_SIN:
case FN_COS:
case FN_TAN: {
if(node->left != nullptr && node->left->node_type != 'L') {
Symbol value = eval(node->left);
switch(fn_type) {
case FN_SIN:
return Symbol(sin(value.dvalue));
break;
case FN_COS:
return Symbol(cos(value.dvalue));
break;
case FN_TAN:
return Symbol(tan(value.dvalue));
break;
}
} else {
throw SymbolException("Function requires one numeric argument");
}
}
break;
case FN_EXIT: {
if(node->left != nullptr && node->left->node_type != 'L') {
Symbol s = eval(node->left);
#ifdef DEBUG_INFO
std::cout << "Exiting error code: " << s.dvalue << "\n";
#endif
exit(static_cast<int>(s.dvalue));
} else {
throw SymbolException("exit requires one argment of error code");
}
}
break;
case FN_PRINTLN:
case FN_PRINT: {
std::string end;
if(node != nullptr && node->sym != nullptr)
end = (node->sym->function.fn == FN_PRINTLN) ? "\n" : "";
AST *n = node;
if(n != nullptr && n->left != nullptr && n->left->node_type == 'L') {
n = n->left;
if(n != nullptr) {
while(n != nullptr && n->left != nullptr) {
Symbol sym = eval(n->left);
printSymbol(sym, "");
n = n->right;
}
if(n != nullptr) {
Symbol sym = eval(n);
printSymbol(sym, end);
}
}
return Symbol(0);
} else if(n != nullptr && n->left != nullptr) {
Symbol sym = eval(n->left);
printSymbol(sym, end);
return Symbol(0);
}
}
break;
}
}
break;
}
}
return s;
}
int grabParam(std::vector<Symbol> &values, AST *node) {
int counter = 0;
AST *n = node;
if(n != nullptr && n->left != nullptr && n->left->node_type == 'L') {
n = n->left;
if(n != nullptr) {
while(n != nullptr && n->left != nullptr) {
Symbol sym = eval(n->left);
values.push_back(sym);
counter++;
n = n->right;
}
if(n != nullptr) {
Symbol sym = eval(n);
values.push_back(sym);
counter++;
}
}
return counter;
} else if(n != nullptr && n->left != nullptr) {
Symbol sym = eval(n->left);
values.push_back(sym);
counter++;
return counter;
}
return counter;
}
void printSymbol(Symbol &s, std::string end) {
switch(s.type) {
case Symbol_Type::NUMERIC:
case Symbol_Type::CONSTANT_NUMERIC:
std::cout << s.dvalue << end;
break;
case Symbol_Type::STRING:
case Symbol_Type::CONSTANT_STRING:
std::cout << s.value << end;
break;
case Symbol_Type::EMPTY:
break;
case Symbol_Type::FUNCTION:
break;
}
}
}