396 lines
15 KiB
Plaintext
396 lines
15 KiB
Plaintext
|
|
/* Syntax Analyzer with Bison (3.8.2) */
|
|
/* The Translators - Spring 2025 */
|
|
|
|
%{
|
|
#include <stdio.h>
|
|
#include "../src/symbol_table.c"
|
|
#include <math.h>
|
|
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 <integ> idlist
|
|
%type <words> assignable
|
|
%type <words> expression
|
|
%type <words> constant
|
|
%type <words> id_or_types
|
|
%type <words> types
|
|
%token <words> ID 101
|
|
%token <words> T_INTEGER 201
|
|
%token <words> T_ADDRESS 202
|
|
%token <words> T_BOOLEAN 203
|
|
%token <words> T_CHARACTER 204
|
|
%token <words> T_STRING 205
|
|
%token <integ> C_INTEGER 301
|
|
%token <words> C_NULL 302
|
|
%token <words> C_CHARACTER 303
|
|
%token <words> C_STRING 304
|
|
%token <words> C_TRUE 305
|
|
%token <words> 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", $<words>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), $<words>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), $<words>1)))), $<words>4, NULL);
|
|
}R_PAREN ASSIGN sblock
|
|
| ID {
|
|
TableNode *node = table_lookup(getAncestor(cur), $<words>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), $<words>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, $<words>1);
|
|
} COMMA idlist {$$ = $<integ>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, $<words>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", $<words>1, $<words>3) ; CreateEntry(cur,table_lookup(getAncestor(cur),$<words>1),$<words>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.",$<words>1);} {$$ = $<words>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");} {$$ = $<words>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 {$<integ>$ = $<integ>2;} R_PAREN
|
|
;
|
|
|
|
argument_list:
|
|
expression COMMA argument_list {$<integ>$ = $<integ>3 + 1;}
|
|
| expression {$<integ>$ = 1;}
|
|
;
|
|
|
|
|
|
memOp:
|
|
RESERVE {printdebug("reserve expression");}
|
|
| RELEASE {printdebug("release expression");}
|
|
;
|
|
|
|
|
|
constant:
|
|
C_STRING {$$ = $<words>1;}
|
|
| C_INTEGER {$$ = "integer";}
|
|
| C_NULL {$$ = $<words>1;}
|
|
| C_CHARACTER {$$ = $<words>1;}
|
|
| C_TRUE {$$ = $<words>1;}
|
|
| C_FALSE {$$ = $<words>1;}
|
|
;
|
|
|
|
types:
|
|
// Commented out T_String below
|
|
// T_STRING {printdebug("string of T_STRING in types is %s",$<words>1);} {$$ = $<words>1;}
|
|
T_INTEGER {printdebug("string of T_INTEGER in types is %s",$<words>1);} {$$ = $1;}
|
|
| T_ADDRESS {printdebug("string of T_ADDRESS in types is %s",$<words>1);} {$$ = $1;}
|
|
| T_CHARACTER {printdebug("string of T_CHARACTER in types is %s",$<words>1);} {$$ = $1;}
|
|
| T_BOOLEAN {printdebug("string of T_BOOLEAN in types is %s",$<words>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);
|
|
}
|