%{ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Μιχάλης Παπακυριάκου mpapakyr@softlab.ece.ntua.gr * * * * Θοδωρής Τσόκος tsokos@softlab.ece.ntua.gr * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Εισαγωγή στους Μεταγλωττιστές * * Εργαστήριο Τεχνολογίας Λογισμικού * * * * Θέμα: `Κατασκευή Μεταγλωττιστή γλώσσας Calvin` * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * File Name: grammar.y * * Version: 1.0 Final * * Description: Bison source file * * Date: 21/8/2003 3:25πμ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* #define NDEBUG */ #include #include #include #include #include #include #include "quad2asm.c" #include "lexyy.c" #include "symbtest.c" void CheckParam(char *,SymbolEntry *); SymbolEntry *callFunctionParams(char , SymbolEntry *, char *,Type ,SymbolEntry *); void endFunctionParams(SymbolEntry *); SymbolEntry *cur_func, *tmp, *main_func, *func_call, *param; /*Quad_list *L1, *L2;*/ Quad_list *L3; Type cur_type,n; FILE *fp_quad, *fp_asm, *fp_data; char *f_name; bool check4void, forw, arr_pred = false, if_while_pred = false, extrn = true, end = false; int ass_pred = 0; typedef struct stack2_tag { SymbolEntry *data; struct stack2_tag *next; } stack2; void push2(SymbolEntry *); SymbolEntry *pop2(); SymbolEntry *get(); stack2 *Top2; b b_op,bd_op; c c_op,cd_op; d d_op,dd_op; int x,label_c = 1; %} /* Define the type of semantic values */ %union { char name[256]; /* Semantic val of terminal symbols */ int integer; char ch; char *s; SymbolEntry *se; Type t; struct { bool code; Type t; SymbolEntry *v; } e; struct { Quad_list *true_list, *false_list; } b; struct { Quad_list *next; } stmnt; struct { int x; Quad_list *L1, *L2; } tmp; }; /* * Declaration of Calvin tokens * and the precedence and associativity of operators */ %token TK_WORD_CHAR %token TK_WORD_ELSE %token TK_WORD_IF %token TK_WORD_INTEGER %token TK_WORD_MAIN %token TK_WORD_RETURN %token TK_WORD_VOID %token TK_WORD_WHILE %nonassoc TK_ASSIGN %left TK_OP_PLUS, TK_OP_MINUS %left TK_OP_MULT, TK_OP_DIV %left TK_OP_MOD %nonassoc TK_OP_EQUAL %nonassoc TK_OP_NOTEQUAL %nonassoc TK_OP_GREATEREQ %nonassoc TK_OP_GREATER %nonassoc TK_OP_LESSEQ %nonassoc TK_OP_LESS %left TK_OP_OR %left TK_OP_AND %left TK_OP_NOT %token TK_AGKISTRO_OPEN %token TK_AGKISTRO_CLOSE %token TK_AGK_OPEN %token TK_AGK_CLOSE %token TK_PAR_OPEN %token TK_PAR_CLOSE %token TK_COMMA %token TK_AMPERSAND %token TK_EROTIM %token TK_IDENT %token TK_INT %token TK_CHAR %token TK_STRING %type if_tail %type stmnt_list %type stmnt_list_ne %type TK_IDENT %type TK_INT %type TK_CHAR %type TK_STRING %type data_type %type l_value %type pure_expr %type expression %type func_call %type func_prot %type actual_param_l %type void_func_call %type b_expression %type func_header %type statement %type compound_stmnt /* * Declare the non-terminal symbols and the * types of their semantic values */ %start program %% program: { initSymbolTable(256); openScope(); } extrn_and_start {initAsmFile(fp_asm);openScope();} local_def_list { b_op.q_union.x = main_func = newFunction("main"); endFunctionHeader(b_op.q_union.x, typeVoid); genquad(label_c++, UNIT_QUAD, b_op, c_op, d_op, 0); //print_one_quad(fp_quad, head3); } compound_stmnt { //fprintf(stdout, "Ready to backpatch (Comp/NEXT):%d\n",label_c); //printQuadList(stdout, $6.next); BackPatch($6.next, label_c); b_op.q_union.x = main_func; genquad(label_c, ENDU_QUAD, b_op, c_op, d_op, 0); ScopeQuads2file(fp_quad, &head3); ScopeQuads2asm(fp_asm, &head2); //printSymbolTable(); closeScope(); end = true; } ; local_def_list: /* empty */ | local_def local_def_list ; extrn_and_start: TK_WORD_VOID TK_WORD_MAIN TK_PAR_OPEN TK_PAR_CLOSE { extrn = false; /* b_op.q_union.x = main_func = newFunction("main"); openScope(); endFunctionHeader(b_op.q_union.x, typeVoid); genquad(label_c++, UNIT_QUAD, b_op, c_op, d_op, 0); print_one_quad(fp_quad, head3); */ } | func_prot extrn_and_start { $1->nestingLevel = 0; // push_FuncList(currentScope->nestingLevel, 0, $1->id); fprintf(fp_data, "extrn _%s:near\n", $1->id); } ; local_def: func_prot {;} | func_def {;} | var_def ; func_prot: func_header TK_EROTIM { closeScope(); forwardFunction($1.v); $$ = $1.v; } ; func_def: func_header local_def_list { cur_func = $1.v; b_op.q_union.x = $1.v; genquad(label_c++, UNIT_QUAD, b_op, c_op, d_op, 0); } compound_stmnt { //fprintf(stdout, "Ready to backpatch (Comp/NEXT):%d\n",label_c); //printQuadList(stdout, $4.next); BackPatch($4.next, label_c); b_op.q_union.x = $1.v; genquad(label_c++, ENDU_QUAD, b_op, c_op, d_op, 0); //printSymbolTable(); ScopeQuads2file(fp_quad, &head3); ScopeQuads2asm(fp_asm, &head2); closeScope(); } ; func_header: data_type TK_IDENT { cur_func = newFunction($2); openScope(); /* *** */ if(!cur_func->u.eFunction.is2) { if(extrn) push_FuncList(currentScope->nestingLevel, 0, $2); else push_FuncList(currentScope->nestingLevel, block_counter++, $2); /* *** */ } } TK_PAR_OPEN maybe_formal TK_PAR_CLOSE { $$.v = cur_func; $$.t = $1; endFunctionHeader(cur_func, $1); } | TK_WORD_VOID TK_IDENT { cur_func = newFunction($2); openScope(); if(!cur_func->u.eFunction.is2) { if(extrn) push_FuncList(currentScope->nestingLevel, 0, $2); else push_FuncList(currentScope->nestingLevel, block_counter++, $2); /* *** */ } } TK_PAR_OPEN maybe_formal TK_PAR_CLOSE { $$.v = cur_func; $$.t = typeVoid; endFunctionHeader(cur_func, typeVoid); } ; maybe_formal: /* empty */ | formal_param {;} | formal_param TK_COMMA maybe_formal {;} ; formal_param: data_type TK_IDENT { newParameter($2, $1, PASS_BY_VALUE, cur_func); } | data_type TK_IDENT TK_AGK_OPEN TK_AGK_CLOSE { n = typeIArray($1); newParameter($2, n, PASS_BY_VALUE, cur_func); } | data_type TK_AMPERSAND TK_IDENT { newParameter($3, $1, PASS_BY_REFERENCE, cur_func); } | data_type TK_AMPERSAND TK_IDENT TK_AGK_OPEN TK_AGK_CLOSE { n = typeIArray($1); newParameter($3, n, PASS_BY_REFERENCE, cur_func); } ; data_type: TK_WORD_INTEGER {$$ = typeInteger;cur_type = typeInteger;} | TK_WORD_CHAR {$$ = typeChar;cur_type = typeChar;} ; var_def: data_type def_var_list TK_EROTIM {;} ; def_var_list: def_one_var | def_one_array | def_one_var TK_COMMA def_var_list | def_one_array TK_COMMA def_var_list ; def_one_var: TK_IDENT { if(lookupEntry($1, LOOKUP_CURRENT_SCOPE, false)!=NULL) error("Identifier already declared. Cannot declare duplicate " " identifers : %s",$1); newVariable($1, cur_type); } ; def_one_array: TK_IDENT TK_AGK_OPEN TK_INT TK_AGK_CLOSE { if(lookupEntry($1, LOOKUP_CURRENT_SCOPE, false)!=NULL) error("Identifier already declared. Cannot declare duplicate " " identifers : %s",$1); n = typeArray($3, cur_type); newVariable($1, n); } ; statement: l_value { if(($1.v->entryType == ENTRY_PARAMETER)&&($1.v->u.eParameter.mode == PASS_BY_VALUE)&&($1.v->u.eParameter.type->kind == TYPE_IARRAY)) { error("Cannot assign a value to a passed by value array :%s",$1.v->id); } } TK_ASSIGN { assert(ass_pred == 0); ass_pred++; } expression TK_EROTIM { ass_pred--; if( $1.t->kind != $5.t->kind ) error("Incopatible types"); if(arr_pred == false ) { b_op.q_union.x = $5.v; b_op.code = $5.code; c_op.code = false; d_op.q_union.x = $1.v; genquad(label_c++, ASSIGN_QUAD, b_op, c_op, d_op, $1.t->kind == 1 ? 1:0); } else if(arr_pred == true) { arr_pred = false; b_op.q_union.x = $5.v; b_op.code = $5.code; genquad(label_c++, T2ARR_QUAD, b_op, cd_op, dd_op, dd_op.code); } $$.next = NULL; } | TK_WORD_IF TK_PAR_OPEN {if_while_pred = true;} b_expression { if_while_pred = false; //fprintf(stdout, "Ready to backpatch (IF/TRUE):%d\n",label_c); //printQuadList(stdout, $4.true_list); BackPatch($4.true_list, label_c ); $$.L1 = $4.false_list; $$.L2 = NULL; } TK_PAR_CLOSE statement if_tail { if($5.L2 == NULL) $$.next = MergeList($5.L1, $7.next); else $$.next = MergeList(MergeList($5.L1, $7.next), $5.L2); } | TK_WORD_WHILE { $$.x = label_c ; } TK_PAR_OPEN { if_while_pred = true;} b_expression TK_PAR_CLOSE { if_while_pred = false; //fprintf(stdout, "Ready to backpatch (WHILE/TRUE):%d\n",label_c); //printQuadList(stdout, $5.true_list); BackPatch($5.true_list, label_c ); } statement { //fprintf(stdout, "Ready to backpatch (WHILE/NEXT):%d\n",label_c); //printQuadList(stdout, $8.next); BackPatch($8.next, $2.x); d_op.q_union.label = $2.x ; genquad(label_c++, JMP_QUAD, b_op, c_op, d_op, 0); $$.next = $5.false_list; } | void_func_call {$$.next = NULL;} | return_stmnt {$$.next = NULL;} | TK_AGKISTRO_OPEN stmnt_list TK_AGKISTRO_CLOSE { $$.next = $2.next; } | TK_EROTIM {$$.next = NULL;} ; A: { ass_pred++; }; l_value: TK_IDENT { tmp = lookupEntry($1,LOOKUP_ALL_SCOPES,false); if(tmp==NULL) error("Uknown identifier : %s",$1); switch(tmp->entryType) { case ENTRY_FUNCTION: { error("Invalid use of function : %s",$1); } case ENTRY_PARAMETER: if(tmp->u.eParameter.type->kind==TYPE_ARRAY) error("Invalid use of array, without pointer : %s",$1); $$.t = tmp->u.eParameter.type; $$.v = tmp; $$.code = false; break; case ENTRY_VARIABLE: if(tmp->u.eVariable.type->kind == TYPE_ARRAY) error("Invalid use of array, without pointer : %s",$1); $$.t = tmp->u.eVariable.type; $$.v = tmp; $$.code = false; break; default: error("Invalid use of identifier : %s",$1); break; } } | TK_IDENT TK_AGK_OPEN A expression TK_AGK_CLOSE { ass_pred--; tmp = lookupEntry($1,LOOKUP_ALL_SCOPES,false); if(tmp==NULL) error("Uknown identifier : %s",$1); switch(tmp->entryType) { case ENTRY_FUNCTION: error("Invalid use of function : %s",$1); case ENTRY_VARIABLE: if(tmp->u.eVariable.type->kind != TYPE_ARRAY && tmp->u.eVariable.type->kind != TYPE_IARRAY) error("Invalid use of variable, with pointer : %s",$1); if($4.t != typeInteger) error("Pointer of an array must be integer : %s",$1); $$.t = tmp->u.eVariable.type->refType; $$.code = false; b_op.q_union.x = tmp; b_op.code = false; c_op.q_union.x = $4.v; c_op.code = $4.code; if(ass_pred > 0 || if_while_pred) { $$.v = d_op.q_union.x = newTemporary(tmp->u.eVariable.type->refType); genquad(label_c++, ARR2T_QUAD, b_op, c_op, d_op, tmp->u.eVariable.type->refType->kind == TYPE_INTEGER ? 1:0); } else { $$.v = tmp; arr_pred = true; cd_op.code = c_op.code; cd_op.q_union.x = c_op.q_union.x; dd_op.q_union.x = tmp; dd_op.code = tmp->u.eVariable.type->refType->kind == TYPE_INTEGER ? 1:0; } break; case ENTRY_PARAMETER: if(tmp->u.eParameter.type->kind != TYPE_ARRAY && tmp->u.eVariable.type->kind != TYPE_IARRAY) { error("Invalid use of variable, with pointer : %s",$1); } if($4.t != typeInteger) error("Pointer of an array must be integer : %s",$1); $$.t = tmp->u.eParameter.type->refType; b_op.q_union.x = tmp; c_op.q_union.x = $4.v; c_op.code = $4.code; $$.code = false; if(ass_pred > 0 || if_while_pred) { $$.v = d_op.q_union.x = newTemporary(tmp->u.eVariable.type->refType); genquad(label_c++, ARR2T_QUAD, b_op, c_op, d_op, tmp->u.eVariable.type->refType->kind == TYPE_INTEGER ? 1:0); } else { $$.v = tmp; arr_pred = true; cd_op.code = c_op.code; cd_op.q_union.x = c_op.q_union.x; dd_op.q_union.x = tmp; dd_op.code = dd_op.code = tmp->u.eVariable.type->refType->kind == TYPE_INTEGER ? 1:0; } break; default: error("Invalid use of identifier : %s",$1); break; } } ; if_tail: /* empty */ {;} | TK_WORD_ELSE { L3 = $-2.L1; d_op.q_union.label = 0; genquad(label_c++, JMP_QUAD, b_op, c_op, d_op, 0); $-2.L1 = MakeList(NextQuad()); //fprintf(stdout, "Ready to backpatch (IF/L3):%d\n",label_c); //printQuadList(stdout, L3); BackPatch(L3 , label_c ); } statement { $-2.L2 = $3.next; } ; void_func_call: func_call TK_EROTIM { //$$.v = $1.v; //$$.t = $1.t; //$$.code = $1.code; //check4void = true; } ; func_call: TK_IDENT { func_call = lookupEntry($1, LOOKUP_ALL_SCOPES, 0); if(func_call == NULL) error("The function : %s is not specified",$1); if(func_call->entryType == ENTRY_FUNCTION) { func_call->u.eFunction.lastArgument = NULL; push2(func_call); } else error("Identifier is not a function : %s ",$1); } TK_PAR_OPEN actual_param_l TK_PAR_CLOSE { endFunctionParams(get()); //$$ = $4 ; if(get()->u.eFunction.resultType != typeVoid ) { $$ = b_op.q_union.x = newTemporary(get()->u.eFunction.resultType); b_op.code = false; c_op.q_union.pass = RET; //d_op.q_union.x = get(); d_op.q_union.x = NULL; d_op.code = false; genquad(label_c++, PAR_QUAD, b_op, c_op, d_op, get()->u.eFunction.resultType == typeInteger ? true:false); } d_op.q_union.x = get(); genquad(label_c++, CALL_QUAD, b_op, c_op, d_op, 0); } ; actual_param_l: /* empty */ {;} | actual_param { ; } | actual_param TK_COMMA actual_param_l {//$$ = $3; } ; actual_param: pure_expr { param = callFunctionParams('p', get(), "", $1.t, NULL); b_op.q_union.x = $1.v; b_op.code = $1.code; c_op.q_union.pass = param->u.eParameter.mode; d_op.q_union.x = NULL; d_op.code = false; genquad(label_c++, PAR_QUAD, b_op, c_op, d_op, $1.t == typeInteger ? true:false); } | TK_IDENT { tmp = lookupEntry($1, LOOKUP_ALL_SCOPES, false); param = callFunctionParams('v', get(), $1, NULL, tmp); if(tmp==NULL) error("Uknown identifier : %s",$1); /*else if(param->u.eParameter.type->kind == TYPE_IARRAY && param->u.eParameter.type->refType->kind == TYPE_CHAR) { b_op.q_union.name = (char *)malloc(5 + strlen(itoa(str_counter, NULL, 10))); strcpy(b_op.q_union.name, String2asm(fp_data, )); c_op.q_union.pass = V; d_op.code = true; genquad(label_c++, PAR_QUAD, b_op, c_op, d_op, 0); }*/ else { switch(tmp->entryType) { case ENTRY_FUNCTION: error("Invalid use of function without parameters : %s",$1); break; case ENTRY_PARAMETER: if(param->u.eParameter.mode == PASS_BY_REFERENCE && tmp->entryType == ENTRY_PARAMETER && tmp->u.eParameter.mode == PASS_BY_VALUE) error("Cannot pass by reference a passed by value array : %s", tmp->id); if(tmp->u.eParameter.type == typeChar) d_op.label = 0; else d_op.label = 1; break; case ENTRY_VARIABLE: if(tmp->u.eVariable.type == typeChar) d_op.label = 0; else if(tmp->u.eVariable.type == typeInteger) d_op.label = 1; else if(tmp->u.eVariable.type->kind == TYPE_ARRAY) d_op.label = 1; break; } b_op.q_union.x = tmp; b_op.code = false; c_op.q_union.pass = param->u.eParameter.mode; d_op.q_union.x = NULL; d_op.code = false; genquad(label_c++, PAR_QUAD, b_op, c_op, d_op, d_op.label == 1 ? true:false); } } | TK_IDENT TK_AGK_OPEN A expression TK_AGK_CLOSE { ass_pred--; tmp = lookupEntry($1, LOOKUP_ALL_SCOPES, 0); param = callFunctionParams('a', get(), $1, NULL, tmp); if(tmp->u.eVariable.type->kind != TYPE_ARRAY && tmp->u.eVariable.type->kind != TYPE_IARRAY) error("Invalid use of variable, with pointer : %s",$1); if($4.t->kind != TYPE_INTEGER) error("An array pointer must be integer"); if(param->u.eParameter.mode == PASS_BY_VALUE) { b_op.q_union.x = tmp; b_op.code = false; c_op.q_union.x = $4.v; c_op.code = $4.code; d_op.q_union.x = newTemporary(tmp->u.eVariable.type->refType); genquad(label_c++, ARR2T_QUAD, b_op, c_op, d_op, tmp->u.eVariable.type->refType->kind == TYPE_INTEGER ? 1:0); bd_op.q_union.x = d_op.q_union.x; b_op.code = false; c_op.q_union.pass = param->u.eParameter.mode; d_op.q_union.x = NULL; d_op.code = false; genquad(label_c++, PAR_QUAD, bd_op, c_op , d_op, tmp->u.eVariable.type->refType->kind == TYPE_INTEGER ? 1:0); } else { b_op.q_union.x = $4.v; b_op.code = $4.code; c_op.code = false; d_op.q_union.x = newTemporary(tmp->u.eVariable.type->refType); genquad(label_c++, ASSIGN_QUAD, b_op, c_op, d_op, 1); // assign the index, at a temporary b_op.q_union.x = tmp; b_op.code = false; c_op.q_union.pass = param->u.eParameter.mode; // d_op.q_union.x as above (temporary) d_op.code = false; genquad(label_c++, PAR_QUAD, b_op, c_op , d_op, tmp->u.eVariable.type->refType == typeInteger ? 1:0); } } | TK_STRING { char *tt; tt = (char *)malloc(strlen($1)+1); strcpy(tt, $1); callFunctionParams('s', get(), "", NULL, NULL); b_op.q_union.name = (char *)malloc(5 + strlen(itoa(str_counter, NULL, 10))); strcpy(b_op.q_union.name, String2asm(fp_data, tt)); c_op.q_union.pass = V; d_op.code = true; genquad(label_c++, PAR_QUAD, b_op, c_op, d_op, 0); } ; return_stmnt: TK_WORD_RETURN { assert(ass_pred == 0); ass_pred++; } return_stmnt_queue { ass_pred--; } ; return_stmnt_queue:TK_EROTIM {/* acceptable for all types */} { genquad(label_c++, RET_QUAD, b_op, c_op, d_op, 0); } | expression TK_EROTIM { if(!(equalType(cur_func->u.eFunction.resultType,$1.t))) error("Incopatible return type for function : %s",cur_func->id); c_op.code = true; b_op.q_union.x = $1.v; b_op.code = $1.code; genquad(label_c++, ASSIGN_QUAD, b_op, c_op, d_op, $1.t == typeInteger ? true:false); genquad(label_c++, RET_QUAD, b_op, c_op, d_op, 0); } ; compound_stmnt: TK_AGKISTRO_OPEN stmnt_list TK_AGKISTRO_CLOSE {$$.next = $2.next;} ; stmnt_list: /* empty */ { $$.next = NULL; } | stmnt_list_ne { $$.next = $1.next; } ; stmnt_list_ne: statement { $$.next = $1.next; } | statement { //fprintf(stdout, "Ready to backpatch (NEXT):%d\n",label_c); //printQuadList(stdout, $1.next); BackPatch($1.next, label_c ); } stmnt_list_ne { $$.next = $3.next; } ; b_expression: b_expression TK_OP_AND { BackPatch($1.true_list, label_c ); } b_expression { $$.true_list = $4.true_list; $$.false_list = MergeList($1.false_list, $4.false_list); } | b_expression TK_OP_OR { BackPatch($1.false_list, label_c );; } b_expression { $$.true_list = MergeList($1.true_list, $4.true_list); $$.false_list = $4.false_list; } | TK_OP_NOT b_expression { $$.true_list = $2.false_list; $$.false_list = $2.true_list; } | TK_PAR_OPEN b_expression TK_PAR_CLOSE { $$.true_list = $2.true_list; $$.false_list = $2.false_list; } | expression TK_OP_EQUAL expression { if(($1.t==typeInteger&&$3.t!=typeInteger)||($1.t==typeChar&&$3.t!=typeChar)) error("Incopatible types"); b_op.q_union.x = $1.v; b_op.code = $1.code; c_op.q_union.x = $3.v; c_op.code = $3.code; d_op.q_union.label = 0; genquad(label_c++, EQ_QUAD, b_op, c_op, d_op, $1.t->kind == 1 ? 1:0); $$.true_list = MakeList(NextQuad()); genquad(label_c++, JMP_QUAD, b_op, c_op, d_op, 0); $$.false_list = MakeList(NextQuad()); } | expression TK_OP_NOTEQUAL expression { if(($1.t==typeInteger&&$3.t!=typeInteger)||($1.t==typeChar&&$3.t!=typeChar)) error("Incopatible types"); b_op.q_union.x = $1.v; b_op.code = $1.code; c_op.q_union.x = $3.v; c_op.code = $3.code; d_op.q_union.label = 0; genquad(label_c++, NE_QUAD, b_op, c_op, d_op, $1.t->kind == 1 ? 1:0); $$.true_list = MakeList(NextQuad()); genquad(label_c++, JMP_QUAD, b_op, c_op, d_op, 0); $$.false_list = MakeList(NextQuad()); } | expression TK_OP_GREATER expression { if(($1.t==typeInteger&&$3.t!=typeInteger)||($1.t==typeChar&&$3.t!=typeChar)) error("Incopatible types"); b_op.q_union.x = $1.v; b_op.code = $1.code; c_op.q_union.x = $3.v; c_op.code = $3.code; d_op.q_union.label = 0; genquad(label_c++, GT_QUAD, b_op, c_op, d_op, $1.t->kind == 1 ? 1:0); $$.true_list = MakeList(NextQuad()); genquad(label_c++, JMP_QUAD, b_op, c_op, d_op, 0); $$.false_list = MakeList(NextQuad()); } | expression TK_OP_LESS expression { if(($1.t==typeInteger&&$3.t!=typeInteger)||($1.t==typeChar&&$3.t!=typeChar)) error("Incopatible types"); b_op.q_union.x = $1.v; b_op.code = $1.code; c_op.q_union.x = $3.v; c_op.code = $3.code; d_op.q_union.label = 0; genquad(label_c++, LT_QUAD, b_op, c_op, d_op, $1.t->kind == 1 ? 1:0); $$.true_list = MakeList(NextQuad()); genquad(label_c++, JMP_QUAD, b_op, c_op, d_op, 0); $$.false_list = MakeList(NextQuad()); } | expression TK_OP_GREATEREQ expression { if(($1.t==typeInteger&&$3.t!=typeInteger)||($1.t==typeChar&&$3.t!=typeChar)) error("Incopatible types"); b_op.q_union.x = $1.v; b_op.code = $1.code; c_op.q_union.x = $3.v; c_op.code = $3.code; d_op.q_union.label = 0; genquad(label_c++, GE_QUAD, b_op, c_op, d_op, $1.t->kind == 1 ? 1:0); $$.true_list = MakeList(NextQuad()); genquad(label_c++, JMP_QUAD, b_op, c_op, d_op, 0); $$.false_list = MakeList(NextQuad()); } | expression TK_OP_LESSEQ expression { if(($1.t==typeInteger&&$3.t!=typeInteger)||($1.t==typeChar&&$3.t!=typeChar)) error("Incopatible types"); b_op.q_union.x = $1.v; b_op.code = $1.code; c_op.q_union.x = $3.v; c_op.code = $3.code; d_op.q_union.label = 0; genquad(label_c++, LE_QUAD, b_op, c_op, d_op, $1.t->kind == 1 ? 1:0); $$.true_list = MakeList(NextQuad()); genquad(label_c++, JMP_QUAD, b_op, c_op, d_op, 0); $$.false_list = MakeList(NextQuad()); } ; expression: pure_expr { $$.t = $1.t; $$.v = $1.v; $$.code = $1.code; } | l_value { $$.t = $1.t; $$.v = $1.v; $$.code = $1.code; } ; pure_expr: expression TK_OP_PLUS expression { if ($1.t == typeInteger && $3.t == typeInteger) { $$.t = typeInteger; b_op.q_union.x = $1.v; b_op.code = $1.code ; c_op.q_union.x = $3.v; c_op.code = $3.code ; $$.v = d_op.q_union.x = newTemporary(typeInteger); $$.code = false; genquad(label_c++, PLUS_QUAD, b_op, c_op, d_op, 1); } else error("Incopatible variable types. Only integers can be use here!"); } | expression TK_OP_MINUS expression { if ($1.t == typeInteger && $3.t == typeInteger) { $$.t = typeInteger; b_op.q_union.x = $1.v; b_op.code = $1.code ; c_op.q_union.x = $3.v; c_op.code = $3.code ; $$.v = d_op.q_union.x = newTemporary(typeInteger); $$.code = false; genquad(label_c++, MINUS_QUAD, b_op, c_op, d_op, 1); } else error("Incopatible variable types. Only integers can be use here!"); } | expression TK_OP_MULT expression { if ($1.t == typeInteger && $3.t == typeInteger) { $$.t = typeInteger; b_op.q_union.x = $1.v; b_op.code = $1.code ; c_op.q_union.x = $3.v; c_op.code = $3.code ; $$.v = d_op.q_union.x = newTemporary(typeInteger); $$.code = false; genquad(label_c++, MULT_QUAD, b_op, c_op, d_op, 1); } else error("Incopatible variable types. Only integers can be use here!"); } | expression TK_OP_DIV expression { if ($1.t == typeInteger && $3.t == typeInteger) { $$.t = typeInteger; b_op.q_union.x = $1.v; b_op.code = $1.code ; c_op.q_union.x = $3.v; c_op.code = $3.code ; $$.v = d_op.q_union.x = newTemporary(typeInteger); $$.code = false; genquad(label_c++, DIV_QUAD, b_op, c_op, d_op, 1); } else error("Incopatible variable types. Only integers can be use here!"); } | expression TK_OP_MOD expression { if ($1.t == typeInteger && $3.t == typeInteger) { $$.t = typeInteger; b_op.q_union.x = $1.v; b_op.code = $1.code ; c_op.q_union.x = $3.v; c_op.code = $3.code ; $$.v = d_op.q_union.x = newTemporary(typeInteger); $$.code = false; genquad(label_c++, MOD_QUAD, b_op, c_op, d_op, 1); } else error("Incopatible variable types. Only integers can be use here!"); } | TK_OP_PLUS expression { if ($2.t == typeInteger) { $$.t = typeInteger; b_op.q_union.x = 0; b_op.code = true; c_op.q_union.x = $2.v; c_op.code = $2.code ; $$.v = d_op.q_union.x = newTemporary(typeInteger); $$.code = false; genquad(label_c++, PLUS_QUAD, b_op, c_op, d_op, 1); } else error("Character instead of digits"); } | TK_OP_MINUS expression { if ($2.t == typeInteger) { $$.t = typeInteger; b_op.q_union.x = 0; b_op.code = true ; c_op.q_union.x = $2.v; c_op.code = ( $2.code ? 1:0 ); $$.v = d_op.q_union.x = newTemporary(typeInteger); $$.code = false; genquad(label_c++, MINUS_QUAD, b_op, c_op, d_op, 1); } else error("Character instead of digits"); } | TK_INT { $$.t = typeInteger; $$.v = $1; $$.code = true; } | TK_CHAR { $$.t = typeChar; $$.v = $1; $$.code = true; } | func_call { func_call = pop2(); $$.t = func_call->u.eFunction.resultType; $$.code =false; $$.v = $1; } | TK_PAR_OPEN expression TK_PAR_CLOSE { $$ = $2; } ; %% int yyerror(const char *message) { if(depth) fprintf(stderr, "%s:%d, parse error. ", include_name, line_count); else fprintf(stderr, "%s:%d, parse error. ", f_name, line_count); } int main(int argc, char *argv[]) { int i; bool as, qd; char *exe, *cmd; exe = malloc(sizeof(char) * 6); strcpy(exe, "a.com"); init_tags(); FILE *fp_input; fp_asm = init_file("a.asm"); fp_quad = init_file("a.qud"); fp_data = init_file("data.asm"); if(!strcmp(argv[1], "-h")) { fprintf(stdout, "Usage: calv [options] file\n"); fprintf(stdout, "\t -h\t\t Help\n"); fprintf(stdout, "\t -q\t\t Keeps the quad file\n"); fprintf(stdout, "\t -a\t\t Keeps the assembly files\n"); fprintf(stdout, "\t -l\t\t Keeps the quad and the assembly files\n"); fprintf(stdout, "\t -o \t Place the output into file\n"); fprintf(stdout, "\t -d\t\t Enables the debugging mode of GNU/Bison\n\n\n"); fprintf(stdout, "For bug reporting instructions, please contact :\n"); fprintf(stdout, "sokos@softlab.ntua.gr\n"); fprintf(stdout, "mpapakyr@softlab.ntua.gr\n"); exit(1); } if(argc == 0 || argv[argc-1][0] == '-') { fprintf(stderr, "No input \n"); exit(1); } fp_input = fopen( argv[argc-1], "r"); if(fp_input == NULL) { fprintf(stderr, "Cannot open file.\n") ; exit(1); } for(i = 1; i <= argc-2; i++) { if(argv[i][0] == '-' ) switch(argv[i][1]) { case 'q': qd = true; break; case 'a': as = true; break; case 'l': as = true; qd = true; break; case 'd': yydebug = 1; break; case 'o': i++; exe = malloc(strlen(argv[i]) + 1); strcpy(exe, argv[i]); strcat(exe, ".com"); break; default: fprintf(stderr, "Wrong use of parameters. For help type \"calv -h\"\n"); break; } else { fprintf(stderr, "Wrong use of parameters. For help type \"calv -h\"\n"); exit(1); } } if(fp_input == NULL) { fprintf(stderr, "Wrong input file name\n"); exit(1); } else yyin = fp_input; f_name = (char *)malloc(strlen(argv[i-1])); strcpy(f_name, argv[i-1]); initDataFile(fp_data); yyparse(); endAsmFile(fp_asm); closeScope(); //destroySymbolTable(); fclose(fp_quad); fclose(fp_asm); fclose(fp_input); fclose(fp_data); if(!found_error && end) { cmd = malloc(sizeof(char)*40); sprintf(cmd, "masm /ml a.asm, a.obj, nul, nul ;"); system(cmd); sprintf(cmd, "link /noi /tiny a, %s, nul, library, nul,", exe); system(cmd); if(!qd) system("del a.qud"); if(!as) { system("del a.asm"); system("del data.asm"); } //system("del a.lst"); system("del a.obj"); //system("del a.map"); //system("del a.crf"); } } void CheckParam(char *name, SymbolEntry *function) { SymbolEntry *param; param = function->u.eFunction.firstArgument; while(param != NULL) { if(!strcmp(name , param->id)) error("Redeclaration of parameter not possible"); param = param->u.eParameter.next; } } SymbolEntry *callFunctionParams(char mode, SymbolEntry *function, char *name,Type type, SymbolEntry *tmp) { SymbolEntry *e; e = function->u.eFunction.lastArgument; if (e == NULL) e = function->u.eFunction.firstArgument; else e = e->u.eParameter.next; if (e == NULL) error("More parameters than expected in call " "of function %s", function->id); else switch(mode) { case 'p': if(!(equalType(e->u.eParameter.type,type)) && ( e->u.eParameter.type->kind == TYPE_IARRAY && e->u.eParameter.type->refType->kind == TYPE_CHAR && type->kind != TYPE_CHAR)) error("Type mismatch at parameter : %s",e->id); if(e->u.eParameter.mode==PASS_BY_REFERENCE) error("Cannot pass regular expressions by reference"); break; case 'v': //tmp = lookupEntry(name, LOOKUP_ALL_SCOPES, false); if(tmp==NULL) error("Identifier doen't exists : %s",tmp->id); else if((tmp->entryType != ENTRY_VARIABLE)&&(tmp->entryType != ENTRY_PARAMETER)) error("Invalid use of identifier : %s",tmp->id); /*else if(e->u.eParameter.type->kind == TYPE_IARRAY && equalType(e->u.eParameter.type->refType , typeChar) && (tmp->entryType == ENTRY_VARIABLE && equalType(tmp->u.eVariable.type , typeChar )) || tmp->entryType == ENTRY_PARAMETER && equalType(tmp->u.eParameter.type , typeChar )) ;*/ else if(tmp->entryType == ENTRY_VARIABLE) { if(e->u.eParameter.type->kind == TYPE_IARRAY) { if(tmp->u.eVariable.type->kind != TYPE_ARRAY) error("Cannot pass a non array as an array parameter : %s", e->id); else if(tmp->u.eVariable.type->refType->kind != e->u.eParameter.type->refType->kind) error("Type mismatch (type of array difers) at parameter : %s",e->id);; } else if(!equalType(e->u.eParameter.type, tmp->u.eVariable.type)) { error("Type mismatch at parameter : %s",e->id); } } else if(tmp->entryType == ENTRY_PARAMETER) { if(e->u.eParameter.type->kind == TYPE_IARRAY) { if(tmp->u.eParameter.type->kind != TYPE_IARRAY ) error("Cannot pass a non array as an array parameter : %s", e->id); else if(e->u.eParameter.type->kind == TYPE_IARRAY && tmp->u.eParameter.type->refType->kind != e->u.eParameter.type->refType->kind) { error("Type mismatch (type of array difers) at parameter : %s",e->id); } } else if(!equalType(e->u.eParameter.type, tmp->u.eParameter.type)) error("Type mismatch at parameter : %s",e->id); } break; case 'a': //tmp = lookupEntry(name, LOOKUP_ALL_SCOPES, false); if(tmp==NULL) error("Identifier doen't exists : %s",tmp->id); else if((tmp->entryType != ENTRY_VARIABLE)&&(tmp->entryType != ENTRY_PARAMETER)) error("Invalid use of identifier : %s",tmp->id); /*else if(e->u.eParameter.type->kind == TYPE_IARRAY && equalType(e->u.eParameter.type->refType , typeChar) && (tmp->entryType == ENTRY_VARIABLE && equalType(tmp->u.eVariable.type->refType , typeChar )) || tmp->entryType == ENTRY_PARAMETER && equalType(tmp->u.eParameter.type->refType , typeChar )) ;*/ else if(tmp->entryType == ENTRY_VARIABLE && e->u.eParameter.type->kind != tmp->u.eVariable.type->refType->kind || tmp->entryType == ENTRY_PARAMETER && e->u.eParameter.type->kind != tmp->u.eParameter.type->refType->kind) error("Type mismatch at parameter : %s",e->id); break; case 's': if(e->u.eParameter.type->kind != TYPE_ARRAY && e->u.eParameter.type->refType != typeChar ) error("Parameter must be char[] at declaration"); if(e->u.eParameter.mode==PASS_BY_REFERENCE) // error("Cannot pass a string by reference"); break; } function->u.eFunction.lastArgument = e; return e; } void endFunctionParams(SymbolEntry *f) { if ((f->u.eFunction.lastArgument != NULL && f->u.eFunction.lastArgument->u.eParameter.next != NULL) || (f->u.eFunction.lastArgument == NULL && f->u.eFunction.firstArgument != NULL)) error("Fewer parameters than expected in call " "of function %s", f->id); } void push2(SymbolEntry *f) { stack2 *new; new = (stack2 *)malloc(sizeof(stack2)); new->data = f; new->next = Top2; Top2 = new; } SymbolEntry *get() { return Top2->data; } SymbolEntry *pop2() { SymbolEntry *newt; stack2 *new; if(Top2 == NULL) { fprintf(stderr, "Pop should not be NULL\n"); return NULL; } else { newt = Top2->data; new = Top2; Top2 = Top2->next; free(Top); new = NULL; return newt; } }