1143 lines
43 KiB
Plaintext
1143 lines
43 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);
|
||
extern FILE *asc_flag;
|
||
extern bool tc_flag;
|
||
int token_tracker;
|
||
TableNode * tn;
|
||
void error_type(TableNode * left, TableNode * right, const char *format, ...);
|
||
%}
|
||
|
||
%union {
|
||
int integ;
|
||
char* words;
|
||
char letter;
|
||
void* tn;
|
||
}
|
||
|
||
%locations
|
||
|
||
|
||
%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
|
||
|
||
//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));
|
||
//putting in all the offsets
|
||
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 {
|
||
printdebug("see function def rule 1\n");
|
||
TableNode *node = table_lookup(getAncestor(cur), $1);
|
||
if (node == undefined) {
|
||
error_type(undefined, undefined, "Undefined node declared.");
|
||
}else if(getAdInfoType(node) != TYPE_FUNCTION_DECLARATION){
|
||
error_type(undefined, undefined, "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);
|
||
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) {
|
||
error_type(undefined, undefined, "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
|
||
error_type(parameter, undefined, "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);
|
||
} else {
|
||
if(type_of_param_type == TYPE_FUNCTION_TYPE){
|
||
CreateEntry(cur, TYPE_FUNCTION_DECLARATION, parameter,NULL, getAdInfo(parameter));
|
||
}
|
||
if(type_of_param_type == TYPE_ARRAY_TYPE){
|
||
CreateEntry(cur, TYPE_ARRAY, parameter,NULL, getAdInfo(parameter));
|
||
}
|
||
if(type_of_param_type == TYPE_PRIMITIVE_TYPE){
|
||
CreateEntry(cur, TYPE_PRIMITIVE, parameter,NULL, getAdInfo(parameter));
|
||
}
|
||
}
|
||
} 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
|
||
error_type(entry, undefined, "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);
|
||
} 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));
|
||
}
|
||
if(type_of_param_type == TYPE_ARRAY){
|
||
printdebug("array type of parameter inside record");
|
||
CreateEntry(cur, TYPE_ARRAY, getTypeEntry(entry),NULL, getAdInfo(entry));
|
||
}
|
||
if(type_of_param_type == TYPE_PRIMITIVE){
|
||
printdebug("primitive type of parameter inside record");
|
||
CreateEntry(cur, TYPE_PRIMITIVE, getTypeEntry(entry),NULL, getAdInfo(entry));
|
||
}
|
||
/*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) {
|
||
error_type(undefined, undefined, "Expected %s as return type but got undefined (possibly NULL). Differing return types in function.", getName(expected));
|
||
} else if ($8 != expected) {
|
||
error_type(undefined, undefined, "Expected %s as return type but got %s. Differing return types in function.", getName(expected), getName($8));
|
||
} else {
|
||
printdebug("CORRECT RETURN 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{
|
||
error_type(undefined, undefined, "Function declatation (%s) is not a valid function type", $2);
|
||
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{
|
||
error_type(undefined, undefined, "Function declatation (%s) is not a valid function type", $3);
|
||
CreateEntry(cur,TYPE_FUNCTION_DECLARATION, look_up(cur, $5), $3, CreateFunctionDeclarationInfo(-1, false));
|
||
|
||
}
|
||
}
|
||
;
|
||
|
||
|
||
|
||
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
|
||
{
|
||
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
|
||
;
|
||
|
||
|
||
|
||
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) {
|
||
error_type(undefined, undefined, "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;
|
||
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_TYPE){
|
||
printdebug("primitive variable at line %d and column %d", @2.first_line, @2.first_column);
|
||
d = TYPE_PRIMITIVE;
|
||
CreateEntry(cur,d,(TableNode*)$1,$3,getAdInfo((TableNode*)$1));
|
||
}else {
|
||
error_type(undefined, undefined, "Invalid type passed in declaration list.");
|
||
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 {
|
||
printdebug("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 {
|
||
printdebug("differing return types within same function at line %d, column %d", @1.first_line, @1.first_column);
|
||
$$ = undefined;
|
||
}
|
||
}
|
||
| simple_statement SEMI_COLON {
|
||
$$ = $1;
|
||
}
|
||
;
|
||
|
||
|
||
|
||
compound_statement:
|
||
WHILE L_PAREN expression R_PAREN sblock {
|
||
$$ = $5;
|
||
}
|
||
| IF L_PAREN expression R_PAREN THEN sblock ELSE sblock {
|
||
if ($6 == undefined && $8 != undefined) {
|
||
$$ = $8;
|
||
} else if ($6 != undefined && $8 == undefined) {
|
||
$$ = $6;
|
||
} else if ($6 == $8) {
|
||
$$ = $6;
|
||
} else {
|
||
printdebug("differing return types within same function at line %d, column %d", @1.first_line, @1.first_column);
|
||
$$ = undefined;
|
||
}
|
||
}
|
||
| sblock {
|
||
$$ = $1;
|
||
}
|
||
;
|
||
|
||
|
||
|
||
simple_statement:
|
||
assignable ASSIGN expression
|
||
{ printdebug("simple statement");
|
||
TableNode* node;
|
||
if((getAdInfoType((TableNode*)$1) == TYPE_FUNCTION_DECLARATION)||
|
||
(getAdInfoType((TableNode*)$1) == TYPE_ARRAY)||
|
||
(getAdInfoType((TableNode*)$1) == TYPE_RECORD)||
|
||
(getAdInfoType((TableNode*)$1) == TYPE_PRIMITIVE)){
|
||
|
||
node = ((TableNode*)$1);
|
||
} else{
|
||
error_type(undefined, undefined, "Invalid type passed to assignable.");
|
||
node = undefined;
|
||
}
|
||
|
||
|
||
if(getAdInfoType(node) == getAdInfoType((TableNode*)$3)){
|
||
//EMIT ASSIGN INSTRUCTION HERE
|
||
printdebug("%s[☺] Passed type check; %s = %s", COLOR_GREEN, getName(node), getName((TableNode*)$3));
|
||
} else {
|
||
error_type(node, (TableNode*)$3, "");
|
||
}
|
||
|
||
$$ = undefined;
|
||
}
|
||
|
||
|
||
| RETURN expression {$$ = getTypeEntry((TableNode*)$2);}
|
||
;
|
||
|
||
|
||
|
||
rec_op:
|
||
DOT
|
||
|
||
|
||
|
||
ablock:
|
||
L_PAREN argument_list R_PAREN
|
||
{
|
||
$$ = $2;
|
||
printdebug("ablock is %d", $$);
|
||
}
|
||
;
|
||
|
||
|
||
|
||
argument_list:
|
||
//NEED TO EMIT PARAMETERS HERE. MAYBE USE STACK STRUCTURE
|
||
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(getTypeEntry((TableNode*)$2) == integ) {
|
||
char* temp = temp_var_gen();
|
||
TableNode* node = CreateEntry(cur,TYPE_PRIMITIVE, integ, temp, NULL);
|
||
//NOTE ADD ASSIGNMENT EMIT HERE (MIGHT NEED TO PUSH TO STACK)
|
||
//result of unary operation
|
||
$$ = node;
|
||
} else {
|
||
$$=undefined;
|
||
error_type(getTypeEntry((TableNode*)$2), integ, "");
|
||
}
|
||
}
|
||
|
||
| NOT expression
|
||
{
|
||
printdebug("not expression");
|
||
if(getTypeEntry((TableNode*)$2) == boo) {
|
||
char* temp = temp_var_gen();
|
||
TableNode* node = CreateEntry(cur,TYPE_PRIMITIVE, boo, temp, NULL);
|
||
//NOTE ADD ASSIGNMENT EMIT HERE (MIGHT NEED TO PUSH TO STACK)
|
||
//result of unary operation
|
||
$$ = node;
|
||
} else {
|
||
$$=undefined;
|
||
error_type(getTypeEntry((TableNode*)$2), boo, "");
|
||
}
|
||
}
|
||
|
||
| 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);
|
||
//NOTE ADD ASSIGNMENT EMIT HERE (MIGHT NEED TO PUSH TO STACK)
|
||
//result of binary operation
|
||
$$ = node;
|
||
} else {
|
||
$$=undefined;
|
||
error_type(getTypeEntry((TableNode*)$1), getTypeEntry((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);
|
||
//NOTE ADD ASSIGNMENT EMIT HERE (MIGHT NEED TO PUSH TO STACK)
|
||
//result of binary operation
|
||
$$ = node;
|
||
} else {
|
||
$$=undefined;
|
||
error_type(getTypeEntry((TableNode*)$1), getTypeEntry((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);
|
||
//NOTE ADD ASSIGNMENT EMIT HERE (MIGHT NEED TO PUSH TO STACK)
|
||
//result of binary operation
|
||
$$ = node;
|
||
} else {
|
||
$$=undefined;
|
||
error_type(getTypeEntry((TableNode*)$1), getTypeEntry((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);
|
||
//NOTE ADD ASSIGNMENT EMIT HERE (MIGHT NEED TO PUSH TO STACK)
|
||
//result of binary operation
|
||
$$ = node;
|
||
} else {
|
||
$$=undefined;
|
||
error_type(getTypeEntry((TableNode*)$1), getTypeEntry((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);
|
||
//NOTE ADD ASSIGNMENT EMIT HERE (MIGHT NEED TO PUSH TO STACK)
|
||
//result of binary operation
|
||
$$ = node;
|
||
} else {
|
||
$$=undefined;
|
||
error_type(getTypeEntry((TableNode*)$1), getTypeEntry((TableNode*)$3), "");
|
||
}
|
||
}
|
||
|
||
| expression AND expression
|
||
{
|
||
printdebug("AND");
|
||
if((getTypeEntry((TableNode*)$1)==getTypeEntry((TableNode*)$3)) && getTypeEntry((TableNode*)$1) == boo) {
|
||
char* temp = temp_var_gen();
|
||
TableNode* node = CreateEntry(cur,TYPE_PRIMITIVE, boo, temp, NULL);
|
||
//NOTE ADD ASSIGNMENT EMIT HERE (MIGHT NEED TO PUSH TO STACK)
|
||
//result of comparison
|
||
$$ = node;
|
||
} else {
|
||
$$=undefined;
|
||
error_type(getTypeEntry((TableNode*)$1), getTypeEntry((TableNode*)$3), "");
|
||
}
|
||
}
|
||
|
||
| expression OR expression
|
||
{
|
||
printdebug("OR");
|
||
if((getTypeEntry((TableNode*)$1)==getTypeEntry((TableNode*)$3)) && getTypeEntry((TableNode*)$1) == boo) {
|
||
char* temp = temp_var_gen();
|
||
TableNode* node = CreateEntry(cur,TYPE_PRIMITIVE, boo, temp, NULL);
|
||
//NOTE ADD ASSIGNMENT EMIT HERE (MIGHT NEED TO PUSH TO STACK)
|
||
//result of comparison
|
||
$$ = node;
|
||
} else {
|
||
$$=undefined;
|
||
error_type(getTypeEntry((TableNode*)$1), getTypeEntry((TableNode*)$3), "");
|
||
}
|
||
}
|
||
|
||
| expression LESS_THAN expression
|
||
{
|
||
printdebug("less than expression");
|
||
if(getTypeEntry((TableNode*)$1) == getTypeEntry((TableNode*)$3) && getTypeEntry((TableNode*)$1)==integ) {
|
||
char* temp = temp_var_gen();
|
||
TableNode* node = CreateEntry(cur,TYPE_PRIMITIVE, boo, temp, NULL);
|
||
//NOTE ADD ASSIGNMENT EMIT HERE (MIGHT NEED TO PUSH TO STACK)
|
||
//result of comparison
|
||
$$ = node;
|
||
} else {
|
||
$$=undefined;
|
||
error_type(getTypeEntry((TableNode*)$1), getTypeEntry((TableNode*)$3), "");
|
||
}
|
||
}
|
||
|
||
| expression EQUAL_TO expression
|
||
{
|
||
printdebug("equals check expression");
|
||
if(getTypeEntry((TableNode*)$1) == getTypeEntry((TableNode*)$3) && getTypeEntry((TableNode*)$1) != undefined) {
|
||
char* temp = temp_var_gen();
|
||
TableNode* node = CreateEntry(cur,TYPE_PRIMITIVE, boo, temp, NULL);
|
||
//NOTE ADD ASSIGNMENT EMIT HERE (MIGHT NEED TO PUSH TO STACK)
|
||
//result of compariosn
|
||
$$ = node;
|
||
|
||
} else {
|
||
$$ = undefined;
|
||
error_type(getTypeEntry((TableNode*)$1), getTypeEntry((TableNode*)$3), "");
|
||
}
|
||
}
|
||
|
||
| assignable
|
||
{
|
||
$$ = $1;
|
||
}
|
||
|
||
| L_PAREN expression R_PAREN
|
||
{
|
||
printdebug("paren expression. current type is %s",getType((TableNode*)$2));
|
||
$$=$2;
|
||
}
|
||
|
||
| memOp assignable
|
||
{
|
||
int d = getAdInfoType((TableNode*)$2);
|
||
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 {
|
||
error_type(undefined, undefined, "Invalid memOp expression (%s).", 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
|
||
{
|
||
TableNode* pass = look_up(cur,$1);
|
||
$$ = pass;
|
||
printdebug("[ASSIGNABLE - RULE 1] assignable = type: %s | ID = %s", getType(pass), getName(pass));
|
||
}
|
||
|
||
| assignable
|
||
{
|
||
printdebug("%sBeginning rule 2 of assignable.", COLOR_CYAN);
|
||
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);
|
||
if (look_up(getParent(cur), getType((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 = getTypeEntry((TableNode*)$1);
|
||
TableNode *param = getParameter(typeNode);
|
||
printTableNode(param);
|
||
|
||
if (getAdInfoType(param) == TYPE_RECORD_TYPE) {
|
||
SymbolTable *recList = getRecList(param);
|
||
TableNode *lastCheckedRef = getFirstEntry(recList);
|
||
TableNode *lastCheckedAct = getFirstEntry(cur);
|
||
while (getNextEntry(lastCheckedRef) != NULL) {
|
||
lastCheckedRef = getNextEntry(lastCheckedRef);
|
||
}
|
||
|
||
if ($3 != getRecLength(param)) {
|
||
printdebug("expected %d arguments but got %d", getRecLength(param), $3);
|
||
}
|
||
//this isn't very efficient, but will hopefully work
|
||
while (lastCheckedAct != NULL && lastCheckedRef != NULL) {
|
||
if (getTypeEntry(lastCheckedRef) != getTypeEntry(lastCheckedAct)) {
|
||
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);
|
||
|
||
}
|
||
lastCheckedAct = getNextEntry(lastCheckedAct);
|
||
TableNode *tn = getFirstEntry(recList);
|
||
|
||
if (tn != lastCheckedRef) {
|
||
while (getNextEntry(tn) != lastCheckedRef) {
|
||
tn = getNextEntry(tn);
|
||
}
|
||
lastCheckedRef = tn;
|
||
} else {break;}
|
||
}
|
||
} else {
|
||
if (strcmp(getName(param), getName(getFirstEntry(cur))) != 0) {
|
||
printdebug("expected %s expression in function call but got %s", getName(param), getName(getFirstEntry(cur)));
|
||
}
|
||
|
||
if (getNextEntry(getFirstEntry(cur)) != NULL) {
|
||
printdebug("expected 1 parameter, but got multiple in function call");
|
||
}
|
||
}
|
||
} else {
|
||
char *expected = getName(getParameter(look_up(getParent(cur), getType((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);
|
||
}
|
||
if ($3 != 1) {
|
||
printdebug("expected 1 argument but got %d", $3);
|
||
}
|
||
}
|
||
printTableNode(getReturn(getTypeEntry((TableNode*)$1)));
|
||
//
|
||
char* temp = temp_var_gen();
|
||
TableNode* typeNode2 = getReturn(getTypeEntry($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;
|
||
printdebug("CHANGE ME [TYPE CHECK] Undefined type stored in record. improper.");
|
||
}
|
||
TableNode* node = CreateEntry(cur,t, typeNode2, temp, NULL);
|
||
$$ = 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(look_up(getParent(cur), getType((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);
|
||
}
|
||
|
||
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;
|
||
printdebug("CHANGE ME [TYPE CHECK] Undefined type stored in record. improper.");
|
||
}
|
||
TableNode* node = CreateEntry(cur,t, typeNode2, temp, NULL);
|
||
//emit assign here
|
||
//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 ID
|
||
{
|
||
if(getAdInfoType((TableNode*)$1) != TYPE_RECORD_TYPE){
|
||
printdebug("CHANGE ME [TYPE CHECK]Invalid type passed to record access");
|
||
}
|
||
else if(undefined != table_lookup(getRecList(table_lookup(getAncestor(cur), getName(getTypeEntry((TableNode*)$1)))), $3)) {
|
||
|
||
TableNode* type = table_lookup(getRecList(table_lookup(getAncestor(cur), getName(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;
|
||
printdebug("CHANGE ME [TYPE CHECK] Undefined type stored in record. improper.");
|
||
}
|
||
|
||
TableNode* node = CreateEntry(cur,t, type, temp, NULL);
|
||
//NOTE ADD ASSIGNMENT EMIT HERE (MIGHT NEED TO PUSH TO STACK)
|
||
//emit_field_access(char* node, char* record, $3)
|
||
$$=node;
|
||
}else{
|
||
printdebug("CHANGE ME [TYPE CHECK] undefined type (Field Access Lookup failed)");
|
||
$$=undefined;
|
||
}
|
||
printdebug("[ASSIGNABLE - RULE 3] record = name: %s | field = %s", getName((TableNode*)($1)), getName((TableNode*)$3));
|
||
}
|
||
|
||
;
|
||
|
||
|
||
|
||
memOp:
|
||
RESERVE
|
||
{
|
||
printdebug("reserve expression");
|
||
}
|
||
|
||
| RELEASE
|
||
{
|
||
printdebug("release expression");
|
||
}
|
||
|
||
;
|
||
|
||
|
||
constant:
|
||
C_STRING
|
||
{
|
||
char* temp = temp_var_gen();
|
||
TableNode* node = CreateEntry(cur,TYPE_PRIMITIVE, 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 error_type(TableNode * left, TableNode * right, const char *format, ...) {
|
||
int line = yylloc.first_line;
|
||
int column = yylloc.first_column;
|
||
|
||
if (tc_flag) {
|
||
yyerror("");
|
||
if (strcmp(format, "") == 0) {
|
||
if (asc_flag != NULL) {
|
||
fprintf(asc_flag, "(%d:%d) ** TYPE ERROR: %s != %s\n", line, column, getName(left), getName(right));
|
||
} else {
|
||
fprintf(stderr, "%s(%d:%d) ** TYPE ERROR%s: %s%s %s!= %s%s\n",
|
||
COLOR_RED, line, column, COLOR_WHITE, COLOR_YELLOW, getName(left), COLOR_WHITE, COLOR_YELLOW, getName(right), COLOR_WHITE);
|
||
}
|
||
} else {
|
||
if (asc_flag != NULL) {
|
||
fprintf(asc_flag, "(%d:%d) ** TYPE ERROR: ", line, column);
|
||
va_list args;
|
||
va_start(args, format);
|
||
vfprintf(asc_flag, format, args);
|
||
va_end(args);
|
||
fprintf(asc_flag, "\n");
|
||
} else {
|
||
fprintf(stderr, "%s(%d:%d) ** TYPE ERROR%s: %s", COLOR_RED, line, column, COLOR_WHITE, COLOR_YELLOW);
|
||
va_list args;
|
||
va_start(args, format);
|
||
vfprintf(stderr, format, args);
|
||
va_end(args);
|
||
fprintf(stderr, "%s\n", COLOR_WHITE);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void yyerror(const char *err) {
|
||
int line = yylloc.first_line;
|
||
int column = yylloc.first_column;
|
||
|
||
// Grammar Fallback Case
|
||
if (strcmp(err, "syntax error") == 0) {
|
||
if (asc_flag != NULL) {
|
||
fprintf(asc_flag, "(%d:%d) ** SYNTAX ERROR: Incorrect syntax at token '%s'\n", line, column, yytext);
|
||
}
|
||
else {
|
||
fprintf(stderr, "%s(%d:%d) ** SYNTAX ERROR%s: Incorrect syntax at token '%s%s%s'\n",
|
||
COLOR_RED, line, column, COLOR_WHITE, COLOR_YELLOW, yytext, COLOR_WHITE);
|
||
}
|
||
}
|
||
}
|