Yab2Cpp/yabDataStructures.cpp
2022-08-05 15:06:35 -05:00

691 lines
14 KiB
C++

/*
** Yab2Cpp
**
** Transpiler by Samuel D. Crow
**
** Based on Yab
**
*/
#include "yab2cpp.h"
#include <fstream>
#include <list>
#include <sstream>
/* forward declaration and static initializers */
class fn;
unsigned int operands::nextID=0;
unordered_map<string, unsigned int> constOp::strConst;
list<tempVar *>tempVar::intQueue;
list<tempVar *>tempVar::floatQueue;
list<tempVar *>tempVar::stringQueue;
/* methods for operands */
enum TYPES operands::getSimpleVarType(enum TYPES t)
{
switch (t)
{
case T_FLOAT:
case T_FLOATCALL_ARRAY:
case T_FLOATVAR:
return T_FLOATVAR;
case T_INT:
case T_INTCALL_ARRAY:
case T_INTVAR:
return T_INTVAR;
case T_STRING:
case T_STRINGCALL_ARRAY:
case T_STRINGVAR:
return T_STRINGVAR;
default:
break;
}
error(E_UNASSIGNABLE_TYPE);
}
enum TYPES operands::getSimpleVarType()
{
return getSimpleVarType(this->getType());
}
/* operands used by expression parser and variables */
operands::operands(enum TYPES t)
{
this->id = ++nextID;
this->type=t;
}
void operands::generateBox(enum SCOPES s)
{
ostringstream ss;
switch (this->getType())
{
case T_INTVAR:
ss << "int v";
break;
case T_FLOATVAR:
ss << "double v";
break;
case T_STRINGVAR:
ss << "string v";
break;
default:
error(E_TYPE_MISMATCH);
}
ss << this->getID() << ";\n";
switch (s)
{
case S_LOCAL:
case S_PARAMETER:
funcs_h << ss.str();
return;
case S_GLOBAL:
case S_STATIC:
heap_h << ss.str();
return;
default:
break;
}
error(E_INTERNAL);
}
operands *operands::createOp(enum TYPES t)
{
if (TRACE)
{
indent();
logfile << "Creating operand of type "
<< TYPENAMES[t] << endl;
}
return tempVar::getOrCreateVar(t);
}
/* only tempVar type needs disposing */
void operands::dispose()
{}
string operands::boxName()
{
ostringstream s;
string x;
switch (this->getType())
{
case T_STRINGVAR:
case T_INTVAR:
case T_FLOATVAR:
s << 'v' << this->getID();
x=s.str();
s.clear();
return x;
break;
default:
error(E_INTERNAL);
}
}
void operands::assignment(expression *value, bool paramDef)
{
operands *op=value->evaluate();
enum TYPES t=op->getSimpleVarType();
stringstream dest;
string d;
if (paramDef)
{
dest << "sub" << callEnumerator << "->v" << this->getID();
}
else
{
dest << this->boxName();
}
d=dest.str();
dest.clear();
switch (this->getType())
{
case T_FLOATVAR:
if (t==T_INTVAR)
{
output_cpp << d << "="
<< "static_cast<double>("
<< op->boxName() << ");\n";
}
else
{
if (t!=T_FLOATVAR) error(E_TYPE_MISMATCH);
}
output_cpp << d << "="
<< op->boxName() << ";\n";
break;
default:
if (t!=this->getType()) error(E_TYPE_MISMATCH);
output_cpp << d << "="
<< op->boxName() << ";\n";
break;
}
delete value;
}
tempVar::tempVar(enum TYPES t):operands(t)
{
generateBox(S_GLOBAL);
}
tempVar *tempVar::getOrCreateVar(enum TYPES t)
{
if (t!=getSimpleVarType(t))
{
error(E_TYPE_MISMATCH);
}
switch (t)
{
case T_INTVAR:
if (intQueue.empty())
{
return new tempVar(t);
}
else
{
tempVar *x=intQueue.back();
intQueue.pop_back();
return x;
}
break;
case T_FLOATVAR:
if (floatQueue.empty())
{
return new tempVar(t);
}
else
{
tempVar *x=floatQueue.back();
floatQueue.pop_back();
return x;
}
break;
case T_STRINGVAR:
if (stringQueue.empty())
{
return new tempVar(t);
}
else
{
tempVar *x=stringQueue.back();
stringQueue.pop_back();
return x;
}
default:
break;
}
/* unreachable code */
error(E_INTERNAL);
}
void tempVar::dispose()
{
switch(this->getType())
{
case T_STRINGVAR:
stringQueue.emplace_front(this);
return;
case T_FLOATVAR:
floatQueue.emplace_front(this);
return;
case T_INTVAR:
intQueue.emplace_front(this);
return;
default:
break;
}
error(E_INTERNAL);
}
void tempVar::eraseQueues()
{
tempVar *i;
while(!intQueue.empty())
{
i=intQueue.back();
if (DUMP)
{
varNames << "variable " << i->boxName()
<< " is a temporary integer" << endl;
}
intQueue.pop_back();
delete i;
}
cerr << "intger temps purged" << endl;
while(!floatQueue.empty())
{
i=floatQueue.back();
if (DUMP)
{
varNames << "variable " << i->boxName()
<< " is a temporary floating point" << endl;
}
floatQueue.pop_back();
delete i;
}
cerr << "floating point temps purged" << endl;
while(!stringQueue.empty())
{
i=stringQueue.back();
if (DUMP)
{
varNames << "variable " << i->boxName()
<< " is a temporary string" << endl;
}
stringQueue.pop_back();
delete i;
}
cerr << "string temps purged" << endl;
if (DUMP) varNames << endl;
}
void constOp::processConst(unsigned int i)
{
stringstream me;
me << 'k' << i;
box=me.str();
}
void constOp::processConst( const string &s)
{
processConst(getID());
consts_h << box << "=" << s << ";\n";
}
void constOp::assignment(expression *v)
{
error(E_BAD_SYNTAX);
}
/* constructor for constOp */
constOp::constOp(const string &s, enum TYPES t):operands(t)
{
/* make sure string folder is initialized */
unordered_map<string, shared_ptr<operands> >strConst;
switch (t)
{
case T_INT:
consts_h << "const int ";
processConst(s);
break;
case T_FLOAT:
consts_h << "const double ";
processConst(s);
break;
case T_STRING:
{
auto i=constOp::strConst.find(s);
if (i!=constOp::strConst.end())
{
processConst((*i).second);
}
else
{
consts_h << "const string ";
processConst(getID());
consts_h << box << "=\"" << s << "\";\n";
constOp::strConst[s]=getID();
}
}
break;
default:
error(E_TYPE_MISMATCH);
break;
}
}
/* expression parsing routines */
expression::expression(expression *l, enum OPERATORS o, expression *r)
{
this->left=l;
this->right=r;
this->oper=o;
}
expression::expression(operands *x)
{
this->op=x;
this->oper=O_TERM;
}
/* binary vs. unary ops */
bool expression::isBinOp()
{
switch (this->getOp())
{
/* fallthrough for multiselect */
case O_NEGATE:
case O_NOT:
case O_INVERT:
case O_INT_TO_FLOAT:
return false;
default:
return true;
}
/* unreachable code */
error(E_INTERNAL);
}
operands *expression::evaluate()
{
if (this->getOp()==O_TERM) return op;
operands *l;
operands *r;
enum TYPES t;
logger("evaluating left");
l=this->getLeft()->evaluate();
logger("left evaluated");
if (this->isBinOp())
{
logger("evaluating right");
r=this->getRight()->evaluate();
logger("evaluated right");
enum TYPES lt=l->getSimpleVarType();
enum TYPES rt=r->getSimpleVarType();
if (lt==T_INTVAR && rt==T_FLOATVAR)
{
l=(new expression(new expression(l), O_INT_TO_FLOAT))->evaluate();
lt=T_FLOATVAR;
}
if (lt==T_FLOATVAR && rt==T_INTVAR)
{
r=(new expression(new expression(r), O_INT_TO_FLOAT))->evaluate();
rt=T_FLOATVAR;
}
if (lt!=rt)error(E_TYPE_MISMATCH);
t=lt;
}
else
{
t=l->getSimpleVarType();
r=nullptr;
}
switch (this->getOp())
{
case O_STRING_CONCAT:
if (t!=T_STRINGVAR) error(E_BAD_SYNTAX);
this->op=operands::createOp(T_STRINGVAR);
output_cpp << this->op->boxName() << "=" << l->boxName()
<< "+" << r->boxName();
break;
case O_INVERT:
this->op=operands::createOp(t);
output_cpp << this->op->boxName() << "= ~" << l->boxName() << ";\n";
break;
case O_NEGATE:
this->op=operands::createOp(t);
output_cpp << this->op->boxName() << "= -" << l->boxName() << ";\n";
break;
case O_NOT:
if (t!=T_INTVAR) error(E_TYPE_MISMATCH);
this->op=operands::createOp(T_INTVAR);
output_cpp << this->op->boxName() << "= !" << l->boxName() << ";\n";
break;
case O_INT_TO_FLOAT: /*Note: this duplicates functionality of variable assignment */
this->op=operands::createOp(T_FLOATVAR);
output_cpp << this->op->boxName() << "= const_cast<double>("
<< l->boxName() << ");\n";
/* TODO: Check for divide by zero error and modulo zero error */
case O_REMAINDER:
if (t!=T_INTVAR) error(E_TYPE_MISMATCH);
this->op=operands::createOp(T_INTVAR);
output_cpp << this->op->boxName() << "=" << l->boxName()
<< "%" << r->boxName() << ";\n";
break;
case O_DIVIDE:
this->op=operands::createOp(t);
output_cpp << this->op->boxName() << "=" << l->boxName()
<< "/" << r->boxName() << ";\n";
break;
case O_PLUS:
this->op=operands::createOp(t);
output_cpp << this->op->boxName() << "=" << l->boxName()
<< "+" << r->boxName() << ";\n";
break;
case O_MINUS:
this->op=operands::createOp(t);
output_cpp << this->op->boxName() << "=" << l->boxName()
<< "-" << r->boxName() << ";\n";
break;
case O_MULTIPLY:
this->op=operands::createOp(t);
output_cpp << this->op->boxName() << "=" << l->boxName()
<< "*" << r->boxName() << ";\n";
logger("multiply done");
break;
case O_OR:
if (t!=T_INTVAR) error(E_TYPE_MISMATCH);
this->op=operands::createOp(T_INTVAR);
output_cpp << this->op->boxName() << "=" << l->boxName()
<< "|" << r->boxName() << ";\n";
break;
case O_AND:
if (t!=T_INTVAR) error(E_TYPE_MISMATCH);
this->op=operands::createOp(T_INTVAR);
output_cpp << this->op->boxName() << "=" << l->boxName()
<< "&" << r->boxName() << ";\n";
break;
case O_GREATER:
this->op=operands::createOp(T_INTVAR);
output_cpp << this->op->boxName() << "=(" << l->boxName()
<< ">" << r->boxName() << ")?-1:0;\n";
break;
case O_LESS:
this->op=operands::createOp(T_INTVAR);
output_cpp << this->op->boxName() << "=(" << l->boxName()
<< "<" << r->boxName() << ")?-1:0;\n";
break;
case O_GREATER_EQUAL:
this->op=operands::createOp(T_INTVAR);
output_cpp << this->op->boxName() << "=(" << l->boxName()
<< ">=" << r->boxName() << ")?-1:0;\n";
break;
case O_LESS_EQUAL:
this->op=operands::createOp(T_INTVAR);
output_cpp << this->op->boxName() << "=(" << l->boxName()
<< "<=" << r->boxName() << ")?-1:0;\n";
break;
case O_EQUAL:
this->op=operands::createOp(T_INTVAR);
output_cpp << this->op->boxName() << "=(" << l->boxName()
<< "==" << r->boxName() << ")?-1:0;\n";
break;
case O_UNEQUAL:
this->op=operands::createOp(T_INTVAR);
output_cpp << this->op->boxName() << "=(" << l->boxName()
<< "!=" << r->boxName() << ")?-1:0;\n";
break;
default:
error(E_INTERNAL);
}
/* convert expression into single operand */
logger("deleting left");
delete left;
logger("left deleted");
if (isBinOp())
{
logger("deleting right");
delete right;
logger("right deleted");
}
this->oper=O_TERM;
return this->op;
}
/* variable definitions */
variableType::variableType(enum SCOPES s, string &name, enum TYPES t, fn *fnHandle):operands(t)
{
this->myScope=s;
this->handle=fnHandle;
switch (s)
{
case S_LOCAL:
if(handle->getLocalVar(name)) error(E_DUPLICATE_SYMBOL);
locals[name]=unique_ptr<variableType>(this);
break;
case S_GLOBAL:
if(globals.find(name)!=globals.end()) error(E_DUPLICATE_SYMBOL);
globals[name]=unique_ptr<variableType>(this);
break;
case S_STATIC:
if(handle->getLocalVar(name)) error(E_DUPLICATE_SYMBOL);
statics[name]=unique_ptr<variableType>(this);
break;
case S_PARAMETER:
if (handle->getLocalVar(name)) error(E_DUPLICATE_SYMBOL);
/* parameter is added to function list by addParamter */
break;
default:
error(E_INTERNAL);
}
}
string variableType::boxName()
{
ostringstream ss;
switch (myScope)
{
case S_LOCAL:
case S_PARAMETER:
ss << "sub" << this->handle->getID() << "->v" << this->getID();
break;
default:
ss << "v" << this->getID();
}
return ss.str();
}
variableType *variableType::getOrCreateVar(string &name, enum TYPES t)
{
variableType *v;
if (currentFunc!=nullptr)
{
v=currentFunc->getLocalVar(name);
if (v!=nullptr) return v;
}
if (globals.find(name)!=globals.end())return globals[name].get();
if (scopeGlobal)
{
v=new variableType(S_GLOBAL, name, t, nullptr);
}
else
{
v=new variableType(S_LOCAL, name, t, currentFunc);
}
v->generateBox(scopeGlobal?S_GLOBAL:S_LOCAL);
return v;
}
list<operands *> &arrayType::evaluateIndexes(list<expression *>indexes)
{
if (indexes.size()!=this->dimensions.size()) error(E_WRONG_NUMBER_OF_DIMENSIONS);
auto param= new list<operands *>();
operands *o;
auto i=indexes.begin();
auto i2 = dimensions.begin();
while (i!=indexes.end())
{
o=(*i)->evaluate();
param->push_back(o);
output_cpp << "if (" << o->boxName() << ">=" << *i2
<< "){state=OUT_OF_RANGE;break;}\n";
++i;
++i2;
}
return *param;
}
operands *arrayType::getElement(list<expression *>indexes)
{
auto parameters = this->evaluateIndexes(indexes);
tempVar *tv=tempVar::getOrCreateVar(getSimpleVarType(this->getType()));
output_cpp << tv->boxName() << "="
<< 'v' << this->getID();
auto i=parameters.begin();
while (i!=parameters.end())
{
output_cpp << '[' << (*i)->boxName() << ']';
++i;
}
output_cpp << ";\n";
parameters.clear();
return tv;
}
void arrayType::generateBox(enum SCOPES s)
{
ostringstream out;
switch (this->getType())
{
case T_STRINGCALL_ARRAY:
out << "string ";
break;
case T_INTCALL_ARRAY:
out << "int ";
break;
case T_FLOATCALL_ARRAY:
out << "double ";
break;
default:
error(E_INTERNAL);
}
out << 'v' << this->getID();
for (auto i=dimensions.begin();i!=dimensions.end();++i)
{
out << '[' << *i << ']';
}
out << ";\n";
(s==S_LOCAL&&!scopeGlobal)?funcs_h:heap_h << out.str();
}
arrayType::arrayType(string &name, enum TYPES t, list<unsigned int>dim):
variableType(S_GLOBAL, name, t, 0)
{
this->dimensions=dim;
}
string arrayType::sourceName(list<operands *>source)
{
ostringstream out;
out << 'v' << this->getID();
for (auto i=source.begin();i!=source.end();++i)
{
out << '[' << (*i)->boxName() << ']';
}
return out.str();
}
void arrayType::assignment(list<expression *>indexes, expression *value)
{
list<operands *>x=this->evaluateIndexes(indexes);
operands *op=value->evaluate();
enum TYPES t=op->getSimpleVarType();
switch (this->getType())
{
case T_FLOATCALL_ARRAY:
if (t==T_INTVAR)
{
output_cpp << this->sourceName(x)
<< "=static_cast<double>("
<< op->boxName() << ");\n";
return;
}
if (t!=T_FLOATVAR) error(E_TYPE_MISMATCH);
break;
case T_INTCALL_ARRAY:
if (t!=T_INTVAR) error(E_TYPE_MISMATCH);
break;
case T_STRINGCALL_ARRAY:
if (t!=T_STRINGVAR) error(E_TYPE_MISMATCH);
break;
default:
error(E_INTERNAL);
}
output_cpp << this->sourceName(x) << '=' << op->boxName() <<";\n";
op->dispose();
delete value;
}