Got past temporary variable deallocation bug. Now working on functions.
This commit is contained in:
@@ -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();
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
62
tester.cpp
62
tester.cpp
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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";
|
||||||
|
|||||||
35
yab2cpp.h
35
yab2cpp.h
@@ -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 *>¶mList);
|
operands *generateCall(string &name, list<operands *>¶mList);
|
||||||
|
/* 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
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
155
yabFunctions.cpp
155
yabFunctions.cpp
@@ -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 *>¶mList)
|
operands *fn::generateCall(string &name, list<operands *>¶mList)
|
||||||
{
|
{
|
||||||
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 *>¶mList)
|
|||||||
++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;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user