/* Symbol Table */ /* The Translators - Spring 2025 */ #include "symbol_table.h" #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; 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 TYPE_ARRAY = 2, // Record is user defined types TYPE_RECORD = 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 } 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 (strcmp(getType(definition), "primitive") != 0) { printf("not checking the size of a primitive -- invalid op\n"); 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) { 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 (strcmp(getType(definition), "array") != 0) { printf("not checking the dim of an array -- invalid op\n"); 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 (strcmp(getType(definition), "array") != 0) { printf("not checking the type of an array -- invalid op\n"); return NULL; } 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 (strcmp(getType(definition), "record") != 0) { printf("not checking the length of an record -- invalid op\n"); 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 (strcmp(getType(definition), "record") != 0) { printf("not checking the list of types of a record -- invalid " "op\n"); return NULL; } return definition->additionalinfo->RecAdInfo->recordScope; } // 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 (strcmp(getType(definition), "function primitive") != 0) { printf("not checking the start line of a function -- invalid " "op\n"); return 0; } return definition->additionalinfo->FunDecAdInfo->startlinenumber; } // checks if "as" keyword was used for function definition. Either 0 or 1 for // not used or used. bool getAsKeyword(TableNode *definition) { if (strcmp(getType(definition), "function primitive") != 0) { printf("not checking if a function is called with as or not -- " "invalid op\n"); return NULL; } return definition->additionalinfo->FunDecAdInfo->regularoras; } // stores the type of a function (parameter type and return type) AdInfo *CreateFunctionTypeInfo(TableNode *parameter, TableNode *returntype) { 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 (strcmp(getType(definition), "function type primitive") != 0) { printf( "not checking the parameter of a function -- invalid op\n"); return NULL; } return definition->additionalinfo->FunTypeAdInfo->parameter; } // returns return type of a function TableNode *getReturn(TableNode *definition) { if (strcmp(getType(definition), "function type primitive") != 0) { printf("not checking the return of a function -- invalid op\n"); return NULL; } 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) { printf( "Cannot initialize a scope that is not the parent scope\n"); return NULL; } integ = (TableNode *)malloc(sizeof(TableNode)); addr = (TableNode *)malloc(sizeof(TableNode)); chara = (TableNode *)malloc(sizeof(TableNode)); stri = (TableNode *)malloc(sizeof(TableNode)); boo = (TableNode *)malloc(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; // 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; prime->next = NULL; // 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; // record recprime = (TableNode *)malloc(sizeof(TableNode)); recprime->theName = "record"; recprime->theType = NULL; recprime->additionalinfo = NULL; recprime->next = NULL; funtypeprime = (TableNode *)malloc(sizeof(TableNode)); funtypeprime->theName = "primitive function type"; funtypeprime->theType = NULL; funtypeprime->additionalinfo = NULL; funtypeprime->next = NULL; 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(4); addr->additionalinfo = CreatePrimitiveInfo(8); chara->additionalinfo = CreatePrimitiveInfo(1); stri->additionalinfo = CreateArrayInfo(1, chara); boo->additionalinfo = CreatePrimitiveInfo(1); // 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){ printf("passed in an invalid table node to modify (NULL).\n"); return NULL; } if(type == NULL){ printf("passed in a NULL type reference to populate a table node. Invalid.\n"); return NULL; } if(info == NULL){ printf("passed in a NULL info reference to populate a table node. Invalid.\n"); return NULL; } tn->theType = type; tn->additionalinfo = info; //returning reference to modified table node return tn; } int getAdInfoType(TableNode* tn){ if(tn == NULL){ printf("passing in NULL table entry. Invalid\n"); return -1; } if(tn->theType == NULL){ printf("Entry being passed in has a null reference for theType. Invalid.\n"); return -1; } if(strcmp(getType(tn),getName(integ))==0){ return TYPE_PRIMITIVE; } if(strcmp(getType(tn),getName(addr))==0){ return TYPE_PRIMITIVE; } if(strcmp(getType(tn),getName(chara))==0){ return TYPE_PRIMITIVE; } if(strcmp(getType(tn),getName(stri))==0){ return TYPE_ARRAY; } if(strcmp(getType(tn),getName(boo))==0){ return TYPE_PRIMITIVE; } if(strcmp(getType(tn),getName(recprime))==0){ return TYPE_RECORD; } if(strcmp(getType(tn),getName(funtypeprime))==0){ return TYPE_FUNCTION_TYPE; } if(strcmp(getType(tn),getName(arrayprim))==0){ return TYPE_ARRAY; } else{ return TYPE_FUNCTION_DECLARATION; } } TableNode *CreateEntry(SymbolTable *table, TableNode *typeOf, char *id, AdInfo *ad) { if (table == NULL) { printf("Null reference to table"); return NULL; } /* TableNode* topDef = (table_lookup(getAncestor(table),typeOf)); if(topDef == NULL){ printf("This type is not defined at the top level\n"); return NULL; } */ if (typeOf == NULL) { printf("This is not pointing to a proper definition\n"); return NULL; } TableNode *newEntry = (TableNode *)malloc(sizeof(TableNode)); newEntry->theType = typeOf /*topDef*/; newEntry->theName = id; newEntry->additionalinfo = ad; if (table->entries == NULL) { table->entries = newEntry; return newEntry; } else { TableNode *oldEntry = table->entries; table->entries = newEntry; newEntry->next = oldEntry; return newEntry; } } char *getType(TableNode *tn) { if(tn == NULL){ printf("passed a NULL table entry to getType\n"); return tn; } if(tn->theType == NULL){ printf("type of entry is currently NULL, undefined type \n"); return tn; } return tn->theType->theName; } char *getName(TableNode *tn) { return tn->theName; } int getLine(SymbolTable *st) { return st->Line_Number; } int getColumn(SymbolTable *st) { return st->Column_Number; } /* //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){ printf("No valid table given for header defs\n"); 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){ printf("already defined at the top level, can't define duplicate names\n"); 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) { TableNode *entrie = table->entries; for (; entrie != NULL; entrie = entrie->next) { if (!strcmp(entrie->theName, x)) { return entrie; } } return NULL; } //check current table and all parents TableNode *look_up(SymbolTable *table, char *x) { if (table == NULL) { return NULL; } TableNode *ret = table_lookup(table, x); if (ret != NULL) { return ret; } return look_up(table->Parent_Scope, x); } void print_symbol_table(SymbolTable *table, FILE *file_ptr) { return; 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"); } } //get top most symbol table SymbolTable *getAncestor(SymbolTable *table) { if (table->Parent_Scope == NULL) { // if table has no parent, return itself 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) { printf("first type not defined\n"); return false; } if (entry2 == NULL) { printf("second type not defined\n"); 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) { 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; } TableNode *getNextEntry(TableNode *tn) { 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); printf("Line number is %d, Column number of scope is %d\n",Second->Line_Number,Second->Column_Number); TableNode* First_Entry = CreateEntry(Second,String,X); printf("The type of the first entry is %s\n",First_Entry->theType); return 0; } */