1665 lines
68 KiB
Plaintext
1665 lines
68 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/grammar.h"
|
||
%}
|
||
%union {
|
||
int integ;
|
||
char* words;
|
||
char letter;
|
||
void* tn;
|
||
}
|
||
|
||
%locations
|
||
|
||
%token <integ> ACCESS 801
|
||
%type <integ> idlist
|
||
%type <tn> assignable
|
||
%type <tn> expression
|
||
%type <tn> constant
|
||
%type <tn> id_or_types
|
||
%type <tn> types
|
||
%type <tn> sblock
|
||
%type <tn> compound_statement
|
||
%type <tn> simple_statement
|
||
%type <tn> statement_list
|
||
%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
|
||
%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
|
||
{
|
||
//$<tn>$ = $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);
|
||
//$<tn>$ = $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(traverse<array_dims){
|
||
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;
|
||
break;
|
||
}
|
||
traverse++;
|
||
t = getNextEntry(t);
|
||
}
|
||
if(traverse != array_dims){
|
||
throw_error(ERROR_TYPE, "Invalid number of arguments for array %s. Expected %d but got %d", getName(n), array_dims, traverse);
|
||
$$= undefined;}
|
||
}
|
||
}
|
||
}
|
||
*/
|
||
}
|
||
| RELEASE ID {
|
||
cur = CreateScope(cur, -2,-1);
|
||
} ablock {
|
||
char* temp = temp_var_gen();
|
||
TableNode* node = CreateEntry(cur,TYPE_PRIMITIVE, integ, 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 Release 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(traverse<array_dims){
|
||
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;
|
||
break;
|
||
}
|
||
traverse++;
|
||
t = getNextEntry(t);
|
||
}
|
||
if(traverse != array_dims){
|
||
throw_error(ERROR_TYPE, "Invalid number of arguments for array %s. Expected %d but got %d", getName(n), array_dims, traverse);
|
||
$$= undefined;}
|
||
}
|
||
}
|
||
}
|
||
*/
|
||
}
|
||
/*
|
||
| RELEASE assignable
|
||
{
|
||
int d = getAdInfoType((TableNode*)$2);
|
||
//commenting out type checks for now since assignable is being resolved to something before reserve is being applied which is tricky
|
||
//if(d == TYPE_ARRAY ||d == TYPE_RECORD) {
|
||
char* temp = temp_var_gen();
|
||
TableNode* node = CreateEntry(cur,TYPE_PRIMITIVE, addr, temp, NULL);
|
||
//NOTE ADD ASSIGNMENT EMIT HERE (MIGHT NEED TO PUSH TO STACK)
|
||
$$ = node;
|
||
// } else {
|
||
// throw_error(ERROR_TYPE, "Invalid memOp expression with object %s of type %s.", getName((TableNode*)$2), getType((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
|
||
{
|
||
TableNode* pass = look_up(cur,$1);
|
||
if(pass == undefined){
|
||
throw_error(ERROR_TYPE, "Undefined variable %s", $1);
|
||
}
|
||
$$ = pass;
|
||
printdebug("[ASSIGNABLE - RULE 1] assignable = type: %s | ID = %s", getType(pass), getName(pass));
|
||
}
|
||
| assignable
|
||
{
|
||
printdebug("%sBeginning rule 2 of assignable.", COLOR_CYAN);
|
||
//Creating a dummy scope where we create entries for all the arguments of a function call
|
||
//Must also consider that we might be in an array access
|
||
cur = CreateScope(cur, -1,-1);
|
||
}
|
||
//we have to consider emmissions in ablocks
|
||
ablock
|
||
{
|
||
//int type = getAdInfoType(look_up(getParent(cur), getName((TableNode*)$1)));
|
||
int type = getAdInfoType(getTypeEntry((TableNode*)$1));
|
||
printdebug("%stype is %d", COLOR_PURPLE, type);
|
||
printdebug("%s", getName((TableNode*)$1));
|
||
|
||
if (type == TYPE_FUNCTION_TYPE) {
|
||
printdebug("%sEntering function call", COLOR_LIGHTGREEN);
|
||
//getting the parameter. The type of assignable is a function type so we need to access the paramater of the type
|
||
TableNode *expected = getParameter(getTypeEntry((TableNode*)$1));
|
||
//Jump into case where the parameter is a record type
|
||
if(getAdInfoType(expected) == TYPE_RECORD_TYPE){
|
||
//int argument_size = getRecSize(cur);
|
||
int parameter_size = getRecSize(getRecList(expected));
|
||
printdebug("argument size is %d\n", $3);
|
||
printdebug("parameter size is %d\n", parameter_size);
|
||
if ($3 != parameter_size) {
|
||
throw_error(ERROR_SYNTAX, "expected %d arguments for this function but got %d", parameter_size, $3);
|
||
}else{
|
||
TableNode* param_arg_type = getFirstEntry(getRecList(expected));
|
||
TableNode* arg_given = getFirstEntry(cur);
|
||
while(arg_given != NULL && arg_given != undefined && getName(arg_given)[0]!='&'){
|
||
arg_given = getNextEntry(arg_given);
|
||
}
|
||
if(getTypeEntry(arg_given) != getTypeEntry(param_arg_type)){
|
||
throw_error(ERROR_TYPE, "expected %s expression as first argument of a record in function call but got %s", getType(param_arg_type), getType(arg_given));
|
||
}
|
||
param_arg_type = getNextEntry(param_arg_type);
|
||
arg_given = getNextEntry(arg_given);
|
||
while(arg_given != NULL && arg_given != undefined && param_arg_type != NULL){
|
||
while(arg_given != NULL && getName(arg_given)[0]!='&'){
|
||
arg_given = getNextEntry(arg_given);
|
||
}
|
||
if(getTypeEntry(arg_given) != getTypeEntry(param_arg_type)){
|
||
throw_error(ERROR_TYPE, "expected type %s expression as argument of a record in function call but got type %s", getType(param_arg_type), getType(arg_given));
|
||
}
|
||
arg_given = getNextEntry(arg_given);
|
||
param_arg_type = getNextEntry(param_arg_type);
|
||
}
|
||
}
|
||
}else{
|
||
TableNode*actual_instance = getFirstEntry(cur);
|
||
while(actual_instance != NULL && actual_instance != undefined && getName(actual_instance)[0] !='&'){
|
||
actual_instance = getNextEntry(actual_instance);
|
||
}
|
||
if(actual_instance == NULL){
|
||
throw_error(ERROR_TYPE, "Invalid function call. No arguments passed");
|
||
break;
|
||
}
|
||
TableNode *actual = getTypeEntry(actual_instance);
|
||
if (expected != actual) {
|
||
throw_error(ERROR_TYPE, "expected %s expression in single argument function call but got %s", getType(expected), getName(actual));
|
||
}
|
||
if ($3 != 1) {
|
||
throw_error(ERROR_SYNTAX, "expected 1 argument but got %d", $3); }
|
||
printTableNode(getReturn(getTypeEntry((TableNode*)$1)));
|
||
}
|
||
char* temp = temp_var_gen();
|
||
TableNode* typeNode2 = getReturn(getTypeEntry((TableNode*)$1));
|
||
int t = -1;
|
||
if(getAdInfoType(typeNode2) == TYPE_PRIMITIVE_TYPE){
|
||
t = TYPE_PRIMITIVE;
|
||
}
|
||
else if(getAdInfoType(typeNode2) == TYPE_ARRAY_TYPE){
|
||
t = TYPE_ARRAY;
|
||
}
|
||
else if(getAdInfoType(typeNode2) == TYPE_RECORD_TYPE){
|
||
t = TYPE_RECORD;
|
||
}
|
||
//this may need to be updated to provide the correct name of things
|
||
else if(getAdInfoType(typeNode2) == TYPE_FUNCTION_TYPE){
|
||
t = TYPE_FUNCTION_DECLARATION;
|
||
}else{
|
||
t= TYPE_UNDEFINED;
|
||
throw_error(ERROR_TYPE, "Undefined type returned by function.");
|
||
}
|
||
TableNode* node = CreateEntry(cur,t, typeNode2, temp, NULL);
|
||
//-----------------------------------------------------------------------------
|
||
// Please don't touch
|
||
// the + 1 is here because I don't detach the last param
|
||
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, $1));
|
||
//-----------------------------------------------------------------------------
|
||
$$ = node;
|
||
//NOTE ADD ASSIGNMENT EMIT HERE (MIGHT NEED TO PUSH TO STACK for function call)
|
||
printdebug("[ASSIGNABLE - RULE 2] assignable = type: %s | name_func = %s", getName(typeNode2), getName((TableNode*)$1));
|
||
} else if (type == TYPE_ARRAY_TYPE) {
|
||
printdebug("%sEntering array call", COLOR_LIGHTGREEN);
|
||
if (getNumArrDim(getTypeEntry((TableNode*)$1)) != $3) {
|
||
throw_error(ERROR_SYNTAX, "expected %d arguments for this array but got %d", getNumArrDim(getTypeEntry((TableNode*)$1)), $3);
|
||
}
|
||
|
||
char* temp = temp_var_gen();
|
||
TableNode* typeNode2 = getArrType(look_up(getAncestor(cur), getType((TableNode*)$1)));
|
||
int t = -1;
|
||
if(getAdInfoType(typeNode2) == TYPE_PRIMITIVE_TYPE){
|
||
t = TYPE_PRIMITIVE;
|
||
}
|
||
else if(getAdInfoType(typeNode2) == TYPE_ARRAY_TYPE){
|
||
t = TYPE_ARRAY;
|
||
}
|
||
else if(getAdInfoType(typeNode2) == TYPE_RECORD_TYPE){
|
||
t = TYPE_RECORD;
|
||
}
|
||
else if(getAdInfoType(typeNode2) == TYPE_FUNCTION_TYPE){
|
||
t = TYPE_FUNCTION_DECLARATION;
|
||
}else{
|
||
t= TYPE_UNDEFINED;
|
||
throw_error(ERROR_TYPE, "Undefined type stored in array.");
|
||
}
|
||
TableNode* node = CreateEntry(cur,t, typeNode2, temp, NULL);
|
||
//TODO: emit assign here
|
||
//TODO: emit_array_access(char* node, char* array, ...)
|
||
$$ = node;
|
||
printdebug("[ASSIGNABLE - RULE 2] assignable = type: %s | name_func = %s", getType((TableNode*)$1), getName((TableNode*)$1));
|
||
}
|
||
cur = getParent(cur);
|
||
}
|
||
| assignable rec_op ACCESS
|
||
{
|
||
if(getAdInfoType((TableNode*)$1) != TYPE_ARRAY){
|
||
throw_error(ERROR_TYPE, "Invalid type passed to array access");
|
||
$$ = undefined;
|
||
}else if($3>getNumArrDim(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);
|
||
}
|
||
}
|
||
}
|
||
|