cplusplus17.Examples/examples/ScanLex/backend_icode.cpp
Source: cplusplus17.Examples/examples/ScanLex/backend_icode.cpp
#include"backend_icode.hpp"
#include<sstream>
#include<algorithm>
namespace backend {
RuntimeException::RuntimeException(const std::string &s) : text{s} {
}
std::string RuntimeException::error() {
return text;
}
void addOne(std::vector<scan::Variable> ¶m, scan::Variable &result) {
if(param.size()==1) {
result = Variable(param[0].val.fval+1);
}
}
void decOne(std::vector<Variable> ¶m, Variable &result) {
if(param.size() == 1) {
result = Variable(param[0].val.fval-1);
}
}
void printEcho(std::vector<Variable> ¶m, Variable &result) {
for(std::size_t i =0; i < param.size(); ++i) {
switch(param[i].type_info) {
case VAR_DOUBLE:
std::cout << param[i].val.fval;
break;
case VAR_STRING:
std::cout << param[i].value;
break;
default:
break;
}
}
result = Variable(double(param.size()));
std::cout << "\n";
}
void printList(std::vector<Variable> ¶m, Variable &result) {
std::cout << "( ";
for(std::size_t i = 0; i < param.size(); ++i) {
if(param[i].type == VAR_CONST) {
switch(param[i].type_info) {
case VAR_DOUBLE:
std::cout << param[i].val.fval << " ";
break;
case VAR_STRING:
std::cout << param[i].value << " ";
break;
default:
break;
}
} else {
std::cout << "VAR VAR\n";
}
}
std::cout << ")\n";
result = Variable(param.size());
}
void inputValue(std::vector<Variable> ¶m, Variable &result) {
(void)param;
double val;
std::cin >> val;
result = Variable(val);
}
void stringLength(std::vector<Variable> ¶m, Variable &result) {
if(param.size()==1) {
result = Variable(param[0].value.length());
return;
}
result = Variable(0);
}
Inc::Inc(OPERATION_TYPE o, const scan::Variable &v, const scan::Variable &v2) : opc{o}, value1{v}, value2{v2} {
}
BackEnd::BackEnd() {
func_table.add("inc", Function(addOne));
func_table.add("dec", Function(decOne));
func_table.add("echo", Function(printEcho));
func_table.add("list", Function(printList));
func_table.add("strlen", Function(stringLength));
func_table.add("scan", Function(inputValue));
}
void BackEnd::put(const Inc &i) {
instruct.push_back(i);
if(i.opc == O_LABEL) {
labels[i.value1.value] = instruct.size()-1;
} else if(i.opc == O_PROC) {
procs[i.value1.value] = instruct.size()-1;
}
}
void BackEnd::decl(const std::string &var, double d) {
vars.enter(var, d);
}
void BackEnd::decl(const std::string &var, const std::string &value) {
vars.enter(var, value);
}
int BackEnd::lookupLabel(const std::string &name) {
auto it = labels.find(name);
if(it != labels.end())
return it->second;
return -1;
}
int BackEnd::lookupProc(const std::string &name) {
auto it = procs.find(name);
if(it != procs.end())
return it->second;
return -1;
}
void BackEnd::go() {
try {
int ip = 0;
int proc_ = lookupProc("main");
if(proc_ == -1)
throw RuntimeException("Could not find main proc");
ip = proc_;
while(ip < static_cast<int>(instruct.size())) {
OPERATION_TYPE type = instruct[ip].opc;
switch(type) {
case O_LABEL:
case O_PROC:
break;
case O_POP:
if(!stack.empty()) {
stack.pop_back();
}
break;
case O_ASSIGN: {
double v = popVal();
Variable &d = vars.getVar(instruct[ip].value1.name);
d.val.fval = v;
d.type_info = VAR_DOUBLE;
}
break;
case O_SASSIGN: {
Variable var = popVar();
Variable &v = vars.getVar(instruct[ip].value1.name);
v.name = instruct[ip].value1.name;
v.value = var.value;
v.type_info = VAR_STRING;
}
break;
case O_PUSH: {
stack.push_back(instruct[ip].value1);
}
break;
case O_ADD:{
double value2 = popVal();
double value1 = popVal();
stack.push_back(scan::Variable(value1+value2));
}
break;
case O_SUB: {
double value2 = popVal();
double value1 = popVal();
stack.push_back(scan::Variable(value1-value2));
}
break;
case O_MUL: {
double value2 = popVal();
double value1 = popVal();
stack.push_back(scan::Variable(value1*value2));
}
break;
case O_DIV: {
double value2 = popVal();
double value1 = popVal();
if(value2 == 0) {
throw RuntimeException("Runtime Exception: Division by Zero");
}
stack.push_back(scan::Variable(value1/value2));
}
break;
case O_EE: {
Variable value2 = popVar();
Variable value1 = popVar();
if(value1.type_info == VAR_DOUBLE) {
runtimeTypeCheck(value2, VAR_DOUBLE);
stack.push_back(Variable(value1.val.fval == value2.val.fval));
} else {
stack.push_back(Variable(value1.value == value2.value));
}
}
break;
case O_NE: {
Variable value2 = popVar();
Variable value1 = popVar();
if(value1.type_info == VAR_DOUBLE) {
runtimeTypeCheck(value2, VAR_DOUBLE);
stack.push_back(Variable(value1.val.fval != value2.val.fval));
} else {
stack.push_back(Variable(value1.value != value2.value));
}
}
break;
case O_LT: {
Variable value2 = popVar();
Variable value1 = popVar();
runtimeTypeCheck(value1, VAR_DOUBLE);
runtimeTypeCheck(value2, VAR_DOUBLE);
if(value1.type_info == VAR_DOUBLE) {
stack.push_back(Variable(value1.val.fval < value2.val.fval));
} else {
stack.push_back(Variable(""));
//throw RuntimeException
}
}
break;
case O_GT: {
Variable value2 = popVar();
Variable value1 = popVar();
runtimeTypeCheck(value1, VAR_DOUBLE);
runtimeTypeCheck(value2, VAR_DOUBLE);
if(value1.type_info == VAR_DOUBLE) {
stack.push_back(Variable(value1.val.fval > value2.val.fval));
} else {
stack.push_back(Variable(""));
}
}
break;
case O_LTE: {
Variable value2 = popVar();
Variable value1 = popVar();
runtimeTypeCheck(value1, VAR_DOUBLE);
runtimeTypeCheck(value2, VAR_DOUBLE);
if(value1.type_info == VAR_DOUBLE) {
stack.push_back(Variable(value1.val.fval <= value2.val.fval));
} else {
stack.push_back(Variable(""));
}
}
break;
case O_GTE: {
Variable value2 = popVar();
Variable value1 = popVar();
runtimeTypeCheck(value1, VAR_DOUBLE);
runtimeTypeCheck(value2, VAR_DOUBLE);
if(value1.type_info == VAR_DOUBLE) {
stack.push_back(Variable(value1.val.fval >= value2.val.fval));
} else {
stack.push_back(Variable(""));
}
}
break;
// end todo
case O_CALL: {
std::string name = instruct[ip].value1.name;
std::vector<scan::Variable> v;
int n = static_cast<int>(instruct[ip].value2.val.fval);
for(int i = 0; i < n; ++i) {
Variable val = popVar();
if(val.name != "") {
v.push_back(vars.getVar(val.name));
} else
v.push_back(val);
}
scan::Variable result;
if(!func_table.valid(name)) {
std::ostringstream stream;
stream << "Runtime Exception: " << name << " function not found!";
throw RuntimeException(stream.str());
}
std::reverse(v.begin(), v.end());
func_table.func_table[name].call(v, result);
stack.push_back(result);
}
break;
case O_EXIT: {
throw RuntimeSuccess();
}
break;
case O_B: {
int lbl = lookupLabel(instruct[ip].value1.value);
if(lbl == -1) {
std::ostringstream stream;
stream << "Label: " << instruct[ip].value1.value << " not found!.\n";
throw RuntimeException(stream.str());
}
ip = lbl;
continue;
}
break;
case O_BNE: {
int lbl = lookupLabel(instruct[ip].value1.value);
if(lbl == -1) {
std::ostringstream stream;
stream << "Label: " << instruct[ip].value1.value << " not found!.\n";
throw RuntimeException(stream.str());
}
Variable value = popVal();
if(value.val.fval == 0) {
ip = lbl;
continue;
}
}
break;
case O_BE: {
int lbl = lookupLabel(instruct[ip].value1.value);
if(lbl == -1) {
std::ostringstream stream;
stream << "Label: " << instruct[ip].value1.value << " not found!.\n";
throw RuntimeException(stream.str());
}
Variable value = popVal();
if(value.val.fval == 1) {
ip = lbl;
continue;
}
}
break;
default:
break;
}
ip++;
}
} catch(RuntimeException &e) {
std::cerr << e.error() << "\n";
} catch(RuntimeSuccess &s) {
std::cout << "... exited normally.\n";
}
vars.print();
}
void BackEnd::print(std::ostream &out) {
for(std::size_t i = 0; i < instruct.size(); ++i) {
if(instruct[i].opc == O_LABEL) {
out << instruct[i].value1.value << ":" << "\n";
continue;
}
if(instruct[i].value1.type == VAR_EMPTY && instruct[i].value2.type == VAR_EMPTY)
out << op_types[instruct[i].opc] << "\n";
else if(instruct[i].value2.type == VAR_EMPTY)
out << op_types[instruct[i].opc] << " " << instruct[i].value1 << "\n";
else
out << op_types[instruct[i].opc] << " " << instruct[i].value1 << ", " << instruct[i].value2 << "\n";
}
}
double BackEnd::popVal() {
if(!stack.empty()) {
Variable v = stack.back();
stack.pop_back();
runtimeTypeCheck(v, VAR_DOUBLE);
if(v.type == VAR_CONST)
return v.val.fval;
if(v.type == VAR_VAR) {
return vars.getDouble(v.name);
}
} else {
throw RuntimeException("Runtime Exception: Stack underflow");
}
return 0;
}
Variable BackEnd::popVar() {
if(!stack.empty()) {
Variable v = stack.back();
stack.pop_back();
if(v.name != "") {
v.value = vars.getString(v.name);
v.val.fval = vars.getDouble(v.name);
}
return v;
} else {
throw RuntimeException("Runtime Exception: Stack underflow");
}
return Variable();
}
void BackEnd::runtimeTypeCheck(const Variable &v, const VAR_TYPE_INFO &i) {
if(v.type_info != i) {
std::ostringstream stream;
stream << "Type mismatch, expected: " << i << " found " << v.type_info;
throw RuntimeException(stream.str());
}
}
}