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

View File

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

View File

@@ -16,16 +16,159 @@ fn *fn::getCurrentSub()
void fn::generateOnNSub(expression *e) void fn::generateOnNSub(expression *e)
{ {
this->ret=new label(); shared_ptr<label>r=new label();
fn::callStack.push_back(this); shared_ptr<fn> self=new fn(r);
fn::callStack.push_back(self);
label::generateOnNTo(e); label::generateOnNTo(e);
output_cpp << "case " << ret->getID() << ":\n"; r->generate();
} }
void fn::generateGosub(shared_ptr<label> sub) void fn::generateGosub(shared_ptr<label> sub)
{ {
this->ret=new label(); shared_ptr<label>r=new label();
fn::callStack.push_back(this); shared_ptr<fn> self=new fn(r);
output_cpp << "state=" << sub->getID() << ";\nbreak;\n"; fn::callStack.push_back(self);
output_cpp << "case " << ret->getID() << ":\n"; 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;
} }