Got past temporary variable deallocation bug. Now working on functions.
This commit is contained in:
@@ -5,6 +5,24 @@
|
||||
*/
|
||||
#include "runtime.h"
|
||||
|
||||
struct subroutine *callStack=nullptr;
|
||||
|
||||
subroutine::subroutine(enum STATES r)
|
||||
{
|
||||
this->ret=r;
|
||||
this->called=callStack;
|
||||
}
|
||||
|
||||
enum STATES subroutine::close()
|
||||
{
|
||||
if (callStack==nullptr) return STACK_UNDERFLOW_ERROR;
|
||||
enum STATES r=callStack->ret;
|
||||
struct subroutine *l=callStack->called;
|
||||
delete callStack;
|
||||
callStack=l;
|
||||
return r;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
unsigned int ret=run();
|
||||
|
||||
@@ -14,9 +14,24 @@ enum STATES:unsigned int
|
||||
{
|
||||
EXIT,
|
||||
UNDEFINED_STATE_ERROR,
|
||||
STACK_UNDERFLOW_ERROR,
|
||||
START
|
||||
};
|
||||
|
||||
class subroutine
|
||||
{
|
||||
struct subroutine *called;
|
||||
enum STATES ret;
|
||||
|
||||
public:
|
||||
static enum STATES close();
|
||||
subroutine(enum STATES r);
|
||||
virtual ~subroutine()
|
||||
{}
|
||||
};
|
||||
|
||||
extern struct subroutine *callStack;
|
||||
|
||||
/* function prototype */
|
||||
unsigned int run();
|
||||
|
||||
|
||||
62
tester.cpp
62
tester.cpp
@@ -72,6 +72,7 @@ const string CODETYPES[]={
|
||||
enum COMPILE_ERRORS errorLevel=E_OK;
|
||||
unsigned int indentLevel=0;
|
||||
bool scopeGlobal=true;
|
||||
unsigned int currentFunc=0;
|
||||
|
||||
bool COMPILE=false;
|
||||
bool DUMP=false;
|
||||
@@ -201,7 +202,7 @@ void setUp()
|
||||
{
|
||||
varNames.open("/dev/null");
|
||||
}
|
||||
if (DEBUG)
|
||||
if (DEBUG || TRACE)
|
||||
{
|
||||
/* dump identifier mode */
|
||||
logfile.open("parse.log");
|
||||
@@ -237,7 +238,7 @@ void logger(string s)
|
||||
if (DEBUG)
|
||||
{
|
||||
indent();
|
||||
logfile << s << "\n";
|
||||
logfile << s << endl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,12 +247,11 @@ void shutDown()
|
||||
{
|
||||
if (errorLevel != E_OK) cerr << "\nERROR: "
|
||||
<< COMPILE_ERROR_NAMES[errorLevel] << "\n\n" << endl;
|
||||
logger("Purging tempVar queues");
|
||||
logger("Shutting Down: Purging tempVar queues");
|
||||
tempVar::eraseQueues();
|
||||
logger("Dumping stack.");
|
||||
if (DUMP && (logfile)) fn::dumpCallStack();
|
||||
if (DUMP)
|
||||
{
|
||||
fn::dumpFunctionIDs();
|
||||
varNames << "Global Variables\n";
|
||||
for(auto iter=globals.begin(); iter!=globals.end(); ++iter)
|
||||
{
|
||||
@@ -276,18 +276,29 @@ void shutDown()
|
||||
|
||||
variableType *v;
|
||||
printSegment *print;
|
||||
fn *func;
|
||||
operands *o;
|
||||
expression *e;
|
||||
list<operands *>p;
|
||||
void testInt()
|
||||
{
|
||||
logger("testInt started");
|
||||
string name=string("v");
|
||||
v=variableType::getOrCreateVar(name, T_INTVAR);
|
||||
v->assignment(new expression(new constOp("2", T_INT)));
|
||||
logger("variable v created");
|
||||
o=new constOp("2", T_INT);
|
||||
logger("constOp 2 created");
|
||||
v->assignment(new expression(o));
|
||||
logger("assignment created");
|
||||
print=new printSegment(new expression(v));
|
||||
print->generate();
|
||||
delete print;
|
||||
logger("testInt cleared.");
|
||||
}
|
||||
|
||||
void testString()
|
||||
{
|
||||
logger("testString started");
|
||||
string name=string("name1");
|
||||
v=variableType::getOrCreateVar(name, T_STRINGVAR);
|
||||
v->assignment(new expression(new constOp("Hello", T_STRING)));
|
||||
@@ -297,10 +308,12 @@ void testString()
|
||||
print=new printSegment(new expression(new constOp(" world!", T_STRING)));
|
||||
print->generate();
|
||||
delete print;
|
||||
logger("testString cleared");
|
||||
}
|
||||
|
||||
void testFloat()
|
||||
{
|
||||
logger("testFloat started");
|
||||
string name=string("floater");
|
||||
v=variableType::getOrCreateVar(name, T_FLOATVAR);
|
||||
v->assignment(new expression(new constOp("3.14159265", T_FLOAT)));
|
||||
@@ -310,6 +323,40 @@ void testFloat()
|
||||
print=new printSegment(new expression(new constOp(" is pi", T_STRING)));
|
||||
print->generate();
|
||||
delete print;
|
||||
logger("testFloat cleared");
|
||||
}
|
||||
|
||||
void testFunc()
|
||||
{
|
||||
logger("testFunc started");
|
||||
string name=string("square");
|
||||
logger("aloha");
|
||||
o = operands::createOp(T_FLOATVAR);
|
||||
logger("mahalo");
|
||||
func=fn::declare(name, T_FLOATFUNC, o);
|
||||
logger("funkBeat");
|
||||
name=string("radius");
|
||||
v=variableType::getOrCreateVar(name, T_FLOATVAR);
|
||||
logger("param made");
|
||||
func->addParameter(v);
|
||||
logger("param added");
|
||||
e=new expression(new expression(v), O_MULTIPLY, new expression(v));
|
||||
logger("expression made");
|
||||
func->generateReturn(e);
|
||||
logger("return generated");
|
||||
func->close();
|
||||
logger("function ended");
|
||||
o=new constOp("3.0", T_FLOAT);
|
||||
p.push_back(o);
|
||||
name=string("square");
|
||||
o=func->generateCall(name, p);
|
||||
logger("call generated");
|
||||
e=new expression(o);
|
||||
print=new printSegment(e);
|
||||
o->dispose();
|
||||
print->generate();
|
||||
delete print;
|
||||
logger("testFunc cleared");
|
||||
}
|
||||
|
||||
/* open files and compile */
|
||||
@@ -319,6 +366,9 @@ void compile()
|
||||
testInt();
|
||||
testString();
|
||||
testFloat();
|
||||
testFunc();
|
||||
label::generateEnd();
|
||||
/*check for nesting error */
|
||||
if (!scopeGlobal) error(E_END_FUNCTION);
|
||||
shutDown();
|
||||
}
|
||||
|
||||
@@ -71,6 +71,7 @@ const string CODETYPES[]={
|
||||
enum COMPILE_ERRORS errorLevel=E_OK;
|
||||
unsigned int indentLevel=0;
|
||||
bool scopeGlobal=true;
|
||||
unsigned int currentFunc=0;
|
||||
|
||||
bool COMPILE=false;
|
||||
bool DUMP=false;
|
||||
@@ -247,8 +248,6 @@ void shutDown()
|
||||
<< COMPILE_ERROR_NAMES[errorLevel] << "\n\n" << endl;
|
||||
logger("Purging tempVar queues");
|
||||
tempVar::eraseQueues();
|
||||
logger("Dumping stack.");
|
||||
if (DUMP && (logfile)) fn::dumpCallStack();
|
||||
if (DUMP)
|
||||
{
|
||||
varNames << "Global Variables\n";
|
||||
|
||||
35
yab2cpp.h
35
yab2cpp.h
@@ -60,7 +60,9 @@ enum COMPILE_ERRORS:unsigned int
|
||||
|
||||
extern enum COMPILE_ERRORS errorLevel;
|
||||
extern unsigned int indentLevel;
|
||||
/*TODO: Replace scopeGlobal with currentFunc==0*/
|
||||
extern bool scopeGlobal;
|
||||
extern unsigned int currentFunc;
|
||||
|
||||
/* flags used internally by the compiler */
|
||||
extern bool COMPILE;
|
||||
@@ -134,6 +136,7 @@ enum SCOPES:unsigned int
|
||||
|
||||
enum OPERATORS:unsigned int
|
||||
{
|
||||
O_NOP,
|
||||
O_PLUS,
|
||||
O_MINUS,
|
||||
O_MULTIPLY,
|
||||
@@ -247,8 +250,7 @@ public:
|
||||
|
||||
/* Terminal expression node */
|
||||
expression(operands *x);
|
||||
virtual ~expression()
|
||||
{}
|
||||
virtual ~expression();
|
||||
};
|
||||
|
||||
/* parent class of all code types */
|
||||
@@ -357,12 +359,14 @@ public:
|
||||
class variableType:public operands
|
||||
{
|
||||
enum SCOPES myScope;
|
||||
unsigned int localID;
|
||||
public:
|
||||
static variableType *getOrCreateVar(string &name, enum TYPES t);
|
||||
|
||||
virtual string boxName();
|
||||
void assignment(expression *value);
|
||||
/* always call generateBox() after new variableType() */
|
||||
variableType(enum SCOPES s, string &name, enum TYPES t);
|
||||
variableType(enum SCOPES s, string &name, enum TYPES t, unsigned int fnID);
|
||||
variableType();
|
||||
~variableType()
|
||||
{}
|
||||
@@ -400,42 +404,43 @@ public:
|
||||
virtual ~forLoop();
|
||||
};
|
||||
|
||||
class fn:codeType
|
||||
class fn
|
||||
{
|
||||
static unordered_map<string, unique_ptr<fn> > functions;
|
||||
static list<fn *> callStack;
|
||||
static unsigned int nextID;
|
||||
list<variableType * >params;
|
||||
string funcName;
|
||||
unsigned int id;
|
||||
enum CODES type;
|
||||
enum TYPES kind;
|
||||
operands *rc;
|
||||
/* two labels common to all subroutine calls */
|
||||
label *startAddr;
|
||||
label *ret;
|
||||
/* private constructor used by generateGosub and generateOnNSub*/
|
||||
fn(label *gosub);
|
||||
/* stamdard constructor called by declare */
|
||||
fn(enum CODES t, operands *returnCode=nullptr);
|
||||
public:
|
||||
static void dumpCallStack();
|
||||
static fn *getCurrentSub();
|
||||
static fn *getSub(string &name);
|
||||
static void generateGosub(label * sub);
|
||||
/* must be called after label::generateOnNSkip */
|
||||
static void generateOnNSub(expression *e, unsigned int skip);
|
||||
|
||||
enum CODES getType() const {return this->type;}
|
||||
unsigned int getID() const {return this->id;}
|
||||
int getNumParams() const {return this->params.size();}
|
||||
size_t getNumParams() const {return this->params.size();}
|
||||
void addParameter(variableType *);
|
||||
|
||||
operands *generateCall(string &name, list<operands *>¶mList);
|
||||
/* standard return is for call */
|
||||
void generateReturn(expression *expr);
|
||||
/* parameterless return is for gosub */
|
||||
void generateReturn();
|
||||
virtual void generateBreak();
|
||||
virtual void close();
|
||||
|
||||
fn(string &name, enum CODES t, operands *returnCode=nullptr);
|
||||
virtual ~fn()
|
||||
{}
|
||||
static fn *declare(string &name, enum CODES t, operands *returnCode=nullptr);
|
||||
static void dumpFunctionIDs();
|
||||
|
||||
/* is called only by unique_ptr in static "functions" hash table */
|
||||
virtual ~fn();
|
||||
};
|
||||
|
||||
class printSegment
|
||||
|
||||
@@ -35,7 +35,7 @@ enum TYPES operands::getSimpleVarType(enum TYPES t)
|
||||
case T_STRINGVAR:
|
||||
return T_STRINGVAR;
|
||||
default:
|
||||
break;
|
||||
break;
|
||||
}
|
||||
error(E_UNASSIGNABLE_TYPE);
|
||||
}
|
||||
@@ -87,19 +87,18 @@ void operands::generateBox(enum SCOPES s)
|
||||
|
||||
operands *operands::createOp(enum TYPES t)
|
||||
{
|
||||
if (DEBUG)
|
||||
if (TRACE)
|
||||
{
|
||||
operands *x=createOp(t);
|
||||
x->generateBox(scopeGlobal?S_GLOBAL:S_LOCAL);
|
||||
return x;
|
||||
indent();
|
||||
logfile << "Creating operand of type "
|
||||
<< TYPENAMES[t] << endl;
|
||||
}
|
||||
return tempVar::getOrCreateVar(t);
|
||||
}
|
||||
|
||||
/* only tempVar type needs disposing */
|
||||
void operands::dispose()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
{}
|
||||
|
||||
string operands::boxName()
|
||||
{
|
||||
@@ -295,8 +294,8 @@ expression::expression(expression *l, enum OPERATORS o, expression *r)
|
||||
|
||||
expression::expression(operands *x)
|
||||
{
|
||||
op=x;
|
||||
oper=O_TERM;
|
||||
this->op=x;
|
||||
this->oper=O_TERM;
|
||||
}
|
||||
|
||||
/* binary vs. unary ops */
|
||||
@@ -323,10 +322,14 @@ operands *expression::evaluate()
|
||||
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)
|
||||
@@ -398,6 +401,7 @@ operands *expression::evaluate()
|
||||
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);
|
||||
@@ -445,21 +449,32 @@ operands *expression::evaluate()
|
||||
error(E_INTERNAL);
|
||||
}
|
||||
/* convert expression into single operand */
|
||||
this->oper=O_TERM;
|
||||
l->dispose();
|
||||
logger("deleting left");
|
||||
delete left;
|
||||
if (getRight()!=nullptr)
|
||||
logger("left deleted");
|
||||
if (isBinOp())
|
||||
{
|
||||
r->dispose();
|
||||
logger("deleting right");
|
||||
delete right;
|
||||
logger("right deleted");
|
||||
}
|
||||
this->oper=O_TERM;
|
||||
return this->op;
|
||||
}
|
||||
|
||||
expression::~expression()
|
||||
{
|
||||
if(this->getOp()==O_TERM)
|
||||
{
|
||||
op->dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/* variable definitions */
|
||||
variableType::variableType(enum SCOPES s, string &name, enum TYPES t):operands(t)
|
||||
variableType::variableType(enum SCOPES s, string &name, enum TYPES t, unsigned int fnID):operands(t)
|
||||
{
|
||||
this->myScope=s;
|
||||
this->localID=fnID;
|
||||
switch (s)
|
||||
{
|
||||
case S_LOCAL:
|
||||
@@ -481,6 +496,18 @@ variableType::variableType(enum SCOPES s, string &name, enum TYPES t):operands(t
|
||||
}
|
||||
}
|
||||
|
||||
string variableType::boxName()
|
||||
{
|
||||
ostringstream ss;
|
||||
if (myScope==S_LOCAL)
|
||||
{
|
||||
ss << "sub" << this->localID << "->v" << this->getID();
|
||||
return ss.str();
|
||||
}
|
||||
ss << "v" << this->getID();
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
variableType *variableType::getOrCreateVar(string &name, enum TYPES t)
|
||||
{
|
||||
if (!scopeGlobal)
|
||||
@@ -491,7 +518,15 @@ variableType *variableType::getOrCreateVar(string &name, enum TYPES t)
|
||||
if(i!=statics.end())return i->second.get();
|
||||
}
|
||||
if (globals.find(name)!=globals.end())return globals[name].get();
|
||||
variableType *v=new variableType(scopeGlobal?S_GLOBAL:S_LOCAL, name, t);
|
||||
variableType *v;
|
||||
if (scopeGlobal)
|
||||
{
|
||||
v=new variableType(S_GLOBAL, name, t, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
v=new variableType(S_LOCAL, name, t, currentFunc);
|
||||
}
|
||||
v->generateBox(scopeGlobal?S_GLOBAL:S_LOCAL);
|
||||
return v;
|
||||
}
|
||||
@@ -522,7 +557,6 @@ void variableType::assignment(expression *value)
|
||||
<< op->boxName() << ";\n";
|
||||
break;
|
||||
}
|
||||
op->dispose();
|
||||
delete value;
|
||||
}
|
||||
|
||||
@@ -566,7 +600,7 @@ string arrayType::generateBox(enum SCOPES s)
|
||||
}
|
||||
|
||||
arrayType::arrayType(string &name, enum TYPES t, list<unsigned int>dim):
|
||||
variableType(S_GLOBAL, name, t)
|
||||
variableType(S_GLOBAL, name, t, 0)
|
||||
{
|
||||
this->dimensions=dim;
|
||||
}
|
||||
|
||||
155
yabFunctions.cpp
155
yabFunctions.cpp
@@ -10,35 +10,30 @@
|
||||
|
||||
/* static initializers */
|
||||
unordered_map<string, unique_ptr<fn> > fn::functions;
|
||||
list<fn *>fn::callStack;
|
||||
unsigned int fn::nextID=0;
|
||||
unsigned int fn::nextID;
|
||||
|
||||
/* function definitions */
|
||||
void fn::dumpCallStack()
|
||||
void fn::dumpFunctionIDs()
|
||||
{
|
||||
auto i=callStack.rbegin();
|
||||
if (i==callStack.rend())
|
||||
varNames << "Function IDs\n";
|
||||
auto i=functions.begin();
|
||||
if (i==functions.end())
|
||||
{
|
||||
logfile << "call stack was empty\n";
|
||||
varNames << "no named functions\n";
|
||||
return;
|
||||
}
|
||||
do
|
||||
{
|
||||
logfile << (*i)->funcName << "\n";
|
||||
varNames << "Function " << i->first
|
||||
<< " has ID f" << i->second.get()->getID() << "\n";
|
||||
++i;
|
||||
} while(i!=callStack.rend());
|
||||
}
|
||||
|
||||
fn *fn::getCurrentSub()
|
||||
{
|
||||
return callStack.back();
|
||||
} while (i!=functions.end());
|
||||
}
|
||||
|
||||
void fn::generateOnNSub(expression *e, unsigned int skip)
|
||||
{
|
||||
label *r=new label();
|
||||
fn *self=new fn(r);
|
||||
fn::callStack.push_back(self);
|
||||
output_cpp << "callStack=new subroutine(" << r->getID() << ");\n";
|
||||
label::generateOnNTo(e, skip);
|
||||
r->generate();
|
||||
}
|
||||
@@ -46,18 +41,11 @@ void fn::generateOnNSub(expression *e, unsigned int skip)
|
||||
void fn::generateGosub(label *sub)
|
||||
{
|
||||
label *r=new label();
|
||||
fn *self=new fn(r);
|
||||
fn::callStack.push_back(self);
|
||||
output_cpp << "callStack=new subroutine(" << r->getID() << ");\n";
|
||||
sub->generateJumpTo();
|
||||
r->generate();
|
||||
}
|
||||
|
||||
fn::fn(label *gosub):codeType(T_GOSUB)
|
||||
{
|
||||
this->funcName="unnamed gosub";
|
||||
this->ret=gosub;
|
||||
}
|
||||
|
||||
fn *fn::getSub(string &name)
|
||||
{
|
||||
auto iter=fn::functions.find(name);
|
||||
@@ -65,32 +53,42 @@ fn *fn::getSub(string &name)
|
||||
return iter->second.get();
|
||||
}
|
||||
|
||||
void fn::addParameter(variableType *v)
|
||||
{
|
||||
this->params.push_back(v);
|
||||
}
|
||||
|
||||
/* TODO needs to be broken into smaller pieces */
|
||||
operands *fn::generateCall(string &name, list<operands *>¶mList)
|
||||
{
|
||||
auto v=params.begin();
|
||||
operands *current;
|
||||
label *retAddr=new label();
|
||||
fn *g=fn::getSub(name);
|
||||
if (g==nullptr)
|
||||
{
|
||||
error(E_SUBROUTINE_NOT_FOUND);
|
||||
}
|
||||
if (paramList.size()>params.size())
|
||||
if (paramList.size() > this->getNumParams())
|
||||
{
|
||||
error(E_TOO_MANY_PARAMETERS);
|
||||
}
|
||||
/* TODO CHECK THIS */
|
||||
output_cpp << "struct f" << g->getID()
|
||||
<< "*sub" << this->getID()
|
||||
<< " *sub" << this->getID()
|
||||
<< "= new struct f" << g->getID()
|
||||
<< "();\n";
|
||||
<< "(" << retAddr->getID() << ");\n"
|
||||
<< "callStack = sub" <<this->getID() << ";\n";
|
||||
|
||||
/* TODO Make parameter processing a separate function */
|
||||
while(paramList.size()>0)
|
||||
{
|
||||
current= paramList.front();
|
||||
current=paramList.front();
|
||||
paramList.pop_front();
|
||||
if(current->getSimpleVarType()!=(*v)->getType())
|
||||
{
|
||||
cerr << "assigning " << TYPENAMES[current->getType()]
|
||||
<< " to " << (*v)->getType() << endl;
|
||||
error(E_TYPE_MISMATCH);
|
||||
}
|
||||
(*v)->assignment(new expression(current));
|
||||
@@ -115,53 +113,44 @@ operands *fn::generateCall(string &name, list<operands *>¶mList)
|
||||
++v;
|
||||
}
|
||||
g->startAddr->generateJumpTo();
|
||||
g->ret->generate();
|
||||
retAddr->generate();
|
||||
return g->rc;
|
||||
}
|
||||
|
||||
/* typeless return for gosub family */
|
||||
void fn::generateReturn()
|
||||
{
|
||||
fn *c=getCurrentSub();
|
||||
switch(c->getType())
|
||||
{
|
||||
case T_UNKNOWNFUNC:
|
||||
/* set return type to NONE */
|
||||
this->kind=T_NONE;
|
||||
/*fallthrough*/
|
||||
case T_GOSUB:
|
||||
c->ret->generateJumpTo();
|
||||
fn::callStack.pop_back();
|
||||
break;
|
||||
default:
|
||||
error(E_TYPE_MISMATCH);
|
||||
}
|
||||
output_cpp << "state=subroutine::close();\nbreak;\n";
|
||||
}
|
||||
|
||||
void fn::generateReturn(expression *expr)
|
||||
{
|
||||
logger("evaluating expression");
|
||||
this->rc=expr->evaluate();
|
||||
logger("expression evaluated");
|
||||
this->kind=rc->getSimpleVarType();
|
||||
this->ret->generateJumpTo();
|
||||
fn::callStack.pop_back();
|
||||
delete expr;
|
||||
logger("generating return");
|
||||
generateReturn();
|
||||
switch (this->getType())
|
||||
{
|
||||
case T_UNKNOWNFUNC:
|
||||
return;
|
||||
break;
|
||||
case T_STRINGFUNC:
|
||||
if (kind!=T_STRINGVAR) error(E_TYPE_MISMATCH);
|
||||
return;
|
||||
break;
|
||||
case T_INTFUNC:
|
||||
if (kind!=T_INTVAR&&kind!=T_FLOATVAR) error(E_TYPE_MISMATCH);
|
||||
return;
|
||||
break;
|
||||
case T_FLOATFUNC:
|
||||
if(kind!=T_FLOATVAR) error(E_TYPE_MISMATCH);
|
||||
return;
|
||||
break;
|
||||
case T_GOSUB:
|
||||
error(E_GOSUB_CANNOT_RETURN_VALUE);
|
||||
default:
|
||||
error(E_BAD_SYNTAX);
|
||||
}
|
||||
logger("deleting expression");
|
||||
delete expr;
|
||||
}
|
||||
|
||||
/* not allowed in function definitions directly */
|
||||
@@ -181,31 +170,79 @@ void fn::close()
|
||||
this->generateReturn();
|
||||
}
|
||||
funcs_h << "};\n";
|
||||
if(DUMP)
|
||||
{
|
||||
auto i=locals.begin();
|
||||
varNames << "\nLocal variables in function f" << this->getID() << "\n";
|
||||
if(i==locals.end())
|
||||
{
|
||||
varNames << "no non-static locals\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
varNames << "variable " << i->first << " has id v"
|
||||
<< i->second.get()->getID() << "\n";
|
||||
++i;
|
||||
}while(i!=locals.end());
|
||||
}
|
||||
i=statics.begin();
|
||||
varNames << "\n Static locals in function f" << this->getID() << "\n";
|
||||
if (i==statics.end())
|
||||
{
|
||||
varNames << "no static locals\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
varNames << "variable " << i->first << " has id v"
|
||||
<< i->second.get()->getID() << "\n";
|
||||
++i;
|
||||
} while (i!=statics.end());
|
||||
}
|
||||
}
|
||||
locals.clear();
|
||||
statics.clear();
|
||||
this->params.clear();
|
||||
currentFunc=0;
|
||||
scopeGlobal=true;
|
||||
}
|
||||
|
||||
fn::fn(string &s, enum CODES t, operands *returnCode):codeType(t)
|
||||
fn *fn::declare(string &s, enum CODES t, operands *returnCode)
|
||||
{
|
||||
/*check for nesting error */
|
||||
if (!scopeGlobal) error(E_END_FUNCTION);
|
||||
/*check if this function name is already used*/
|
||||
if (fn::functions.find(s)!=fn::functions.end()) error(E_DUPLICATE_SYMBOL);
|
||||
this->funcName=s;
|
||||
logger("declaration name cleared");
|
||||
fn *self=new fn(t, returnCode);
|
||||
logger("fn allocated");
|
||||
fn::functions.insert({s,unique_ptr<fn>(self)});
|
||||
logger("fn inserted");
|
||||
/* initiate local scope */
|
||||
currentFunc=self->getID();
|
||||
scopeGlobal=false;
|
||||
return self;
|
||||
}
|
||||
|
||||
/* standard constructor for block-formatted functions */
|
||||
fn::fn(enum CODES t, operands *returnCode)
|
||||
{
|
||||
this->params.clear();
|
||||
this->type=t;
|
||||
this->id= ++nextID;
|
||||
/*define storage for locals*/
|
||||
funcs_h << "struct f" << this->id <<"\n{\n";
|
||||
/*define label space for return*/
|
||||
this->ret=new label();
|
||||
/*allocate function name*/
|
||||
fn::functions[s]=unique_ptr<fn>(this);
|
||||
/* initiate local scope */
|
||||
scopeGlobal=false;
|
||||
if (t!=T_GOSUB) funcs_h << "struct f" << this->id <<":public subroutine\n{\n";
|
||||
/*keep track of where the return code will be sent to*/
|
||||
this->rc=returnCode;
|
||||
/*allocate and generate start address label*/
|
||||
this->startAddr=new label();
|
||||
startAddr->generate();
|
||||
}
|
||||
|
||||
fn::~fn()
|
||||
{
|
||||
this->params.clear();
|
||||
delete startAddr;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user