saving progress on functions and variables

This commit is contained in:
Samuel D. Crow
2021-03-15 14:04:53 -05:00
parent 4b2b567a42
commit 4eb08efc9d
4 changed files with 280 additions and 116 deletions

112
yab2cpp.h
View File

@@ -40,7 +40,12 @@ enum COMPILE_ERRORS {
E_BAD_ALLOC,
E_STACK_UNDERFLOW,
E_INTERNAL,
E_DUPLICATE_SYMBOL
E_DUPLICATE_SYMBOL,
E_END_FUNCTION,
E_GOSUB_CANNOT_RETURN_VALUE,
E_SUBROUTINE_NOT_FOUND,
E_TOO_MANY_PARAMETERS,
E_UNASSIGNABLE_TYPE
};
extern enum COMPILE_ERRORS errorLevel;
@@ -56,11 +61,14 @@ const char *COMPILE_ERROR_NAMES[]={
"failed allocation",
"stack underflow",
"internal compiler error",
"duplicated label"
"duplicated label",
"previous subroutine didn't end",
"value returned from gosub call",
"undefined subroutine name",
"too many parameters in function call",
"value cannot be assigned"
};
extern enum COMPILEERRORS errorLevel;
/* flags used internally by the compiler
(must be powers of 2) */
#define COMPILE 1
@@ -70,7 +78,8 @@ extern enum COMPILEERRORS errorLevel;
/* list of all variable and constant types */
enum TYPES
{
T_NONE=0,
T_UNKNOWN=0,
T_NONE,
T_STRING,
T_INT,
T_FLOAT,
@@ -80,6 +89,7 @@ enum TYPES
T_INTCALL_ARRAY,
T_FLOATCALL_ARRAY,
T_STRINGCALL_ARRAY,
T_VOIDCALL
}
/* list of all kinds of other code structures */
enum CODES
@@ -97,11 +107,17 @@ enum CODES
T_ASSIGNMENT,
T_LABEL,
T_PARAMLIST,
T_DATAITEM
T_DATAITEM,
T_STRINGFUNC,
T_FLOATFUNC,
T_INTFUNC,
T_VOIDFUNC,
T_UNKNOWNFUNC
};
/* These correspond to the types of enum TYPES. */
const string TYPENAMES[]={
"unknown",
"none",
"string constant",
"integer constant",
@@ -111,7 +127,9 @@ const string TYPENAMES[]={
"floating point variable",
"string array or function",
"integer array or function",
"floating point array or function"
"floating point array or function",
"string array or function",
"function"
};
const string CODETYPES[]={
@@ -127,7 +145,12 @@ const string CODETYPES[]={
"assignment",
"label",
"parameter list or array index",
"data item"
"data item",
"function returning string",
"function returning floating point",
"function returning integer",
"function returning nothing",
"function"
};
typedef union
@@ -165,25 +188,30 @@ enum OPERATORS
O_OR,
O_AND,
O_STRING_CONCAT,
O_INT_TO_FLOAT,
O_TERM
};
/* global prototype */
void error(enum COMPILE_ERRORS err);
/* internal states used by the parser */
class operands
{
enum TYPES type;
unsigned int id;
static unsigned int nextID;
static unordered_map<string &, operands *> globals;
static unordered_map<string &, unsigned int> strConst;
static unordered_map<string, operands *> globals;
static unordered_map<string, unsigned int> strConst;
public:
enum TYPES getType() const {return type;}
unsigned int getID() const {return id;}
static operands *findGlobal(string &s);
static void dumpVars(ostream &out);
static unsigned int getOrCreateStr(ostream &k, string &s);
static operands *createConst(ostream &k, string &s, enum TYPES t);
static operands *getOrCreateGlobal(ostream &heap, string &s, enum TYPES t);
static unsigned int getOrCreateStr(string &s);
static operands *createConst(string &s, enum TYPES t);
static operands *getOrCreateGlobal(string &s, enum TYPES t);
enum TYPES getSimpleVarType();
void generateBox(ostream &scope);
@@ -223,19 +251,17 @@ public:
op=x;
oper=O_TERM;
}
/*TODO: Recycle temporary variables when not in debug mode*/
virtual ~expression();
};
/* parent class of all code types */
class codeType
{
unsigned int id;
enum CODES type;
static unsigned int nextID;
static list<codeType *> nesting;
public:
enum CODES getType() const {return this->type;}
unsigned int getID() const {return this->id;}
static codeType *getCurrent();
@@ -258,7 +284,7 @@ public:
unsigned int getID() const {return id;}
void generateJumpTo();
void generateOnNSkip(ostream &k, list<label *> &dest);
void generateOnNSkip(list<shared_ptr<label> >dest);
void generateOnNTo(expression *e);
void generateCondJump(expression *e);
void generate();
@@ -313,7 +339,7 @@ public:
virtual void generateBreak() override;
virtual void close() override;
explicit doLoop():codeType(T_DOLOOP);
explicit doLoop();
virtual ~doLoop();
};
@@ -327,14 +353,15 @@ public:
virtual void generateBreak() override;
virtual void close() override;
explicit whileLoop(expression *e):codeType(T_WHILELOOP);
explicit whileLoop(expression *e);
virtual ~whileLoop();
};
class variable:public operands
{
ostream &myScope;
public:
static variable *getOrCreateVarName(ostream &func, ostream &heap, string &name, enum TYPES t);
static shared_ptr<variable>getOrCreateVarName(string &name, enum TYPES t);
void assignment(expression *value);
explicit variable(ostream &scope, string &name, enum TYPES t);
@@ -348,7 +375,7 @@ class arrayType:public variable
public:
virtual string &boxName(list<unsigned int>indexes) override;
explicit arrayType(ostream &heap, string &name, enum TYPES t, list<unsigned int>dim);/*:variable(scope, name, t);*/
explicit arrayType(string &name, enum TYPES t, list<unsigned int>dim);/*:variable(scope, name, t);*/
virtual ~arrayType()
{}
};
@@ -364,37 +391,46 @@ public:
virtual void generateBreak();
virtual void close();
explicit forLoop(ostream &k, variable *v, expression *start, expression *stop, expression *stepVal=NULL);
explicit forLoop(variable *v, expression *start, expression *stop, expression *stepVal=NULL);
virtual ~forLoop();
};
class fn:codeType
{
static unordered_map<string, operands *>locals;
static unordered_map<string, operands *>statics;
static unordered_map<string, fn>functions;
static list<fn *> callStack;
static unordered_map<string, shared_ptr<variable> >locals;
static unordered_map<string, shared_ptr<variable> >statics;
static unordered_map<string, shared_ptr<fn> >functions;
static list<shared_ptr<fn> > callStack;
static unsigned int nextID;
list<shared_ptr<variable> >params;
unsigned int id;
enum TYPES kind;
shared_ptr<label>startAddr;
shared_ptr<label>ret;
unsigned int parameters;
/* private constructor used by generateGosub and generateOnNSub*/
fn(label *gosub);
public:
static variable *getOrCreateVar(enum TYPES t, string &s, bool stat);
static void dumpCallStack();
static fn *getCurrentSub();
void setParameters(unsigned int num) const {this->parameters=num;}
void generateCall(string &name, unsigned int params);
void generateReturn(expression *expr=NULL);
void generateGosub(shared_ptr<label> sub);
static shared_ptr<fn>getCurrentSub();
static shared_ptr<fn>getSub(string &name);
static void generateGosub(shared_ptr<label> sub);
/* must be called after label::generateOnNSkip */
void generateOnNSub(expression *e);
static void generateOnNSub(expression *e);
unsigned int getID() const {return this->id;}
int getNumParams() const {return this->params.size;}
void addParameter(shared_ptr<variable>);
operands *generateCall(string &name, list<shared_ptr<operands> >&paramList);
operands *generateReturn(expression *expr);
void generateReturn();
virtual void generateBreak();
virtual void close();
fn(string &name);
fn(label *gosub);
virtual ~fn();
fn(string &name, enum CODES t);
virtual ~fn()
{}
};
/* The next two structures are used to implement the PRINT statement. */

View File

@@ -11,7 +11,6 @@
/* base class of all the code structure types */
codeType::codeType(enum CODES t)
{
this->id= ++nextID;
nesting.push_back(this);
this->type=t;
}
@@ -48,7 +47,7 @@ void label::generateJumpTo()
output_cpp << "state=" << this->getID() << ";\nbreak;\n";
}
void label::generateOnNSkip(list<label *> &dest)
void label::generateOnNSkip(list<shared_ptr<label> >dest)
{
if (dest->size()<2)
{

View File

@@ -9,6 +9,16 @@
#include "yab2cpp.h"
/* methods for operands */
static operands *findGlobal(string &s)
{
auto iter=operands::globals.find(s);
if (iter==operands::globals.end())
{
return NULL;
}
return iter->second;
}
static void operands::dumpVars()
{
varNames << "Global Variables\n";
@@ -48,7 +58,7 @@ unsigned int operands::createConst(string &s, enum TYPES t)
exit(1);
}
}
k << me->getID() << "=" << s << ";\n";
consts_h << me->getID() << "=" << s << ";\n";
return me;
}
@@ -69,40 +79,7 @@ enum TYPES operands::getSimpleVarType()
case T_STRINGVAR:
return T_STRINGVAR;
}
return T_NONE;
}
enum TYPES operands::coerceTypes(enum TYPES l, enum TYPES r)
{
if this->isBinOp()
{
if (l==T_INTVAR && r==T_FLOATVAR)
{
/* promote l to float */
t=T_FLOATVAR;
break;
}
if (l==T_FLOAT && r==T_INT)
{
/* promote r to float */
t=T_FLOATVAR;
break;
}
if (l==r)
{
break;
}
errorLevel=E_TYPE_MISMATCH;
exit(1);
}
else
{
if (t==T_NONE)
{
errorLevel=E_TYPE_MISMATCH;
}
}
error(E_UNASSIGNABLE_TYPE);
}
/* operands used by expression parser and variables */
@@ -154,9 +131,7 @@ void operands::boxName(ostream &scope)
break;
default:
errorLevel=E_INTERNAL;
exit(1);
break;
error(E_INTERNAL);
}
scope << "v" << this->getID();
}
@@ -171,6 +146,7 @@ bool expression::isBinOp()
case O_NEGATE:
case O_NOT:
case O_INVERT:
case O_INT_TO_FLOAT:
return false;
break;
}
@@ -187,7 +163,20 @@ operands *expression::evaluate()
if (this->isBinOp())
{
r=this->getRight()->evaluate();
t=this->coerceTypes(l->getSimpleVarType(), r->getSimpleVarType());
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
{
@@ -208,13 +197,20 @@ operands *expression::evaluate()
output_cpp << this->op->boxName() << "= -" << l->boxName() << ";\n";
break;
case O_NOT:
this->op=new operands(t);
if (t!=T_INTVAR) error(E_TYPE_MISMATCH);
this->op=new operands(T_INTVAR);
this->op->generateBox(scope);
output_cpp << this->op->boxName() << "= !" << l->boxName() << ";\n";
break;
case O_INT_TO_FLOAT: /*Note: this duplicates functionality of variable assignment */
this->op=new operands(T_FLOATVAR);
this->op->generateBox(scope);
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:
this->op=new operands(t);
if (t!=T_INTVAR) error(E_TYPE_MISMATCH);
this->op=new operands(T_INTVAR);
this->op->generateBox(scope);
output_cpp << this->op->boxName() << "=" << l->boxName() << "%" << r->boxName() << ";\n";
break;
@@ -239,22 +235,14 @@ operands *expression::evaluate()
output_cpp << this->op->boxName() << "=" << l->boxName() << "*" << r->boxName() << ";\n";
break;
case O_OR:
if (t!=T_INTVAR)
{
errorLevel=E_TYPE_MISMATCH;
exit(1);
}
this->op=new operands(t);
if (t!=T_INTVAR) error(E_TYPE_MISMATCH);
this->op=new operands(T_INTVAR);
this->op->generateBox(scope);
output_cpp << this->op->boxName() << "=" << l->boxName() << "|" << r->boxName() << ";\n";
break;
case O_AND:
if (t!=T_INTVAR)
{
errorLevel=E_TYPE_MISMATCH;
exit(1);
}
this->op=new operands(t);
if (t!=T_INTVAR) error(E_TYPE_MISMATCH);
this->op=new operands(T_INTVAR);
this->op->generateBox(scope);
output_cpp << this->op->boxName() << "=" << l->boxName() << "&" << r->boxName() << ";\n";
break;
@@ -349,7 +337,7 @@ expression::~expression()
/* variable definitions */
variable::variable(ostream &scope, string &name, enum TYPES t):operands(t)
{
this->generateBox(scope);
this->generateBox(scope); /*TODO: FINISH THIS*/
}
variable *variable::getOrCreateVarName(string &name, enum TYPES t)
@@ -359,8 +347,10 @@ variable *variable::getOrCreateVarName(string &name, enum TYPES t)
return fn::getOrCreateVar(t, name, false);
}
/* TODO: verify if type is compatible */
operands op=operands::getOrCreateGlobal(name);
return reinterpret_cast<variable *>op;
shared_ptr<operands>op=operands::getOrCreateGlobal(name);
shared_ptr<variable>v=new variable();
v->assignment(new expression(op));
return v;
}
void variable::assignment(expression *value)
@@ -372,25 +362,21 @@ void variable::assignment(expression *value)
case T_FLOATVAR:
if (t==T_INTVAR)
{
/* TODO: convert int to float */
output_cpp << this->boxName() << "="
<< "static_cast<double>("
<< op->boxName() << ");\n";
}
else
{
if (t!=T_FLOATVAR)
{
errorLevel=E_TYPE_MISMATCH;
exit(1);
}
if (t!=T_FLOATVAR) error(E_TYPE_MISMATCH);
}
output_cpp << this->boxName() << "="
<< op->boxName() << ";\n";
break;
default:
if (t!=this->getType())
{
errorLevel=E_TYPE_MISMATCH;
exit(1);
}
if (t!=this->getType()) error(E_TYPE_MISMATCH);
output_cpp << this->boxName() << "="
<< op->boxName() << ";\n";
break;
}
output_cpp << this->boxName() << "="
<< op->boxName() << ";\n";
}

View File

@@ -16,16 +16,159 @@ fn *fn::getCurrentSub()
void fn::generateOnNSub(expression *e)
{
this->ret=new label();
fn::callStack.push_back(this);
shared_ptr<label>r=new label();
shared_ptr<fn> self=new fn(r);
fn::callStack.push_back(self);
label::generateOnNTo(e);
output_cpp << "case " << ret->getID() << ":\n";
r->generate();
}
void fn::generateGosub(shared_ptr<label> sub)
{
this->ret=new label();
fn::callStack.push_back(this);
output_cpp << "state=" << sub->getID() << ";\nbreak;\n";
output_cpp << "case " << ret->getID() << ":\n";
shared_ptr<label>r=new label();
shared_ptr<fn> self=new fn(r);
fn::callStack.push_back(self);
sub->generateJumpTo();
r->generate();
}
fn::fn(shared_ptr<label>gosub):codeType(T_GOSUB)
{
this->ret=gosub;
}
shared_ptr<fn> fn::getSub(string &name)
{
auto iter=fn::functions.find(name)
if(iter==fn::functions.end()) return NULL;
return iter->second;
}
operands *fn::generateCall(string &name, list<shared_ptr<operands> >&paramList)
{
auto v=params.begin();
shared_ptr<operands>current;
shared_ptr<fn>g=fn::getSub(name);
if (g==NULL)
{
errorLevel=E_SUBROUTINE_NOT_FOUND;
exit(1);
}
if (paramList.size()>params.size())
{
errorLevel=E_TOO_MANY_PARAMETERS;
exit(1);
}
output_cpp << "struct *f" << /* TODO: finish this */
<< "= new struct f" << g->getID();
while(paramList.size()>0)
{
current=paramList.front;
paramList.pop_front();
if(current->getSimpleVarType()!=*v->getType())
{
errorLevel=E_TYPE_MISMATCH;
exit(1);
}
*v->assignment(new expression(current));
++v;
}
return g->/*TODO FINISH THIS*/
}
void fn::generateReturn()
{
shared_ptr<fn>c=fn::getCurrent();
switch(c->getType())
{
case T_UNKNOWNFUNC:
this->kind=T_NONE;
/*fallthrough*/
case T_GOSUB:
c->ret->generateJumpTo();
fn::callStack.pop_back();
break;
default:
errorLevel=E_TYPE_MISMATCH;
exit(1);
}
}
operands *fn::generateReturn(expression *expr)
{
operands *out=expr->evaluate();
this->kind=out->getSimpleVarType();
this->ret->generateJumpTo();
fn::callStack.pop_back();
switch (this->getType())
{
case T_UNKNOWNFUNC:
return out;
case T_STRINGFUNC:
if (kind!=T_STRINGVAR)
{
errorLevel=E_TYPE_MISMATCH;
exit(1);
}
return out;
case T_INTFUNC:
if (kind!=T_INTVAR&&kind!=T_FLOATVAR)
{
errorLevel=E_TYPE_MISMATCH;
exit(1);
}
return out;
case T_FLOATFUNC:
if(kind!=T_FLOATVAR)
{
errorLevel=E_TYPE_MISMATCH;
exit(1);
}
return out;
case T_GOSUB:
{
errorLevel=E_GOSUB_CANNOT_RETURN_VALUE;
exit(1);
}
default:
{
errorLevel=E_BAD_SYNTAX;
exit(1);
}
}
}
/* not allowed in function definitions directly */
void fn::generateBreak()
{
error(E_BAD_SYNTAX);
}
void fn::close()
{
/* check if no returns and no return type */
enum CODES t=this->getType();
if (this->kind==T_UNKNOWN&&
(t==T_UNKNOWNFUNC||t==T_VOIDFUNC))
{
/* generate a typeless return */
this->generateReturn()
}
funcs_h << "};\n";
fn::locals.clear();
fn::statics.clear();
this->params.clear();
scopeGlobal=true;
}
fn::fn(string &s, enum CODES t):codeType(t)
{
if (!scopeGlobal) error(E_END_FUNCTION);
if (fn::functions->find(s)!=fn::functions.end()) error(E_DUPLICATE_SYMBOL);
this->id= ++nextID;
funcs_h << "struct f" << this->id <<"\n{\n";
this->ret=new label();
fn::functions[s]=this;
scopeGlobal=false;
}