/* Symbol Table */ /* The Translators - Spring 2025 */ #include "symbol_table.h" Constant_Stack *head = NULL; int temp2_count = 0; int temp3_count = 0; 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"); } } char *temp_var_gen() { char *ret = calloc(9, sizeof(*ret)); sprintf(ret, "$t%d", temp2_count); temp2_count++; return ret; } char *arg_var_gen() { char *ret = calloc(9, sizeof(*ret)); sprintf(ret, "&%d", temp3_count); temp3_count++; return ret; } Constant_Stack *Push(TableNode *type, void *value, bool isConst) { if (type == NULL || type == undefined) { printdebug( "passed a NULL reference/undefined reference to " "CreateConstantStack. Invalid."); return NULL; } Constant_Stack *cs = (Constant_Stack *)malloc(sizeof(Constant_Stack)); cs->theType = type; cs->theValue = value; cs->isConst = isConst; if (head == NULL) { head = cs; cs->next = NULL; } else { cs->next = head; head = cs; } return cs; } Constant_Stack *Pop() { if (head == NULL) { printf("cannot pop from an empty stack. Invalid.\n"); return NULL; } Constant_Stack *cs = head; head = head->next; printf("Popped something of type %s\n", getName(cs->theType)); return cs; } Constant_Stack *Print_Stack() { if (head == NULL) { printdebug("cannot print an empty stack. Invalid."); return NULL; } Constant_Stack *cs = head; while (cs != NULL) { if (cs->theValue == NULL) { printf("Type: %s, Value: NULL", getName(cs->theType)); } if (cs->theType == stri) { printf("Type: %s, Value: %c\n", getName(cs->theType), *(char *)(cs->theValue)); } if (cs->theType == integ) { printf("Type: %s, Value: %d\n", getName(cs->theType), *(int *)(cs->theValue)); } if (cs->theType == chara) { printf("Type: %s, Value: %c\n", getName(cs->theType), *(char *)cs->theValue); } if (cs->theType == boo) { if (*(bool *)cs->theValue == true) { printf("Type: %s, Value: true\n", getName(cs->theType)); } else { printf("Type: %s, Value: false\n", getName(cs->theType)); } } cs = cs->next; } return cs; } // 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; } // 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, 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 (getAdInfoType(definition) != TYPE_ARRAY_TYPE) { printdebug( "passed an invalid node to getNumArrDim. Seeing tag %d in getNumArrDim. Invalid.", getAdInfoType(definition)); return -1; } 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 undefined; } if (definition == undefined) { printdebug( "passed an undefined entry to getArrType " "function. Invalid."); return undefined; } if (getAdInfoType(definition) != TYPE_ARRAY_TYPE) { printdebug( "passed an invalid node to getArrType. Seeing tag %d. Invalid.", getAdInfoType(definition)); 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 getRecTotal(TableNode *node) { if (node == NULL) { printdebug( "passed a NULL node to getRecTotal. Invalid."); return -1; } if (getAdInfoType(node) != TYPE_RECORD_TYPE) { printdebug( "passed an invalid node to getRecTotal. Invalid."); return -1; } if (node->additionalinfo == NULL) { printdebug( "node has NULL additionalinfo. Invalid."); return -1; } return node->additionalinfo->RecAdInfo->total_size; } TableNode *setRecOffsetInfo(SymbolTable *scope, TableNode *node) { if (node == NULL) { printdebug( "passed a NULL node to setRecOffsetInfo. Invalid."); return undefined; } if (scope == NULL) { printdebug( "passed an NULL scope to setRecOffsetInfo. Invalid."); return undefined; } if (getFirstEntry(scope) == NULL) { printdebug( "passed an empty scope to setRecOffsetInfo. Invalid."); return undefined; } TableNode *this = getFirstEntry(scope); int largest = 0; int k = getRecLength(node); int total_size = 0; int counter = 0; int *offsets = (int *)calloc(2 * k, sizeof(int)); if (getAdInfoType(this) == TYPE_FUNCTION_DECLARATION) { offsets[counter] = 8; total_size = total_size + offsets[counter]; largest = 8; counter++; } else if ((getAdInfoType(this) == TYPE_RECORD)) { offsets[counter] = 8; total_size = total_size + offsets[counter]; largest = offsets[counter]; counter++; } else if (getAdInfoType(this) == TYPE_PRIMITIVE) { offsets[counter] = getPrimSize(getTypeEntry(this)); total_size = total_size + offsets[counter]; largest = offsets[counter]; counter++; } else if (getAdInfoType(this) == TYPE_ARRAY) { offsets[counter] = 8; total_size = total_size + offsets[counter]; largest = offsets[counter]; counter++; } else { printdebug( "[TYPE CHECK] passed an invalid (first) parameter to a function definition. seeing %d. Type of entry is %s. Name attempted to pass is %s.", getAdInfoType(this), getType(this), getName(this)); return undefined; } this = getNextEntry(this); while (this != NULL) { if (getAdInfoType(this) == TYPE_FUNCTION_DECLARATION) { int s = 8; if (s > largest) { largest = s; } //make sure current location is aligned properly offsets[counter] = (total_size % s); total_size = total_size + offsets[counter]; counter++; //add in the size of the entry and increment offsets[counter] = s; total_size = total_size + offsets[counter]; counter++; this = getNextEntry(this); } else if (getAdInfoType(this) == TYPE_ARRAY) { int s = 8; if (s > largest) { largest = s; } //make sure current location is aligned properly offsets[counter] = (total_size % s); total_size = total_size + offsets[counter]; counter++; //add in the size of the entry and increment offsets[counter] = s; total_size = total_size + offsets[counter]; counter++; this = getNextEntry(this); } else if ((getAdInfoType(this) == TYPE_RECORD)) { int s = 8; if (s > largest) { largest = s; } //make sure current location is aligned properly printTableNode(this); printTableNode(node); offsets[counter] = (total_size % s); total_size = total_size + offsets[counter]; counter++; //add in the size of the entry and increment offsets[counter] = s; total_size = total_size + offsets[counter]; counter++; this = getNextEntry(this); } else if (getAdInfoType(this) == TYPE_PRIMITIVE) { int s = getPrimSize(getTypeEntry(this)); if (s > largest) { largest = s; } //make sure current location is aligned properly offsets[counter] = (total_size % s); total_size = total_size + offsets[counter]; counter++; //add in the size of the entry and increment offsets[counter] = s; total_size = total_size + offsets[counter]; counter++; this = getNextEntry(this); } else { printdebug( "[TYPE CHECK] passed an invalid parameter at position %d in record.", ((counter + 1) / 2)); return undefined; } } //make sure that size of whole structure is aligned with largest element in struct: offsets[counter] = (total_size % largest); total_size = total_size + offsets[counter]; node->additionalinfo->RecAdInfo->offsets = offsets; node->additionalinfo->RecAdInfo->total_size = total_size; return node; } int *getRecOffsets(TableNode *node) { if (node == NULL) { printdebug( "passed a NULL node to getRecTotal. Invalid."); return NULL; } if (getAdInfoType(node) != TYPE_RECORD_TYPE) { printdebug( "passed an invalid node to getRecTotal. Invalid."); return NULL; } if (node->additionalinfo == NULL) { printdebug( "node has NULL additionalinfo. Invalid."); return NULL; } return node->additionalinfo->RecAdInfo->offsets; } 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 of type %s", getType(definition)); 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 (definition->additionalinfo == NULL) { printdebug( "node has NULL additionalinfo. 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 undefined; } if (definition == undefined) { printdebug( "passed an undefined entry to getReturn " "function. Invalid."); return undefined; } if (strcmp(getType(definition), "primitive function type") != 0) { printdebug( "not checking the return of a function -- invalid op"); return undefined; } if (definition->additionalinfo == NULL) { printdebug( "node has NULL additionalinfo. Invalid."); return undefined; } printdebug("function:%s with return type %s\n",getName(definition),getName(definition->additionalinfo->FunTypeAdInfo->returntype)); 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 *reservetype = (TableNode *)calloc(1, sizeof(TableNode)); TableNode *reserve = (TableNode *)calloc(1, sizeof(TableNode)); TableNode *releasetype = (TableNode *)calloc(1, sizeof(TableNode)); TableNode *release = (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 = reservetype; reservetype->next = reserve; reserve->next = releasetype; releasetype->next = release; release->next = NULL; integ->theName = "integer"; addr->theName = "address"; chara->theName = "character"; boo->theName = "Boolean"; stri->theName = "string"; reserve->theName = "reserve"; reservetype->theName = "reserve type"; releasetype->theName = "release type"; release->theName = "release"; // 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; reserve->theType = reservetype; reservetype->theType = funtypeprime; releasetype->theType = funtypeprime; release->theType = releasetype; // 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); reserve->additionalinfo = CreateFunctionDeclarationInfo(0, false); reservetype->additionalinfo = CreateFunctionTypeInfo(integ, addr); releasetype->additionalinfo = CreateFunctionTypeInfo(addr, integ); release->additionalinfo = CreateFunctionDeclarationInfo(0, false); integ->tag = TYPE_PRIMITIVE_TYPE; // explicitly set the type for integ addr->tag = TYPE_PRIMITIVE_TYPE; // explicitly set the type for addr chara->tag = TYPE_PRIMITIVE_TYPE; // explicitly set the type for chara stri->tag = TYPE_ARRAY_TYPE; // explicitly set the type for stri boo->tag = TYPE_PRIMITIVE_TYPE; // explicitly set the type for boo reserve->tag = TYPE_FUNCTION_DECLARATION; reservetype->tag = TYPE_FUNCTION_TYPE; releasetype->tag = TYPE_FUNCTION_TYPE; release->tag = TYPE_FUNCTION_DECLARATION; // 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((id != NULL) && table_lookup(cur,id)!=undefined){ printdebug("This name is already defined in the current scope"); //throw_error(ERROR_TYPE, "Already defined."); return undefined; } 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; while (oldEntry->next != NULL) { oldEntry = oldEntry->next; } oldEntry->next = newEntry; newEntry->next = NULL; //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; } // 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; } } printdebug("Could not find %s in scope using table_lookup", x); return undefined; } // check current table and all parents TableNode *look_up(SymbolTable *table, char *x) { if (table == NULL) { printdebug("Could not find %s in any scope using lookup", x); 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); } int col_widths[5] = {30, 8, 8, 35, 35}; void printline(FILE *file_ptr, bool b) { if (b) { fprintf(file_ptr, "oop\n"); } for (int i = 0; i < 5; i++) { for (int ii = 0; ii < col_widths[i]; ii++) { fprintf(file_ptr, "-"); } fprintf(file_ptr, ":"); } fprintf(file_ptr, "\n"); } void st_fprint(FILE *file_ptr, char *label1, int label2, int label3, char *label4, char *label5) { if (label3 == -100) { fprintf(file_ptr, "%-*s: %0*d : %*s :%-*s:%-*s\n", col_widths[0], (label1 ? label1 : ""), col_widths[1] - 2, label2, col_widths[2] - 2, "", col_widths[3], (label4 ? label4 : ""), col_widths[4], (label5 ? label5 : "")); } else { fprintf(file_ptr, "%-*s: %0*d : %0*d :%-*s:%-*s\n", col_widths[0], (label1 ? label1 : ""), col_widths[1] - 2, label2, col_widths[2] - 2, label3, col_widths[3], (label4 ? label4 : ""), col_widths[4], (label5 ? label5 : "")); } } 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, "%-*s:%-*s:%-*s:%-*s:%-*s:\n", col_widths[0], "NAME", col_widths[1], " SCOPE", col_widths[2], " PARENT", col_widths[3], " TYPE", col_widths[4], " EXTRA ANNOTATION"); } TableNode *entry = table->entries; printline(file_ptr, false); int parentScopeNum = 0; int currentScopeNum = 0; if (table->Parent_Scope != NULL) { parentScopeNum = getParent(table)->Line_Number * 1000 + getParent(table)->Column_Number; currentScopeNum = table->Line_Number * 1000 + table->Column_Number; } else { currentScopeNum = 1001; } if (entry == NULL) { st_fprint(file_ptr, "", currentScopeNum, parentScopeNum, "", " Empty Scope"); } for (; entry != NULL; entry = getNextEntry(entry)) { if((getName(entry)[0] == '$' || getName(entry)[0] == '&') && ir_flag == NULL){ continue; } if (getAdInfoType(entry) == TYPE_ARRAY_TYPE) { char *arrayType = (char *)malloc(100); sprintf(arrayType, " %d -> %s", getNumArrDim(entry), getName(getArrType(entry))); if (parentScopeNum == 0) { st_fprint(file_ptr, getName(entry), currentScopeNum, -100, arrayType, " Type of Array"); } else { st_fprint(file_ptr, getName(entry), currentScopeNum, parentScopeNum, arrayType, " Type of Array"); } } if (getAdInfoType(entry) == TYPE_ARRAY) { char *arrayType = (char *)malloc(sizeof(getType(entry) + 1)); sprintf(arrayType, " %s", getType(entry)); if (parentScopeNum == 0) { st_fprint(file_ptr, getName(entry), currentScopeNum, -100, arrayType, " Array Instance"); } else { st_fprint(file_ptr, getName(entry), currentScopeNum, parentScopeNum, arrayType, " Array Instance"); } } if (getAdInfoType(entry) == TYPE_RECORD_TYPE) { char *recordAdInfo = (char *)malloc(100); sprintf(recordAdInfo, " elements-%d size-%d bytes", getRecLength(entry), getRecTotal(entry)); if (parentScopeNum == 0) { st_fprint(file_ptr, getName(entry), currentScopeNum, -100, " Record Type", recordAdInfo); } else { st_fprint(file_ptr, getName(entry), currentScopeNum, parentScopeNum, " Record Type", recordAdInfo); } } if (getAdInfoType(entry) == TYPE_RECORD) { char *recordAdInfo = (char *)malloc(100); sprintf(recordAdInfo, " elements-%d", getRecLength(entry)); char *recordType = (char *)malloc(sizeof(getType(entry) + 1)); sprintf(recordType, " %s", getType(entry)); if (parentScopeNum == 0) { st_fprint(file_ptr, getName(entry), currentScopeNum, -100, recordType, " Record Instance"); } else { st_fprint(file_ptr, getName(entry), currentScopeNum, parentScopeNum, recordType, " Record Instance"); } } if (getAdInfoType(entry) == TYPE_PRIMITIVE_TYPE) { char *primAdInfo = (char *)malloc(100); sprintf(primAdInfo, " size-%d bytes", getPrimSize(entry)); if (parentScopeNum == 0) { st_fprint(file_ptr, getName(entry), currentScopeNum, -100, " Primitive Type", primAdInfo); } else { char *primType = (char *)malloc(sizeof(getType(entry) + 1)); sprintf(primType, " %s", getType(entry)); st_fprint(file_ptr, getName(entry), currentScopeNum, parentScopeNum, primType, primAdInfo); } } if (getAdInfoType(entry) == TYPE_PRIMITIVE) { char *primAdInfo = (char *)malloc(100); sprintf(primAdInfo, " size-%d bytes", getPrimSize(getTypeEntry(entry))); if (parentScopeNum == 0) { st_fprint(file_ptr, getName(entry), currentScopeNum, -100, " Primitive", primAdInfo); } else { char *primType = (char *)malloc(sizeof(getType(entry) + 1)); sprintf(primType, " %s", getType(entry)); st_fprint(file_ptr, getName(entry), currentScopeNum, parentScopeNum, primType, " Primitive Instance"); } } if (getAdInfoType(entry) == TYPE_FUNCTION_TYPE) { char *functiontype = (char *)malloc(100); sprintf(functiontype, " %s -> %s", getName(getParameter(entry)), getName(getReturn(entry))); if (parentScopeNum == 0) { st_fprint(file_ptr, getName(entry), currentScopeNum, -100, functiontype, " Type of Function"); } else { st_fprint(file_ptr, getName(entry), currentScopeNum, parentScopeNum, functiontype, " Type of Function"); } } if (getAdInfoType(entry) == TYPE_FUNCTION_DECLARATION) { char *functiontype = (char *)malloc(100); sprintf(functiontype, " %s", getName(getTypeEntry(entry))); if (parentScopeNum == 0) { st_fprint(file_ptr, getName(entry), currentScopeNum, -100, functiontype, " Function Definition"); } else { st_fprint(file_ptr, getName(entry), currentScopeNum, parentScopeNum, functiontype, " Function Definition"); } } if (getAdInfoType(entry) == TYPE_UNDEFINED) { if (parentScopeNum == 0) { st_fprint(file_ptr, getName(entry), currentScopeNum, -100, " undefined", "undefined entry"); } else { st_fprint(file_ptr, getName(entry), currentScopeNum, parentScopeNum, " undefined", "undefined entry"); } } } if (getChildren(table) != NULL) { ListOfTable *node = getChildren(table); for (; node != NULL; node = getRestOfChildren(node)) { if ((getFirstChild(node)) == NULL) { print_symbol_table(getFirstChild(node), file_ptr); } else { if (getLine(getFirstChild(node)) == -1) { continue; } else { print_symbol_table(getFirstChild(node), file_ptr); } } } } if (getParent(table) == NULL) { printline(file_ptr, true); } } // 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; } // Prints all info about a table node // Uses pointers to the table node to print the info TableNode *printTableNode(TableNode *tn) { if (DEBUG == 0) { return tn; } if (tn == NULL) { printdebug("%s[PrintTN] Passed a NULL tablenode!", COLOR_RED); return undefined; } if (tn == undefined) { printdebug("%s[PrintTN] Passed an undefined tablenode!", COLOR_RED); return undefined; } if (tn->theName == NULL) { printdebug("%s[PrintTN] Passed a tablenode with NULL name!", COLOR_RED); return undefined; } if (tn->theType == NULL) { printdebug("%s[PrintTN] Passed a tablenode with NULL type!", COLOR_RED); return undefined; } if (tn->additionalinfo == NULL) { printdebug( "%s[PrintTN] Passed a tablenode with NULL additional info!", COLOR_RED); return undefined; } printdebug("%s[PrintTN] Printing tablenode...", COLOR_ORANGE); printdebug(" %sName: %s%s", COLOR_YELLOW, COLOR_LIGHTBLUE, tn->theName); printdebug(" %sType: %s%s", COLOR_YELLOW, COLOR_LIGHTBLUE, tn->theType->theName); printdebug(" %sTag: %s%d", COLOR_YELLOW, COLOR_LIGHTBLUE, tn->tag); if (tn->next == NULL) { printdebug(" %sNext: %sNULL", COLOR_YELLOW, COLOR_LIGHTBLUE); } else { printdebug(" %sNext: %s%s (tn)", COLOR_YELLOW, COLOR_LIGHTBLUE, tn->next->theName); } if (tn->tag == TYPE_RECORD_TYPE || tn->tag == TYPE_RECORD) { printdebug(" %sAdditional Info: %sRecAdInfo", COLOR_YELLOW, COLOR_LIGHTBLUE); printdebug(" %snumberOfElements: %s%d", COLOR_YELLOW, COLOR_LIGHTBLUE, tn->additionalinfo->RecAdInfo->numofelements); if (tn->additionalinfo->RecAdInfo->recordScope == NULL) { printdebug(" %srecordScope (line): %s(NULL)", COLOR_YELLOW, COLOR_LIGHTBLUE); } else { printdebug(" %srecordScope (line): %s%d", COLOR_YELLOW, COLOR_LIGHTBLUE, tn->additionalinfo->RecAdInfo->recordScope ->Line_Number); } } else if (tn->tag == TYPE_ARRAY_TYPE || tn->tag == TYPE_ARRAY) { printdebug(" %sAdditional Info: %sArrayAdInfo", COLOR_YELLOW, COLOR_LIGHTBLUE); printdebug(" %snumberOfDimensions: %s%d", COLOR_YELLOW, COLOR_LIGHTBLUE, tn->additionalinfo->ArrayAdInfo->numofdimensions); printdebug( " %stypeOfArray: %s%s", COLOR_YELLOW, COLOR_LIGHTBLUE, tn->additionalinfo->ArrayAdInfo->typeofarray->theName); } else if (tn->tag == TYPE_FUNCTION_TYPE) { printdebug(" %sAdditional Info: %sFunTypeAdInfo", COLOR_YELLOW, COLOR_LIGHTBLUE); printdebug( " %sparameter: %s%s", COLOR_YELLOW, COLOR_LIGHTBLUE, tn->additionalinfo->FunTypeAdInfo->parameter->theName); printdebug( " %sreturntype: %s%s", COLOR_YELLOW, COLOR_LIGHTBLUE, tn->additionalinfo->FunTypeAdInfo->returntype->theName); } else if (tn->tag == TYPE_FUNCTION_DECLARATION) { printdebug(" %sAdditional Info: %sFunDecAdInfo", COLOR_YELLOW, COLOR_LIGHTBLUE); printdebug(" %sstartLineNumber: %s%d", COLOR_YELLOW, COLOR_LIGHTBLUE, tn->additionalinfo->FunDecAdInfo->startlinenumber); printdebug(" %sregularOrAs: %s%s", COLOR_YELLOW, COLOR_LIGHTBLUE, tn->additionalinfo->FunDecAdInfo->regularoras ? "true" : "false"); } else if (tn->tag == TYPE_PRIMITIVE) { printdebug(" %sAdditional Info: %sPrimAdInfo", COLOR_YELLOW, COLOR_LIGHTBLUE); printdebug(" %ssize: %s%d", COLOR_YELLOW, COLOR_LIGHTBLUE, tn->additionalinfo->PrimAdInfo->size); } else { printdebug(" AdInfo not handled."); } return tn; }