/* Symbol Table */ /* The Translators - Spring 2025 */ #include "symbol_table.h" #include #include #include #include char *typey = "type"; char *funy = "function"; TableNode *funprime; TableNode *arrayprim; extern SymbolTable *cur; TableNode *integ; TableNode *addr; TableNode *chara; TableNode *stri; TableNode *boo; TableNode *recprime; TableNode *funtypeprime; TableNode *undefined; char *COLOR_RED = "\033[0;31m"; char *COLOR_GREEN = "\033[0;32m"; char *COLOR_ORANGE = "\033[0;33m"; char *COLOR_BLUE = "\033[0;34m"; char *COLOR_PURPLE = "\033[0;35m"; char *COLOR_CYAN = "\033[0;36m"; char *COLOR_LIGHTGRAY = "\033[0;37m"; char *COLOR_DARKGRAY = "\033[1;30m"; char *COLOR_LIGHTRED = "\033[1;31m"; char *COLOR_LIGHTGREEN = "\033[1;32m"; char *COLOR_YELLOW = "\033[1;33m"; char *COLOR_LIGHTBLUE = "\033[1;34m"; char *COLOR_LIGHTPURPLE = "\033[1;35m"; char *COLOR_LIGHTCYAN = "\033[1;36m"; char *COLOR_WHITE = "\033[1;37m"; bool DEBUG = false; void printdebug_impl(char *file, int line, const char *format, ...); void printdebug_impl(char *file, int line, const char *format, ...) { if (DEBUG) { printf("%s<%s> [%d]%s ", COLOR_DARKGRAY, file, line, COLOR_WHITE); va_list args; va_start(args, format); vprintf(format, args); va_end(args); printf("\n"); } } #define printdebug(format, ...) \ printdebug_impl(__FILE__, __LINE__, format, ##__VA_ARGS__) // AdInfo *Undefined_function_type_info; typedef enum { // First 4 below are primitive types that are all encapsulated in // primitive type // TYPE_INTEGER, // TYPE_CHARACTER, // TYPE_BOOLEAN, // TYPE_ADDRESS, // Type String is an array of char enclosed in double quotes per lexer TYPE_STRING = 1, // Array can be multidimensional. Information should be stored here. // This is the type of the array TYPE_ARRAY_TYPE = 2, // Record is user defined types TYPE_RECORD_TYPE = 3, // Declaring what type a particular function is without as TYPE_FUNCTION_DECLARATION = 4, // Declaring what type a particular function is with as // TYPE_AS_FUNCTION_DECLARATION, // Declaring what type a function is (what the parameters and output // are) TYPE_FUNCTION_TYPE = 5, // The Type being pointed to by the first 4 above that only stores the // size TYPE_PRIMITIVE = 6, // likely NULL TYPE_ALL_ELSE = 7, TYPE_UNDEFINED = 8, TYPE_RECORD = 9, TYPE_ARRAY = 10, TYPE_SYSTEM_DEFINED = 11 // for system defined entries like funprimetype etc. } types; /* put in symbol_table.h typedef struct{ int size; if(strcmp(getType(tn),getName(integ))==0){ return } }primitive_info; typedef struct{ int length; char* location; }string_info; typedef struct{ int numofdimensions; //the above value tells you how long the below array is. For example if num of dimensions is 5, I can store 1,3,2,5,9 to define > int* sizesofdimensions; TableNode* typeofarray; }array_info; typedef struct{ //similar to above we define a record to hold the number of elements and an array of tablenodes (types) that it contains in the order specified by the user int numofelements; TableNode* listoftypes; }record_info; typedef struct{ int startlinenumber; bool regularoras; }function_declaration_info; typedef struct{ TableNode* parameter; TableNode* returntype; }function_type_info; typedef union { PrimAdInfo* primitive_info; ArrayAdInfo* array_info; RecAdInfo* record_info; StringAdInfo* string_info; FunDecAdInfo* func_dec_info; FunTypeAdInfo* func_type_info; }AdInfo; */ // primitive additional info only stores the size of that type AdInfo *CreatePrimitiveInfo(int size) { AdInfo *info = (AdInfo *)malloc(sizeof(AdInfo)); info->PrimAdInfo = (primitive_info *)malloc(sizeof(primitive_info)); info->PrimAdInfo->size = size; return info; } // only gets the size of a primitive type int getPrimSize(TableNode *definition) { if (definition == NULL) { printdebug( "passed an NULL entry to getPrimSize function. Invalid."); return -1; } if (definition == undefined) { printdebug("passed an undefined entry to getPrimSize function. " "Invalid."); return -1; } if (definition->additionalinfo == NULL) { printdebug("node has NULL additionalinfo. Invalid."); return -1; } if (strcmp(getType(definition), "primitive") != 0) { printdebug( "not checking the size of a primitive -- invalid op"); return 0; } return definition->additionalinfo->PrimAdInfo->size; } // probably don't need the below structure since can create from an array /*string_info* CreateStringInfo(int length, char* loc){ string_info* stringy = (string_info*)malloc(sizeof(string_info)); stringy.length=length; char* location = loc; return stringy; } */ // Only information stored in array info is the number of dimensions and the // type stored in the array per professor, the actual size of the array is // calculated at runtime so bounds checking only needs to be done then AdInfo *CreateArrayInfo(int dim, /*int* sizes,*/ TableNode *type) { if (type == NULL) { printdebug("passed a NULL reference to " "CreateArrayInfo. Invalid."); return NULL; } if (type == undefined) { printdebug("passed an undefined reference to " "CreateArrayInfo. Invalid."); return NULL; } if (type == undefined) { printdebug("passed a undefined type reference to " "CreateArrayInfo. Invalid."); return NULL; } AdInfo *info = (AdInfo *)malloc(sizeof(AdInfo)); info->ArrayAdInfo = (array_info *)malloc(sizeof(array_info)); info->ArrayAdInfo->numofdimensions = dim; info->ArrayAdInfo->typeofarray = type; // avoiding storing any types like below // int* dimensionsizes = loc; return info; } // This gets the number of dimensions from array info int getNumArrDim(TableNode *definition) { if (definition == NULL) { printdebug("passed an NULL entry to getNumArrDim " "function. Invalid."); return -1; } if (definition == undefined) { printdebug("passed an undefined entry to getNumArrDim " "function. Invalid."); return -1; } if (strcmp(getType(definition), "array") != 0) { printdebug("not checking the dim of an array -- invalid op"); return 0; } return definition->additionalinfo->ArrayAdInfo->numofdimensions; } // This gets the type stored in an array from arrtype. It returns a reference to // the entry of that type TableNode *getArrType(TableNode *definition) { if (definition == NULL) { printdebug("passed an NULL entry to getArrType " "function. Invalid."); return NULL; } if (definition == undefined) { printdebug("passed an undefined entry to getArrType " "function. Invalid."); return NULL; } if (strcmp(getType(definition), "array") != 0) { printdebug("not checking the type of an array -- invalid op"); return undefined; } return definition->additionalinfo->ArrayAdInfo->typeofarray; } // Record type currently stores the number of elements as well as the types, in // order, of what make up that type in an array. Unfortunately this second part // should probably instead be replaced by a reference to a scope in which those // elements are found. AdInfo *CreateRecordInfo(int length, SymbolTable *recordScope) { AdInfo *info = (AdInfo *)malloc(sizeof(AdInfo)); info->RecAdInfo = (record_info *)malloc(sizeof(record_info)); info->RecAdInfo->numofelements = length; // replace below with reference to a scope, not an array info->RecAdInfo->recordScope = recordScope; return info; } // This gets the number of elements that make up a record. // Perhaps this may not be needed since we need to iterate over all elements // anyways. int getRecLength(TableNode *definition) { if (definition == NULL) { printdebug("passed an NULL entry to getRecLength " "function. Invalid."); return -1; } if (definition == undefined) { printdebug("passed an undefined entry to getRecLength " "function. Invalid."); return -1; } if (strcmp(getType(definition), "record") != 0) { printdebug( "not checking the length of an record -- invalid op"); return 0; } return definition->additionalinfo->RecAdInfo->numofelements; } // This gets the array. Needs to up be updated to get the scope instead SymbolTable *getRecList(TableNode *definition) { if (definition == NULL) { printdebug("passed a NULL entry to getRecList " "function. Invalid."); return NULL; } if (definition == undefined) { printdebug("passed an undefined entry to getRecList " "function. Invalid."); return NULL; } if (strcmp(getType(definition), "record") != 0) { printdebug( "not checking the list of types of a record -- invalid " "op"); return NULL; } return definition->additionalinfo->RecAdInfo->recordScope; } TableNode *setRecSize(TableNode *tn, int n) { if (tn == NULL) { printdebug("passed in NULL entry for setRecSize. Invalid"); return undefined; } if (tn == undefined) { printdebug("passed in undefined entry for setRecSize. Invalid"); return undefined; } tn->additionalinfo->RecAdInfo->numofelements = n; return tn; } int getRecSize(SymbolTable *tn) { if (tn == NULL) { printdebug( "passed in NULL SymbolTable for getRecSize. Invalid"); return -1; } int s = 1; TableNode *cur = getFirstEntry(tn); if (cur != NULL) { while (getNextEntry(cur) != NULL) { s++; cur = getNextEntry(cur); } return s; } return -1; } // below function takes a bool to see if parameter should be decomposed or not ; // note that functions only take one input and have one output // using "as" the input record can be decomposed to give the illusion of // multiple inputs Below function also has the line number where the function is // first defined AdInfo *CreateFunctionDeclarationInfo(int line, bool asorregular) { AdInfo *info = (AdInfo *)malloc(sizeof(AdInfo)); info->FunDecAdInfo = (function_declaration_info *)malloc( sizeof(function_declaration_info)); info->FunDecAdInfo->startlinenumber = line; info->FunDecAdInfo->regularoras = asorregular; return info; } // gets the line at which the function was first defined. (Can be used to print // out in table if needed) int getStartLine(TableNode *definition) { if (definition == NULL) { printdebug("passed a NULL entry to getStartLine " "function. Invalid."); return -1; } if (definition == undefined) { printdebug("passed an undefined entry to getStartLine " "function. Invalid."); return -1; } if (strcmp(getType(definition), "primitive function") != 0) { printdebug( "not checking the start line of a function -- invalid " "op"); return 0; } return definition->additionalinfo->FunDecAdInfo->startlinenumber; } TableNode *setStartLine(TableNode *tn, int start) { if (tn == NULL) { printdebug("passing in a NULL entry to setStartLine. " "invalid"); return undefined; } if (tn == undefined) { printdebug("passing in an undefined entry to setStartLine. " "invalid"); return undefined; } tn->additionalinfo->FunDecAdInfo->startlinenumber = start; return tn; } // checks if "as" keyword was used for function definition. Either 0 or 1 for // not used or used. bool getAsKeyword(TableNode *definition) { if (definition == NULL) { printdebug("passed a NULL entry to getAsKeyword " "function. Invalid."); return false; } if (definition == undefined) { printdebug("passed an undefined entry to getAsKeyword " "function. Invalid."); return false; } if (strcmp(getType(definition), "primitive function") != 0) { printdebug( "not checking if a function is called with as or not (%s) -- " "invalid op", getType(definition)); return 0; } return definition->additionalinfo->FunDecAdInfo->regularoras; } TableNode *setAsKeyword(TableNode *tn, bool as) { if (tn == NULL) { printdebug("passing in a NULL entry to setAsKeyword. " "invalid"); return undefined; } if (tn == undefined) { printdebug("passing in an undefined entry to setAsKeyword. " "invalid"); return undefined; } tn->additionalinfo->FunDecAdInfo->regularoras = as; return tn; } // stores the type of a function (parameter type and return type) AdInfo *CreateFunctionTypeInfo(TableNode *parameter, TableNode *returntype) { if (parameter == NULL) { printdebug("passed a NULL parameter to " "CreateFunctionTypeInfo. Invalid."); return NULL; } if (parameter == undefined) { printdebug("passed an undefined parameter to " "CreateFunctionTypeInfo. Invalid."); return NULL; } if (returntype == NULL) { printdebug("passed a NULL return type to " "CreateFunctionTypeInfo. Invalid."); return NULL; } if (returntype == undefined) { printdebug("passed an undefined return type to " "CreateFunctionTypeInfo. Invalid."); return NULL; } AdInfo *info = (AdInfo *)malloc(sizeof(AdInfo)); info->FunTypeAdInfo = (function_type_info *)malloc(sizeof(function_type_info)); info->FunTypeAdInfo->parameter = parameter; info->FunTypeAdInfo->returntype = returntype; return info; } // returns parameter type of a function TableNode *getParameter(TableNode *definition) { if (definition == NULL) { printdebug("passed a NULL entry to getParameter " "function. Invalid."); return undefined; } if (definition == undefined) { printdebug("passed an undefined entry to getParameter " "function. Invalid."); return undefined; } if (strcmp(getType(definition), "primitive function type") != 0) { printdebug( "not checking the parameter of a function -- invalid op"); return undefined; } return definition->additionalinfo->FunTypeAdInfo->parameter; } // returns return type of a function TableNode *getReturn(TableNode *definition) { if (definition == NULL) { printdebug("passed a NULL entry to getReturn " "function. Invalid."); return NULL; } if (definition == undefined) { printdebug("passed an undefined entry to getReturn " "function. Invalid."); return NULL; } if (strcmp(getType(definition), "primitive function type") != 0) { printdebug( "not checking the return of a function -- invalid op"); return undefined; } return definition->additionalinfo->FunTypeAdInfo->returntype; } // creates a new scope (not the top scope though) SymbolTable *CreateScope(SymbolTable *ParentScope, int Line, int Column) { SymbolTable *table = (SymbolTable *)malloc(sizeof(SymbolTable)); table->Line_Number = Line; table->Column_Number = Column; table->Parent_Scope = ParentScope; table->Children_Scope = NULL; table->entries = NULL; if (ParentScope != NULL) { if (ParentScope->Children_Scope == NULL) { ListOfTable *newEntry = (ListOfTable *)malloc(sizeof(ListOfTable)); newEntry->next = NULL; // newEntry->prev = NULL; newEntry->table = table; ParentScope->Children_Scope = newEntry; } else { ListOfTable *newEntry = (ListOfTable *)malloc(sizeof(ListOfTable)); // newEntry->prev = NULL; newEntry->table = table; ListOfTable *oldEntry = ParentScope->Children_Scope; ParentScope->Children_Scope = newEntry; newEntry->next = oldEntry; } } return table; } // create entry just for things below top level scope // This function defines the integer, address, character, and bool primitive // types SymbolTable *init(SymbolTable *start) { if (start->Parent_Scope != NULL) { printdebug("%s[FATAL] Cannot initialize a scope that is not " "the parent scope", COLOR_RED); return NULL; } integ = (TableNode *)calloc(1, sizeof(TableNode)); addr = (TableNode *)calloc(1, sizeof(TableNode)); chara = (TableNode *)calloc(1, sizeof(TableNode)); stri = (TableNode *)calloc(1, sizeof(TableNode)); boo = (TableNode *)calloc(1, sizeof(TableNode)); // TableNode* arr = (TableNode*)malloc(sizeof(SymbolTable)); start->entries = integ; integ->next = addr; addr->next = chara; chara->next = stri; stri->next = boo; // boo->next = arr; boo->next = NULL; integ->theName = "integer"; addr->theName = "address"; chara->theName = "character"; boo->theName = "Boolean"; stri->theName = "string"; // arr->theName= "array" // root TableNode that all are pointing to but not in table // This is only to solve the issue that all entries must have a name and // a type and the type must point to an actual table entry Again, this // primitive table entry isn't in the top scope. It is outside the top // scope and is only there to facilitate the fact that these are // primitive TableNode *prime = (TableNode *)malloc(sizeof(TableNode)); prime->theName = "primitive"; prime->theType = NULL; prime->additionalinfo = NULL; prime->next = NULL; prime->tag = TYPE_SYSTEM_DEFINED; // not sure exatly how to get array types to look right so using a dummy // Table Node below and updating the print symbol table function to // access the additional information to print for array types, similar // to function types when printing symbol table, if array is seen arrayprim = (TableNode *)malloc(sizeof(TableNode)); arrayprim->theName = "array"; arrayprim->theType = NULL; arrayprim->additionalinfo = NULL; arrayprim->next = NULL; prime->tag = TYPE_SYSTEM_DEFINED; // funprime = CreateEntry(NULL,NULL,strdup("function primitive"),NULL); // similar workaround to arrays above funprime = (TableNode *)malloc(sizeof(TableNode)); funprime->theName = "primitive function"; funprime->theType = NULL; funprime->additionalinfo = NULL; funprime->next = NULL; funprime->tag = TYPE_SYSTEM_DEFINED; // record recprime = (TableNode *)malloc(sizeof(TableNode)); recprime->theName = "record"; recprime->theType = NULL; recprime->additionalinfo = NULL; recprime->next = NULL; recprime->tag = TYPE_SYSTEM_DEFINED; funtypeprime = (TableNode *)malloc(sizeof(TableNode)); funtypeprime->theName = "primitive function type"; funtypeprime->theType = NULL; funtypeprime->additionalinfo = NULL; funtypeprime->next = NULL; funtypeprime->tag = TYPE_SYSTEM_DEFINED; undefined = (TableNode *)malloc(sizeof(TableNode)); undefined->theName = "undefined"; undefined->theType = NULL; undefined->additionalinfo = NULL; undefined->next = NULL; undefined->tag = TYPE_SYSTEM_DEFINED; // Undefined_function_type_info = CreateFunctionTypeInfo(undefined, // undefined); integ->theType = prime; addr->theType = prime; chara->theType = prime; stri->theType = arrayprim; boo->theType = prime; // arr->theType=arrayprim; // filling in all the values for the additional info for initial types // These numbers below for create primitive specifically are supposed to // be the size of these primitive types. We can change these if needed // to not be hard coded numbers as a reminder, stri below is defined as // a one dimensional array of characters integ->additionalinfo = CreatePrimitiveInfo(SIZE_INT); addr->additionalinfo = CreatePrimitiveInfo(SIZE_ADDR); chara->additionalinfo = CreatePrimitiveInfo(SIZE_CHAR); stri->additionalinfo = CreateArrayInfo(1, chara); boo->additionalinfo = CreatePrimitiveInfo(SIZE_BOOL); integ->tag = TYPE_PRIMITIVE; // explicitly set the type for integ addr->tag = TYPE_PRIMITIVE; // explicitly set the type for addr chara->tag = TYPE_PRIMITIVE; // explicitly set the type for chara stri->tag = TYPE_ARRAY_TYPE; // explicitly set the type for stri boo->tag = TYPE_PRIMITIVE; // explicitly set the type for boo // addr->additionalinfo = CreatePrimitiveInfo(8); start->Line_Number = 1; start->Column_Number = 1; start->Parent_Scope = NULL; start->Children_Scope = NULL; return start; } /* TableNode* integ; TableNode* addr; TableNode* chara; TableNode* stri; TableNode* boo; TableNode* recprime; TableNode* funtypeprime; */ TableNode *populateTypeAndInfo(TableNode *tn, TableNode *type, AdInfo *info) { if (tn == NULL) { printdebug( "passed in an NULL table node to populateTypeAndInfo."); return undefined; } if (tn == undefined) { printdebug( "passed in an undefined table node to populateTypeAndInfo"); return undefined; } if (type == NULL) { printdebug("passed in a NULL type reference to " "populate a table node. Invalid."); return undefined; } if (type == undefined) { printdebug("passed in an undefined type reference to " "populate a table node. Invalid."); return undefined; } if (info == NULL) { printdebug( "passed in a NULL info reference to populate a table " "node. Invalid."); return undefined; } tn->theType = type; tn->additionalinfo = info; // returning reference to modified table node return tn; } AdInfo *getAdInfo(TableNode *tn) { if (tn == NULL) { printdebug("passed a NULL table entry to getAdInfo. Invalid."); return NULL; } if (tn == undefined) { printdebug( "passed an undefined table entry to getAdInfo. Invalid."); return NULL; } if (tn->additionalinfo == NULL) { printdebug( "no additional info found in the table node. Invalid."); return NULL; } return tn->additionalinfo; } //simplified getAdInfoType int getAdInfoType(TableNode *tn) { if (tn == NULL) { printdebug( "passing in NULL table entry to getAdInfoType. Invalid"); return -1; } return tn->tag; /* if (tn == undefined) { printdebug("passing in undefined table entry to getAdInfoType. " "Invalid"); return -1; } if (tn->theType == NULL) { printdebug("Entry being passed in has a null" "reference for theType to getAdInfoType. Invalid."); return -1; } if (tn->theType == undefined) { printdebug("Entry being passed in an undefined " "reference for theType to getAdInfoType. Invalid."); return -1; } if (strcmp(getName(tn), getName(integ)) == 0) { return TYPE_PRIMITIVE; } if (strcmp(getName(tn), getName(addr)) == 0) { return TYPE_PRIMITIVE; } if (strcmp(getName(tn), getName(chara)) == 0) { return TYPE_PRIMITIVE; } if (strcmp(getName(tn), getName(stri)) == 0) { return TYPE_ARRAY_TYPE; } if (strcmp(getName(tn), getName(boo)) == 0) { return TYPE_PRIMITIVE; } if (strcmp(getName(tn), getName(recprime)) == 0) { return TYPE_RECORD_TYPE; } if (strcmp(getName(tn), getName(funtypeprime)) == 0) { return TYPE_FUNCTION_TYPE; } if (strcmp(getName(tn), getName(arrayprim)) == 0) { return TYPE_ARRAY_TYPE; // changed from TYPE_ARRAY cuz } if (strcmp(getName(tn), getName(undefined)) == 0) { return TYPE_UNDEFINED; } else { if (strcmp(getType(tn), getName(funtypeprime)) == 0) { printdebug("passed in a function to getAdInfoType"); return TYPE_FUNCTION_DECLARATION; } if (strcmp(getType(tn), getName(arrayprim)) == 0) { printdebug("passed in an array to getAdInfoType"); return TYPE_ARRAY_TYPE; } if (strcmp(getType(tn), getName(recprime)) == 0) { printdebug("passed in a record to getAdInfoType"); return TYPE_RECORD; } printdebug( "passed in an entry that is not a primitive type, array, " "or record. Invalid."); return TYPE_FUNCTION_DECLARATION; }*/ } TableNode *CreateEntry(SymbolTable *table, int tag, TableNode *typeOf, char *id, AdInfo *ad) { if (table == NULL) { printdebug("Null reference to table"); return undefined; } /* TableNode* topDef = (table_lookup(getAncestor(table),typeOf)); if(topDef == NULL){ printdebug("This type is not defined at the top level"); return NULL; } */ if (typeOf == NULL) { printdebug("Passing an NULL Type Node to Create Entry"); return undefined; } if (typeOf == undefined) { printdebug("Passing an undefined Type Node to Create Entry"); return undefined; } TableNode *newEntry = (TableNode *)calloc(1, sizeof(TableNode)); if(tag<1 && tag>11){ printdebug("Note- not passing in valid 'tag' identifier to create entry function. Setting tag to undefined"); newEntry->tag = TYPE_UNDEFINED; } else{ newEntry->tag = tag; } newEntry->theType = typeOf /*topDef*/; newEntry->theName = id; newEntry->additionalinfo = ad; if (table->entries == NULL) { table->entries = newEntry; printdebug("[CreateEntry] Adding %s to the symbol table", id); return newEntry; } else { TableNode *oldEntry = table->entries; table->entries = newEntry; newEntry->next = oldEntry; printdebug("[CreateEntry] Adding %s to the symbol table", id); return newEntry; } } TableNode *getTypeEntry(TableNode *tn) { if (tn == NULL) { printdebug("passed a NULL table entry to getType"); return undefined; } if (tn == undefined) { printdebug("passed an undefined table entry to getType"); return undefined; } if (tn->theType == NULL) { printdebug("type of entry is currently NULL type"); return undefined; } if (tn->theType == undefined) { printdebug("type of entry is currently undefined type"); return undefined; } return tn->theType; } char *getType(TableNode *tn) { if (tn == NULL) { printdebug("passed a NULL table entry to getType"); return getName(undefined); } if (tn == undefined) { printdebug("passed an undefined table entry to getType"); return getName(undefined); } if (tn->theType == NULL) { printdebug("type of entry is currently NULL type"); return getName(undefined); } if (tn->theType == undefined) { printdebug("type of entry is currently undefined type"); return getName(undefined); } return tn->theType->theName; } char *getName(TableNode *tn) { if (tn == NULL) { printdebug("passed a NULL table entry to getName"); return undefined->theName; } if (tn == undefined) { printdebug("passed an undefined table entry to getName"); return undefined->theName; } if (tn->theName == NULL) { printdebug("name of entry is currently NULL, undefined"); return undefined->theName; } return tn->theName; } int getLine(SymbolTable *st) { if (st == NULL) { printdebug("passed a NULL symbol table to getLine function. " "Invalid."); return -1; } return st->Line_Number; } int getColumn(SymbolTable *st) { if (st == NULL) { printdebug("passed a NULL symbol table to getColumn function. " "Invalid."); return -1; } return st->Column_Number; } TableNode *addName(TableNode *tn, char *str) { if (tn == NULL) { printdebug("passed a Null table node to the addName " "function. Invalid."); return undefined; } if (tn == undefined) { printdebug("passed an undefined table node to the addName " "function. Invalid."); return undefined; } if (tn->theName != NULL) { //printdebug( //"Name doesn't look like it is empty before you change. " //"Are you sure you need to update name?"); if (str != NULL) { tn->theName = str; return tn; } printdebug("passed a NULL string to the addName function"); return undefined; } if (str == NULL) { printdebug( "passed a NULL string to the addName function. Invalid."); return undefined; } tn->theName = str; return tn; } SymbolTable *setLineNumber(SymbolTable *st, int line) { if (st == NULL) { printdebug("passed a Null Symbol Table to the setLineNumber " "function. Invalid."); return st; } st->Line_Number = line; return st; } SymbolTable *setColumnNumber(SymbolTable *st, int column) { if (st == NULL) { printdebug("passed a Null Symbol Table to the setColumnNumber " "function. Invalid."); return st; } st->Line_Number = column; return st; } /* //we use false for type defs and true for functions for parameter of typeOf TableNode* Define(SymbolTable* table, bool typeOf, char* id) { if(table ==NULL || table->Parent_Scope != NULL){ printdebug("No valid table given for header defs"); return NULL; } TableNode* newEntry = (TableNode*)malloc(sizeof(TableNode)); //possible issues with referencing text instead of heap if(typeOf == 0){ newEntry->theType = typey; } if (typeOf == 1){ newEntry->theType = funy; } if(table_lookup(table,id) != NULL){ printdebug("already defined at the top level, can't define duplicate names"); return NULL; } newEntry->theName = id; if (table->entries == NULL) { table->entries = newEntry; return newEntry; } else { TableNode* oldEntry = table->entries; table->entries = newEntry; newEntry->next = oldEntry; return newEntry; } } */ // only check table that is given TableNode *table_lookup(SymbolTable *table, char *x) { if (table == NULL) { printdebug("passed in empty scope. error."); return undefined; } TableNode *entrie = table->entries; for (; entrie != NULL; entrie = entrie->next) { if (!strcmp(entrie->theName, x)) { return entrie; } } return undefined; } // check current table and all parents TableNode *look_up(SymbolTable *table, char *x) { if (table == NULL) { printdebug("passed in empty scope. error."); return undefined; } TableNode *ret = table_lookup(table, x); if (ret != NULL && ret != undefined) { return ret; } printdebug( "could not find %s in scope that started at line %d and column " "%d so moving up a scope", x, getLine(table), getColumn(table)); return look_up(table->Parent_Scope, x); } /* void print_symbol_table(SymbolTable *table, FILE *file_ptr) { if (table->Parent_Scope == NULL) { fprintf(file_ptr, "%-17s: %-6s : %-6s : %-21s: %-28s\n", "NAME", "SCOPE", "PARENT", "TYPE", "Extra annotation"); } TableNode *entrie = table->entries; fprintf(file_ptr, "-----------------:--------:--------:----------------" "------:---------" "--------------------\n"); int parant_scope = 0; int current_scope = 0; if (table->Parent_Scope != NULL) { parant_scope = table->Parent_Scope->Line_Number * 1000 + table->Parent_Scope->Column_Number; current_scope = table->Line_Number * 1000 + table->Column_Number; } else { current_scope = 1001; } if (entrie == NULL) { fprintf(file_ptr, "%-17s: %06d : %06d : %-21s: %-28s\n", "", current_scope, parant_scope, "", "Empty Scope"); } for (; entrie != NULL; entrie = entrie->next) { if (parant_scope == 0) { /*have to update if (strcmp(entrie->theType->theName, "function primitive") || strcmp(entrie->theType->theName, "array")) { } fprintf(file_ptr, "%-17s: %06d : : %-21s: %-28s\n", entrie->theName, current_scope, entrie->theType->theName, "Extra annotation"); } else { fprintf(file_ptr, "%-17s: %06d : %06d : %-21s: %-28s\n", entrie->theName, current_scope, parant_scope, entrie->theType->theName, "Extra annotation"); } } if (table->Children_Scope != NULL) { ListOfTable *node = table->Children_Scope; for (; node != NULL; node = node->next) { print_symbol_table(node->table, file_ptr); } } if (table->Parent_Scope == NULL) { fprintf(file_ptr, "-----------------:--------:--------:--------" "--------------:-------" "----------------------\n"); } }*/ void print_symbol_table(SymbolTable *table, FILE *file_ptr) { if (table == NULL) { printdebug( "%s[FATAL] passed in NULL table to print_symbol_table", COLOR_RED); return; } if (table->Parent_Scope == NULL) { fprintf(file_ptr, "%-25s: %-6s : %-6s : %-25s: %-30s\n", "NAME", "SCOPE", "PARENT", "TYPE", "Extra annotation"); } TableNode *entrie = table->entries; fprintf(file_ptr, "-------------------------:--------:--------:------------------" "--------:------------------------------\n"); int parant_scope = 0; int current_scope = 0; if (table->Parent_Scope != NULL) { parant_scope = getParent(table)->Line_Number * 1000 + getParent(table)->Column_Number; current_scope = table->Line_Number * 1000 + table->Column_Number; } else { current_scope = 1001; } if (entrie == NULL) { fprintf(file_ptr, "%-25s: %06d : %06d : %-25s: %-30s\n", "", current_scope, parant_scope, "", "Empty Scope"); } for (; entrie != NULL; entrie = getNextEntry(entrie)) { if (getAdInfoType(entrie) == TYPE_ARRAY_TYPE) { if (parant_scope == 0) { fprintf(file_ptr, "%-25s: %06d : : %d -> %-20s: " "%-30s\n", entrie->theName, current_scope, entrie->additionalinfo->ArrayAdInfo ->numofdimensions, entrie->additionalinfo->ArrayAdInfo ->typeofarray->theName, "Type of Array"); } else { fprintf(file_ptr, "%-25s: %06d : : %d -> %-20s: " "%-30s\n", entrie->theName, current_scope, parant_scope, entrie->additionalinfo->ArrayAdInfo ->numofdimensions, entrie->additionalinfo->ArrayAdInfo ->typeofarray->theName, "Type of Array"); } } if (getAdInfoType(entrie) == TYPE_RECORD) { if (parant_scope == 0) { fprintf(file_ptr, "%-25s: %06d : : %-25s: " "elements-%-30d\n", entrie->theName, current_scope, "record", entrie->additionalinfo->RecAdInfo ->numofelements); } else { fprintf(file_ptr, "%-25s: %06d : %06d : %-25s: " "elements-%-30d\n", entrie->theName, current_scope, parant_scope, "record", entrie->additionalinfo->RecAdInfo ->numofelements); } } if (getAdInfoType(entrie) == TYPE_PRIMITIVE) { if (parant_scope == 0) { fprintf( file_ptr, "%-25s: %06d : : %-25s: size-%d " "bytes\n", entrie->theName, current_scope, "Primitive", entrie->additionalinfo->PrimAdInfo->size); } else { fprintf( file_ptr, "%-25s: %06d : %06d : %-25s: size-%-30d " "bytes\n", entrie->theName, current_scope, parant_scope, "Primitive", entrie->additionalinfo->PrimAdInfo->size); } } if (getAdInfoType(entrie) == TYPE_FUNCTION_TYPE) { if (parant_scope == 0) { fprintf(file_ptr, "%-25s: %06d : : %-25s -> " "%-25s: %-30s\n", entrie->theName, current_scope, entrie->additionalinfo->FunTypeAdInfo ->parameter->theName, entrie->additionalinfo->FunTypeAdInfo ->returntype->theName, "Type of Function"); } else { fprintf(file_ptr, "%-25s: %06d : %06d : %-25s -> %-21s: " "%-30s\n", entrie->theName, current_scope, parant_scope, entrie->additionalinfo->FunTypeAdInfo ->parameter->theName, entrie->additionalinfo->FunTypeAdInfo ->returntype->theName, "Type of Function"); } } if (getAdInfoType(entrie) == TYPE_FUNCTION_DECLARATION) { if (parant_scope == 0) { fprintf(file_ptr, "%-25s: %06d : : %-25s: %-30s\n", entrie->theName, current_scope, getType(entrie), "User Defined"); } else { fprintf(file_ptr, "%-25s: %06d : %06d : %-25s: %-30s\n", entrie->theName, current_scope, parant_scope, getType(entrie), "User Defined"); } } if (getAdInfoType(entrie) == TYPE_UNDEFINED) { if (parant_scope == 0) { fprintf(file_ptr, "%-25s: %06d : : %-25s: %-30s\n", entrie->theName, current_scope, "undefined", "undefined entry"); } else { fprintf(file_ptr, "%-25s: %06d : %06d : %-25s: %-30s\n", entrie->theName, current_scope, parant_scope, "undefined", "undefined entry"); } } } if (getChildren(table) != NULL) { ListOfTable *node = getChildren(table); for (; node != NULL; node = node->next) { if ((node->table) == NULL) { print_symbol_table(node->table, file_ptr); } else { if ((node->table)->Line_Number == -1) { continue; } else { print_symbol_table(node->table, file_ptr); } } } } if (getParent(table) == NULL) { fprintf(file_ptr, "-------------------------:--------:--------:----------" "----------------:------------------------------\n"); } } // get top most symbol table SymbolTable *getAncestor(SymbolTable *table) { if (table == NULL) { printdebug("passing a NULL reference to getAncestor. Invalid."); return NULL; } if (table->Parent_Scope == NULL) { // if table has no parent, return itself printdebug("already at top scope!"); if (table == cur) { printdebug("passed in the current scope"); } else { printdebug("passed in a different scope"); } return table; } else { // call function recursively to grab ancestor return getAncestor(table->Parent_Scope); } } SymbolTable *removeEntry(SymbolTable *scope, char *search) { if (scope == NULL) { return NULL; } if (scope->entries == NULL) { return scope; } TableNode *prev = NULL; TableNode *now = scope->entries; while (now != NULL) { if (strcmp(getName(now), search) == 0) { if (prev == NULL) { scope->entries = getNextEntry(now); return scope; } else { prev->next = now->next; return scope; } } prev = now; now = now->next; } return scope; } // almost certainly don't need to use the below function since type checking // happens by passing types up the grammar bool typeCheck(char *firstID, char *secondID) { TableNode *entry1 = look_up(cur, firstID); TableNode *entry2 = look_up(cur, secondID); if (entry1 == NULL) { printdebug("first type is NULL in type check. Invalid."); return false; } if (entry1 == undefined) { printdebug("first type is undefined in type check. Invalid."); return false; } if (entry2 == NULL) { printdebug("second type is NULL in type check. Invalid."); return false; } if (entry2 == undefined) { printdebug("second type is undefined in type check. Invalid."); return false; } if (table_lookup(getAncestor(cur), getType(look_up(cur, firstID))) == table_lookup(getAncestor(cur), getType(look_up(cur, secondID)))) { if (strcmp(getType(look_up(cur, firstID)), "array") == 0) { if (look_up(cur, firstID) ->additionalinfo->ArrayAdInfo ->numofdimensions == look_up(cur, secondID) ->additionalinfo->ArrayAdInfo ->numofdimensions && look_up(cur, firstID) ->additionalinfo->ArrayAdInfo ->typeofarray == look_up(cur, secondID) ->additionalinfo->ArrayAdInfo ->typeofarray) { return true; } else { return false; } } return true; } return false; } SymbolTable *getParent(SymbolTable *st) { if (st == NULL) { printdebug("passed a NULL symbol table to getParent function. " "Invalid."); return NULL; } if (st->Parent_Scope == NULL) { printdebug("passed a top level scope to getParent function. " "Invalid."); return st; } return st->Parent_Scope; } ListOfTable *getChildren(SymbolTable *st) { return st->Children_Scope; } SymbolTable *getFirstChild(ListOfTable *lt) { return lt->table; } ListOfTable *getRestOfChildren(ListOfTable *lt) { return lt->next; } TableNode *getFirstEntry(SymbolTable *st) { return st->entries; } // Segfaults when passed an invalid table node! TableNode *getNextEntry(TableNode *tn) { if (tn == NULL) { printdebug("passed a NULL table node to getNextEntry"); return undefined; } if (tn == undefined) { printdebug("passed an undefined table node to getNextEntry"); return undefined; } return tn->next; } // uncomment the below main function along with the headers above for a simple // standalone test of table and entry creation /* int main(){ char* String = "STRING"; char* X = "X"; SymbolTable* Second = CreateScope(NULL, 2,2); printdebug("Line number is %d, Column number of scope is %d",Second->Line_Number,Second->Column_Number); TableNode* First_Entry = CreateEntry(Second,String,X); printdebug("The type of the first entry is %s",First_Entry->theType); return 0; } */