Got past temporary variable deallocation bug. Now working on functions.

This commit is contained in:
Samuel D. Crow
2021-04-08 15:31:36 -05:00
parent 8797cb8870
commit d37eb38ad1
7 changed files with 258 additions and 100 deletions

View File

@@ -5,6 +5,24 @@
*/ */
#include "runtime.h" #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[]) int main(int argc, char *argv[])
{ {
unsigned int ret=run(); unsigned int ret=run();

View File

@@ -14,9 +14,24 @@ enum STATES:unsigned int
{ {
EXIT, EXIT,
UNDEFINED_STATE_ERROR, UNDEFINED_STATE_ERROR,
STACK_UNDERFLOW_ERROR,
START 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 */ /* function prototype */
unsigned int run(); unsigned int run();

View File

@@ -72,6 +72,7 @@ const string CODETYPES[]={
enum COMPILE_ERRORS errorLevel=E_OK; enum COMPILE_ERRORS errorLevel=E_OK;
unsigned int indentLevel=0; unsigned int indentLevel=0;
bool scopeGlobal=true; bool scopeGlobal=true;
unsigned int currentFunc=0;
bool COMPILE=false; bool COMPILE=false;
bool DUMP=false; bool DUMP=false;
@@ -201,7 +202,7 @@ void setUp()
{ {
varNames.open("/dev/null"); varNames.open("/dev/null");
} }
if (DEBUG) if (DEBUG || TRACE)
{ {
/* dump identifier mode */ /* dump identifier mode */
logfile.open("parse.log"); logfile.open("parse.log");
@@ -237,7 +238,7 @@ void logger(string s)
if (DEBUG) if (DEBUG)
{ {
indent(); indent();
logfile << s << "\n"; logfile << s << endl;
} }
} }
@@ -246,12 +247,11 @@ void shutDown()
{ {
if (errorLevel != E_OK) cerr << "\nERROR: " if (errorLevel != E_OK) cerr << "\nERROR: "
<< COMPILE_ERROR_NAMES[errorLevel] << "\n\n" << endl; << COMPILE_ERROR_NAMES[errorLevel] << "\n\n" << endl;
logger("Purging tempVar queues"); logger("Shutting Down: Purging tempVar queues");
tempVar::eraseQueues(); tempVar::eraseQueues();
logger("Dumping stack.");
if (DUMP && (logfile)) fn::dumpCallStack();
if (DUMP) if (DUMP)
{ {
fn::dumpFunctionIDs();
varNames << "Global Variables\n"; varNames << "Global Variables\n";
for(auto iter=globals.begin(); iter!=globals.end(); ++iter) for(auto iter=globals.begin(); iter!=globals.end(); ++iter)
{ {
@@ -276,18 +276,29 @@ void shutDown()
variableType *v; variableType *v;
printSegment *print; printSegment *print;
fn *func;
operands *o;
expression *e;
list<operands *>p;
void testInt() void testInt()
{ {
logger("testInt started");
string name=string("v"); string name=string("v");
v=variableType::getOrCreateVar(name, T_INTVAR); 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=new printSegment(new expression(v));
print->generate(); print->generate();
delete print; delete print;
logger("testInt cleared.");
} }
void testString() void testString()
{ {
logger("testString started");
string name=string("name1"); string name=string("name1");
v=variableType::getOrCreateVar(name, T_STRINGVAR); v=variableType::getOrCreateVar(name, T_STRINGVAR);
v->assignment(new expression(new constOp("Hello", T_STRING))); 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=new printSegment(new expression(new constOp(" world!", T_STRING)));
print->generate(); print->generate();
delete print; delete print;
logger("testString cleared");
} }
void testFloat() void testFloat()
{ {
logger("testFloat started");
string name=string("floater"); string name=string("floater");
v=variableType::getOrCreateVar(name, T_FLOATVAR); v=variableType::getOrCreateVar(name, T_FLOATVAR);
v->assignment(new expression(new constOp("3.14159265", T_FLOAT))); 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=new printSegment(new expression(new constOp(" is pi", T_STRING)));
print->generate(); print->generate();
delete print; 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 */ /* open files and compile */
@@ -319,6 +366,9 @@ void compile()
testInt(); testInt();
testString(); testString();
testFloat(); testFloat();
testFunc();
label::generateEnd(); label::generateEnd();
/*check for nesting error */
if (!scopeGlobal) error(E_END_FUNCTION);
shutDown(); shutDown();
} }

View File

@@ -71,6 +71,7 @@ const string CODETYPES[]={
enum COMPILE_ERRORS errorLevel=E_OK; enum COMPILE_ERRORS errorLevel=E_OK;
unsigned int indentLevel=0; unsigned int indentLevel=0;
bool scopeGlobal=true; bool scopeGlobal=true;
unsigned int currentFunc=0;
bool COMPILE=false; bool COMPILE=false;
bool DUMP=false; bool DUMP=false;
@@ -247,8 +248,6 @@ void shutDown()
<< COMPILE_ERROR_NAMES[errorLevel] << "\n\n" << endl; << COMPILE_ERROR_NAMES[errorLevel] << "\n\n" << endl;
logger("Purging tempVar queues"); logger("Purging tempVar queues");
tempVar::eraseQueues(); tempVar::eraseQueues();
logger("Dumping stack.");
if (DUMP && (logfile)) fn::dumpCallStack();
if (DUMP) if (DUMP)
{ {
varNames << "Global Variables\n"; varNames << "Global Variables\n";

View File

@@ -60,7 +60,9 @@ enum COMPILE_ERRORS:unsigned int
extern enum COMPILE_ERRORS errorLevel; extern enum COMPILE_ERRORS errorLevel;
extern unsigned int indentLevel; extern unsigned int indentLevel;
/*TODO: Replace scopeGlobal with currentFunc==0*/
extern bool scopeGlobal; extern bool scopeGlobal;
extern unsigned int currentFunc;
/* flags used internally by the compiler */ /* flags used internally by the compiler */
extern bool COMPILE; extern bool COMPILE;
@@ -134,6 +136,7 @@ enum SCOPES:unsigned int
enum OPERATORS:unsigned int enum OPERATORS:unsigned int
{ {
O_NOP,
O_PLUS, O_PLUS,
O_MINUS, O_MINUS,
O_MULTIPLY, O_MULTIPLY,
@@ -247,8 +250,7 @@ public:
/* Terminal expression node */ /* Terminal expression node */
expression(operands *x); expression(operands *x);
virtual ~expression() virtual ~expression();
{}
}; };
/* parent class of all code types */ /* parent class of all code types */
@@ -357,12 +359,14 @@ public:
class variableType:public operands class variableType:public operands
{ {
enum SCOPES myScope; enum SCOPES myScope;
unsigned int localID;
public: public:
static variableType *getOrCreateVar(string &name, enum TYPES t); static variableType *getOrCreateVar(string &name, enum TYPES t);
virtual string boxName();
void assignment(expression *value); void assignment(expression *value);
/* always call generateBox() after new variableType() */ /* 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();
~variableType() ~variableType()
{} {}
@@ -400,42 +404,43 @@ public:
virtual ~forLoop(); virtual ~forLoop();
}; };
class fn:codeType class fn
{ {
static unordered_map<string, unique_ptr<fn> > functions; static unordered_map<string, unique_ptr<fn> > functions;
static list<fn *> callStack;
static unsigned int nextID; static unsigned int nextID;
list<variableType * >params; list<variableType * >params;
string funcName;
unsigned int id; unsigned int id;
enum CODES type;
enum TYPES kind; enum TYPES kind;
operands *rc; operands *rc;
/* two labels common to all subroutine calls */ /* two labels common to all subroutine calls */
label *startAddr; label *startAddr;
label *ret; /* stamdard constructor called by declare */
/* private constructor used by generateGosub and generateOnNSub*/ fn(enum CODES t, operands *returnCode=nullptr);
fn(label *gosub);
public: public:
static void dumpCallStack();
static fn *getCurrentSub();
static fn *getSub(string &name); static fn *getSub(string &name);
static void generateGosub(label * sub); static void generateGosub(label * sub);
/* must be called after label::generateOnNSkip */ /* must be called after label::generateOnNSkip */
static void generateOnNSub(expression *e, unsigned int skip); static void generateOnNSub(expression *e, unsigned int skip);
enum CODES getType() const {return this->type;}
unsigned int getID() const {return this->id;} 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 *); void addParameter(variableType *);
operands *generateCall(string &name, list<operands *>&paramList); operands *generateCall(string &name, list<operands *>&paramList);
/* standard return is for call */
void generateReturn(expression *expr); void generateReturn(expression *expr);
/* parameterless return is for gosub */
void generateReturn(); void generateReturn();
virtual void generateBreak(); virtual void generateBreak();
virtual void close(); virtual void close();
fn(string &name, enum CODES t, operands *returnCode=nullptr); static fn *declare(string &name, enum CODES t, operands *returnCode=nullptr);
virtual ~fn() static void dumpFunctionIDs();
{}
/* is called only by unique_ptr in static "functions" hash table */
virtual ~fn();
}; };
class printSegment class printSegment

View File

@@ -35,7 +35,7 @@ enum TYPES operands::getSimpleVarType(enum TYPES t)
case T_STRINGVAR: case T_STRINGVAR:
return T_STRINGVAR; return T_STRINGVAR;
default: default:
break; break;
} }
error(E_UNASSIGNABLE_TYPE); error(E_UNASSIGNABLE_TYPE);
} }
@@ -87,19 +87,18 @@ void operands::generateBox(enum SCOPES s)
operands *operands::createOp(enum TYPES t) operands *operands::createOp(enum TYPES t)
{ {
if (DEBUG) if (TRACE)
{ {
operands *x=createOp(t); indent();
x->generateBox(scopeGlobal?S_GLOBAL:S_LOCAL); logfile << "Creating operand of type "
return x; << TYPENAMES[t] << endl;
} }
return tempVar::getOrCreateVar(t); return tempVar::getOrCreateVar(t);
} }
/* only tempVar type needs disposing */
void operands::dispose() void operands::dispose()
{ {}
delete this;
}
string operands::boxName() string operands::boxName()
{ {
@@ -295,8 +294,8 @@ expression::expression(expression *l, enum OPERATORS o, expression *r)
expression::expression(operands *x) expression::expression(operands *x)
{ {
op=x; this->op=x;
oper=O_TERM; this->oper=O_TERM;
} }
/* binary vs. unary ops */ /* binary vs. unary ops */
@@ -323,10 +322,14 @@ operands *expression::evaluate()
operands *l; operands *l;
operands *r; operands *r;
enum TYPES t; enum TYPES t;
logger("evaluating left");
l=this->getLeft()->evaluate(); l=this->getLeft()->evaluate();
logger("left evaluated");
if (this->isBinOp()) if (this->isBinOp())
{ {
logger("evaluating right");
r=this->getRight()->evaluate(); r=this->getRight()->evaluate();
logger("evaluated right");
enum TYPES lt=l->getSimpleVarType(); enum TYPES lt=l->getSimpleVarType();
enum TYPES rt=r->getSimpleVarType(); enum TYPES rt=r->getSimpleVarType();
if (lt==T_INTVAR && rt==T_FLOATVAR) if (lt==T_INTVAR && rt==T_FLOATVAR)
@@ -398,6 +401,7 @@ operands *expression::evaluate()
this->op=operands::createOp(t); this->op=operands::createOp(t);
output_cpp << this->op->boxName() << "=" << l->boxName() output_cpp << this->op->boxName() << "=" << l->boxName()
<< "*" << r->boxName() << ";\n"; << "*" << r->boxName() << ";\n";
logger("multiply done");
break; break;
case O_OR: case O_OR:
if (t!=T_INTVAR) error(E_TYPE_MISMATCH); if (t!=T_INTVAR) error(E_TYPE_MISMATCH);
@@ -445,21 +449,32 @@ operands *expression::evaluate()
error(E_INTERNAL); error(E_INTERNAL);
} }
/* convert expression into single operand */ /* convert expression into single operand */
this->oper=O_TERM; logger("deleting left");
l->dispose();
delete left; delete left;
if (getRight()!=nullptr) logger("left deleted");
if (isBinOp())
{ {
r->dispose(); logger("deleting right");
delete right; delete right;
logger("right deleted");
} }
this->oper=O_TERM;
return this->op; return this->op;
} }
expression::~expression()
{
if(this->getOp()==O_TERM)
{
op->dispose();
}
}
/* variable definitions */ /* 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->myScope=s;
this->localID=fnID;
switch (s) switch (s)
{ {
case S_LOCAL: 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) variableType *variableType::getOrCreateVar(string &name, enum TYPES t)
{ {
if (!scopeGlobal) if (!scopeGlobal)
@@ -491,7 +518,15 @@ variableType *variableType::getOrCreateVar(string &name, enum TYPES t)
if(i!=statics.end())return i->second.get(); if(i!=statics.end())return i->second.get();
} }
if (globals.find(name)!=globals.end())return globals[name].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); v->generateBox(scopeGlobal?S_GLOBAL:S_LOCAL);
return v; return v;
} }
@@ -522,7 +557,6 @@ void variableType::assignment(expression *value)
<< op->boxName() << ";\n"; << op->boxName() << ";\n";
break; break;
} }
op->dispose();
delete value; delete value;
} }
@@ -566,7 +600,7 @@ string arrayType::generateBox(enum SCOPES s)
} }
arrayType::arrayType(string &name, enum TYPES t, list<unsigned int>dim): 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; this->dimensions=dim;
} }

View File

@@ -10,35 +10,30 @@
/* static initializers */ /* static initializers */
unordered_map<string, unique_ptr<fn> > fn::functions; unordered_map<string, unique_ptr<fn> > fn::functions;
list<fn *>fn::callStack; unsigned int fn::nextID;
unsigned int fn::nextID=0;
/* function definitions */ /* function definitions */
void fn::dumpCallStack() void fn::dumpFunctionIDs()
{ {
auto i=callStack.rbegin(); varNames << "Function IDs\n";
if (i==callStack.rend()) auto i=functions.begin();
if (i==functions.end())
{ {
logfile << "call stack was empty\n"; varNames << "no named functions\n";
return; return;
} }
do do
{ {
logfile << (*i)->funcName << "\n"; varNames << "Function " << i->first
<< " has ID f" << i->second.get()->getID() << "\n";
++i; ++i;
} while(i!=callStack.rend()); } while (i!=functions.end());
}
fn *fn::getCurrentSub()
{
return callStack.back();
} }
void fn::generateOnNSub(expression *e, unsigned int skip) void fn::generateOnNSub(expression *e, unsigned int skip)
{ {
label *r=new label(); label *r=new label();
fn *self=new fn(r); output_cpp << "callStack=new subroutine(" << r->getID() << ");\n";
fn::callStack.push_back(self);
label::generateOnNTo(e, skip); label::generateOnNTo(e, skip);
r->generate(); r->generate();
} }
@@ -46,18 +41,11 @@ void fn::generateOnNSub(expression *e, unsigned int skip)
void fn::generateGosub(label *sub) void fn::generateGosub(label *sub)
{ {
label *r=new label(); label *r=new label();
fn *self=new fn(r); output_cpp << "callStack=new subroutine(" << r->getID() << ");\n";
fn::callStack.push_back(self);
sub->generateJumpTo(); sub->generateJumpTo();
r->generate(); r->generate();
} }
fn::fn(label *gosub):codeType(T_GOSUB)
{
this->funcName="unnamed gosub";
this->ret=gosub;
}
fn *fn::getSub(string &name) fn *fn::getSub(string &name)
{ {
auto iter=fn::functions.find(name); auto iter=fn::functions.find(name);
@@ -65,32 +53,42 @@ fn *fn::getSub(string &name)
return iter->second.get(); 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 *>&paramList) operands *fn::generateCall(string &name, list<operands *>&paramList)
{ {
auto v=params.begin(); auto v=params.begin();
operands *current; operands *current;
label *retAddr=new label();
fn *g=fn::getSub(name); fn *g=fn::getSub(name);
if (g==nullptr) if (g==nullptr)
{ {
error(E_SUBROUTINE_NOT_FOUND); error(E_SUBROUTINE_NOT_FOUND);
} }
if (paramList.size()>params.size()) if (paramList.size() > this->getNumParams())
{ {
error(E_TOO_MANY_PARAMETERS); error(E_TOO_MANY_PARAMETERS);
} }
/* TODO CHECK THIS */ /* TODO CHECK THIS */
output_cpp << "struct f" << g->getID() output_cpp << "struct f" << g->getID()
<< "*sub" << this->getID() << " *sub" << this->getID()
<< "= new struct f" << g->getID() << "= new struct f" << g->getID()
<< "();\n"; << "(" << retAddr->getID() << ");\n"
<< "callStack = sub" <<this->getID() << ";\n";
/* TODO Make parameter processing a separate function */ /* TODO Make parameter processing a separate function */
while(paramList.size()>0) while(paramList.size()>0)
{ {
current= paramList.front(); current=paramList.front();
paramList.pop_front(); paramList.pop_front();
if(current->getSimpleVarType()!=(*v)->getType()) if(current->getSimpleVarType()!=(*v)->getType())
{ {
cerr << "assigning " << TYPENAMES[current->getType()]
<< " to " << (*v)->getType() << endl;
error(E_TYPE_MISMATCH); error(E_TYPE_MISMATCH);
} }
(*v)->assignment(new expression(current)); (*v)->assignment(new expression(current));
@@ -115,53 +113,44 @@ operands *fn::generateCall(string &name, list<operands *>&paramList)
++v; ++v;
} }
g->startAddr->generateJumpTo(); g->startAddr->generateJumpTo();
g->ret->generate(); retAddr->generate();
return g->rc; return g->rc;
} }
/* typeless return for gosub family */
void fn::generateReturn() void fn::generateReturn()
{ {
fn *c=getCurrentSub(); output_cpp << "state=subroutine::close();\nbreak;\n";
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);
}
} }
void fn::generateReturn(expression *expr) void fn::generateReturn(expression *expr)
{ {
logger("evaluating expression");
this->rc=expr->evaluate(); this->rc=expr->evaluate();
logger("expression evaluated");
this->kind=rc->getSimpleVarType(); this->kind=rc->getSimpleVarType();
this->ret->generateJumpTo(); logger("generating return");
fn::callStack.pop_back(); generateReturn();
delete expr;
switch (this->getType()) switch (this->getType())
{ {
case T_UNKNOWNFUNC: case T_UNKNOWNFUNC:
return; break;
case T_STRINGFUNC: case T_STRINGFUNC:
if (kind!=T_STRINGVAR) error(E_TYPE_MISMATCH); if (kind!=T_STRINGVAR) error(E_TYPE_MISMATCH);
return; break;
case T_INTFUNC: case T_INTFUNC:
if (kind!=T_INTVAR&&kind!=T_FLOATVAR) error(E_TYPE_MISMATCH); if (kind!=T_INTVAR&&kind!=T_FLOATVAR) error(E_TYPE_MISMATCH);
return; break;
case T_FLOATFUNC: case T_FLOATFUNC:
if(kind!=T_FLOATVAR) error(E_TYPE_MISMATCH); if(kind!=T_FLOATVAR) error(E_TYPE_MISMATCH);
return; break;
case T_GOSUB: case T_GOSUB:
error(E_GOSUB_CANNOT_RETURN_VALUE); error(E_GOSUB_CANNOT_RETURN_VALUE);
default: default:
error(E_BAD_SYNTAX); error(E_BAD_SYNTAX);
} }
logger("deleting expression");
delete expr;
} }
/* not allowed in function definitions directly */ /* not allowed in function definitions directly */
@@ -181,31 +170,79 @@ void fn::close()
this->generateReturn(); this->generateReturn();
} }
funcs_h << "};\n"; 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(); locals.clear();
statics.clear(); statics.clear();
this->params.clear(); currentFunc=0;
scopeGlobal=true; 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 */ /*check for nesting error */
if (!scopeGlobal) error(E_END_FUNCTION); if (!scopeGlobal) error(E_END_FUNCTION);
/*check if this function name is already used*/ /*check if this function name is already used*/
if (fn::functions.find(s)!=fn::functions.end()) error(E_DUPLICATE_SYMBOL); 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; this->id= ++nextID;
/*define storage for locals*/ /*define storage for locals*/
funcs_h << "struct f" << this->id <<"\n{\n"; if (t!=T_GOSUB) funcs_h << "struct f" << this->id <<":public subroutine\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;
/*keep track of where the return code will be sent to*/ /*keep track of where the return code will be sent to*/
this->rc=returnCode; this->rc=returnCode;
/*allocate and generate start address label*/ /*allocate and generate start address label*/
this->startAddr=new label(); this->startAddr=new label();
startAddr->generate(); startAddr->generate();
} }
fn::~fn()
{
this->params.clear();
delete startAddr;
}