%{ #include #include #include #include #include #include #include "parser.h" #include "interpret.h" bool show_icode = false; bool show_nametable = false; bool show_debug = false; bool std_input = false; bool wasErrors = false; static int base_type = TYPE_UNDEFINED; //... NameTable name_table; IProgram icode; static char error_text[128]; static int binOper = 0; static const Label* breakLabel = 0; static const Label* continueLabel = 0; static const Label* endifLabel = 0; static void genExpr(const TreeNode* tree); static void genFuncArgs(const string& name, const TreeNode* tree); static void genFunc_args(const TreeNode* tree); // recursive static void genFuncCallArgs(const TreeNode* tree); static void genFuncCall_args(const TreeNode* tree); // recursive static int listLength(const TreeNode* tree); static void releaseTree(TreeNodePtr& tree); // Either trueLabel or falseLabel == 0 static void genLExpr( const TreeNode* tree, // Represents a logical expression const Label* trueLabel, const Label* falseLabel ); static void genNop(const Label* label); static void genGoto(const Label* label); static const Label* genLabel(); static void printWarning(const char *text); static void printError(const char *text); %} %term NAME INT_CONST DOUBLE_CONST STRING_CONST REF %term WHILE ENDWHILE IF ENDIF ELSE ELSEIF TYPE BREAK CONTINUE %term INPUT OUTPUT OUTPUTLN %term FUNCTION ENDFUNCTION RETURN NONLOCAL %term SM CM RBR RPAR END ILLEGAL /*... %term INPUT OUTPUT OUTPUTLN ...*/ %right ASG %nonassoc RELOP %left LOR %left LAND %left LNOT %left PLUS MINUS %left MUL DIV MOD %right POW %nonassoc UMINUS %left LBR LPAR POINT %% program : stms { if (show_icode) { icode.print(); printf("--------\n\n"); } } | stms END { if (show_icode) { icode.print(); printf("--------\n\n"); } // YYACCEPT; return 0; } ; stms : stm { // printf("stms: stm\n"); } | stms stm { // printf("stms: stms stm\n"); } ; stm : oper { // printf("stm: oper\n"); } | decl { // printf("stm: decl\n"); } | funcdef { // printf("stm: funcdef\n"); } ; | error SM { // printf("stm: error SM\n"); } | error ENDIF { // printf("stm: error ENDIF\n"); } | error ENDWHILE { // printf("stm: error WHILE\n"); } | error ENDFUNCTION { // printf("stm: error FUNCTION\n"); } ; funcdef : FUNCTION NAME LPAR args RPAR { // printf("funcdef\n"); const Label* endfunction_label = genLabel(); const Label* function_label = genLabel(); IProgram::iterator c = icode.addNewCommand(); c->type = ICommand::function_def; c->label_ptr = function_label; c->label = function_label->number; c->string_value = $2.name; c->int_value = function_label->number; genGoto(endfunction_label); $1.label2 = endfunction_label; genNop(function_label); // Beginning of function genFuncArgs($2.name, $4.tree); releaseTree($4.tree); } funcbody ENDFUNCTION { IProgram::iterator c = icode.addNewCommand(); c->type = ICommand::function_exit; genNop($1.label2); // end of function } ; funcbody : /* empty */ | stms ; args : /* empty */ { $$.tree = 0; } | arglist { $$.tree = $1.tree; } ; arglist : arg { $$.tree = $1.tree; } | arglist CM arg { $3.tree->addLeftSon($1.tree); $$.tree = $3.tree; } ; arg : NAME { TreeNode* t = new TreeNode(); t->nodeType = TreeNode::list; TreeNode* t1 = new TreeNode(); t1->stringValue = $1.name; t1->nodeType = TreeNode::name; t->addRightSon(t1); $$.tree = t; } | REF NAME { TreeNode* t = new TreeNode(); t->nodeType = TreeNode::list; TreeNode* t1 = new TreeNode(); t1->stringValue = $2.name; t1->nodeType = TreeNode::name_ref; t->addRightSon(t1); $$.tree = t; } ; decl : NONLOCAL defs SM { // printf("decl\n"); } ; defs : def { // printf("def\n"); } | defs CM def { // printf("defs CM def\n"); } ; def : NAME { IProgram::iterator c = icode.addNewCommand(); c->type = ICommand::def_global; c->string_value = $1.name; } ; oper : expr SM { genExpr($1.tree); releaseTree($1.tree); IProgram::iterator c = icode.addNewCommand(); c->type = ICommand::pop; } | if | while | BREAK SM { if (breakLabel == 0) { yyerror("break out of loop"); } else { genGoto(breakLabel); } } | CONTINUE SM { if (continueLabel == 0) { yyerror("continue out of loop"); } else { genGoto(continueLabel); } } | ret { } /*... Now these are functions...*/ | input | output | outputln /*...*/ ; /*... assign : lval ASG expr SM { // printf("assign: right expr:\n"); // $3.tree->print(); genExpr($3.tree); releaseTree($3.tree); IProgram::iterator c = icode.addNewCommand(); c->type = ICommand::assign; } ; ...*/ ret : RETURN expr SM { // printf("return: expr:\n"); // $3.tree->print(); genExpr($2.tree); releaseTree($2.tree); IProgram::iterator c = icode.addNewCommand(); c->type = ICommand::ret; } | RETURN SM { IProgram::iterator c = icode.addNewCommand(); c->type = ICommand::int_const; c->int_value = 0; c = icode.addNewCommand(); c->type = ICommand::ret; } ; /*... lval : lval_name | lval_name LBR expr RBR { genExpr($3.tree); releaseTree($3.tree); IProgram::iterator c = icode.addNewCommand(); c->type = ICommand::array_lvalue; } ; lval_name : NAME { NameDef* n = name_table.addName($1.name); // printf("l-value %s\n", n->name); ++(n->numWrites); IProgram::iterator c = icode.addNewCommand(); c->type = ICommand::name_lvalue; c->name_ptr = n; } ; ...*/ expr : expr PLUS expr { binOper = TreeNode::plus; LBinOper: ; TreeNode* t = new TreeNode(); t->nodeType = binOper; t->addLeftSon($1.tree); t->addRightSon($3.tree); $$.tree = t; } | expr MINUS expr { binOper = TreeNode::minus; goto LBinOper; } | expr MUL expr { binOper = TreeNode::mul; goto LBinOper; } | expr DIV expr { binOper = TreeNode::div; goto LBinOper; } | expr MOD expr { binOper = TreeNode::mod; goto LBinOper; } | expr POW expr { binOper = TreeNode::power; goto LBinOper; } | MINUS expr %prec UMINUS { TreeNode* t = new TreeNode(); t->nodeType = TreeNode::uminus; t->addLeftSon($2.tree); $$.tree = t; } | expr LBR expr RBR { TreeNode* t = new TreeNode(); t->nodeType = TreeNode::array_element; t->addLeftSon($1.tree); t->addRightSon($3.tree); $$.tree = t; } | typecast { } | func { } | classmethod { } | expr ASG expr { // printf("expr : expr ASG expr\n"); TreeNode* t = new TreeNode(); t->nodeType = TreeNode::assign; t->addLeftSon($1.tree); t->addRightSon($3.tree); $$.tree = t; } | NAME { // printf("expr : NAME\n name=%s\n", $1.name.c_str()); TreeNode* t = new TreeNode(); t->stringValue = $1.name; t->nodeType = TreeNode::name; $$.tree = t; } | INT_CONST { TreeNode* t = new TreeNode(); t->nodeType = TreeNode::int_const; t->intValue = $1.int_value; $$.tree = t; } | DOUBLE_CONST { TreeNode* t = new TreeNode(); t->nodeType = TreeNode::double_const; t->doubleValue = $1.double_value; $$.tree = t; } | STRING_CONST { TreeNode* t = new TreeNode(); t->nodeType = TreeNode::string_const; t->stringValue = $1.name; $$.tree = t; } | array { } | LPAR expr RPAR { $$.tree = $2.tree; } ; typecast : TYPE LPAR expr RPAR { TreeNode* t = new TreeNode(); t->nodeType = TreeNode::typecast; t->intValue = $1.int_value; // base type t->addLeftSon($3.tree); $$.tree = t; } ; func : expr LPAR expressions RPAR { TreeNode* t = new TreeNode(); t->nodeType = TreeNode::function_call; t->addLeftSon($1.tree); if ($3.tree != 0) t->addRightSon($3.tree); $$.tree = t; } ; expressions: /* empty */ { $$.tree = 0; } | exprlist { $$.tree = $1.tree; } ; exprlist : expr { TreeNode* t = new TreeNode(); t->nodeType = TreeNode::list; t->addRightSon($1.tree); $$.tree = t; } | exprlist CM expr { TreeNode* t = new TreeNode(); t->nodeType = TreeNode::list; t->addRightSon($3.tree); t->addLeftSon($1.tree); $$.tree = t; } ; classmethod : expr POINT method { } ; method : NAME LPAR expressions RPAR { } ; array : LBR arraycontent RBR { $$.tree = $2.tree; } ; arraycontent : /* empty */ { TreeNode* t = new TreeNode(); t->nodeType = TreeNode::empty_array; $$.tree = t; } | arrayelements { $$.tree = $1.tree; } ; arrayelements : expr { TreeNode* t = new TreeNode(); t->nodeType = TreeNode::array_append; TreeNode* t1 = new TreeNode(); t1->nodeType = TreeNode::empty_array; t->addLeftSon(t1); t->addRightSon($1.tree); $$.tree = t; } | arrayelements CM expr { TreeNode* t = new TreeNode(); t->nodeType = TreeNode::array_append; t->addLeftSon($1.tree); t->addRightSon($3.tree); $$.tree = t; } ; if : ifh stms ENDIF { // printf("if: ifh stmd ENDIF\n"); genNop($1.label1); // Label of endif } | ifh stms { const Label* endif_label = genLabel(); $1.label2 = endif_label; $1.saved_label2 = endifLabel; endifLabel = endif_label; genGoto(endif_label); genNop($1.label1); } else ENDIF { genNop($1.label2); endifLabel = $1.saved_label2; } | ifh stms { const Label* endif_label = genLabel(); $1.label2 = endif_label; $1.saved_label2 = endifLabel; // Save previous endif label endifLabel = endif_label; genGoto(endif_label); genNop($1.label1); } elseifs ENDIF { genNop($1.label2); endifLabel = $1.saved_label2; } ; ifh : IF LPAR lexpr RPAR { // printf("ifh\n"); const Label* l = genLabel(); // $3.tree->print(); genLExpr($3.tree, 0, l); $$.label1 = l; } ; elseifs : elseiflist | elseiflist else ; elseiflist : elseif | elseiflist elseif ; else : ELSE stms ; elseif : elseifh stms { genGoto(endifLabel); genNop($1.label1); } ; elseifh : ELSEIF LPAR lexpr RPAR { const Label* l = genLabel(); genLExpr($3.tree, 0, l); $$.label1 = l; } ; lexpr : expr RELOP expr { TreeNode* t = new TreeNode(); t->nodeType = TreeNode::relop; t->intValue = $2.int_value; // operation: RELOP_EQ, etc. t->addLeftSon($1.tree); t->addRightSon($3.tree); $$.tree = t; } | lexpr LOR lexpr { TreeNode* t = new TreeNode(); t->nodeType = TreeNode::lor; t->addLeftSon($1.tree); t->addRightSon($3.tree); $$.tree = t; } | lexpr LAND lexpr { TreeNode* t = new TreeNode(); t->nodeType = TreeNode::land; t->addLeftSon($1.tree); t->addRightSon($3.tree); $$.tree = t; } | LNOT lexpr { TreeNode* t = new TreeNode(); t->nodeType = TreeNode::lnot; t->addLeftSon($2.tree); $$.tree = t; } | LPAR lexpr RPAR { $$.tree = $2.tree; } ; while : whileh stms ENDWHILE { // printf("while\n"); // Restore loop labels genGoto($1.label1); genNop($1.label2); continueLabel = $1.saved_label1; breakLabel = $1.saved_label2; } ; whileh : WHILE LPAR lexpr RPAR { // printf("whileh\n"); const Label* beginLab = genLabel(); const Label* endLab = genLabel(); $$.label1 = beginLab; $$.label2 = endLab; genNop(beginLab); genLExpr($3.tree, 0, endLab); $$.saved_label1 = continueLabel; $$.saved_label2 = breakLabel; continueLabel = beginLab; breakLabel = endLab; } ; input : INPUT expr SM { genExpr($2.tree); releaseTree($2.tree); IProgram::iterator c = icode.addNewCommand(); c->type = ICommand::input; } ; output : OUTPUT outputlst SM ; outputln : OUTPUTLN SM { LNewLine: ; // Output the "new line" character IProgram::iterator c = icode.addNewCommand(); c->type = ICommand::string_const; c->string_value = "\n"; c = icode.addNewCommand(); c->type = ICommand::output; } | OUTPUTLN outputlst SM { goto LNewLine; } ; outputlst : expr { genExpr($1.tree); releaseTree($1.tree); IProgram::iterator c = icode.addNewCommand(); c->type = ICommand::output; } | outputlst CM expr { genExpr($3.tree); releaseTree($3.tree); IProgram::iterator c = icode.addNewCommand(); c->type = ICommand::output; } ; /*... Now these are functions input : INPUT inputlst SM ; inputlst : lval { LInput: ; IProgram::iterator c = icode.addNewCommand(); c->type = ICommand::input; } | inputlst CM lval { goto LInput; } ; output : OUTPUT outputlst SM ; outputln : OUTPUTLN SM { LNewLine: ; // Output the "new line" character IProgram::iterator c = icode.addNewCommand(); c->type = ICommand::string_const; c->string_value = "\n"; c = icode.addNewCommand(); c->type = ICommand::output; } | OUTPUTLN outputlst SM { goto LNewLine; } ; outputlst : expr { LOutput: ; genExpr($1.tree); releaseTree($1.tree); IProgram::iterator c = icode.addNewCommand(); c->type = ICommand::output; } | outputlst CM expr { goto LOutput; } ; ...*/ %% static void printHelp(); int main(int argc, char *argv[]) { FILE* f = NULL; // Parse arguments of command line int argIdx = 1; while (argIdx < argc) { const char* arg = argv[argIdx]; const char* p = arg; if (*p == '-') { ++p; if (*p == '-') ++p; if (strcmp(p, "show_icode") == 0) { show_icode = true; } else if (strcmp(p, "show_nametable") == 0) { show_nametable = true; } else if (strcmp(p, "std_input") == 0) { std_input = true; } else if (strcmp(p, "show_debug") == 0) { show_debug = true; show_icode = true; show_nametable = true; } else { printHelp(); return 1; } } else { break; } ++argIdx; } if (argIdx >= argc && !std_input) { printHelp(); return 1; } if (!std_input) { // Open an input file FILE* f = fopen(argv[argIdx], "r"); if (f != NULL) { yyin = f; } else { perror("Cannot open input file"); return (-1); } } yyparse(); if (f != NULL) fclose(f); if (wasErrors) // Do not execute the program with syntax errors return (-1); // Initialize the random generator time_t tim; srand(time(&tim)); ICodeInterpretator interpretator; interpretator.initialize(&icode); int lastLine = 0; // Number of the last line executed try { interpretator.execute( lastLine // Output parameter used in case of exception ); } catch (InterpretatorException& e) { printf( "InterpretatorException: %s in line %d\n", e.reason, lastLine ); exit(1); } catch (StackException& e) { printf( "StackException: %s in line %d\n", e.reason, lastLine ); exit(1); } catch (OutOfRangeException& e) { printf( "OutOfRangeException: %s in line %d\n", e.reason, lastLine ); exit(1); } return 0; } static void printHelp() { printf( "Delta Compiler + Interpreter.\n" "Usage:\n" " delta [-show_icode] [-show_nametable]\n" " [-std_input] [-debug] [source_file]\n" "where\n" "-show_icode Print intermediate code\n" "-show_nametable Print global nametable\n" "-std_input Read program from standard input\n" "-show_debug Print a lot of debugging information\n" "source_file File with a source program\n" ); } int yyerror(const char *s) { printf("%s in line %d\n", s, yylineno); wasErrors = true; return 0; } static void genExpr(const TreeNode* tree) { // printf("genExpr\n"); // tree->print(); if (tree == 0) return; IProgram::iterator c; int binop; switch(tree->nodeType) { case TreeNode::int_const: c = icode.addNewCommand(); c->type = ICommand::int_const; c->int_value = tree->intValue; break; case TreeNode::double_const: c = icode.addNewCommand(); c->type = ICommand::double_const; c->double_value = tree->doubleValue; break; case TreeNode::string_const: c = icode.addNewCommand(); c->type = ICommand::string_const; c->string_value = tree->stringValue; break; case TreeNode::name: c = icode.addNewCommand(); c->type = ICommand::name; c->string_value = tree->stringValue; break; case TreeNode::empty_array: c = icode.addNewCommand(); c->type = ICommand::empty_array; break; case TreeNode::array_append: genExpr(tree->left); genExpr(tree->right); c = icode.addNewCommand(); c->type = ICommand::array_append; break; case TreeNode::array_element: if (tree->left == 0 || tree->right == 0) { yyerror("Illegal expression"); return; } genExpr(tree->left); genExpr(tree->right); c = icode.addNewCommand(); c->type = ICommand::array_element; break; case TreeNode::plus: binop = ICommand::plus; LBinOp: ; if (tree->left == 0 || tree->right == 0) { yyerror("Illegal expression"); return; } // printf("genExpr: binop=%d\n", binop); genExpr(tree->left); genExpr(tree->right); c = icode.addNewCommand(); c->type = binop; break; case TreeNode::minus: binop = ICommand::minus; goto LBinOp; case TreeNode::mul: binop = ICommand::mul; goto LBinOp; case TreeNode::div: binop = ICommand::div; goto LBinOp; case TreeNode::mod: binop = ICommand::mod; goto LBinOp; case TreeNode::power: binop = ICommand::power; goto LBinOp; case TreeNode::assign: binop = ICommand::assign; goto LBinOp; case TreeNode::uminus: if (tree->left == 0) { yyerror("Illegal expression"); return; } genExpr(tree->left); c = icode.addNewCommand(); c->type = ICommand::uminus; break; case TreeNode::typecast: if (tree->left == 0) { yyerror("Illegal expression"); return; } genExpr(tree->left); c = icode.addNewCommand(); c->type = ICommand::typecast; c->int_value = tree->intValue; // base type break; case TreeNode::function_call: genFuncCallArgs(tree->right); genExpr(tree->left); c = icode.addNewCommand(); c->type = ICommand::function_call; break; default: yyerror("Illegal expression"); } } static void genFuncArgs(const string& name, const TreeNode* tree) { IProgram::iterator c = icode.addNewCommand(); c->type = ICommand::function_entry; c->string_value = name; int numArgs = 0; if (tree != 0) { //... numArgs = TreeNode::height(tree) - 1; numArgs = listLength(tree); } c = icode.addNewCommand(); c->type = ICommand::int_const; c->int_value = numArgs; c = icode.addNewCommand(); // Check a number of args c->type = ICommand::cmp; // Compare c = icode.addNewCommand(); c->type = ICommand::if_throw; c->ext = ICommand::ne; c->string_value = "Incorrect number of function arguments"; if (tree != 0) genFunc_args(tree); } static void genFunc_args(const TreeNode* tree) { if (tree == 0) return; assert(tree->nodeType == TreeNode::list); assert( tree->right != 0 && ( tree->right->nodeType == TreeNode::name || tree->right->nodeType == TreeNode::name_ref ) ); if (tree->left != 0) { genFunc_args(tree->left); } IProgram::iterator c = icode.addNewCommand(); c->type = ICommand::name; c->string_value = tree->right->stringValue; c = icode.addNewCommand(); c->type = ICommand::exch; c = icode.addNewCommand(); if (tree->right->nodeType == TreeNode::name) c->type = ICommand::assign_local; else c->type = ICommand::assign_ref; c = icode.addNewCommand(); c->type = ICommand::pop; } static void genFuncCallArgs(const TreeNode* tree) { int numArgs = 0; if (tree != 0) { //... numArgs = TreeNode::height(tree) - 1; numArgs = listLength(tree); } genFuncCall_args(tree); IProgram::iterator c = icode.addNewCommand(); c->type = ICommand::int_const; c->int_value = numArgs; } static void genFuncCall_args(const TreeNode* tree) { if (tree == 0) return; assert(tree->right != 0); genExpr(tree->right); if (tree->left != 0) { genFuncCall_args(tree->left); } } static int listLength(const TreeNode* tree) { int l = 0; while (tree != 0 && tree->nodeType == TreeNode::list) { if (tree->right != 0) ++l; tree = tree->left; } return l; } static void genNop(const Label* label) { IProgram::iterator c = icode.addNewCommand(); label->location = c; c->type = ICommand::nop; c->label_ptr = label; c->label = label->number; } static void genGoto(const Label* label) { IProgram::iterator c = icode.addNewCommand(); c->type = ICommand::go_to; c->goto_label_ptr = label; c->goto_label = label->number; } static int baseLabel = 0; static const Label* genLabel() { ++baseLabel; const Label* lab = label_table.addLabel(baseLabel); return lab; } static void genLExpr( const TreeNode* tree, // Represents a logical expression const Label* trueLabel, const Label* falseLabel ) { IProgram::iterator c; switch (tree->nodeType) { case TreeNode::relop: if (tree->left == 0 || tree->right == 0) { yyerror("Illegal comparing"); return; } genExpr(tree->left); genExpr(tree->right); c = icode.addNewCommand(); c->type = ICommand::cmp; // Compare c = icode.addNewCommand(); c->type = ICommand::if_goto; if (trueLabel != 0) { switch (tree->intValue) { // relation case RELOP_EQ: c->ext = ICommand::eq; break; case RELOP_NE: c->ext = ICommand::ne; break; case RELOP_LT: c->ext = ICommand::lt; break; case RELOP_LE: c->ext = ICommand::le; break; case RELOP_GT: c->ext = ICommand::gt; break; case RELOP_GE: c->ext = ICommand::ge; break; } c->goto_label_ptr = trueLabel; c->goto_label = trueLabel->number; } else { assert(falseLabel != 0); switch (tree->intValue) { // relation case RELOP_EQ: c->ext = ICommand::ne; break; // Inverse case RELOP_NE: c->ext = ICommand::eq; break; case RELOP_LT: c->ext = ICommand::ge; break; case RELOP_LE: c->ext = ICommand::gt; break; case RELOP_GT: c->ext = ICommand::le; break; case RELOP_GE: c->ext = ICommand::lt; break; } c->goto_label_ptr = falseLabel; c->goto_label = falseLabel->number; } break; case TreeNode::lor: if (tree->left == 0 || tree->right == 0) { yyerror("Illegal logical expression"); return; } if (trueLabel != 0) { genLExpr(tree->left, trueLabel, 0); genLExpr(tree->right, trueLabel, 0); } else { const Label* lab = genLabel(); genLExpr(tree->left, lab, 0); genLExpr(tree->right, 0, falseLabel); genNop(lab); } break; case TreeNode::land: if (falseLabel != 0) { genLExpr(tree->left, 0, falseLabel); genLExpr(tree->right, 0, falseLabel); } else { const Label* lab = genLabel(); genLExpr(tree->left, 0, lab); genLExpr(tree->right, trueLabel, 0); genNop(lab); } break; case TreeNode::lnot: genLExpr(tree->left, falseLabel, trueLabel); break; } } static void printWarning(const char *text) { fprintf(stderr, "Warning: %s\n", text); } static void printError(const char *text) { fprintf(stderr, "Error: %s\n", text); } static void releaseTree(TreeNodePtr& tree) { TreeNode::release(tree); tree = 0; }