/* Syntax Analyzer with Bison (3.8.2) */ /* The Translators - Spring 2025 */ %{ #include #include "../src/symbol_table.c" #include extern int yylex(void); void yyerror(const char *err); extern char* yytext; extern int yyleng; extern int yychar; extern SymbolTable * cur; //char* cur_value; //char* cur_type; int token_tracker; extern int line_number; extern int column_number; extern FILE * yyin; extern TableNode* funprime; extern TableNode* arrayprim; extern TableNode* recprime; extern TableNode* funtypeprime; extern TableNode* integ; extern TableNode* addr; extern TableNode* chara; extern TableNode* stri; extern TableNode* boo; TableNode * tn; %} //%define api.location.type {location_t} %locations %union { int integ; char * words; } %type idlist %type assignable %type expression %type constant %type id_or_types %type types %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 //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 ; prototype_or_definition_list: prototype prototype_or_definition_list | definition prototype_or_definition_list | prototype | definition ; prototype: L_PAREN EXTERNAL R_PAREN FUNCTION ID COLON ID; definition: TYPE ID COLON { printdebug("Currently see a record definition for %s", $2); tn = CreateEntry(getAncestor(cur), recprime, $2, CreateRecordInfo(0, cur = CreateScope(cur, 0, 0))); if (table_lookup(getAncestor(cur), $2) == undefined) { printdebug("rec not found "); } }dblock { setRecSize(table_lookup(getParent(cur), $2), getRecSize(cur)); 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, $6, $4); CreateEntry(cur, arrayprim, $2, CreateArrayInfo($4, look_up(cur, $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, $4, $6); CreateEntry(cur,funtypeprime,$2,CreateFunctionTypeInfo(table_lookup(cur,$4),table_lookup(cur,$6))); } | ID { TableNode *node = table_lookup(getAncestor(cur), $1); if (node == NULL) { printdebug("function not declared at line %d, column %d", @1.first_line, @1.first_column); }else if(getAdInfoType(node) != TYPE_FUNCTION_DECLARATION){ printdebug("function not declared at line %d, column %d", @1.first_line, @1.first_column); } else { setStartLine(node, @1.first_line); setAsKeyword(node, false); } cur = CreateScope(cur, 0, 0); } L_PAREN ID { printdebug("Currently see a function definition taking only one parameter (no as) of name %s and argument name %s", $1,$4); CreateEntry(cur, getParameter(table_lookup(getAncestor(cur), getType(table_lookup(getAncestor(cur), $1)))), $4, NULL); }R_PAREN ASSIGN sblock | ID { TableNode *node = table_lookup(getAncestor(cur), $1); if (node == NULL) { printdebug("null check"); } if (node == NULL) { printdebug("function not declared at line %d, column %d", @1.first_line, @1.first_column); }else if(getAdInfoType(node) != TYPE_FUNCTION_DECLARATION){ printdebug("function not declared at line %d, column %d", @1.first_line, @1.first_column); } else { setStartLine(node, @1.first_line); setAsKeyword(node, false); } cur = CreateScope(cur, 0, 0); }AS L_PAREN { TableNode *parameter = getParameter(table_lookup(getAncestor(cur), getType(table_lookup(getAncestor(cur), $1)))); if (parameter == NULL) { printdebug("function defined with as, but parameter is not a record at line %d, column %d", @1.first_line, @1.first_column); }else if(getAdInfoType(parameter) != TYPE_RECORD){ printdebug("function defined with as, but parameter is not a record at line %d, column %d", @1.first_line, @1.first_column); }else { for (TableNode* entry = getFirstEntry(getRecList(parameter)); entry!= NULL; entry = getNextEntry(entry)){ CreateEntry(cur, entry, NULL, NULL); } } } idlist {printdebug("Currently see a function definition taking one paramter (with as) of name %s and number of arguments %d", $1,$6);} R_PAREN ASSIGN sblock ; function_declaration: FUNCTION ID COLON ID {CreateEntry(cur, look_up(cur, $4), $2, CreateFunctionDeclarationInfo(-1, false));} | EXTERNAL FUNCTION ID COLON ID {CreateEntry(cur, look_up(cur, $5), $3, NULL);} ; idlist: ID { TableNode *entry = getFirstEntry(cur); while (getName(entry) != NULL) { 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); } COMMA idlist {$$ = $3 + 1;} | ID { TableNode *entry = getFirstEntry(cur); while (getName(entry) != NULL) { 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); $$ = 1; } ; sblock: L_BRACE {if (getLine(cur) != 0 && getColumn(cur))cur = CreateScope(cur,@1.first_line,@1.first_column);} statement_list {cur = getParent(cur);} R_BRACE | L_BRACE {if (getLine(cur) != 0 && getColumn(cur))cur = CreateScope(cur,@1.first_line,@1.first_column);} dblock {printdebug("seen sblock with dblock");} statement_list {cur = getParent(cur);} R_BRACE ; dblock: L_BRACKET declaration_list R_BRACKET; declaration_list: declaration SEMI_COLON declaration_list | declaration ; declaration: id_or_types COLON ID {printdebug("ID/TYPE: %s, ID: %s", $1, $3) ; CreateEntry(cur,table_lookup(getAncestor(cur),$1),$3,NULL); } ; id_or_types: ID {printdebug("string of id is %s in ID pattern of id_or_type rule.", $1); $$ = $1;} //{printdebug("string of id is %s in ID pattern of id_or_type rule. Type passed up the tree is %s.",$1,getType(look_up(cur,$1))); $$ = getType(look_up(cur,$1));} | types {printdebug("string of type is %s in types pattern of id_or_type rule.",$1);} {$$ = $1;} //{printdebug("string of type is %s in types pattern of id_or_type rule. That is passed up the tree.",$1);} {$$ = $1;} ; ; statement_list: compound_statement statement_list | compound_statement | simple_statement SEMI_COLON statement_list | simple_statement SEMI_COLON ; compound_statement: WHILE L_PAREN expression R_PAREN sblock | IF L_PAREN expression R_PAREN THEN sblock ELSE sblock | sblock //{printdebug("seen a compound statement rule");} ; simple_statement: assignable ASSIGN expression {if(strcmp($1, $3) == 0){ } else { printdebug("Mismatch at line %d and column%d", @2.first_line, @2.first_column); }} | RETURN expression ; assignable: ID {$$ = getType(look_up(cur,$1));} | assignable ablock {$$ = getName(getReturn(look_up(cur, $1)));} //add array case here | assignable rec_op ID {if(undefined != table_lookup(getRecList(look_up(cur, $1)), $3)){ {$$ = getName(table_lookup(getRecList(look_up(cur, $1)), $3));}};} ; rec_op : DOT expression: constant {printdebug("constant expression");} {$$ = $1;} | SUB_OR_NEG expression %prec UMINUS {printdebug("negative expression");if(strcmp($2,"integer") != 0) {printdebug("cant negate something not an integer at line %d and column %d",@2.first_line,@2.first_column); $$=strdup("undefined");}else{$$=$2;}} | NOT expression {printdebug("not expression"); if(strcmp($2,"Boolean")==0){$$=$2;}else{$$=strdup("undefined"); printdebug("mismatch at line %d and column %d. Invalid type being negated is %s", @1.first_line,@1.first_column,$2);}} | expression ADD expression {printdebug("add expression");if(strcmp($1,$3)==0 && strcmp($1,"integer")==0){$$=strdup("integer");} else{printdebug("mismatch at line %d and column %d. Invalid types %s and %s.", @2.first_line,@2.first_column,$1,$3); $$=strdup("undefined");}} | expression SUB_OR_NEG expression {printdebug("sub or neg expression");if(strcmp($1,$3)==0 &&strcmp($1,"integer")==0){$$=strdup("integer");} else{printdebug("mismatch at line %d and column %d. Invalid types %s and %s.", @2.first_line,@2.first_column,$1,$3); $$=strdup("undefined");}} | expression MUL expression {printdebug("multiply expression"); if(strcmp($1,$3)==0 &&strcmp($1,"integer")==0){$$=strdup("integer");} else{printdebug("mismatch at line %d and column %d. Invalid types %s and %s.", @2.first_line,@2.first_column,$1,$3); $$=strdup("undefined");}} | expression DIV expression {printdebug("divide expression");if(strcmp($1,$3)==0 && strcmp($1,"integer")==0){$$=strdup("integer");} else{printdebug("mismatch at line %d and column %d. Invalid types %s and %s.", @2.first_line,@2.first_column,$1,$3); $$=strdup("undefined");}} | expression REM expression {printdebug("remainder expression");if(strcmp($1,$3)==0 && strcmp($1,"integer")==0){$$=strdup("integer");} else{printdebug("mismatch at line %d and column %d. Invalid types %s and %s.", @2.first_line,@2.first_column,$1,$3); $$=strdup("undefined");}} | expression AND expression {printdebug("AND expression");if(strcmp($1,$3)==0 && strcmp($1,"Boolean")==0){$$=strdup("Boolean");} else{printdebug("mismatch at line %d and column %d. Invalid types %s and %s.", @2.first_line,@2.first_column,$1,$3); $$=strdup("undefined");}} | expression OR expression {printdebug("OR");if(strcmp($1,$3)==0 && strcmp($1,"Boolean")==0){$$=strdup("Boolean");} else{printdebug("mismatch at line %d and column %d. Invalid types %s and %s.", @2.first_line,@2.first_column,$1,$3); $$=strdup("undefined");}} | expression LESS_THAN expression {printdebug("less than expression");if(strcmp($1,$3)==0 && strcmp($1,"integer")==0){$$=strdup("Boolean");} else{printdebug("mismatch at line %d and column %d. Invalid types %s and %s.", @2.first_line,@2.first_column,$1,$3); $$=strdup("undefined");}} | expression EQUAL_TO expression {printdebug("equals check expression"); if(strcmp($1,$3)==0){$$=strdup("Boolean");} else if((strcmp($1,"array")==0||strcmp($1,"record")==0|| strcmp($1,"function type primitive")==0) && (strcmp($3,"address")==0)){$$=strdup("Boolean");} else{printdebug("mismatch at line %d and column %d. Invalid types %s and %s", @2.first_line,@2.first_column,$1,$3);$$=strdup("undefined");}} | assignable {printdebug("assignable expression. current type is %s",$1);$$=$1;} | L_PAREN expression R_PAREN {printdebug("paren expression. current type is %s",$2);$$=$2;} | memOp assignable {$$ = strdup("address");} ; ablock: L_PAREN argument_list {$$ = $2;} R_PAREN ; argument_list: expression COMMA argument_list {$$ = $3 + 1;} | expression {$$ = 1;} ; memOp: RESERVE {printdebug("reserve expression");} | RELEASE {printdebug("release expression");} ; constant: C_STRING {$$ = $1;} | C_INTEGER {$$ = "integer";} | C_NULL {$$ = $1;} | C_CHARACTER {$$ = $1;} | C_TRUE {$$ = $1;} | C_FALSE {$$ = $1;} ; types: // Commented out T_String below // T_STRING {printdebug("string of T_STRING in types is %s",$1);} {$$ = $1;} T_INTEGER {printdebug("string of T_INTEGER in types is %s",$1);} {$$ = $1;} | T_ADDRESS {printdebug("string of T_ADDRESS in types is %s",$1);} {$$ = $1;} | T_CHARACTER {printdebug("string of T_CHARACTER in types is %s",$1);} {$$ = $1;} | T_BOOLEAN {printdebug("string of T_BOOLEAN in types is %s",$1);} {$$ = $1;} ; %% void yyerror(const char *err) { fprintf(stderr, "ERROR: %s at token %s at line number %d,column number %d", err,yytext,yylloc.first_line,yylloc.first_column); }