All pastes #1789155 Raw Edit

Something

public c v1 · immutable
#1789155 ·published 2010-02-07 16:46 UTC
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);	}}