diff --git a/.gitignore b/.gitignore index 8693b6d..6020296 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ yab *.so .vscode/* yab2cpp +tester +output/* diff --git a/Makefile b/Makefile index 2142861..4ee2ae2 100644 --- a/Makefile +++ b/Makefile @@ -6,19 +6,24 @@ LFLAGS := ODIR := build -YABCODESTRUCTURES_SOURCE_DEPS := yabCodeStructures.cpp yab2cpp.h yab2cpp.cpp -YAB2CPP_SOURCE_DEPS := yab2cpp.cpp yab2cpp.h -YABDATASTRUCTURES_SOURCE_DEPS := yabDataStructures.cpp yab2cpp.h yab2cpp.cpp -YABFUNCTIONS_SOURCE_DEPS := yabFunctions.cpp yab2cpp.h yab2cpp.cpp +YABCODESTRUCTURES_SOURCE_DEPS := yabCodeStructures.cpp yab2cpp.h yab2cpp.cpp tester.cpp +YAB2CPP_SOURCE_DEPS := yab2cpp.cpp yab2cpp.h tester.cpp +YABDATASTRUCTURES_SOURCE_DEPS := yabDataStructures.cpp yab2cpp.h yab2cpp.cpp tester.cpp +YABFUNCTIONS_SOURCE_DEPS := yabFunctions.cpp yab2cpp.h yab2cpp.cpp tester.cpp +YABIO_SOURCE_DEPS := yab2cpp.h yab2cpp.cpp tester.cpp all: binaries $(ODIR): @mkdir $(ODIR) -binaries: bin_yab2cpp +binaries: bin_yab2cpp bin_tester -YAB2CPP_OBJECT_DEPS := $(ODIR)/yabCodeStructures.o $(ODIR)/yabFunctions.o $(ODIR)/yabDataStructures.o $(ODIR)/yab2cpp.o +YAB2CPP_OBJECT_DEPS := $(ODIR)/yabCodeStructures.o $(ODIR)/yabFunctions.o $(ODIR)/yabDataStructures.o $(ODIR)/yabIO.o $(ODIR)/yab2cpp.o +TESTER_OBJECT_DEPS := $(ODIR)/yabCodeStructures.o $(ODIR)/yabFunctions.o $(ODIR)/yabDataStructures.o $(ODIR)/yabIO.o $(ODIR)/tester.o + +bin_tester: $(ODIR) $(TESTER_OBJECT_DEPS) + $(CC) -o tester $(TESTER_OBJECT_DEPS) $(LFLAGS) bin_yab2cpp: $(ODIR) $(YAB2CPP_OBJECT_DEPS) $(CC) -o yab2cpp $(YAB2CPP_OBJECT_DEPS) $(LFLAGS) @@ -26,9 +31,15 @@ bin_yab2cpp: $(ODIR) $(YAB2CPP_OBJECT_DEPS) $(ODIR)/yabCodeStructures.o: $(ODIR) $(YABCODESTRUCTURES_SOURCE_DEPS) $(CC) -c $(CFLAGS) yabCodeStructures.cpp -o $(ODIR)/yabCodeStructures.o +$(ODIR)/tester.o: $(ODIR) $(YAB2CPP_SOURCE_DEPS) + $(CC) -c $(CFLAGS) tester.cpp -o $(ODIR)/tester.o + $(ODIR)/yab2cpp.o: $(ODIR) $(YAB2CPP_SOURCE_DEPS) $(CC) -c $(CFLAGS) yab2cpp.cpp -o $(ODIR)/yab2cpp.o +$(ODIR)/yabIO.o: $(ODIR) $(YABIO_SOURCE_DEPS) + $(CC) -c $(CFLAGS) yabIO.cpp -o $(ODIR)/yabIO.o + $(ODIR)/yabDataStructures.o: $(ODIR) $(YABDATASTRUCTURES_SOURCE_DEPS) $(CC) -c $(CFLAGS) yabDataStructures.cpp -o $(ODIR)/yabDataStructures.o @@ -37,4 +48,4 @@ $(ODIR)/yabFunctions.o: $(ODIR) $(YABFUNCTIONS_SOURCE_DEPS) .PHONY: clean clean: - rm -rf build/* yab2cpp + rm -rf build/* yab2cpp tester \ No newline at end of file diff --git a/tester.cpp b/tester.cpp new file mode 100644 index 0000000..5d50903 --- /dev/null +++ b/tester.cpp @@ -0,0 +1,269 @@ +/* +** Tester.cpp +** +** Transpiler framework tester +** by Samuel D. Crow +** +** Based on Yab +** +*/ +#include "yab2cpp.h" +#include + +unordered_map >globals; +unordered_map >locals; +unordered_map >statics; + +/* These correspond to the enum COMPILE_ERRORS. */ +const char *COMPILE_ERROR_NAMES[]={ + "no error", + "incorrect syntax", + "wrong type", + "failed allocation", + "stack underflow", + "internal compiler error", + "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" +}; + +/* These correspond to the types of enum TYPES. */ +const string TYPENAMES[]={ + "unknown", + "none", + "string constant", + "integer constant", + "floating point constant", + "string variable", + "integer variable", + "floating point variable", + "string array or function", + "integer array or function", + "floating point array or function", + "string array or function", + "function" +}; + +const string CODETYPES[]={ + "print sequence", + "print segment", + "while loop", + "for loop", + "repeat loop", + "do loop", + "if statement", + "procedure statement", + "function statement", + "assignment", + "label", + "parameter list or array index", + "data item", + "function returning string", + "function returning floating point", + "function returning integer", + "function returning nothing", + "function" +}; + +enum COMPILE_ERRORS errorLevel=E_OK; +unsigned int indentLevel=0; +bool scopeGlobal=true; + +bool COMPILE=false; +bool DUMP=false; +bool DEBUG=false; +bool TRACE=false; + +ifstream src; +ofstream output_cpp; +ofstream funcs_h; +ofstream heap_h; +ofstream consts_h; +ofstream logfile; +ofstream varNames; + +/* private prototypes */ +void helpText(const string); +void setup(); +void compile(); +void shutDown(); + +/* process command line parameters */ +int main(int argc, char *argv[]) +{ + atexit(shutDown); + switch (argc) + { + case 1: + COMPILE=true; + cout << "\nCompile initiated." << endl; + compile(); + break; + case 2: + if (argv[1][0]=='-') + { + switch (argv[1][1]) + { + case 'd': + cout << "\nIdentifier dump initiated." << endl; + DUMP=true; + compile(); + break; + case 'v': + cout << "\n" << argv[0] << " version " + << VER_MAJOR << "." << VER_MINOR << "." << VER_RELEASE << endl; + break; + case 'V': + cout << "\nVerbose compile initiated." << endl; + DUMP=true; + COMPILE=true; + compile(); + break; + case 'D': + cout << "\nCompiler debug and dump mode initiated." << endl; + DUMP=true; + DEBUG=true; + compile(); + break; + case 'G': + cout << "\nDebug, dump and compile initiated." << endl; + DUMP=true; + DEBUG=true; + COMPILE=true; + compile(); + break; + case 't': + cout << "\nDebug, dump and trace initiated." << endl; + DEBUG=true; + DUMP=true; + TRACE=true; + compile(); + break; + default: + helpText(argv[0]); + break; + } + } + break; + default: + helpText(argv[0]); + break; + } + return 0; +} + +/* print the help text to stdout */ +void helpText(const string commandname) +{ + cout << commandname << "[-d|D|V|v|G|t] < 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" << + "-t activates dump, debug and trace\n" << + "-G activates dump, debug and compile all at once.\n" << endl; +} + +/* open files and initialize them*/ +void setUp() +{ + if (COMPILE) + { + /* compile mode */ + output_cpp.open("output/output.cpp"); + funcs_h.open("output/functions.h"); + consts_h.open("output/consts.h"); + heap_h.open("output/heap.h"); + output_cpp << "#include \n#include \"consts.h\"\n" + << "#include \"heap.h\"\n#include \"functions.h\"\n" + << "int main(int argc, char *argv[])\n{\n" + << "unsigned int state=start;\nint run(){\nwhile (state>=start){\n" + << "switch(state){\ncase start:" << endl; + if (DUMP) + { + varNames.open("varnames.txt"); + } + } + if (DEBUG) + { + /* dump identifier mode */ + logfile.open("parse.log"); + logger("Setup complete."); + } +} + +[[noreturn]] void error(enum COMPILE_ERRORS e) +{ + errorLevel=e; + exit(1); +} + +void indent() +{ + unsigned int count=indentLevel; + while (count > 0) + { + logfile << '\t'; + --count; + } + +} + +/* write a note in the logfile */ +void logger(string s) +{ + if (DEBUG) + { + indent(); + logfile << s << endl; + } +} + +/* shutdown the compiler and exit */ +void shutDown() +{ + if (errorLevel != E_OK) cerr << "\nERROR: " + << COMPILE_ERROR_NAMES[errorLevel] << "\n\n" << endl; + logger("Dumping stack."); + if (DUMP && (logfile)) + { + fn::dumpCallStack(); + } + varNames << "Global Variables\n"; + for(auto iter=globals.begin(); iter!=globals.end(); ++iter) + { + varNames << "variable " << iter->first + << " has ID " << iter->second << "\n"; + } + varNames << endl; + label::dumpLabels(); + output_cpp << "}\n}return state;\n}"<< endl; +} + +void testInt() +{ + string name="v"; + shared_ptrv= + variableType::getOrCreateVar(name, T_INTVAR); + v->assignment(shared_ptr(new expression( + shared_ptr(new constOp("2", T_INT))))); + shared_ptrprint=shared_ptr( + new printSegment(shared_ptr(new expression(v)))); + print->generate(); +} + +/* open files and compile */ +void compile() +{ + setUp(); + + testInt(); + + shutDown(); +} + diff --git a/yab2cpp.cpp b/yab2cpp.cpp index 319c9fb..72eda75 100644 --- a/yab2cpp.cpp +++ b/yab2cpp.cpp @@ -8,9 +8,9 @@ */ #include "yab2cpp.h" -unordered_map >globals; -unordered_map >locals; -unordered_map >statics; +unordered_map >globals; +unordered_map >locals; +unordered_map >statics; /* These correspond to the enum COMPILE_ERRORS. */ const char *COMPILE_ERROR_NAMES[]={ @@ -179,6 +179,7 @@ void setUp() heap_h.open("output/heap.h"); output_cpp << "#include \n#include \"consts.h\"\n" << "#include \"heap.h\"\n#include \"functions.h\"\n" + << "int main(int argc, char *argv[])\n{\n" << "unsigned int state=start;\nint run(){\nwhile (state>=start){\n" << "switch(state){\ncase start:" << endl; if (DUMP) diff --git a/yab2cpp.h b/yab2cpp.h index 476d162..4932277 100644 --- a/yab2cpp.h +++ b/yab2cpp.h @@ -22,16 +22,16 @@ using namespace std; #define VER_MINOR 0 #define VER_RELEASE 1 -class variable; +class variableType; extern ofstream output_cpp; extern ofstream funcs_h; extern ofstream heap_h; extern ofstream consts_h; extern ofstream logfile; extern ofstream varNames; -extern unordered_map >globals; -extern unordered_map >locals; -extern unordered_map >statics; +extern unordered_map >globals; +extern unordered_map >locals; +extern unordered_map >statics; extern const string CODETYPES[]; extern const string TYPENAMES[]; @@ -67,7 +67,7 @@ extern bool DUMP; extern bool DEBUG; extern bool TRACE; -/* list of all variable and constant types */ +/* list of all variableType and constant types */ enum TYPES { T_UNKNOWN=0, @@ -245,7 +245,7 @@ public: op=x; oper=O_TERM; } - /*TODO: Recycle temporary variables when not in debug mode*/ + /*TODO: Recycle temporary variableTypes when not in debug mode*/ virtual ~expression() {} }; @@ -357,21 +357,21 @@ public: {} }; -class variable:public operands +class variableType:public operands { enum SCOPES myScope; public: - static shared_ptrgetOrCreateVar(string &name, enum TYPES t); + static shared_ptrgetOrCreateVar(string &name, enum TYPES t); void assignment(shared_ptrvalue); - /* always call generateBox() after new variable() */ - variable(enum SCOPES s, string &name, enum TYPES t); - variable(); - ~variable() + /* always call generateBox() after new variableType() */ + variableType(enum SCOPES s, string &name, enum TYPES t); + variableType(); + ~variableType() {} }; -class arrayType:public variable +class arrayType:public variableType { list dimensions; public: @@ -383,23 +383,23 @@ public: shared_ptrvalue); explicit arrayType(string &name, enum TYPES t, listdim); - /*:variable(scope, name, t);*/ + /*:variableType(scope, name, t);*/ virtual ~arrayType() {} }; class forLoop:public codeType { - shared_ptrvar; - shared_ptrstartTemp; - shared_ptrstopTemp; + shared_ptrvar; + shared_ptrstartTemp; + shared_ptrstopTemp; shared_ptrinfrastructure; shared_ptrstep; public: virtual void generateBreak(); virtual void close(); - explicit forLoop(shared_ptrv, shared_ptrstart, + explicit forLoop(shared_ptrv, shared_ptrstart, shared_ptrstop, shared_ptrstepVal=NULL); virtual ~forLoop() {} @@ -410,7 +410,7 @@ class fn:codeType static unordered_map > functions; static list > callStack; static unsigned int nextID; - list >params; + list >params; string funcName; unsigned int id; enum TYPES kind; @@ -430,7 +430,7 @@ public: unsigned int getID() const {return this->id;} int getNumParams() const {return this->params.size();} - void addParameter(shared_ptr); + void addParameter(shared_ptr); shared_ptrgenerateCall(string &name, list >¶mList); @@ -444,26 +444,17 @@ public: {} }; -/* The next two structures are used to implement the PRINT statement. */ -class printSegments +class printSegment { shared_ptrcargo; - enum SEPARATORS kind; + enum SEPARATORS sep; public: - printSegments(shared_ptre, enum SEPARATORS k) - { - this->cargo=e; - this->kind=k; - } - printSegments(shared_ptre) {printSegments(e, S_LINEFEED);} - printSegments() {printSegments(NULL);} - virtual ~printSegments() + void generate(); + printSegment(shared_ptre, enum SEPARATORS s); + printSegment(shared_ptre) {printSegment(e, S_LINEFEED);} + printSegment() {printSegment(NULL);} + virtual ~printSegment() {} }; -struct printStatement -{ - list >segments; -}; - #endif diff --git a/yabCodeStructures.cpp b/yabCodeStructures.cpp index c852dad..a502151 100644 --- a/yabCodeStructures.cpp +++ b/yabCodeStructures.cpp @@ -203,7 +203,7 @@ void whileLoop::close() loopEnd->generate(); } -forLoop::forLoop(shared_ptrv, +forLoop::forLoop(shared_ptrv, shared_ptrstart, shared_ptrstop, shared_ptrstepVal):codeType(T_FORLOOP) { diff --git a/yabDataStructures.cpp b/yabDataStructures.cpp index 71b83fb..95fc718 100644 --- a/yabDataStructures.cpp +++ b/yabDataStructures.cpp @@ -330,7 +330,7 @@ shared_ptrexpression::evaluate() } /* variable definitions */ -variable::variable(enum SCOPES s, string &name, enum TYPES t):operands(t) +variableType::variableType(enum SCOPES s, string &name, enum TYPES t):operands(t) { this->myScope=s; switch (s) @@ -338,23 +338,23 @@ variable::variable(enum SCOPES s, string &name, enum TYPES t):operands(t) case S_LOCAL: if(locals.find(name)!=locals.end() || statics.find(name)!=statics.end() ) error(E_DUPLICATE_SYMBOL); - locals[name]=shared_ptr(this); + locals[name]=shared_ptr(this); break; case S_GLOBAL: if(globals.find(name)!=globals.end()) error(E_DUPLICATE_SYMBOL); - globals[name]=shared_ptr(this); + globals[name]=shared_ptr(this); break; case S_STATIC: if(locals.find(name)!=locals.end() || statics.find(name)!=statics.end() ) error(E_DUPLICATE_SYMBOL); - statics[name]=shared_ptr(this); + statics[name]=shared_ptr(this); break; default: error(E_INTERNAL); } } -shared_ptr variable::getOrCreateVar(string &name, enum TYPES t) +shared_ptr variableType::getOrCreateVar(string &name, enum TYPES t) { if (!scopeGlobal) { @@ -364,13 +364,13 @@ shared_ptr variable::getOrCreateVar(string &name, enum TYPES t) if(i!=statics.end())return i->second; } if (globals.find(name)!=globals.end())return globals[name]; - shared_ptrv=shared_ptr(new variable( + shared_ptrv=shared_ptr(new variableType( scopeGlobal?S_GLOBAL:S_LOCAL, name, t)); v->generateBox(scopeGlobal?S_GLOBAL:S_LOCAL); return v; } -void variable::assignment(shared_ptrvalue) +void variableType::assignment(shared_ptrvalue) { shared_ptrop=value->evaluate(); enum TYPES t=op->getSimpleVarType(); @@ -444,7 +444,7 @@ string arrayType::generateBox(enum SCOPES s) } arrayType::arrayType(string &name, enum TYPES t, listdim): - variable(S_GLOBAL, name, t) + variableType(S_GLOBAL, name, t) { this->dimensions=dim; } diff --git a/yabIO.cpp b/yabIO.cpp new file mode 100644 index 0000000..595c14b --- /dev/null +++ b/yabIO.cpp @@ -0,0 +1,51 @@ +/* +** Yab2Cpp +** +** Transpiler by Samuel D. Crow +** +** based on Yab +** +*/ +#include "yab2cpp.h" + +printSegment::printSegment(shared_ptre, enum SEPARATORS s) +{ + cargo=e; + sep=s; +} + +void printSegment::generate() +{ + if (cargo!=NULL) + { + shared_ptrop=cargo->evaluate(); + switch (op->getSimpleVarType()) + { + case T_STRINGVAR: + output_cpp << "printf(\"%s\", " << op->boxName() << ");\n"; + break; + case T_INTVAR: + output_cpp << "printf(\"%d\", " << op->boxName() << ");\n"; + break; + case T_FLOATVAR: + output_cpp << "printf(\"%f\", " << op->boxName() << ");\n"; + break; + default: + break; + } + } + switch (sep) + { + case S_LINEFEED: + output_cpp << "puts(\"\n\");\n"; + return; + case S_SEMICOLON: + return; + case S_COMMA: + output_cpp << "putc('\t');\n"; + return; + default: + error(E_BAD_SYNTAX); + break; + } +}