/* Syntax Analyzer with Bison (3.8.2) */ /* The Translators - Spring 2025 */ // ----- THIS FILE MUST BE FORMATTED CORRECTLY FOR READABILITY ----- // // ✏️ FORMATTING RULES: // 1️⃣ Use 4 spaces for indentation. // 2️⃣ Grammar rules (terminals and nonterminals) should always be on their own line. // 3️⃣ Grammar rules and C-blocks should always begin 8 spaces in. // 4️⃣ Rule end-markers (;, |) should always be 4 spaces in. // 5️⃣ C-blocks should always be clearly defined and follow clang formatting rules. // 6️⃣ 1-line if/for/while statements must be wrapped in curly braces. // 7️⃣ Comments should always be above rules // 8️⃣ DO NOT USE TABS. EVER. // Please ask Scarlett if you are unsure of how to format something. Thanks! 😀 %{ #include "../src/grammar.h" %} %union { int integ; char* words; char letter; void* tn; } %locations %token ACCESS 801 %type idlist %type assignable %type expression %type constant %type id_or_types %type types %type sblock %type compound_statement %type simple_statement %type statement_list %type argument_list %type ablock %token ID 101 %token T_INTEGER 201 %token T_ADDRESS 202 %token T_BOOLEAN 203 %token T_CHARACTER 204 %token T_STRING 205 %token C_INTEGER 301 %token C_NULL 302 %token C_CHARACTER 303 %token C_STRING 304 %token C_TRUE 305 %token C_FALSE 306 %token WHILE 401 %token IF 402 %token THEN 403 %token ELSE 404 %token TYPE 405 %token FUNCTION 406 %token RETURN 407 %token EXTERNAL 408 %token AS 409 %token L_PAREN 501 %token R_PAREN 502 %token L_BRACKET 503 %token R_BRACKET 504 %token L_BRACE 505 %token R_BRACE 506 %token SEMI_COLON 507 %token COLON 508 %token COMMA 509 %token ARROW 510 %token MUL 603 %token DIV 604 %token REM 605 %token ADD 601 %token LESS_THAN 606 %token EQUAL_TO 607 %token AND 610 %token OR 611 %token ASSIGN 608 %token SUB_OR_NEG 602 %token NOT 609 %token DOT 612 %token RESERVE 613 %token RELEASE 614 %token COMMENT 700 %token INCLUDE 901 //precedence order %left ASSIGN %left OR %left AND %left EQUAL_TO %left LESS_THAN %left ADD SUB_OR_NEG %left MUL DIV REM %precedence NOT %precedence UMINUS %precedence DOT %precedence RESERVE RELEASE %% program: prototype_or_definition_list | include_list | include_list prototype_or_definition_list ; prototype_or_definition_list: prototype prototype_or_definition_list | definition prototype_or_definition_list | prototype | definition | prototype error { yyerrok; } | definition error { yyerrok; } ; prototype: L_PAREN EXTERNAL R_PAREN FUNCTION ID COLON ID ; include_list: include_statement include_list | include_statement ; include_statement: INCLUDE C_STRING ; definition: TYPE ID COLON { printdebug("Currently see a record definition for %s", $2); tn = CreateEntry(getAncestor(cur),TYPE_RECORD_TYPE, recprime, $2, CreateRecordInfo(0, cur = CreateScope(cur, 0, 0))); printdebug("Created a new scope"); } dblock { setRecSize(look_up(getParent(cur), $2), getRecSize(cur)); setRecOffsetInfo(cur, look_up(getParent(cur),$2)); printdebug("Moving up a scope after seeing a record definition"); cur = getParent(cur); } | TYPE ID COLON C_INTEGER ARROW id_or_types { printdebug("Currently see a array definition of name %s,storing type %s, of dimensions %d", $2, getName((TableNode*)$6), $4); CreateEntry(cur,TYPE_ARRAY_TYPE, arrayprim, $2, CreateArrayInfo($4, (TableNode*)$6)); printdebug("%sID: %s, dimensions: %d, typeOfArray: %s", COLOR_GREEN, $2, $4, getName((TableNode*)$6)); } | function_declaration | TYPE ID COLON id_or_types ARROW id_or_types { printdebug("Currently see a function type definition of name %s,parameter type %s, of return type %s", $2, getName((TableNode*)$4), getName((TableNode*)$6)); CreateEntry(cur,TYPE_FUNCTION_TYPE,funtypeprime,$2,CreateFunctionTypeInfo((TableNode*)$4 ,(TableNode*)$6)); } | ID { emit_function_start(table_lookup(cur,$1)); //printf("ID: %s\n", $1); //printf("Type: %s\n", getType(table_lookup(getAncestor(cur), $1))); printdebug("see function def rule 1\n"); TableNode *node = table_lookup(getAncestor(cur), $1); if (node == undefined) { printdebug("Undefined node declared."); }else if(getAdInfoType(node) != TYPE_FUNCTION_DECLARATION){ throw_error(ERROR_SYNTAX, "Not a valid function declaration."); } else { printdebug("setting as keyword to true"); setStartLine(node, @1.first_line); setAsKeyword(node, true); } cur = CreateScope(cur, 0, 0); setFunScope(node, cur); printdebug("Created a new scope"); } L_PAREN { TableNode * parameter = getParameter(getTypeEntry(table_lookup(getAncestor(cur), $1))); //TableNode *parameter = getParameter(table_lookup(getAncestor(cur), getType(table_lookup(getAncestor(cur), $1)))); printdebug("type of parameter: %s", getName(parameter)); if (parameter == undefined) { throw_error(ERROR_TYPE, "Undefined parameter in function definition."); }else if(getAdInfoType(parameter) != TYPE_RECORD_TYPE){ int type_of_param_type = getAdInfoType(parameter);//this is an enum value defined in symbol_table.h if( type_of_param_type == TYPE_UNDEFINED || type_of_param_type == TYPE_FUNCTION_DECLARATION || type_of_param_type == TYPE_ARRAY || type_of_param_type == TYPE_PRIMITIVE || type_of_param_type == TYPE_ALL_ELSE || type_of_param_type == TYPE_SYSTEM_DEFINED || type_of_param_type == TYPE_RECORD || type_of_param_type == TYPE_STRING){ // note that strings are actually arrays so this is unused throw_error(ERROR_TYPE, "Invalid type (%s) of parameter in function definition.", getAdInfo(parameter)); type_of_param_type = TYPE_UNDEFINED; // setting tag as undefined in these cases } if(type_of_param_type == TYPE_UNDEFINED){ CreateEntry(cur,type_of_param_type, undefined, NULL, NULL); // throw_error(ERROR_TYPE, "Duplicate defination of parameter in function definition."); } else { if(type_of_param_type == TYPE_FUNCTION_TYPE){ CreateEntry(cur, TYPE_FUNCTION_DECLARATION, parameter,NULL, getAdInfo(parameter)); // throw_error(ERROR_TYPE, "Duplicate defination of parameter in function definition."); } if(type_of_param_type == TYPE_ARRAY_TYPE){ CreateEntry(cur, TYPE_ARRAY, parameter,NULL, getAdInfo(parameter)); //throw_error(ERROR_TYPE, "Duplicate defination of parameter in function definition."); } if(type_of_param_type == TYPE_PRIMITIVE_TYPE){ CreateEntry(cur, TYPE_PRIMITIVE, parameter,NULL, getAdInfo(parameter))==undefined; // throw_error(ERROR_TYPE, "Duplicate defination of parameter in function definition.");} } } } else { printdebug("record found"); for (TableNode* entry = getFirstEntry(getRecList(parameter)); entry!= NULL; entry = getNextEntry(entry)){ int type_of_param_type = getAdInfoType(entry); if( type_of_param_type == TYPE_UNDEFINED || type_of_param_type == TYPE_FUNCTION_TYPE || type_of_param_type == TYPE_ARRAY_TYPE || type_of_param_type == TYPE_PRIMITIVE_TYPE || type_of_param_type == TYPE_ALL_ELSE || type_of_param_type == TYPE_SYSTEM_DEFINED || type_of_param_type == TYPE_RECORD_TYPE || type_of_param_type == TYPE_STRING){ // note that strings are actually arrays so this is unused throw_error(ERROR_TYPE, "Invalid type (%s) of parameter in function definition.", getAdInfo(entry)); type_of_param_type = TYPE_UNDEFINED; // setting tag as undefined in these cases }else{ printdebug("type of parameter correctly being passed in to AS function definition is %s which is valid", getType(entry)); } if(type_of_param_type == TYPE_UNDEFINED){ printdebug("undefined type of parameter inside record"); CreateEntry(cur,type_of_param_type, undefined, NULL, NULL); //throw_error(ERROR_TYPE, "Duplicate defination of parameter in function definition."); } else { if(type_of_param_type == TYPE_FUNCTION_DECLARATION){ printdebug("function declaration of parameter inside record"); CreateEntry(cur, TYPE_FUNCTION_DECLARATION, getTypeEntry(entry),NULL, getAdInfo(entry)); //throw_error(ERROR_TYPE, "Duplicate defination of parameter in function definition."); } if(type_of_param_type == TYPE_ARRAY){ printdebug("array type of parameter inside record"); CreateEntry(cur, TYPE_ARRAY, getTypeEntry(entry),NULL, getAdInfo(entry)); //throw_error(ERROR_TYPE, "Duplicate defination of parameter in function definition."); } if(type_of_param_type == TYPE_PRIMITIVE){ printdebug("primitive type of parameter inside record"); CreateEntry(cur, TYPE_PRIMITIVE, getTypeEntry(entry),NULL, getAdInfo(entry)); //throw_error(ERROR_TYPE, "Duplicate defination of parameter in function definition.");} } if(type_of_param_type == TYPE_RECORD){ printdebug("record type of parameter inside record"); CreateEntry(cur, TYPE_RECORD, getTypeEntry(entry),NULL, getAdInfo(entry)); //throw_error(ERROR_TYPE, "Duplicate defination of parameter in function definition.");} } /*printdebug("creating entry of type %s for function", getType(entry)); CreateEntry(cur, getTypeEntry(entry), "undefined", NULL);*/ } } } //counter = 0; printdebug("Created a new scope after seeing a function definition"); } idlist R_PAREN ASSIGN sblock { TableNode *expected = getReturn(getTypeEntry(look_up(cur, $1))); if ($8 == undefined) { throw_error(ERROR_TYPE, "Expected %s as return type but got undefined (possibly NULL). Differing return types in function.", getName(expected)); } else if (getAdInfoType(expected)==TYPE_ARRAY_TYPE && $8 == addr){ printdebug("CORRECT RETURN TYPE!!!"); } else if (getAdInfoType(expected)==TYPE_RECORD_TYPE && $8 == addr){ printdebug("CORRECT RETURN TYPE!!!"); }else if ($8 != expected) { throw_error(ERROR_TYPE, "Expected %s as return type but got %s. Differing return types in function.", getName(expected), getName($8)); } else { printdebug("CORRECT RETURN TYPE!!!"); } //printf("Ending ID: %s\n", $1); //printf("Ending Type: %s\n", getType(table_lookup(getAncestor(cur), $1))); } ; function_declaration: FUNCTION ID COLON ID { if(getAdInfoType(table_lookup(cur, $4))==TYPE_FUNCTION_TYPE){ //printf("%s\n",$1); //printf("%s\n",getName(table_lookup(cur, $4))); if (CreateEntry(cur,TYPE_FUNCTION_DECLARATION, table_lookup(cur, $4), $2, CreateFunctionDeclarationInfo(-1, false,NULL)) == undefined) { throw_error(ERROR_TYPE, "Duplicate defination of function in function declaration"); } } else{ throw_error(ERROR_TYPE, "Function declatation (%s) is not a valid function type", $2); CreateEntry(cur,TYPE_FUNCTION_DECLARATION, look_up(cur, $4), $2, CreateFunctionDeclarationInfo(-1, false,NULL)); } emit_function_dec(table_lookup(cur, $2)); } | EXTERNAL FUNCTION ID COLON ID { if(getAdInfoType(look_up(cur, $5))==TYPE_FUNCTION_TYPE){ if (CreateEntry(cur,TYPE_FUNCTION_DECLARATION, look_up(cur, $5), $3, CreateFunctionDeclarationInfo(-1, false,NULL)) == undefined) { throw_error(ERROR_TYPE, "Duplicate defination of function in function declaration"); } } else{ throw_error(ERROR_TYPE, "Function declatation (%s) is not a valid function type", $3); CreateEntry(cur,TYPE_FUNCTION_DECLARATION, look_up(cur, $5), $3, CreateFunctionDeclarationInfo(-1, false,NULL)); } } ; idlist: ID { printdebug("idlist rule 1 ID: %s", $1); TableNode *entry = getFirstEntry(cur); while((getName(entry) != getName(undefined))){ entry = getNextEntry(entry); } if (entry == NULL){ printdebug("mismatch in number of parameters passed to function"); } else if(entry->theName == NULL){ addName(entry, $1); printdebug("name added to entry of type %s is %s in function parameter scope",getType(entry), $1); } else { printdebug("undefined types passed in to function scope. Improper."); addName(entry, $1); } printTableNode(entry); //while (strcmp(getName(entry),"undefined") != 0) { // entry = getNextEntry(entry); //} //if (getNextEntry(entry) == NULL) { // printdebug("too many parameters at line %d column %d", @1.first_line, @1.first_column); //} //addName(entry, $1); //printdebug("name added to entry is %s", $1); //printTableNode(entry); } COMMA idlist { $$ = $4 + 1; } | ID { printdebug("idlist rule 2 ID: %s", $1); TableNode *entry = getFirstEntry(cur); while((getName(entry) != getName(undefined))){ entry = getNextEntry(entry); } if (entry == NULL){ printdebug("mismatch in number of parameters passed to function"); } else if(entry->theName == NULL){ addName(entry, $1); printdebug("name added to entry of type %s is %s in function parameter scope",getType(entry), $1); } else { printdebug("undefined types passed in to function scope. Improper."); addName(entry, $1); } printTableNode(entry); printdebug("Name of entry is now %s", getName(entry)); printdebug("Type of entry is %s", getType(entry)); printdebug("tag is %d", getAdInfoType(entry)); } ; sblock: L_BRACE { // emit_label(label_gen()); if (getLine(cur) != 0) { cur = CreateScope(cur,@1.first_line,@1.first_column); printdebug("Created a new scope"); } else { setLineNumber(cur, @1.first_line); setColumnNumber(cur,@1.first_line); } } statement_list { //$$ = $3; printdebug("Moving up a scope after seeing sblock"); cur = getParent(cur); } R_BRACE {$$ = $3;} | L_BRACE { if (getLine(cur) != 0) { cur = CreateScope(cur,@1.first_line,@1.first_column); printdebug("Created a new scope when seeing an L brace"); } else { setLineNumber(cur, @1.first_line); setColumnNumber(cur,@1.first_line); printdebug("Did not create a new scope when saw L Brace, set line number to %d", @1.first_line); } } dblock { printdebug("seen sblock with dblock"); } statement_list { printdebug("Moving up a scope after seeing sblock with dblock"); cur = getParent(cur); //$$ = $5; } R_BRACE {$$ = $5;} ; dblock: L_BRACKET { if (getLine(cur) == 0) { setLineNumber(cur, @1.first_line); setColumnNumber(cur,@1.first_line); printdebug("Did not create a new scope when saw dblock, set line number to %d instead", @1.first_line); } else{ //cur = CreateScope(cur,@1.first_line,@1.first_column); // <----- What is this? printdebug("Created a new scope when seeing a dblock"); } } declaration_list R_BRACKET ; declaration_list: declaration SEMI_COLON declaration_list | declaration | error SEMI_COLON { yyerrok; } declaration_list //only perform error recovery once we see semi-colon ; declaration: id_or_types COLON ID { printdebug("ID/TYPE: %s, ID: %s", getName((TableNode*)$1), $3) ; int d = getAdInfoType((TableNode*)$1); if(d == TYPE_UNDEFINED) { throw_error(ERROR_TYPE, "Undefined type passed in declaration list"); printdebug("Undefined type passed in declaration list"); CreateEntry(cur,d,(TableNode*)$1,$3,getAdInfo((TableNode*)$1)); } else if(d == TYPE_FUNCTION_TYPE) { printdebug("invalid (function) type passed in declaration list in dblock", @2.first_line, @2.first_column); d = TYPE_FUNCTION_DECLARATION; if(CreateEntry(cur,d,(TableNode*)$1,$3,NULL) == undefined){ throw_error(ERROR_TYPE, "Duplicate defination of function in declaration list"); } } else if(d == TYPE_ARRAY_TYPE){ printdebug("array variable at line %d and column %d", @2.first_line, @2.first_column); d = TYPE_ARRAY; if(CreateEntry(cur,d,(TableNode*)$1,$3,getAdInfo((TableNode*)$1)) == undefined){ throw_error(ERROR_TYPE, "Duplicate defination of array in declaration list"); } } else if(d == TYPE_RECORD_TYPE){ printdebug("record variable at line %d and column %d", @2.first_line, @2.first_column); d = TYPE_RECORD; if(CreateEntry(cur,d,(TableNode*)$1,$3,getAdInfo((TableNode*)$1))== undefined){ throw_error(ERROR_TYPE, "Duplicate defination of record in declaration list"); } } else if(d == TYPE_PRIMITIVE_TYPE){ printdebug("primitive variable at line %d and column %d", @2.first_line, @2.first_column); d = TYPE_PRIMITIVE; if(CreateEntry(cur,d,(TableNode*)$1,$3,getAdInfo((TableNode*)$1)) == undefined){ throw_error(ERROR_TYPE, "Duplicate defination of primitive in declaration list"); } }else { throw_error(ERROR_TYPE, "%s is being defined with an undefined type", $3); CreateEntry(cur,d,(TableNode*)$1,$3,getAdInfo((TableNode*)$1)); } } ; id_or_types: ID { printdebug("string of id is %s in ID pattern of id_or_type rule.", $1); $$ = table_lookup(getAncestor(cur), $1); } | types { printdebug("string of type is %s in types pattern of id_or_type rule.",getName((TableNode*)$1)); $$ = (TableNode*)$1; } ; statement_list: compound_statement statement_list { if ($1 == undefined && $2 != undefined) { $$ = $2; } else if ($1 != undefined && $2 == undefined) { $$ = $1; } else if ($1 == $2) { $$ = $1; }else if((getAdInfoType((TableNode*)$1) == TYPE_ARRAY_TYPE) && ((TableNode*)$2)==addr){ $$ = $1; }else if((getAdInfoType((TableNode*)$1) == TYPE_RECORD_TYPE) && ((TableNode*)$2)==addr){ $$ = $1; }else if(((TableNode*)$1)==addr && (getAdInfoType((TableNode*)$2) == TYPE_ARRAY_TYPE)){ $$ = $2; }else if(((TableNode*)$1)==addr && (getAdInfoType((TableNode*)$2) == TYPE_RECORD_TYPE)){ $$ = $2; } else { printdebug("1 differing return types within same function at line %d, column %d", @1.first_line, @1.first_column); $$ = undefined; } } | compound_statement { $$ = $1; } | simple_statement SEMI_COLON statement_list{ if ($1 == undefined && $3 != undefined) { $$ = $3; } else if ($1 != undefined && $3 == undefined) { $$ = $1; } else if ($1 == $3) { $$ = $1; }else if((getAdInfoType((TableNode*)$1) == TYPE_ARRAY_TYPE) && ((TableNode*)$3)==addr){ $$ = $1; }else if((getAdInfoType((TableNode*)$1) == TYPE_RECORD_TYPE) && ((TableNode*)$3)==addr){ $$ = $1; }else if(((TableNode*)$1)==addr && (getAdInfoType((TableNode*)$3) == TYPE_ARRAY_TYPE)){ $$ = $3; }else if(((TableNode*)$1)==addr && (getAdInfoType((TableNode*)$3) == TYPE_RECORD_TYPE)){ $$ = $3; } else { printdebug("2 differing return types within same function at line %d, column %d", @1.first_line, @1.first_column); $$ = undefined; } } | simple_statement SEMI_COLON { $$ = $1; } | error SEMI_COLON { yyerrok; } statement_list { $$ = $4; } ; compound_statement: WHILE L_PAREN { S_Push(TrueList, S_Init(), 0); S_Push(FalseList, S_Init(), 0); int *l = calloc(1, sizeof(int)); *l = label_gen(); emit_label(*l); S_Push(stack, l, 2); } expression R_PAREN { emit_label(label_gen()); emit_backpatch(S_Pop(TrueList), getLabel(current)); } sblock { $$ = $7; int l = label_gen(); emit_backpatch(S_Pop(FalseList), l); emit_goto(*(int*)(S_Pop(stack))); emit_label(l); } // IF L_PAREN expression R_PAREN THEN sblock ELSE sblock | IF L_PAREN { S_Push(TrueList, S_Init(), 0); S_Push(FalseList, S_Init(), 0); }expression R_PAREN THEN { int l = label_gen(); emit_conditional_jump(E_IF_X_TRUE, l, tn_or_const(NODE, $4)); Stack * t = S_Peek(TrueList); S_Push(t, current, 1); emit_goto(0); t = S_Peek(FalseList); S_Push(t, current, 1); emit_label(l); emit_backpatch(S_Pop(TrueList), getLabel(current)); } sblock ELSE { // NOTE we are not going back to int l = label_gen(); emit_backpatch(S_Pop(FalseList), l); S_Push(stack, S_Init(), 0); emit_goto(0); S_Push(S_Peek(stack), current, 1); emit_label(l); } sblock { int l = label_gen(); emit_backpatch(S_Pop(stack), l); emit_label(l); if ($8 == undefined && $11 != undefined) { $$ = $11; } else if ($8 != undefined && $11 == undefined) { $$ = $8; } else if ($8 == $11) { $$ = $8; }else if((getAdInfoType((TableNode*)$8) == TYPE_ARRAY_TYPE) && ((TableNode*)$11)==addr){ $$ = $8; }else if((getAdInfoType((TableNode*)$8) == TYPE_RECORD_TYPE) && ((TableNode*)$11)==addr){ $$ = $8; }else if(((TableNode*)$8)==addr && (getAdInfoType((TableNode*)$11) == TYPE_ARRAY_TYPE)){ $$ = $11; }else if(((TableNode*)$8)==addr && (getAdInfoType((TableNode*)$11) == TYPE_RECORD_TYPE)){ $$ = $11; } else { printdebug("3 differing return types within same function at line %d, column %d", @1.first_line, @1.first_column); //printf("%s\n", getName((TableNode*)$6)); //printf("%s\n", getName((TableNode*)$8)); $$ = undefined; } } | sblock { $$ = $1; } ; simple_statement: assignable{ S_Push(TrueList, S_Init(), 0); S_Push(FalseList, S_Init(), 0); } ASSIGN expression { // ---------------------------------------------------------------------------- if ( getTypeEntry((TableNode*)$4) == boo ) { emit_label(label_gen()); } emit_backpatch(S_Pop(TrueList), getLabel(current)); emit_backpatch(S_Pop(FalseList), getLabel(current)); // ---------------------------------------------------------------------------- printdebug("simple statement"); TableNode* node; if((getAdInfoType((getTypeEntry((TableNode*)$1))) == TYPE_FUNCTION_TYPE)|| (getAdInfoType((getTypeEntry((TableNode*)$1))) == TYPE_ARRAY_TYPE)|| (getAdInfoType((getTypeEntry((TableNode*)$1))) == TYPE_RECORD_TYPE)|| (getAdInfoType((getTypeEntry((TableNode*)$1))) == TYPE_PRIMITIVE_TYPE)){ node = ((TableNode*)$1); } else { //printf("%d\n",getAdInfoType((getTypeEntry((TableNode*)$1)))); throw_error(ERROR_TYPE, "Invalid type passed to assignable."); //printf("%d, %d\n", @1.first_line, @1.first_column); //printf("%s\n", getType(getTypeEntry((TableNode*)$1))); //printf("%s\n\n", getType(getTypeEntry((TableNode*)$3))); node = undefined; } if(getAdInfoType(node) == getAdInfoType((TableNode*)$4)){ emit_assignment($1, tn_or_const(NODE, $4)); printdebug("%s[☺] Passed type check; %s = %s", COLOR_GREEN, getType(node), getType((TableNode*)$4)); } else if (getTypeEntry(getTypeEntry(node)) == arrayprim && getTypeEntry((TableNode*)$4) == addr) { emit_assignment($1, tn_or_const(NODE, $4)); printdebug("%s[☺] Passed type check; %s = %s", COLOR_GREEN, getType(node), getType((TableNode*)$4)); } else if (getTypeEntry(getTypeEntry(node)) == recprime && getTypeEntry((TableNode*)$4) == addr) { emit_assignment($1, tn_or_const(NODE, $4)); printdebug("%s[☺] Passed type check; %s = %s", COLOR_GREEN, getType(node), getType((TableNode*)$4)); } else { //printf("%d\n",getAdInfoType((TableNode*)$1)); //printf("%d\n",getAdInfoType((TableNode*)$3)); //printf("%d\n",getAdInfoType((TableNode*)$1)); //printf("%d\n",getAdInfoType((TableNode*)$3)); throw_error(ERROR_TYPE, "Assignable Assign Expression - Object %s of type %s != Object %s of type %s", getName(node), getType(node), getName((TableNode*)$4), getType((TableNode*)$4)); } $$ = undefined; } | RETURN expression { $$ = getTypeEntry((TableNode*)$2); emit_return(tn_or_const(NODE,(TableNode*)$2));} |simple_statement error {yyerrok; yyclearin; printdebug("error in simple statement");} ; rec_op: DOT ; ablock: L_PAREN{ if (stack == NULL){ stack = S_Init(); } Stack * t = S_Init(); S_Push(stack, t, 0); } argument_list { } R_PAREN { // here $$ = $3; printdebug("ablock is %d", $$); } ; argument_list: expression{ TableNode * arg = CreateEntry(cur, getAdInfoType((TableNode*)$1), getTypeEntry((TableNode*)$1), arg_var_gen(), NULL); if(getLine(cur)==-2){ if(getTypeEntry(arg) != integ){ throw_error(ERROR_TYPE, "Argument %s of type %s is not of type integer for an array argument", getName(arg), getType(arg)); } } // ---------------------------------------------------------------------------- // this is emitting the param withthe wrong TableNode // We need to fiture out how to get the right one. Stack * t = S_Peek(stack); if(t==NULL){ t = S_Init(); S_Push(stack, t, 1); } emit_parameter(tn_or_const(NODE,$1)); S_Push(t, current, 1); emit_detach(); // ---------------------------------------------------------------------------- } COMMA argument_list {$$ = $4 + 1;} | expression { TableNode* arg = CreateEntry(cur, getAdInfoType((TableNode*)$1), getTypeEntry((TableNode*)$1), arg_var_gen(), NULL); if(getLine(cur)==-2){ if(getTypeEntry(arg) != integ){ throw_error(ERROR_TYPE, "Argument %s of type %s is not of type integer for an array argument", getName(arg), getType(arg)); } } emit_parameter(tn_or_const(NODE,$1)); $$ = 1; printdebug("[ARGUMENT_LIST] argument list is %d", $$); } ; // will ALWAYS be a TYPE expression: constant { printdebug("constant expression"); $$ = (TableNode*)$1; } | SUB_OR_NEG expression %prec UMINUS { printdebug("negative expression"); if(getTypeEntry((TableNode*)$2) == integ) { char* temp = temp_var_gen(); TableNode* node = CreateEntry(cur,TYPE_PRIMITIVE, integ, temp, NULL); emit_unary_op(E_NEG,node,tn_or_const(NODE,$2)); //NOTE ADD ASSIGNMENT EMIT HERE (MIGHT NEED TO PUSH TO STACK) //result of unary operation $$ = node; } else { $$=undefined; throw_error(ERROR_TYPE, "Object %s of type %s is not of type integer and can't be negated", getName((TableNode*)$2), getType((TableNode*)$2)); } } | NOT expression { printdebug("not expression"); if(getTypeEntry((TableNode*)$2) == boo) { char* temp = temp_var_gen(); TableNode* node = CreateEntry(cur,TYPE_PRIMITIVE, boo, temp, NULL); Stack * t = S_Pop(TrueList); Stack * f = S_Pop(FalseList); S_Push(TrueList, f, 0); S_Push(FalseList, t, 0); //result of unary operation $$ = node; } else { $$=undefined; throw_error(ERROR_TYPE, "Object %s of type %s is not of type Boolean and can't be negated", getName((TableNode*)$2), getType((TableNode*)$2)); } } | expression ADD expression { printdebug("add expression"); if((getTypeEntry((TableNode*)$1) == getTypeEntry((TableNode*)$3)) && getTypeEntry((TableNode*)$1) == integ) { char* temp = temp_var_gen(); TableNode* node = CreateEntry(cur,TYPE_PRIMITIVE, integ, temp, NULL); emit_binary_op(E_ADD,node,tn_or_const(NODE,$1),tn_or_const(NODE,$3)); $$ = node; } else { $$=undefined; throw_error(ERROR_TYPE, "%s != %s", getName((TableNode*)$1), getName((TableNode*)$3)); throw_error(ERROR_TYPE, "Object %s of type %s and Object %s of type %s must both be integers", getName((TableNode*)$1), getType((TableNode*)$1), getName((TableNode*)$3), getType((TableNode*)$3)); } } | expression SUB_OR_NEG expression { printdebug("sub or neg expression"); if((getTypeEntry((TableNode*)$1) == getTypeEntry((TableNode*)$3)) && getTypeEntry((TableNode*)$1) == integ) { char* temp = temp_var_gen(); TableNode* node = CreateEntry(cur,TYPE_PRIMITIVE, integ, temp, NULL); emit_binary_op(E_SUB,node,tn_or_const(NODE,$1),tn_or_const(NODE,$3)); $$ = node; } else { $$=undefined; throw_error(ERROR_TYPE, "Object %s of type %s and Object %s of type %s must both be integers", getName((TableNode*)$1), getType((TableNode*)$1), getName((TableNode*)$3), getType((TableNode*)$3)); } } | expression MUL expression { printdebug("multiply expression"); if((getTypeEntry((TableNode*)$1) == getTypeEntry((TableNode*)$3)) && getTypeEntry((TableNode*)$1) == integ) { char* temp = temp_var_gen(); TableNode* node = CreateEntry(cur,TYPE_PRIMITIVE, integ, temp, NULL); emit_binary_op(E_MUL,node,tn_or_const(NODE,$1),tn_or_const(NODE,$3)); $$ = node; } else { $$=undefined; throw_error(ERROR_TYPE, "Object %s of type %s and Object %s of type %s must both be integers", getName((TableNode*)$1), getType((TableNode*)$1), getName((TableNode*)$3), getType((TableNode*)$3)); } } | expression DIV expression { printdebug("divide expression"); if((getTypeEntry((TableNode*)$1) == getTypeEntry((TableNode*)$3)) && getTypeEntry((TableNode*)$1) == integ) { char* temp = temp_var_gen(); TableNode* node = CreateEntry(cur,TYPE_PRIMITIVE, integ, temp, NULL); emit_binary_op(E_DIV,node,tn_or_const(NODE,$1),tn_or_const(NODE,$3)); $$ = node; } else { $$=undefined; throw_error(ERROR_TYPE, "Object %s of type %s and Object %s of type %s must both be integers", getName((TableNode*)$1), getType((TableNode*)$1), getName((TableNode*)$3), getType((TableNode*)$3)); } } | expression REM expression { printdebug("remainder expression"); if((getTypeEntry((TableNode*)$1) == getTypeEntry((TableNode*)$3)) && getTypeEntry((TableNode*)$1) == integ) { char* temp = temp_var_gen(); TableNode* node = CreateEntry(cur,TYPE_PRIMITIVE, integ, temp, NULL); emit_binary_op(E_MOD,node,tn_or_const(NODE,$1),tn_or_const(NODE,$3)); $$ = node; } else { $$=undefined; throw_error(ERROR_TYPE, "Object %s of type %s and Object %s of type %s must both be integers", getName((TableNode*)$1), getType((TableNode*)$1), getName((TableNode*)$3), getType((TableNode*)$3)); } } | expression AND expression { char* temp = temp_var_gen(); TableNode* node = CreateEntry(cur,TYPE_PRIMITIVE, boo, temp, NULL); // ---------------------------------------------------------------------------- uint_least8_t b = 0; emit_assignment(node, tn_or_const(BOOLEAN,&b)); // emit_label(label_gen()); // emit_backpatch(S_Pop(TrueList), getLabel(current)); emit_conditional_jump(E_IF_X_FALSE, 0, tn_or_const(NODE, $1)); Stack * t1 = S_Peek(FalseList); if(t1==NULL){ t1 = S_Init(); S_Push(FalseList, t1, 1); } S_Push(t1, current, 1); emit_goto(0); t1 = S_Peek(TrueList); if(t1==NULL){ t1 = S_Init(); S_Push(TrueList, t1, 1); } S_Push(t1, current, 1); emit_label(label_gen()); emit_backpatch(S_Pop(TrueList), getLabel(current)); emit_conditional_jump(E_IF_X_FALSE, 0, tn_or_const(NODE, $3)); Stack * t = S_Peek(FalseList); if(t==NULL){ t = S_Init(); S_Push(FalseList, t, 1); } S_Push(t, current, 1); b = 1; emit_assignment(node, tn_or_const(BOOLEAN,&b)); emit_goto(0); t = S_Peek(TrueList); if(t==NULL){ t = S_Init(); S_Push(TrueList, t, 1); } S_Push(t, current, 1); S_Merge(FalseList); // ---------------------------------------------------------------------------- printdebug("AND"); if((getTypeEntry((TableNode*)$1)==getTypeEntry((TableNode*)$3)) && getTypeEntry((TableNode*)$1) == boo) { //emit_binary_op(E_AND,node,tn_or_const(NODE,$1),tn_or_const(NODE,$3)); $$ = node; } else { $$=undefined; throw_error(ERROR_TYPE, "Object %s of type %s and Object %s of type %s must both be Boolean", getName((TableNode*)$1), getType((TableNode*)$1), getName((TableNode*)$3), getType((TableNode*)$3)); } } | expression OR expression { char* temp = temp_var_gen(); TableNode* node = CreateEntry(cur,TYPE_PRIMITIVE, boo, temp, NULL); // ---------------------------------------------------------------------------- uint_least8_t b = 1; emit_assignment(node, tn_or_const(BOOLEAN,&b)); // emit_label(label_gen()); // emit_backpatch(S_Pop(TrueList), getLabel(current)); emit_conditional_jump(E_IF_X_TRUE, 0, tn_or_const(NODE, $1)); Stack * t1 = S_Peek(TrueList); if(t1==NULL){ t1 = S_Init(); S_Push(TrueList, t1, 1); } S_Push(t1, current, 1); emit_goto(0); t1 = S_Peek(FalseList); if(t1==NULL){ t1 = S_Init(); S_Push(FalseList, t1, 1); } S_Push(t1, current, 1); emit_label(label_gen()); emit_backpatch(S_Pop(FalseList), getLabel(current)); emit_conditional_jump(E_IF_X_TRUE, 0, tn_or_const(NODE, $3)); Stack * t = S_Peek(TrueList); if(t==NULL){ t = S_Init(); S_Push(TrueList, t, 1); } S_Push(t, current, 1); b = 0; emit_assignment(node, tn_or_const(BOOLEAN,&b)); emit_goto(0); t = S_Peek(FalseList); if(t==NULL){ t = S_Init(); S_Push(FalseList, t, 1); } S_Push(t, current, 1); S_Merge(TrueList); // ---------------------------------------------------------------------------- printdebug("OR"); if((getTypeEntry((TableNode*)$1)==getTypeEntry((TableNode*)$3)) && getTypeEntry((TableNode*)$1) == boo) { $$ = node; } else { $$=undefined; throw_error(ERROR_TYPE, "Object %s of type %s and Object %s of type %s must both be Boolean", getName((TableNode*)$1), getType((TableNode*)$1), getName((TableNode*)$3), getType((TableNode*)$3)); } } | expression LESS_THAN expression { char* temp = temp_var_gen(); TableNode* node = CreateEntry(cur,TYPE_PRIMITIVE, boo, temp, NULL); // ---------------------------------------------------------------------------- // emit_label(label_gen()); // emit_backpatch(S_Pop(TrueList), getLabel(current)); emit_binary_op(E_LESS_THAN, node, tn_or_const(NODE,$1), tn_or_const(NODE,$3)); /* emit_conditional_jump(E_IF_X_TRUE, 0, tn_or_const(NODE, node)); Stack * t = S_Peek(TrueList); if(t==NULL){ t = S_Init(); S_Push(TrueList, t, 1); } S_Push(t, current, 1); emit_goto(0); t = S_Peek(FalseList); if(t==NULL){ t = S_Init(); S_Push(FalseList, t, 1); } S_Push(t, current, 1); */ // ---------------------------------------------------------------------------- printdebug("less than expression"); if(getTypeEntry((TableNode*)$1) == getTypeEntry((TableNode*)$3) && getTypeEntry((TableNode*)$1)==integ) { $$ = node; } else if(getTypeEntry((TableNode*)$1) == getTypeEntry((TableNode*)$3) && getTypeEntry((TableNode*)$1)==boo){ $$ = node; }else { $$=undefined; throw_error(ERROR_TYPE, "Object %s of type %s and Object %s of type %s must both be integers", getName((TableNode*)$1), getType((TableNode*)$1), getName((TableNode*)$3), getType((TableNode*)$3)); } } | expression EQUAL_TO expression { char* temp = temp_var_gen(); TableNode* node = CreateEntry(cur,TYPE_PRIMITIVE, boo, temp, NULL); // ---------------------------------------------------------------------------- emit_binary_op(E_EQUAL_TO, node, tn_or_const(NODE,$1), tn_or_const(NODE,$3)); /* emit_conditional_jump(E_IF_X_TRUE, 0, tn_or_const(NODE, node)); Stack * t = S_Peek(TrueList); if(t==NULL){ t = S_Init(); S_Push(TrueList, t, 1); } S_Push(t, current, 1); emit_goto(0); t = S_Peek(FalseList); if(t==NULL){ t = S_Init(); S_Push(FalseList, t, 1); } S_Push(t, current, 1); */ // emit_label(label_gen()); // emit_backpatch(S_Pop(TrueList), getLabel(current)); // ---------------------------------------------------------------------------- printdebug("equals check expression"); if(getTypeEntry((TableNode*)$1) == getTypeEntry((TableNode*)$3) && getTypeEntry((TableNode*)$1) != undefined) { // emit_binary_op(E_EQUAL_TO, node, tn_or_const(NODE,$1), tn_or_const(NODE,$3)); $$ = node; } else { $$ = undefined; throw_error(ERROR_TYPE, "Object %s of type %s and Object %s of type %s must both be the same type", getName((TableNode*)$1), getType((TableNode*)$1), getName((TableNode*)$3), getType((TableNode*)$3)); } } | assignable { $$ = $1; } | L_PAREN expression R_PAREN // TODO: We need to check if we need to backpatch here. { printdebug("paren expression. current type is %s",getType((TableNode*)$2)); $$=$2; } // TODO: We need to type check this. | RESERVE ID { char* temp = temp_var_gen(); TableNode* node = CreateEntry(cur,TYPE_PRIMITIVE, addr, temp, NULL); TableNode * n = look_up(cur, $2); if(getAdInfoType(n) != TYPE_RECORD){ throw_error(ERROR_TYPE, "Invalid Reserve expression with object %s of type %s.", getName((TableNode*)n), getType((TableNode*)n)); $$=undefined; } int v = getRecTotal(getTypeEntry(n)); emit_reserve(node, tn_or_const(INTEGER, &v)); $$ = node; } | RELEASE ID { TableNode * n = look_up(cur, $2); if(getAdInfoType(n) != TYPE_RECORD){ throw_error(ERROR_TYPE, "Invalid Release expression with object %s of type %s.", getName((TableNode*)n), getType((TableNode*)n)); $$=undefined; } char* temp = temp_var_gen(); TableNode* node = CreateEntry(cur,TYPE_PRIMITIVE, integ, temp, NULL); //emit release needed here $$ = node; } | RESERVE ID { cur = CreateScope(cur, -2,-1); } ablock { char* temp = temp_var_gen(); TableNode* node = CreateEntry(cur,TYPE_PRIMITIVE, addr, temp, NULL); int a = S_Size(S_Peek(stack)) + 1; emit_push_all(S_Peek(stack)); S_Pop(stack); emit_function_call(node, a, tn_or_const(NODE, $2)); $$ = node; TableNode * n = look_up(cur, $2); if(getAdInfoType(n) != TYPE_ARRAY){ throw_error(ERROR_TYPE, "Invalid Reserve expression with object %s of type %s.", getName(n), getType(n)); $$=undefined; } //doing more complicated type checking in a block if(getNumArrDim(getTypeEntry(n)) != $4){ throw_error(ERROR_SYNTAX, "expected %d dimensions for this array but got %d", getNumArrDim(getTypeEntry(n)), $4); $$=undefined; } cur = getParent(cur); /*TableNode * t = getFirstEntry(cur); TableNode * n = look_up(cur, $2); if(getAdInfoType(n) == TYPE_ARRAY){ int array_dims = getNumArrDim(getTypeEntry(n)); if ($5 != array_dims) { throw_error(ERROR_SYNTAX, "expected %d dimensions for this array but got %d", array_dims, $5); }else{ int traverse = 0; while(t != NULL && t != undefined && getName(t)[0] != '&'){ t = getNextEntry(t); } if(getTypeEntry(t) != integ){ throw_error(ERROR_TYPE, "Arg for an array is not of type integer"); $$= undefined; }else{ //seen first number traverse++; t = getNextEntry(t); while(traversegetNumArrDim(getTypeEntry((TableNode*)$1))){ throw_error(ERROR_TYPE, "Invalid trying to access the size of dimension %d but this array only has %d dimensions", $3, getNumArrDim(getTypeEntry((TableNode*)$1))); $$ = undefined; } else{ char* temp = temp_var_gen(); int t = 6; //emission // arr._1 .... $$ = CreateEntry(cur,t, integ, temp, NULL); } } | assignable rec_op ID { if(getAdInfoType((TableNode*)$1) != TYPE_RECORD){ throw_error(ERROR_TYPE, "Invalid type passed to record access"); $$ = undefined; } else if(undefined != table_lookup(getRecList(getTypeEntry((TableNode*)$1)), $3)) { TableNode* type = getTypeEntry(table_lookup(getRecList(getTypeEntry((TableNode*)$1)), $3)); char* temp = temp_var_gen(); int t = -1; if(getAdInfoType(type) == TYPE_PRIMITIVE_TYPE){ t = TYPE_PRIMITIVE; } else if(getAdInfoType(type) == TYPE_ARRAY_TYPE){ t = TYPE_ARRAY; } else if(getAdInfoType(type) == TYPE_RECORD_TYPE){ t = TYPE_RECORD; } else if(getAdInfoType(type) == TYPE_FUNCTION_TYPE){ t = TYPE_FUNCTION_DECLARATION; }else{ t= TYPE_UNDEFINED; throw_error(ERROR_TYPE, "Undefined type stored in record."); } TableNode* node = CreateEntry(cur,t, type, temp, NULL); // getElementOffset(rec, ID) //NOTE ADD ASSIGNMENT EMIT HERE (MIGHT NEED TO PUSH TO STACK) //emit_field_access(char* node, char* record, $3) $$=node; }else{ throw_error(ERROR_TYPE, "Invalid field access %s", $3); $$=undefined; } printdebug("[ASSIGNABLE - RULE 3] record = name: %s | field = %s", getName((TableNode*)($1)), getName((TableNode*)$3)); } ; constant: C_STRING { char* temp = temp_var_gen(); TableNode* node = CreateEntry(cur,TYPE_ARRAY, stri, temp, NULL); emit_assignment(node, tn_or_const(STRING,$1)); printdebug("string of C_STRING in constant is %s", $1); $$ = node; } | C_INTEGER { char* temp = temp_var_gen(); TableNode* node = CreateEntry(cur,TYPE_PRIMITIVE, integ, temp, NULL); emit_assignment(node, tn_or_const(INTEGER,&$1)); printdebug("number of C_INTEGER in constant is %d", $1); $$ = node; } | C_NULL { char* temp = temp_var_gen(); TableNode* node = CreateEntry(cur,TYPE_PRIMITIVE, addr, temp, NULL); emit_assignment(node, tn_or_const(ADDRESS,$1)); printdebug("string of C_NULL in constant is NULL"); $$ = node; } | C_CHARACTER { char* temp = temp_var_gen(); TableNode* node = CreateEntry(cur,TYPE_PRIMITIVE, chara, temp, NULL); emit_assignment(node, tn_or_const(CHARACTER,&$1)); //printdebug("string of C_CHARACTER in constant is %s",$1); $$ = node; } | C_TRUE { char* temp = temp_var_gen(); TableNode* node = CreateEntry(cur,TYPE_PRIMITIVE, boo, temp, NULL); uint_least8_t b = 1; emit_assignment(node, tn_or_const(BOOLEAN,&b)); printdebug("string of C_TRUE in constant is true"); $$ = node; } | C_FALSE { char* temp = temp_var_gen(); TableNode* node = CreateEntry(cur,TYPE_PRIMITIVE, boo, temp, NULL); uint_least8_t b = 0; emit_assignment(node, tn_or_const(BOOLEAN,&b)); printdebug("string of C_FALSE in constant is false"); $$ = node; } ; types: T_INTEGER { $$ = $1; printdebug("string of T_INTEGER in types is %s",getName((TableNode*)$1)); } | T_ADDRESS { $$ = $1; printdebug("string of T_ADDRESS in types is %s",getName((TableNode*)$1)); } | T_CHARACTER { $$ = $1; printdebug("string of T_CHARACTER in types is %s",getName((TableNode*)$1)); } | T_BOOLEAN { $$ = $1; printdebug("string of T_BOOLEAN in types is %s",getName((TableNode*)$1)); } ; %% void throw_error(ErrorType error_type, const char *format, ...) { int line = yylloc.first_line; int column = yylloc.first_column; char * error_name = ""; switch (error_type) { case ERROR_RUNTIME: error_name = malloc(strlen("RUNTIME") + 1); strcpy(error_name, "RUNTIME"); break; case ERROR_SYNTAX: error_name = malloc(strlen("SYNTAX") + 1); strcpy(error_name, "SYNTAX"); break; case ERROR_TYPE: error_name = malloc(strlen("TYPE") + 1); strcpy(error_name, "TYPE"); break; case ERROR_UNDEFINED: error_name = malloc(strlen("UNDEFINED") + 1); strcpy(error_name, "UNDEFINED"); break; } if (asc_flag) { yyerror(""); int needed = snprintf(NULL, 0, " LINE (%d:%d) ** %s ERROR: ", line, column, error_name); char *error_message = malloc(needed + 1); snprintf(error_message, needed + 1, " LINE (%d:%d) ** %s ERROR: ", line, column, error_name); va_list args; va_start(args, format); va_list args_copy; va_copy(args_copy, args); int needed2 = vsnprintf(NULL, 0, format, args_copy) + 1; va_end(args_copy); char *error_message2 = malloc(needed2); if (error_message2 == NULL) { fprintf(stderr, "Memory allocation failed\n"); va_end(args); return; } vsnprintf(error_message2, needed2, format, args); va_end(args); int total_needed = needed + needed2 + 2; char *total_error_message = malloc(total_needed); if (total_error_message == NULL) { fprintf(stderr, "Memory allocation failed\n"); free(error_message); free(error_message2); return; } snprintf(total_error_message, total_needed, "%s%s\n", error_message, error_message2); if (tc_flag) { insert_code_line(total_error_message, line); } else { if (error_type != ERROR_TYPE) { insert_code_line(total_error_message, line); } } free(error_message); free(error_message2); free(total_error_message); } } void yyerror(const char *err) { int line = yylloc.first_line; int column = yylloc.first_column; contains_errors = true; // Grammar Fallback Case if (strcmp(err, "syntax error") == 0) { if (asc_flag != NULL) { int needed = snprintf(NULL, 0, " LINE (%d:%d) ** SYNTAX ERROR: Incorrect syntax at token '%s'\n", line, column, yytext); char *error_message = malloc(needed + 1); snprintf(error_message, needed + 1, " LINE (%d:%d) ** SYNTAX ERROR: Incorrect syntax at token '%s'\n", line, column, yytext); insert_code_line(error_message, line); } else { fprintf(stderr, " LINE (%d:%d) ** SYNTAX ERROR: Incorrect syntax at token %s\n", line, column, yytext); } } }