/* 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, //Array can be multidimensional. Information should be stored here TYPE_ARRAY, //Record is user defined types TYPE_RECORD, //Declaring what type a particular function is without as TYPE_FUNCTION_DECLARATION, //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, //The Type being pointed to by the first 4 above that only stores the size TYPE_PRIMITIVE } types; /* put in symbol_table.h typedef struct{ int size; }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; */ AdInfo* CreatePrimitiveInfo(int size){ AdInfo* info = (AdInfo*)malloc(sizeof(AdInfo)); info->PrimAdInfo = (primitive_info*)malloc(sizeof(primitive_info)); info->PrimAdInfo->size=size; return info; } 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; } */ 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; } 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; } 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; } AdInfo* CreateRecordInfo(int length, TableNode* typesarray){ AdInfo* info = (AdInfo*)malloc(sizeof(AdInfo)); info->RecAdInfo = (record_info*)malloc(sizeof(record_info)); info->RecAdInfo->numofelements=length; info->RecAdInfo->listoftypes = typesarray; return info; } 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; } TableNode* 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->listoftypes; } //below function takes a bool to see if parameter should be decomposed or not 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; } 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; } 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; } 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; } 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; } 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; } 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 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 primitive"; //arr->theName= "array" //root TableNode that all are pointing to but not in table TableNode* prime = (TableNode*)malloc(sizeof(TableNode)); prime->theName= "primitive"; prime->theType=NULL; prime->additionalinfo = NULL; prime->next = NULL; //note sur 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 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 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* CreateEntry(SymbolTable* table, char* 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; } TableNode* newEntry = (TableNode*)malloc(sizeof(TableNode)); newEntry->theType = 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) { 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; } } */ 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; } 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) { 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"); } } 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; } 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; } */