diff --git a/.gitignore b/.gitignore index 61cec5a..db3ecb0 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,4 @@ flex.c bison.output yab *.o -libyab.so -libyab_x86.so +*.so diff --git a/data/licenses/Artistic b/data/licenses/Artistic new file mode 100644 index 0000000..5f22124 --- /dev/null +++ b/data/licenses/Artistic @@ -0,0 +1,131 @@ + + + + + The "Artistic License" + + Preamble + +The intent of this document is to state the conditions under which a +Package may be copied, such that the Copyright Holder maintains some +semblance of artistic control over the development of the package, +while giving the users of the package the right to use and distribute +the Package in a more-or-less customary fashion, plus the right to make +reasonable modifications. + +Definitions: + + "Package" refers to the collection of files distributed by the + Copyright Holder, and derivatives of that collection of files + created through textual modification. + + "Standard Version" refers to such a Package if it has not been + modified, or has been modified in accordance with the wishes + of the Copyright Holder as specified below. + + "Copyright Holder" is whoever is named in the copyright or + copyrights for the package. + + "You" is you, if you're thinking about copying or distributing + this Package. + + "Reasonable copying fee" is whatever you can justify on the + basis of media cost, duplication charges, time of people involved, + and so on. (You will not be required to justify it to the + Copyright Holder, but only to the computing community at large + as a market that must bear the fee.) + + "Freely Available" means that no fee is charged for the item + itself, though there may be fees involved in handling the item. + It also means that recipients of the item may redistribute it + under the same conditions they received it. + +1. You may make and give away verbatim copies of the source form of the +Standard Version of this Package without restriction, provided that you +duplicate all of the original copyright notices and associated disclaimers. + +2. You may apply bug fixes, portability fixes and other modifications +derived from the Public Domain or from the Copyright Holder. A Package +modified in such a way shall still be considered the Standard Version. + +3. You may otherwise modify your copy of this Package in any way, provided +that you insert a prominent notice in each changed file stating how and +when you changed that file, and provided that you do at least ONE of the +following: + + a) place your modifications in the Public Domain or otherwise make them + Freely Available, such as by posting said modifications to Usenet or + an equivalent medium, or placing the modifications on a major archive + site such as uunet.uu.net, or by allowing the Copyright Holder to include + your modifications in the Standard Version of the Package. + + b) use the modified Package only within your corporation or organization. + + c) rename any non-standard executables so the names do not conflict + with standard executables, which must also be provided, and provide + a separate manual page for each non-standard executable that clearly + documents how it differs from the Standard Version. + + d) make other distribution arrangements with the Copyright Holder. + +4. You may distribute the programs of this Package in object code or +executable form, provided that you do at least ONE of the following: + + a) distribute a Standard Version of the executables and library files, + together with instructions (in the manual page or equivalent) on where + to get the Standard Version. + + b) accompany the distribution with the machine-readable source of + the Package with your modifications. + + c) give non-standard executables non-standard names, and clearly + document the differences in manual pages (or equivalent), together + with instructions on where to get the Standard Version. + + d) make other distribution arrangements with the Copyright Holder. + +5. You may charge a reasonable copying fee for any distribution of this +Package. You may charge any fee you choose for support of this +Package. You may not charge a fee for this Package itself. However, +you may distribute this Package in aggregate with other (possibly +commercial) programs as part of a larger (possibly commercial) software +distribution provided that you do not advertise this Package as a +product of your own. You may embed this Package's interpreter within +an executable of yours (by linking); this shall be construed as a mere +form of aggregation, provided that the complete Standard Version of the +interpreter is so embedded. + +6. The scripts and library files supplied as input to or produced as +output from the programs of this Package do not automatically fall +under the copyright of this Package, but belong to whoever generated +them, and may be sold commercially, and may be aggregated with this +Package. If such scripts or library files are aggregated with this +Package via the so-called "undump" or "unexec" methods of producing a +binary executable image, then distribution of such an image shall +neither be construed as a distribution of this Package nor shall it +fall under the restrictions of Paragraphs 3 and 4, provided that you do +not represent such an executable image as a Standard Version of this +Package. + +7. C subroutines (or comparably compiled subroutines in other +languages) supplied by you and linked into this Package in order to +emulate subroutines and variables of the language defined by this +Package shall not be considered part of this Package, but are the +equivalent of input as in Paragraph 6, provided these subroutines do +not change the language in any way that would cause it to fail the +regression tests for the language. + +8. Aggregation of this Package with a commercial distribution is always +permitted provided that the use of this Package is embedded; that is, +when no overt attempt is made to make this Package's interfaces visible +to the end user of the commercial distribution. Such use shall not be +construed as a distribution of this Package. + +9. The name of the Copyright Holder may not be used to endorse or promote +products derived from this software without specific prior written permission. + +10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + The End diff --git a/yab2cpp.cpp b/yab2cpp.cpp new file mode 100644 index 0000000..052c125 --- /dev/null +++ b/yab2cpp.cpp @@ -0,0 +1,584 @@ +#include "yab2cpp.h" + +enum COMPILEERRORS errorLevel=E_OK; +unsigned int mode=0; +unsigned int indentLevel=0; +bool scopeGlobal=true; + +extern ofstream output_cpp; +extern ofstream funcs_h; +extern ofstream heap_h; +extern ofstream consts_h; +extern ofstream logfile; +extern ofstream varNames; + +extern ifstream src; + +/* private prototypes */ +void helpText(string &); +void shutDown(); +void logger(string &); + +/* process command line parameters */ +int main(int argc, char *argv[]) +{ + atexit(shutDown); + switch (argc) + { + case 1: + mode=COMPILE; + cout << "\nCompile initiated." << endl; + compile(); + break; + case 2: + if (argv[1][0]=='-') + { + switch (argv[1][1]) + { + case 'd': + cout << "\nIdentifier dump initiated." << endl; + mode=DUMP; + compile(); + break; + case 'v': + cout << "\n" << argv[0] << " version " + << VER_MAJOR << "." << VER_MINOR << "." << VER_RELEASE << endl; + break; + case 'V': + cout << "\nVerbose compile initiated." << endl; + mode=DUMP|COMPILE; + compile(); + break; + case 'D': + cout << "\nCompiler debug and dump mode initiated." << endl; + mode=DUMP|DEBUG; + compile(); + break; + case 'G': + cout << "\nDebug, dump and compile initiated." << endl; + mode=DUMP|DEBUG|COMPILE; + compile(); + break; + default: + helpText(argv[0]); + break; + } + } + break; + default: + helpText(argv[0]); + break; + } + return 0; +} + +/* print the help text to stdout */ +void helpText(string &commandname) +{ + cout << commandname << "[-d|D|V|v|G] < filename.mb\n" << + "Compiles filename.mb by default unless a flag is specified.\n" << + "\n The optional flags are as follows:\n" << + "-d is a dump of build to the parse.log file.\n" << + "-D is a dump of identifiers and logged build.\n" << + "-V is for a verbose build where the compiler logs and compiles.\n" << + "-v prints the version and exits.\n\n" << + "-G activates dump, debug and compile all at once.\n" << endl; +} + +/* open files and initialize them*/ +void setUp() +{ + if (mode & COMPILE) + { + /* compile mode */ + output_cpp=new ofstream("build/output.cpp"); + funcs_h=new ofstream ("functions.h"); + consts_h=new ofstream("consts.h"); + heap_h=new ofstream("heap.h"); + output_cpp << "#include \n#include \"consts.h\"\n" + << "#include \"heap.h\"\n#include \"functions.h\"\n" + << "unsigned int state=start;\nint run(){\nwhile (state>=start){\n" + << "switch(state){\ncase start:" << endl; + if (mode & DEBUG) + { + varNames=new ofstream("varnames.txt"); + } + } + if (mode & DUMP) + { + /* dump identifier mode */ + logfile=fopen("parse.log","w"); + logger("Setup complete."); + } +} + +/* write a note in the logfile */ +void logger(string &contents) +{ + unsigned int count; + if (mode & DEBUG) + { + count=indentLevel; + while (count > 0) + { + logfile << '\t'; + --count; + } + logfile << contents << endl; + } +} + +/* shutdown the compiler and exit */ +void shutDown() +{ + if (errorLevel != E_OK) cerr << "\nERROR: " << COMPILEERRORNAMES[errorLevel] << "\n\n" << endl; + if (fn::isCallStackEmpty()) + { + logger("Stack was empty"); + } + else + { + logger("Dumping stack."); + if (mode & DUMP && logfile != NULL) + { + fn::dumpCallStack(logfile); + } + } + operands::dumpVars(); + label::dumpLabels(); + output_cpp << "}\n}return state;\n}"<< endl; + } +} + +/* open files and compile */ +void compile() +{ + setUp(); + + /* parse */ + ctx = mb_create(NULL); + while(mb_parse(ctx, NULL)){logger("done");} + mb_destroy(ctx); + + shutDown(); +} + +/* methods for operands */ +static void operands::dumpVars(ostream &out) +{ + out << "Global Variables\n"; + for(auto iter=globals.begin(); iter!=globals.end(); ++iter) + { + out << "variable " << iter->first << " has ID " << iter->second << "\n"; + } + out << endl; +} +unsigned int operands::getOrCreateStr(string &s, ostream &k) +{ + auto iter=constStr.find(s); + if (iter!=constStr.end()) return iter->second; + ++nextID; + k << "const string sk" << nextID << "=\"" << s << "\";\n"; + constStr[s]=nextID; + return nextID; +} + +enum TYPES operands::getSimpleVarType() +{ + switch type + { + case T_FLOAT: + case T_FLOATCALL_ARRAY: + case T_FLOATVAR: + return T_FLOATVAR; + case T_INT: + case T_INTCALL_ARRAY: + case T_INTVAR: + return T_INTVAR; + case T_STRING: + case T_STRINGCALL_ARRAY: + case T_STRINGVAR: + return T_STRINGVAR; + } + return T_NONE; +} + +enum TYPES operands::coerceTypes() +{ + if this->isBinOp() + { + if (l->getSimpleVarType()==T_INTVAR && r->getSimpleVarType()==T_FLOATVAR) + { + /* promote l to float */ + t=T_FLOATVAR; + break; + } + if (l->getSimpleVarType()==T_FLOAT && r->getSimpleVarType()==T_INT) + { + /* promote r to float */ + t=T_FLOATVAR; + break; + } + if (l->getSimpleVarType()==r->getSimpleVarType()) + { + break; + } + errorLevel=E_TYPE_MISMATCH; + exit(1); + } + else + { + if (t==T_NONE) + { + errorLevel=E_TYPE_MISMATCH; + } + } + +} + +/* operands used by expression parser and variables */ + +operands::operands(enum TYPES t) +{ + this->id = ++nextID; + this->type=t; +} + +void operands::generateBox(ostream &out) +{ + switch (this->getSimpleVarType()) + { + case T_INTVAR: + out << "int v"; + break; + case T_FLOATVAR: + out << "double v"; + break; + case T_STRINGVAR: + out << "string v"; + break; + default: + errorLevel=E_TYPE_MISMATCH; + exit(1); + break; + } + out << this->getID() << ";\n"; +} + +void operands::boxName(ostream &out) +{ + switch (this->getType()) + { + case T_STRINGVAR: + case T_INTVAR: + case T_FLOATVAR: + break; + + default: + errorLevel=E_INTERNAL; + exit(1); + break; + } + out << "v" << this->getID(); +} + +/* expression parsing routines */ + +/* binary vs. unary ops */ +bool expression::isBinOp() +{ + switch this->getOp() + { + case O_NEGATE: + case O_NOT: + case O_INVERT: + return false; + break; + } + return true; +} + +operands *expression::evaluate(ostream &scope, ostream &output_cpp) +{ + operands *l, *r; + if (this->getOp()==O_TERM) return op; + l=this->getLeft()->evaluate(); + enum TYPES t=this->coerceTypes(); + l->getSimpleVarType(); + r=(this->isBinOp()?this->getRight()->evaluate():NULL); + switch (this->getOp()) + { + case O_INVERT: + this->op=new operands(t); + this->op->generateBox(scope); + output_cpp << this->op->boxName() << "= ~" << l->boxName() << ";\n"; + break; + case O_NEGATE: + this->op=new operands(t); + this->op->generateBox(scope); + output_cpp << this->op->boxName() << "= -" << l->boxName() << ";\n"; + break; + case O_NOT: + this->op=new operands(t); + this->op->generateBox(scope); + output_cpp << this->op->boxName() << "= !" << l->boxName() << ";\n"; + break; + /* TODO: Check for divide by zero error and modulo zero error */ + case O_REMAINDER: + this->op=new operands(t); + this->op->generateBox(scope); + output_cpp << this->op->boxName() << "=" << l->boxName() << "%" << r->boxName() << ";\n"; + break; + case O_DIVIDE: + this->op=new operands(t); + this->op->generateBox(scope); + output_cpp << this->op->boxName() << "=" << l->boxName() << "/" << r->boxName() << ";\n"; + break; + case O_PLUS: + this->op=new operands(t); + this->op->generateBox(scope); + output_cpp << this->op->boxName() << "=" << l->boxName() << "+" << r->boxName() << ";\n"; + break; + case O_MINUS: + this->op=new operands(t); + this->op->generateBox(scope); + output_cpp << this->op->boxName() << "=" << l->boxName() << "-" << r->boxName() << ";\n"; + break; + case O_MULTIPLY: + this->op=new operands(t); + this->op->generateBox(scope); + output_cpp << this->op->boxName() << "=" << l->boxName() << "*" << r->boxName() << ";\n"; + break; + case O_OR: + this->op=new operands(t); + this->op->generateBox(scope); + output_cpp << this->op->boxName() << "=" << l->boxName() << "|" << r->boxName() << ";\n"; + break; + case O_AND: + this->op=new operands(t); + this->op->generateBox(scope); + output_cpp << this->op->boxName() << "=" << l->boxName() << "&" << r->boxName() << ";\n"; + break; + case O_GREATER: + this->op=new operands(T_INTVAR); + this->op->generateBox(scope); + output_cpp << this->op->boxName() << "=(" << l->boxName() << ">" << r->boxName() << ")?-1:0;\n"; + break; + case O_LESS: + this->op=new operands(T_INTVAR); + this->op->generateBox(scope); + output_cpp << this->op->boxName() << "=(" << l->boxName() << "<" << r->boxName() << ")?-1:0;\n"; + break; + case O_GREATER_EQUAL: + this->op=new operands(T_INTVAR); + this->op->generateBox(scope); + output_cpp << this->op->boxName() << "=(" << l->boxName() << ">=" << r->boxName() << ")?-1:0;\n"; + break; + case O_LESS_EQUAL: + this->op=new operands(T_INTVAR); + this->op->generateBox(scope); + output_cpp << this->op->boxName() << "=(" << l->boxName() << "<=" << r->boxName() << ")?-1:0;\n"; + break; + case O_EQUAL: + this->op=new operands(T_INTVAR); + this->op->generateBox(scope); + output_cpp << this->op->boxName() << "=(" << l->boxName() << "==" << r->boxName() << ")?-1:0;\n"; + break; + case O_UNEQUAL: + this->op=new operands(T_INTVAR); + this->op->generateBox(scope); + output_cpp << this->op->boxName() << "=(" << l->boxName() << "!=" << r->boxName() << ")?-1:0;\n"; + break; + default: + errorLevel=E_INTERNAL; + exit(1); + break; + } + delete this->left; + this->left=NULL; + if (this->isBinOp()) + { + delete this->right; + this->right=NULL; + } + this->oper=O_TERM; + return this->op; +} + +expression::~expression() +{ + if(this->getOp()==O_TERM) + { + delete this->op; + } + else + { + delete this->left; + if (this->isBinOp()) + { + delete this->right; + } + } +} + +/* base class of all the code structure types */ + +codeType::codeType(enum CODES t) +{ + this->id= ++nextID; + nesting.push_back(this); + this->type=t; +} + +codeType *codeType::getCurrent() +{ + return nesting.back; +} + +void codeType::close() +{ + nesting.pop_back(); +} + +/* label definitions and helper routines */ + +label *label::find(string &s) +{ + auto ret=lookup.find(s); + return(ret==lookup.end()?NULL:ret->second); +} + +void label::dumpLabels(ostream &v) +{ + v << "Global Labels\n\n"; + for(auto iter=lookup.begin(); iter!=lookup.end(); ++iter) + { + v << "label " << iter->first << " has ID " << iter->second->getID() << "\n" ; + } + v << endl; +} + +void label::generateJumpTo(ostream &out) +{ + out << "state=" << this->getID() << ";\nbreak;\n"; +} + +void label::generateOnNSkip(ostream &k, list