rendered paste body%{#include <stdio.h>#include <string.h>#include <stdlib.h>#include "symboltable.h"#include "codegen.h"#include "stack.h"#define YYERROR_VERBOSE yes#define YYDEBUG 1extern int yylex();extern int yylineno;extern FILE *yyin;void yyerror(const char*);/* * forward declarations: * see documentation at the end of file */int combineTypes(int type1, int type2, int op);void matchTypes(int type1, int type2);void makeAssignment(symtabEntry* entry);/* variables */symtabEntry* currentFunction;stack* codeAddressStack;stack* labelStack;char tempString[MAX_LENGTH_OF_COMMAND];char* className;%}/* Typen */%union { char* string; double floatValue; int intValue; int type; int param[MAX_NUMBER_OF_PARAMETER + 1];}/* Token (KW steht fuer Keyword) */%token AND%token OR%token EQ%token NEQ%token LEQ%token GEQ%token LSS%token GRT%token KW_BEGIN%token KW_BOOLEAN%token KW_DO%token KW_ELSE%token KW_END%token KW_FLOAT%token KW_FOR%token KW_IF%token KW_INT%token KW_PRINTF%token KW_RETURN%token KW_VOID%token KW_WHILE%token <intValue> CONST_INT%token <floatValue> CONST_FLOAT%token <intValue> CONST_BOOLEAN%token <string> ID/* definition of association and precedence of operators */%left '+' '-' OR%left '*' '/' AND%nonassoc UMINUS/* workaround for handling dangling else *//* LOWER_THAN_ELSE stands for a not existing else */%nonassoc LOWER_THAN_ELSE%nonassoc KW_ELSE%type <param> lop_actualparameter%type <type> functioncall%type <type> type%type <type> assignment statassignment%type <type> expr%type <type> simpexpr%%/* see EBNF grammar for further information */program: /* empty */ | program declassignment ';' | program functiondefinition ;begin: '{' | KW_BEGIN ;end: '}' | KW_END ;functiondefinition: type ID { currentFunction = symtabInsert($2, $1, CLASS_FUNC); symtabEnterBlock(); } '(' opt_formalparameter ')' { symtabReverseParameterList(currentFunction); codegenEnterFunction(currentFunction); } begin { if (strcmp(currentFunction->name, "main") == 0 && (currentFunction->idtype != TYPE_VOID || currentFunction->paramIndex != 0)) { yyerror("Main function has to be void main().\n"); } } statementlist end { codegenLeaveFunction(currentFunction); symtabLeaveBlock(); } ;opt_formalparameter: /* empty */ {} | type ID lop_formalparameter { symtabEntry* entry = symtabInsert($2, $1, CLASS_PARAM); if ($1 == TYPE_VOID) yyerror("Parameters can't be void."); currentFunction->params[currentFunction->paramIndex++] = entry; } ;lop_formalparameter: /* empty */ {} | ',' type ID lop_formalparameter { symtabEntry* entry = symtabInsert($3, $2, CLASS_PARAM); if ($2 == TYPE_VOID) yyerror("Parameters can't be void."); if (currentFunction->paramIndex >= MAX_NUMBER_OF_PARAMETER-1) { yyerror("Maximal nesting level reached -> aborting (compiler-intern error).\n"); } currentFunction->params[currentFunction->paramIndex++] = entry; } ;statfunctioncall: ID '(' ')' { symtabEntry* entry = symtabGetIdent($1); if (entry->idclass != CLASS_FUNC) yyerror("Trying to make a function call on a non-function.\n"); if (entry->paramIndex != 0) yyerror("Actual but no formal parameters.\n"); } | ID '(' assignment lop_actualparameter ')' { symtabEntry* entry = symtabGetIdent($1); int i; int numOfActParam; if (entry->idclass != CLASS_FUNC) yyerror("Trying to make a function call on a non-function.\n"); for (i = 0; $4[i] != TYPE_TERMINATOR; i++); /* looking for the terminator */ if (i >= MAX_NUMBER_OF_PARAMETER) yyerror("Maximal nesting level reached -> aborting (compiler-intern error).\n"); $4[i + 1] = TYPE_TERMINATOR; $4[i] = $3; numOfActParam = i + 1; if (numOfActParam != entry->paramIndex) yyerror("Number of actual and formal parameters differ.\n"); for (i = numOfActParam - 1; i >= 0; i--) { matchTypes(entry->params[i]->idtype, $4[i]); } } ; functioncall: ID '(' ')' { symtabEntry* entry = symtabGetIdent($1); if (entry->idclass != CLASS_FUNC) yyerror("Trying to make a function call on a non-function.\n"); if (entry->paramIndex != 0) yyerror("Actual but no formal parameters.\n"); $$ = entry->idtype; } | ID '(' assignment lop_actualparameter ')' { symtabEntry* entry = symtabGetIdent($1); int i; int numOfActParam; if (entry->idclass != CLASS_FUNC) yyerror("Trying to make a function call on a non-function.\n"); for (i = 0; $4[i] != TYPE_TERMINATOR; i++); /* looking for the terminator */ if (i >= MAX_NUMBER_OF_PARAMETER) yyerror("Maximal nesting level reached -> aborting (compiler-intern error).\n"); $4[i + 1] = TYPE_TERMINATOR; $4[i] = $3; numOfActParam = i + 1; if (numOfActParam != entry->paramIndex) yyerror("Number of actual and formal parameters differ.\n"); for (i = numOfActParam - 1; i >= 0; i--) { matchTypes(entry->params[i]->idtype, $4[i]); } $$ = entry->idtype; } ; lop_actualparameter: /* empty */ { $$[0] = TYPE_TERMINATOR; } | ',' assignment lop_actualparameter { int i; for (i=0; $3[i]!=TYPE_TERMINATOR; i++) $$[i] = $3[i]; if (i>=MAX_NUMBER_OF_PARAMETER) yyerror("Maximal nesting level reached -> aborting (compiler-intern error).\n"); $$[i+1] = $3[i]; /* copying the terminator */ $$[i] = $2; } ;statementlist: /* empty */ | statementlist block ;block: begin { symtabEnterBlock(); } statementlist { symtabLeaveBlock(); } end | statement ;block2: begin { symtabEnterBlock(); } statementlist { symtabLeaveBlock(); } end | { symtabEnterBlock(); } statement { symtabLeaveBlock(); } ;statement: ifstatement | forstatement | whilestatement | returnstatement ';' | dowhilestatement ';' | printf ';' | declassignment ';' | statassignment ';' | statfunctioncall ';' {} /* just to override standard rule $$=$1 */ ;/* KW_ELSE has higher precedence, so an occuring 'else' will cause the *//* execution of the second rule */ifstatement: KW_IF '(' assignment ')' { if ($3 != TYPE_BOOLEAN) yyerror("constraint in if-branch has to be boolean.\n"); push(codeAddressStack, codegenGetCurrentAddress()); } block2 { int label1 = codegenGetNextLabel(); sprintf(tempString, "ifeq Label%d", label1); codegenInsertCommand(pop(codeAddressStack), tempString, -1); push(codeAddressStack, codegenGetCurrentAddress()); codegenAppendLabel(label1); } elsepart { int label2 = codegenGetNextLabel(); sprintf(tempString, "goto Label%d", label2); codegenInsertCommand(pop(codeAddressStack), tempString, 0); codegenAppendLabel(label2); } ;elsepart: /* empty */ %prec LOWER_THAN_ELSE | KW_ELSE block2 ;forstatement: KW_FOR '(' declassignment ';' expr { if ($5 != TYPE_BOOLEAN) yyerror("constraint in for-loop has to be boolean.\n"); } ';' statassignment ')' block2 | KW_FOR '(' statassignment ';' expr { if ($5 != TYPE_BOOLEAN) yyerror("constraint in for-loop has to be boolean.\n"); } ';' statassignment ')' block2 ;dowhilestatement: KW_DO block2 KW_WHILE '(' assignment ')' { if ($5 != TYPE_BOOLEAN) yyerror("constraint in do-while-statement hast to be boolean.\n"); } ;whilestatement: KW_WHILE '(' assignment ')' { if ($3 != TYPE_BOOLEAN) yyerror("while-constraint has to be boolean.\n"); } block2 ;returnstatement: KW_RETURN { if (currentFunction->idtype != TYPE_VOID) yyerror("return must not have a return-value in a void function.\n"); } | KW_RETURN assignment { matchTypes(currentFunction->idtype, $2); } ;printf: KW_PRINTF { codegenAppendCommand("getstatic java/lang/System/out Ljava/io/PrintStream;", 1); } '(' assignment ')' { if($4 == TYPE_INT) { codegenAppendCommand("invokevirtual java/io/PrintStream/println(I)V", -2); } else if($4 == TYPE_FLOAT) { codegenAppendCommand("invokevirtual java/io/PrintStream/println(F)V", -2); } else if($4 == TYPE_BOOLEAN) { codegenAppendCommand("invokevirtual java/io/PrintStream/println(Z)V", -2); } else { yyerror("Argument of printf() has to be printable (int, float, boolean).\n"); } } ;declassignment: type ID { if ($1 == TYPE_VOID) yyerror("Declaration of void variables is not allowed.\n"); symtabInsert($2, $1, CLASS_VAR); codegenAddVariable($2, $1); } | type ID '=' assignment { if ($1 == TYPE_VOID) yyerror("Declaration of void variables is not allowed.\n"); matchTypes($1, $4); symtabInsert($2, $1, CLASS_VAR); codegenAddVariable($2, $1); makeAssignment(symtabGetIdent($2)); } ;type: KW_BOOLEAN { $$ = TYPE_BOOLEAN; } | KW_FLOAT { $$ = TYPE_FLOAT; } | KW_INT { $$ = TYPE_INT; } | KW_VOID { $$ = TYPE_VOID; } ;statassignment: ID '=' assignment { symtabEntry* entry = symtabGetIdent($1); int type1 = entry->idtype; int type2 = $3; if ((entry->idclass != CLASS_VAR) && (entry->idclass != CLASS_PARAM)) { yyerror("Can only assign to variables or parameters.\n"); } matchTypes(type1, type2); $$ = type1; makeAssignment(symtabGetIdent($1)); } ;assignment: ID '=' assignment { symtabEntry* entry = symtabGetIdent($1); int type1 = entry->idtype; int type2 = $3; if ((entry->idclass != CLASS_VAR) && (entry->idclass != CLASS_PARAM)) { yyerror("Can only assign to variables or parameters.\n"); } matchTypes(type1, type2); $$ = type1; makeAssignment(symtabGetIdent($1)); } | expr { $$ = $1; } ;expr: simpexpr { $$ = $1; } | simpexpr EQ simpexpr { $$ = combineTypes($1, $3, EQ); } | simpexpr NEQ simpexpr { $$ = combineTypes($1, $3, NEQ); } | simpexpr LEQ simpexpr { $$ = combineTypes($1, $3, LEQ); } | simpexpr GEQ simpexpr { $$ = combineTypes($1, $3, GEQ); } | simpexpr LSS simpexpr { $$ = combineTypes($1, $3, LSS); } | simpexpr GRT simpexpr { $$ = combineTypes($1, $3, GRT); } ;simpexpr: simpexpr {push(codeAddressStack, codegenGetCurrentAddress());} '+' simpexpr { $$ = combineTypes($1, $4, '+'); if($1 == TYPE_INT && $4 == TYPE_FLOAT) { codegenInsertCommand(pop(codeAddressStack), "i2f", 0); codegenAppendCommand("fadd", -1); } else if($1 == TYPE_FLOAT && $4 == TYPE_INT) { codegenAppendCommand("i2f", 0); codegenAppendCommand("fadd", -1); pop(codeAddressStack); } else pop(codeAddressStack); if($1 == TYPE_INT && $4 == TYPE_INT) codegenAppendCommand("iadd", -1); if($1 == TYPE_FLOAT && $4 == TYPE_FLOAT) codegenAppendCommand("fadd", -1); } | simpexpr {push(codeAddressStack, codegenGetCurrentAddress());} '-' simpexpr { $$ = combineTypes($1, $4, '-'); if($1 == TYPE_INT && $4 == TYPE_FLOAT) { codegenInsertCommand(pop(codeAddressStack), "i2f", 0); codegenAppendCommand("fsub", -1); } else if($1 == TYPE_FLOAT && $4 == TYPE_INT) { codegenAppendCommand("i2f", 0); codegenAppendCommand("fsub", -1); pop(codeAddressStack); } else pop(codeAddressStack); if($1 == TYPE_INT && $4 == TYPE_INT) codegenAppendCommand("isub", -1); if($1 == TYPE_FLOAT && $4 == TYPE_FLOAT) codegenAppendCommand("fsub", -1); } | simpexpr OR simpexpr { $$ = combineTypes($1, $3, OR); } | simpexpr {push(codeAddressStack, codegenGetCurrentAddress());} '*' simpexpr { $$ = combineTypes($1, $4, '*'); if($1 == TYPE_INT && $4 == TYPE_FLOAT) { codegenInsertCommand(pop(codeAddressStack), "i2f", 0); codegenAppendCommand("fmul", -1); } else if($1 == TYPE_FLOAT && $4 == TYPE_INT) { codegenAppendCommand("i2f", 0); codegenAppendCommand("fmul", -1); pop(codeAddressStack); } else pop(codeAddressStack); if($1 == TYPE_INT && $4 == TYPE_INT) codegenAppendCommand("imul", -1); if($1 == TYPE_FLOAT && $4 == TYPE_FLOAT) codegenAppendCommand("fmul", -1); } | simpexpr {push(codeAddressStack, codegenGetCurrentAddress());} '/' simpexpr { $$ = combineTypes($1, $4, '/'); if($1 == TYPE_INT && $4 == TYPE_FLOAT) { codegenInsertCommand(pop(codeAddressStack), "i2f", 0); codegenAppendCommand("fdiv", -1); } else if($1 == TYPE_FLOAT && $4 == TYPE_INT) { codegenAppendCommand("i2f", 0); codegenAppendCommand("fdiv", -1); pop(codeAddressStack); } else pop(codeAddressStack); if($1 == TYPE_INT && $4 == TYPE_INT) codegenAppendCommand("idiv", -1); if($1 == TYPE_FLOAT && $4 == TYPE_FLOAT) codegenAppendCommand("fdiv", -1); } | simpexpr AND simpexpr { $$ = combineTypes($1, $3, AND); } | '-' simpexpr %prec UMINUS { $$ = $2; if (($2 != TYPE_INT) && ($2 != TYPE_FLOAT)) yyerror("Negation can only be used on float or int.\n"); if($2 == TYPE_INT) codegenAppendCommand("ineg", 0); if($2 == TYPE_FLOAT) codegenAppendCommand("fneg", 0); } | CONST_INT { $$ = TYPE_INT; sprintf(tempString, "ldc %d", $1); codegenAppendCommand(tempString, 1); } | CONST_FLOAT { $$ = TYPE_FLOAT; sprintf(tempString, "ldc %f", $1); codegenAppendCommand(tempString, 1); } | CONST_BOOLEAN { $$ = TYPE_BOOLEAN; sprintf(tempString, "ldc %d", $1); codegenAppendCommand(tempString, 1); } | functioncall { $$ = $1; } | ID { symtabEntry* entry = symtabGetIdent($1); int type = entry->idtype; if ((entry->idclass != CLASS_VAR) && (entry->idclass != CLASS_PARAM)) { yyerror("Trying to access something as a variable which is not.\n"); } $$ = type; if(symtabGetIdent($1)->global) { if(symtabGetIdent($1)->idtype == TYPE_INT) sprintf(tempString, "getstatic %s/%s I", className, $1); else if(symtabGetIdent($1)->idtype == TYPE_FLOAT) sprintf(tempString, "getstatic %s/%s F", className, $1); } else { if(symtabGetIdent($1)->idtype == TYPE_INT) sprintf(tempString, "iload %d", symtabGetIdent($1)->address); else if(symtabGetIdent($1)->idtype == TYPE_FLOAT) sprintf(tempString, "fload %d", symtabGetIdent($1)->address); } codegenAppendCommand(tempString, 1); } | '(' assignment ')' { $$ = $2; } ;%%int main(int argc, char* argv[]) { int success; if (argc != 2) yyin = stdin; else { yyin = fopen(argv[1], "r"); if (yyin == 0) { fprintf(stderr, "Fehler: Konnte Datei %s nicht zum lesen oeffnen.\n", argv[1]); exit(-1); } } yydebug = 0; className = "MinaOut"; /* Initialization */ codeAddressStack = newStack(); labelStack = newStack(); symtabInit(); codegenInit(); /* Parse */ success = yyparse(); /* Make sure there is a void main() */ if (symtabGetIdent("main")->idclass != CLASS_FUNC) yyerror("No void main() defined.\n"); /* Finish code */ codegenFinishCode(); return success;}void yyerror(const char* msg) { fprintf(stderr, "Error in line %d: %s\n", yylineno, msg); exit(-1);}/** * checks wether an assignment is valid between types. If not an error is * reported. * @param type1 type of first operand * @param type2 type of second operand */void matchTypes(int type1, int type2) { if ((type1 != type2) && (!((type1 == TYPE_FLOAT) && (type2 == TYPE_INT)))) { yyerror("Type mismatch.\n"); }}/** * checks wether an operation is valid between two types and returns * the type of the result. If it is not valid an error is reported. * @param type1 type of first operand * @param type2 type of second operand * @param op operation between operands * @return type of the result */int combineTypes(int type1, int type2, int op) { /* no operation allows void-arguments */ if ((type1 == TYPE_VOID) || (type2 == TYPE_VOID)) { yyerror("Void not allowed in arithmetical/logical operation.\n"); } /* EQ and NEQ allow integer, floats and booleans; GEQ, LEQ, ... only integer and floatsnly integer and floats */ else if ((op == EQ) || (op == NEQ) || (op == LEQ) || (op == GEQ) || (op == LSS) || (op == GRT)) { if (((op == LEQ) || (op == GEQ) || (op == LSS) || (op == GRT)) && ((type1 == TYPE_BOOLEAN) || (type2 == TYPE_BOOLEAN))) { yyerror("Boolean not allowed in arithmetical comparison.\n"); } if ((type1 == TYPE_BOOLEAN) || (type2 == TYPE_BOOLEAN)) { if ((type1 != TYPE_BOOLEAN) || (type2 != TYPE_BOOLEAN)) { yyerror("Booleans can only be compared with other Booleans.\n"); } } return TYPE_BOOLEAN; } /* OR and AND are boolean-only operations */ else if ((op == OR) || (op == AND)) { if ((type1 != TYPE_BOOLEAN) || (type2 != TYPE_BOOLEAN)) { yyerror("Boolean expected for logical operation.\n"); } return TYPE_BOOLEAN; } /* operations for numbers ... */ else if ((op == '+') || (op == '-') || (op == '*') || (op == '/')) { if ((type1 == TYPE_BOOLEAN) || (type2 == TYPE_BOOLEAN)) { yyerror("Boolean not allowed in arithmetical operation.\n"); } if ((type1 == TYPE_FLOAT) || (type2 == TYPE_FLOAT)) { return TYPE_FLOAT; } else { return TYPE_INT; } } /* just to make sure we haven't forget something ;-) */ else { yyerror("Unknown operation (compiler-intern error)\n"); } /* just to avoid a warning */ return 0;}/** * Generates an assignment */void makeAssignment(symtabEntry* entry) { if (entry->global == 0) { if ((entry->idtype == TYPE_INT) || (entry->idtype == TYPE_BOOLEAN)) sprintf(tempString, "istore %d", entry->address); else if (entry->idtype == TYPE_FLOAT) sprintf(tempString, "fstore %d", entry->address); else yyerror("compiler-intern error in makeAssignment.\n"); codegenAppendCommand(tempString, -1); } else { if (entry->idtype == TYPE_INT) sprintf(tempString, "putstatic %s/%s I", className, entry->name); else if (entry->idtype == TYPE_FLOAT) sprintf(tempString, "putstatic %s/%s F", className, entry->name); else if (entry->idtype == TYPE_BOOLEAN) sprintf(tempString, "putstatic %s/%s Z", className, entry->name); else yyerror("compiler-intern error in makeAssignment.\n"); codegenAppendCommand(tempString, -1); }}