858 lines
31 KiB
Plaintext
858 lines
31 KiB
Plaintext
|
||
/* 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/symbol_table.c"
|
||
void yyerror(const char *err);
|
||
int token_tracker;
|
||
TableNode * tn;
|
||
%}
|
||
|
||
%union {
|
||
int integ;
|
||
char* words;
|
||
void* tn;
|
||
}
|
||
|
||
%locations
|
||
|
||
%type <integ> idlist
|
||
%type <tn> assignable
|
||
%type <tn> expression
|
||
%type <tn> constant
|
||
%type <tn> id_or_types
|
||
%type <tn> types
|
||
%type <integ> argument_list
|
||
%type <integ> ablock
|
||
%token <words> ID 101
|
||
%token <tn> T_INTEGER 201
|
||
%token <tn> T_ADDRESS 202
|
||
%token <tn> T_BOOLEAN 203
|
||
%token <tn> T_CHARACTER 204
|
||
%token <tn> T_STRING 205
|
||
%token <integ> C_INTEGER 301
|
||
%token <tn> C_NULL 302
|
||
%token <tn> C_CHARACTER 303
|
||
%token <tn> C_STRING 304
|
||
%token <tn> C_TRUE 305
|
||
%token <tn> 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),TYPE_RECORD_TYPE, recprime, $2, CreateRecordInfo(0, cur = CreateScope(cur, 0, 0)));
|
||
printdebug("Created a new scope");
|
||
//if (look_up(cur, $2) == undefined) {
|
||
// printdebug("rec not found");
|
||
//}
|
||
}
|
||
dblock
|
||
{
|
||
//We are scanning through the dblock scope to get the length of the dblock (num of elements) from getRecSize
|
||
//and then putting it in the entry that we created above.
|
||
setRecSize(look_up(getParent(cur), $2), getRecSize(cur));
|
||
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 {
|
||
TableNode *node = table_lookup(getAncestor(cur), $1);
|
||
if (node == undefined) {
|
||
|
||
printdebug(" [TYPE CHECK] undefined nodedeclared at line %d, column %d", @1.first_line, @1.first_column);
|
||
}else if(getAdInfoType(node) != TYPE_FUNCTION_DECLARATION){
|
||
printdebug("[TYPE CHECK] not a valid function declaration at line %d, column %d", @1.first_line, @1.first_column);
|
||
}
|
||
else {
|
||
printdebug("setting as keyword to true");
|
||
setStartLine(node, @1.first_line);
|
||
setAsKeyword(node, true);
|
||
}
|
||
cur = CreateScope(cur, 0, 0);
|
||
printdebug("Created a new scope");
|
||
} L_PAREN {
|
||
TableNode *parameter = getParameter(table_lookup(getAncestor(cur), getType(table_lookup(getAncestor(cur), $1))));
|
||
printdebug("parameter type: %s", getType(parameter));
|
||
if (parameter == undefined) {
|
||
printdebug("[TYPE CHECK] function defined with as, but parameter is undefined at line %d, column %d", @1.first_line, @1.first_column);
|
||
}else if(getAdInfoType(parameter) != TYPE_RECORD){
|
||
int type_of_param_type = getAdInfoType(parameter);
|
||
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_ALL_ELSE
|
||
|| type_of_param_type == TYPE_SYSTEM_DEFINED
|
||
|| type_of_param_type == TYPE_STRING){ // note that strings are actually arrays so this is unused
|
||
printdebug("[TYPE CHECK] type of parameter being passed in to function definition is %s which is invalid", 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);
|
||
} else {
|
||
CreateEntry(cur, getAdInfoType(parameter), parameter,NULL, getAdInfo(parameter));
|
||
}
|
||
} else {
|
||
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_DECLARATION
|
||
|| type_of_param_type == TYPE_ARRAY
|
||
|| type_of_param_type == TYPE_ALL_ELSE
|
||
|| type_of_param_type == TYPE_SYSTEM_DEFINED
|
||
|| type_of_param_type == TYPE_STRING){ // note that strings are actually arrays so this is unused
|
||
printdebug("[TYPE CHECK] type of parameter being passed in to AS function definition is %s which is invalid", getName(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", getName(entry));
|
||
}
|
||
if(type_of_param_type == TYPE_UNDEFINED){
|
||
CreateEntry(cur,type_of_param_type, undefined, NULL, NULL);
|
||
} else {
|
||
CreateEntry(cur,type_of_param_type, entry, NULL, getAdInfo(entry));
|
||
/*printdebug("creating entry of type %s for function", getType(entry));
|
||
CreateEntry(cur, getTypeEntry(entry), "undefined", NULL);*/
|
||
}
|
||
}
|
||
}
|
||
} idlist {
|
||
printdebug("Currently see a function definition taking one paramter (with as) of name %s and number of arguments %d", $1,$5);
|
||
} R_PAREN ASSIGN sblock //check sblock type
|
||
|
||
;
|
||
|
||
function_declaration:
|
||
FUNCTION ID COLON ID
|
||
{
|
||
if(getAdInfoType(look_up(cur, $4))==TYPE_FUNCTION_TYPE){
|
||
CreateEntry(cur,TYPE_FUNCTION_DECLARATION, look_up(cur, $4), $2, CreateFunctionDeclarationInfo(-1, false));
|
||
}
|
||
else{
|
||
printdebug("[TYPE CHECK] function declaration of %s is not a valid function type at line %d, column %d", $2, @1.first_line, @1.first_column);
|
||
CreateEntry(cur,TYPE_FUNCTION_DECLARATION, look_up(cur, $4), $2, CreateFunctionDeclarationInfo(-1, false));
|
||
|
||
}
|
||
}
|
||
|
||
| EXTERNAL FUNCTION ID COLON ID
|
||
{
|
||
if(getAdInfoType(look_up(cur, $5))==TYPE_FUNCTION_TYPE){
|
||
CreateEntry(cur,TYPE_FUNCTION_DECLARATION, look_up(cur, $5), $3, CreateFunctionDeclarationInfo(-1, false));
|
||
}
|
||
else{
|
||
printdebug("[TYPE CHECK] function declaration of %s is not a valid function type at line %d, column %d", $3, @1.first_line, @1.first_column);
|
||
CreateEntry(cur,TYPE_FUNCTION_DECLARATION, look_up(cur, $5), $3, CreateFunctionDeclarationInfo(-1, false));
|
||
|
||
}
|
||
}
|
||
;
|
||
|
||
|
||
|
||
idlist:
|
||
ID
|
||
{
|
||
TableNode *entry = getFirstEntry(cur);
|
||
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);
|
||
}
|
||
COMMA idlist
|
||
{
|
||
$$ = $4 + 1;
|
||
}
|
||
|
||
| ID
|
||
{
|
||
TableNode *entry = getFirstEntry(cur);
|
||
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, $<words>1);
|
||
$$ = 1;
|
||
}
|
||
;
|
||
|
||
|
||
sblock:
|
||
L_BRACE
|
||
{
|
||
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
|
||
{
|
||
printdebug("Moving up a scope after seeing sblock");
|
||
cur = getParent(cur);
|
||
}
|
||
R_BRACE
|
||
|
||
| 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);
|
||
}
|
||
R_BRACE
|
||
;
|
||
|
||
|
||
|
||
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
|
||
;
|
||
|
||
|
||
|
||
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) {
|
||
printdebug("undefined type at line %d and column %d", @2.first_line, @2.first_column);
|
||
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_TYPE;
|
||
CreateEntry(cur,d,(TableNode*)$1,$3,getAdInfo((TableNode*)$1));
|
||
}
|
||
else if(d == TYPE_ARRAY_TYPE){
|
||
printdebug("array variable at line %d and column %d", @2.first_line, @2.first_column);
|
||
d = TYPE_ARRAY;
|
||
CreateEntry(cur,d,(TableNode*)$1,$3,getAdInfo((TableNode*)$1));
|
||
}
|
||
else if(d == TYPE_RECORD_TYPE){
|
||
printdebug("record variable at line %d and column %d", @2.first_line, @2.first_column);
|
||
d = TYPE_RECORD;
|
||
CreateEntry(cur,d,(TableNode*)$1,$3,getAdInfo((TableNode*)$1));
|
||
}
|
||
else if(d == TYPE_PRIMITIVE){
|
||
printdebug("primitive variable at line %d and column %d", @2.first_line, @2.first_column);
|
||
CreateEntry(cur,d,(TableNode*)$1,$3,getAdInfo((TableNode*)$1));
|
||
}else {
|
||
printdebug("other invalid type passed at %d and column %d", @2.first_line, @2.first_column);
|
||
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
|
||
| 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
|
||
;
|
||
|
||
|
||
|
||
simple_statement:
|
||
assignable ASSIGN expression
|
||
{
|
||
bool passCheck = false;
|
||
TableNode * left = (TableNode*)$1;
|
||
TableNode * right = (TableNode*)$3;
|
||
|
||
printTableNode((TableNode*)$1);
|
||
printTableNode((TableNode*)$3);
|
||
|
||
if (strcmp(getType(right), "primitive") == 0) {
|
||
if (strcmp((getType(left)),(getName(right))) == 0) {
|
||
printdebug("%s[☺] Passed primitive type check; %s = %s", COLOR_GREEN, getName(left), getName(right));
|
||
passCheck = true;
|
||
}
|
||
}
|
||
|
||
if(strcmp(getName(left), getName(right)) == 0) {
|
||
printdebug("Passed standard type check; assignable = expression");
|
||
passCheck = true;
|
||
}
|
||
|
||
if((strcmp(getType(left), "array") == 0) && (strcmp(getName(right), "address") == 0)) {
|
||
printdebug("%s[☺] Passed array type check; %s = %s", COLOR_GREEN, getName(left), getName(right));
|
||
passCheck = true;
|
||
}
|
||
|
||
if((strcmp(getType(left), "record") == 0) && (strcmp(getName(right), "address") == 0)) {
|
||
printdebug("%s[☺] Passed address type check; %s = %s", COLOR_GREEN, getName(left), getName(right));
|
||
passCheck = true;
|
||
}
|
||
|
||
if((strcmp(getType(left), "function type primitive") == 0) && (strcmp(getName(right), "address") == 0)) {
|
||
printdebug("%s[☺] Passed function type primitive type check; %s = %s", COLOR_GREEN, getName(left), getName(right));
|
||
passCheck = true;
|
||
}
|
||
|
||
// Type check fails:
|
||
if (!passCheck) {
|
||
printdebug("%s[TYPE CHECK] %sMismatch at %sline %d and column %d%s", COLOR_ORANGE, COLOR_WHITE, COLOR_YELLOW, @2.first_line, @2.first_column, COLOR_WHITE);
|
||
printdebug(" - Invalid types %s$1: %s and $3: %s%s", COLOR_YELLOW, getType(left), getType(right), COLOR_WHITE);
|
||
printdebug(" - %sgetType for address: %s", COLOR_YELLOW, getType(left));
|
||
}
|
||
}
|
||
|
||
| RETURN expression
|
||
;
|
||
|
||
|
||
|
||
rec_op:
|
||
DOT
|
||
|
||
|
||
|
||
ablock:
|
||
L_PAREN argument_list R_PAREN
|
||
{
|
||
$$ = $2;
|
||
printdebug("ablock is %d", $$);
|
||
}
|
||
;
|
||
|
||
|
||
|
||
argument_list:
|
||
expression COMMA argument_list
|
||
{
|
||
CreateEntry(cur,getAdInfoType((TableNode*)$1), (TableNode*)$1, getName((TableNode*)$1), NULL);
|
||
$$ = $3 + 1;
|
||
printdebug("[ARGUMENT_LIST] argument list is %d", $$);
|
||
}
|
||
|
||
| expression
|
||
{
|
||
CreateEntry(cur,getAdInfoType((TableNode*)$1),(TableNode*)$1, getName((TableNode*)$1), NULL);
|
||
$$ = 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((TableNode*)$2 != integ) {
|
||
printdebug("cant negate something not an integer at line %d and column %d",@2.first_line,@2.first_column);
|
||
$$=undefined;
|
||
} else {
|
||
$$=(TableNode*)$2;
|
||
}
|
||
}
|
||
|
||
| NOT expression
|
||
{
|
||
printdebug("not expression");
|
||
if((TableNode*)$2 == boo) {
|
||
$$=(TableNode*)$2;
|
||
} else {
|
||
$$=undefined;
|
||
printdebug("[TYPE CHECK] mismatch at line %d and column %d. Invalid type being negated is %s", @1.first_line,@1.first_column,getName((TableNode*)$2));
|
||
}
|
||
}
|
||
|
||
| expression ADD expression
|
||
{
|
||
printdebug("add expression");
|
||
if((TableNode*)$1 == (TableNode*)$3 && (TableNode*)$1 == integ) {
|
||
$$=(TableNode*)$1;
|
||
} else {
|
||
printdebug("[TYPE CHECK] mismatch at line %d and column %d. Invalid types %s and %s.", @2.first_line,@2.first_column,getName((TableNode*)$1),getName((TableNode*)$3));
|
||
$$=undefined;
|
||
}
|
||
}
|
||
|
||
| expression SUB_OR_NEG expression
|
||
{
|
||
printdebug("sub or neg expression");
|
||
if((TableNode*)$1 == (TableNode*)$3 && (TableNode*)$1 == integ) {
|
||
$$=(TableNode*)$1;
|
||
} else {
|
||
printdebug("[TYPE CHECK] mismatch at line %d and column %d. Invalid types %s and %s.", @2.first_line,@2.first_column,getName((TableNode*)$1),getName((TableNode*)$3));
|
||
$$=undefined;
|
||
}
|
||
}
|
||
|
||
| expression MUL expression
|
||
{
|
||
printdebug("multiply expression");
|
||
if((TableNode*)$1 == (TableNode*)$3 && (TableNode*)$1 == integ) {
|
||
$$=(TableNode*)$1;
|
||
} else{
|
||
printdebug("[TYPE CHECK] mismatch at line %d and column %d. Invalid types %s and %s.", @2.first_line,@2.first_column,getName($1),getName($3));
|
||
$$=undefined;
|
||
}
|
||
}
|
||
|
||
| expression DIV expression
|
||
{
|
||
printdebug("divide expression");
|
||
if((strcmp(getName((TableNode*)$1),getName((TableNode*)$3))==0) && ((TableNode*)$1 == integ)) {
|
||
$$=(TableNode*)$1;
|
||
} else {
|
||
printdebug("[TYPE CHECK] mismatch at line %d and column %d. Invalid types %s and %s.", @2.first_line,@2.first_column,getName((TableNode*)$1),getName((TableNode*)$3));
|
||
$$=undefined;
|
||
}
|
||
}
|
||
|
||
| expression REM expression
|
||
{
|
||
printdebug("remainder expression");
|
||
if($1 == $3 && $1 == integ) {
|
||
$$=$1;
|
||
} else {
|
||
printdebug("[TYPE CHECK] mismatch at line %d and column %d. Invalid types %s and %s.", @2.first_line,@2.first_column,getName((TableNode*)$1),getName((TableNode*)$3));
|
||
$$=undefined;
|
||
}
|
||
}
|
||
|
||
| expression AND expression
|
||
{
|
||
printdebug("AND expression");
|
||
if($1 == $3 && $1 == boo){
|
||
$$=$1;
|
||
} else{
|
||
printdebug("[TYPE CHECK] mismatch at line %d and column %d. Invalid types %s and %s.", @2.first_line,@2.first_column,getName((TableNode*)$1),getName((TableNode*)$3));
|
||
$$=undefined;
|
||
}
|
||
}
|
||
|
||
| expression OR expression
|
||
{
|
||
printdebug("OR");
|
||
if((strcmp(getName((TableNode*)$1),getName((TableNode*)$3))==0) && $1 == boo) {
|
||
$$=$1;
|
||
} else {
|
||
printdebug("[TYPE CHECK] mismatch at line %d and column %d. Invalid types %s and %s.", @2.first_line,@2.first_column,getName((TableNode*)$1),getName((TableNode*)$3));
|
||
$$=undefined;
|
||
}
|
||
}
|
||
|
||
| expression LESS_THAN expression
|
||
{
|
||
printdebug("less than expression");
|
||
if($1 == $3 && $1==integ) {
|
||
$$=boo;
|
||
} else {
|
||
printdebug("[TYPE CHECK] mismatch at line %d and column %d. Invalid types %s and %s.", @2.first_line,@2.first_column,getName((TableNode*)$1),getName((TableNode*)$3));
|
||
$$=undefined;
|
||
}
|
||
}
|
||
|
||
| expression EQUAL_TO expression
|
||
{
|
||
printdebug("equals check expression");
|
||
if($1 == $3 && $1 != undefined) {
|
||
$$=boo;
|
||
} else {
|
||
printdebug("[TYPE CHECK] mismatch at line %d and column %d. Invalid types %s and %s", @2.first_line,@2.first_column,getName((TableNode*)$1),getName((TableNode*)$3));
|
||
$$ = undefined;
|
||
}
|
||
}
|
||
|
||
| assignable
|
||
{
|
||
printdebug("assignable expression. current type is %s",getName((TableNode*)$1));
|
||
if(getAdInfoType((TableNode*)$1) == TYPE_PRIMITIVE||
|
||
getAdInfoType((TableNode*)$1) == TYPE_ARRAY ||
|
||
getAdInfoType((TableNode*)$1) == TYPE_RECORD){
|
||
printdebug("assignable passing up to expression is primitive, array instance, or record instance. Passing up its type");
|
||
$$= getTypeEntry((TableNode*)$1);
|
||
}
|
||
|
||
else if(getAdInfoType((TableNode*)$1) == TYPE_ARRAY_TYPE||
|
||
getAdInfoType((TableNode*)$1) == TYPE_RECORD_TYPE||
|
||
getAdInfoType((TableNode*)$1) == TYPE_FUNCTION_TYPE||
|
||
getAdInfoType((TableNode*)$1) == TYPE_FUNCTION_DECLARATION){
|
||
printdebug("assignable passing up to expression is array type, record type, function type, or function declaration");
|
||
$$= ((TableNode*)$1);
|
||
}
|
||
else {
|
||
printdebug("[TYPE CHECK] assignable passing up an invalid type to expression");
|
||
$$= ((TableNode*)$1);
|
||
}
|
||
|
||
}
|
||
|
||
| L_PAREN expression R_PAREN
|
||
{
|
||
printdebug("paren expression. current type is %s",getName((TableNode*)$2));
|
||
$$=$2;
|
||
}
|
||
|
||
| memOp assignable
|
||
{
|
||
int d = getAdInfoType((TableNode*)$2);
|
||
if(d == TYPE_ARRAY_TYPE || d == TYPE_ARRAY || d == TYPE_RECORD_TYPE || d == TYPE_RECORD) {
|
||
//printdebug("[TYPE CHECK] valid memOp expression");
|
||
$$ = addr;
|
||
} else {
|
||
printdebug("[TYPE CHECK] invalid memOp expression at line %d and column %d.", @2.first_line,@2.first_column,getName((TableNode*)$2));
|
||
$$=undefined;
|
||
}
|
||
}
|
||
|
||
;
|
||
|
||
//UPDATED $$ for tablenodes to this point
|
||
|
||
// prolly right, check back with me later
|
||
// add array case
|
||
// include type check for ablock in arrays - ablock is always the int of the elements in array/rec
|
||
assignable:
|
||
ID
|
||
{
|
||
$$ = look_up(cur,$1);
|
||
printdebug("[ASSIGNABLE - RULE 1] assignable = type: %s | ID = %s", getName((TableNode*)$$), $1);
|
||
}
|
||
|
||
| assignable
|
||
{
|
||
printdebug("%sBeginning rule 2 of assignable.", COLOR_CYAN);
|
||
cur = CreateScope(cur, -1,-1);
|
||
}
|
||
ablock
|
||
{
|
||
int type = getAdInfoType(look_up(getParent(cur), getName((TableNode*)$1)));
|
||
printdebug("%stype is %d", COLOR_PURPLE, type);
|
||
printdebug("%s", getName((TableNode*)$1));
|
||
|
||
if (type == TYPE_FUNCTION_DECLARATION) {
|
||
printdebug("%sEntering function call", COLOR_LIGHTGREEN);
|
||
if (look_up(getParent(cur), getName((TableNode*)$1))->additionalinfo->FunDecAdInfo->regularoras) {
|
||
printdebug("as function");
|
||
//char *funtype = getType(look_up(cur, $1));
|
||
printdebug("%s", getType(look_up(cur, getName((TableNode*)$1))));
|
||
|
||
|
||
|
||
TableNode * typeNode = table_lookup(getAncestor(cur), getType((TableNode*)$1));
|
||
TableNode *param = getParameter(typeNode);
|
||
printTableNode(param);
|
||
|
||
SymbolTable *recList = getRecList(param);
|
||
TableNode *lastCheckedRef = getFirstEntry(recList);
|
||
TableNode *lastCheckedAct = getFirstEntry(cur);
|
||
while (getNextEntry(lastCheckedRef) != NULL) {
|
||
lastCheckedRef = getNextEntry(lastCheckedRef);
|
||
}
|
||
|
||
|
||
//this isn't very efficient, but will hopefully work
|
||
while (lastCheckedAct != NULL && lastCheckedRef != NULL) {
|
||
if (strcmp(getName(lastCheckedAct), getName(lastCheckedRef)) != 0) {
|
||
printdebug("expected %s. expression in function call got %s. at line %d and column %d",getType(lastCheckedRef), getName(lastCheckedAct), @3.first_line, @3.first_column);
|
||
printdebug("%d", strcmp(getName(lastCheckedAct), getName(lastCheckedRef)));
|
||
}
|
||
lastCheckedAct = getNextEntry(lastCheckedAct);
|
||
TableNode *tn = getFirstEntry(recList);
|
||
|
||
if (tn != lastCheckedRef) {
|
||
while (getNextEntry(tn) != lastCheckedRef) {
|
||
tn = getNextEntry(tn);
|
||
}
|
||
lastCheckedRef = tn;
|
||
} else {break;}
|
||
}
|
||
|
||
} else {
|
||
char *expected = getName(getParameter(look_up(getParent(cur), getName((TableNode*)$1))));
|
||
char *actual = getType(getFirstEntry(cur));
|
||
if (strcmp(expected, actual) != 0) {
|
||
printdebug("expected %s expression in function call but got %s at line %d and column %d",expected, actual, @3.first_line, @3.first_column);
|
||
}
|
||
}
|
||
$$ = getReturn((table_lookup(getAncestor(cur), getType((TableNode*)$1))));
|
||
printdebug("[ASSIGNABLE - RULE 2] assignable = type: %s | name_func = %s", getName((TableNode*)$$), getName((TableNode*)$1));
|
||
|
||
} else if (type == TYPE_ARRAY_TYPE) {
|
||
printdebug("%sEntering array call", COLOR_LIGHTGREEN);
|
||
if (getNumArrDim(look_up(getParent(cur), getName((TableNode*)$1))) != $<integ>2) {
|
||
printdebug("expected %d arguments but had %d at line %d and column %d\n", getNumArrDim(look_up(cur, getName((TableNode*)$1))), $<integ>2, @2.first_line, @2.first_column);
|
||
}
|
||
$$ = getArrType(look_up(getParent(cur), getName((TableNode*)$1)));
|
||
printdebug("[ASSIGNABLE - RULE 2] assignable = type: %s | name_func = %s", getName((TableNode*)$$), getName((TableNode*)$1));
|
||
}
|
||
cur = getParent(cur);
|
||
}
|
||
|
||
| assignable rec_op ID
|
||
{
|
||
if(undefined != table_lookup(getRecList(table_lookup(getAncestor(cur), getName((TableNode*)$1))), $3)) {
|
||
|
||
$$ = table_lookup(getRecList(table_lookup(getAncestor(cur), getName((TableNode*)$1))), $3);
|
||
}
|
||
printdebug("[ASSIGNABLE - RULE 3] assignable = type: %s | ID = %s", getName((TableNode*)($$)), $1);
|
||
}
|
||
|
||
;
|
||
|
||
|
||
|
||
memOp:
|
||
RESERVE
|
||
{
|
||
printdebug("reserve expression");
|
||
}
|
||
|
||
| RELEASE
|
||
{
|
||
printdebug("release expression");
|
||
}
|
||
|
||
;
|
||
|
||
|
||
constant:
|
||
C_STRING
|
||
{
|
||
$$ = $1;
|
||
printdebug("string of C_STRING in constant is %s",getName((TableNode*)$1));
|
||
}
|
||
|
||
| C_INTEGER
|
||
{
|
||
$$ = integ;
|
||
printdebug("string of C_INTEGER in constant is integer");
|
||
}
|
||
|
||
| C_NULL
|
||
{
|
||
$$ = $1;
|
||
printdebug("string of C_NULL in constant is %s",getName((TableNode*)$1));
|
||
}
|
||
|
||
| C_CHARACTER
|
||
{
|
||
$$ = $1;
|
||
printdebug("string of C_CHARACTER in constant is %s",getName((TableNode*)$1));
|
||
}
|
||
|
||
| C_TRUE
|
||
{
|
||
$$ = $1;
|
||
printdebug("string of C_TRUE in constant is %s",getName((TableNode*)$1));
|
||
}
|
||
|
||
| C_FALSE
|
||
{
|
||
$$ = $1;
|
||
printdebug("string of C_FALSE in constant is %s",getName((TableNode*)$1));
|
||
}
|
||
|
||
;
|
||
|
||
|
||
|
||
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 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);
|
||
}
|