void patch_symbol_table(ast_node root, symhashtable_t *symtable){ symhashtable_t *hashtable; symnode_t *snode = NULL; switch(root->node_type){ case ID_N: hashtable = find_hashtable(symtable, root->curr_level, root->curr_sib); if(hashtable != NULL){ //snode = lookup_symhashtable(hashtable, root->value_string, NOHASHSLOT); assert(hashtable != NULL); assert(snode == NULL); for(;hashtable != NULL && snode == NULL; hashtable = hashtable->parent) { snode = lookup_symhashtable(hashtable, root->value_string, NOHASHSLOT); } if(snode != NULL){ if(snode->type == VAR_ARRAY_INT_T && root->left_child == NULL){ root->return_type = ARRAY_TYPE_N; // root->node_type = ARRAY_TYPE_N; // change in the future } } break; case ARRAY_TYPE_N: hashtable = find_hashtable(symtable, root->curr_level, root->curr_sib); if(hashtable != NULL){ snode = lookup_symhashtable(hashtable, root->value_string, NOHASHSLOT); if(snode != NULL){ if(snode->type == VAR_INT_T){ snode->type = VAR_ARRAY_INT_T; } } } break; default: break; } } ast_node child; for(child = root->left_child; child != NULL; child = child->right_sibling){ patch_symbol_table(child, symtable); } }
/* * lookup_in_symboltable * * Lookup an entry in a symbol table. If found return a pointer to it. * Otherwise, return NULL */ symnode_t *lookup_in_symboltable(symboltable_t *symtab, char *name, var_type vType) { symnode_t *node; symhashtable_t *hashtable; assert(symtab); int base_len = strlen(name); // Account for potential prefix and null termination char *typed_name = calloc(1, sizeof(char) * (base_len + 3)); switch(vType) { case TEMP_VT : sprintf(typed_name, "%s%s", temp_prefix, name); break; case CONST_VT : sprintf(typed_name, "%s%s", constant_prefix, name); break; default : free(typed_name); typed_name = name; } for (node = NULL, hashtable = symtab->leaf; (node == NULL) && (hashtable != NULL); hashtable = hashtable->parent) { node = lookup_symhashtable(hashtable, typed_name, NOHASHSLOT); } return node; }
/* * Function to check if a particular variable or function identifier * has been redefined. */ int check_if_redef(ast_node anode, symboltable_t *symtab ,int lvl, int sibno) { symhashtable_t *hash = find_hashtable(symtab->root, lvl, sibno); /* If scope with (lvl, sibno) identifier could be found, start search */ if(hash != NULL) { /* node = NULL in case we don't find anything */ symnode_t *node = NULL; node = lookup_symhashtable(hash, anode->value_string, NOHASHSLOT); /* Found a match in current or parent scope? */ if(node != NULL){ /* If abstract syntax node has a type, it was previously defined */ if(anode->return_type != ROOT_N && anode->isDecl == 1) { symtabError = 1; if(anode->node_type == FUNC_DECLARATION_N) { fprintf(stderr, "line: %d | error: redefinition of function %s\n", anode->line_num ,anode->value_string); } if(anode->node_type == ID_N || anode->node_type == ARRAY_TYPE_N) { fprintf(stderr, "line: %d | error: redefinition of identifier %s\n", anode->line_num ,anode->value_string); } return 0; } } } /* Not found */ return 1; }
/* * instert_into_symboltable * * Insert an entry into the innermost scope of symbol table. First * make sure it's not already in that scope. Return a pointer to the * entry. */ symnode_t *insert_into_symboltable(symboltable_t *symtab, var_lookup_type type, char *name, int lineno) { assert(symtab); assert(symtab->leaf); symnode_t *node = lookup_symhashtable(symtab->leaf, name, NOHASHSLOT); /* error check!! */ if (node == NULL) { node = insert_into_symhashtable(symtab->leaf, type, name, lineno, LOCAL_VT); return node; } else { return NULL; } }
symnode_t *insert_temp(symboltable_t *symtab, var_lookup_type type, char *name, int lineno) { assert(symtab); assert(symtab->leaf); int name_len = strlen(name); char *typed_name = calloc(1, sizeof(char) * (name_len + 3)); sprintf(typed_name, "%s%s", temp_prefix, name); symnode_t *node = lookup_symhashtable(symtab->leaf, typed_name, NOHASHSLOT); if (node == NULL) { node = insert_into_symhashtable(symtab->root, type, typed_name, lineno, TEMP_VT); return node; } else { return NULL; } }
/* Insert a new entry into a symhashtable, but only if it is not already present. */ symnode_t *insert_into_symhashtable(symhashtable_t *hashtable, var_lookup_type type, char *name, int lineno, var_type vType) { assert(hashtable); int slot = hashPJW(name, hashtable->size); symnode_t *node = lookup_symhashtable(hashtable, name, slot); /* error check if node already existed! */ if (node == NULL) { node = create_symnode(name, type, hashtable, lineno); node->vType = vType; node->next = hashtable->table[slot]; hashtable->table[slot] = node; } return node; }
/* Insert an entry into the innermost scope of symbol table. First make sure it's not already in that scope. Return a pointer to the entry. */ symnode_t *insert_into_symboltable(symboltable_t *symtab, ast_node astnode) { char *name = astnode->value_string; assert(symtab); assert(symtab->leaf); symnode_t *node = lookup_symhashtable(symtab->leaf, name, NOHASHSLOT); /* error check!! */ if (node == NULL) { node = insert_into_symhashtable(symtab->leaf, astnode); return node; } else { return NULL; } }
/* * Checks if a particular variable has already been declared. */ int check_if_declared(ast_node anode, symboltable_t *symtab ,int lvl, int sibno) { symhashtable_t *hash = find_hashtable(symtab->root, lvl, sibno); assert(hash != NULL); assert(anode != NULL); /* Set node to NULL so that, if no match is found, it will be NULL and we can * act accordingly. */ symnode_t *node = NULL; /* * Recurse up until hash table with matching identifier, or the root, is found. */ for(;hash != NULL && node == NULL; hash = hash->parent) { node = lookup_symhashtable(hash, anode->value_string, NOHASHSLOT); } /* If not found, variable or function is undeclared. */ if(node == NULL) { symtabError = 1; if(anode->node_type == FUNCTION_N) { fprintf(stderr, "line: %d | error: use of undeclared function %s\n", anode->line_num, anode->value_string); } else if(anode->node_type == ID_N || anode->node_type == ARRAY_TYPE_N) { fprintf(stderr, "line: %d | error: use of undeclared identifier %s\n", anode->line_num, anode->value_string); } return 0; } else { /* Otherwise, declaration for variable or function has been found */ return 1; } }
/* Looks up a node in a symhashtable without knowing the hashslot */ symnode_t *lookup_in_symhashtable(symhashtable_t *hashtable, char *name) { return lookup_symhashtable(hashtable, name, NOHASHSLOT); }
void link_ast_to_symnode(ast_node root, symboltable_t *symtab) { symhashtable_t *hash = NULL; symnode_t *snode = NULL; /* Depending on node types, go deeper, create sibling scopes, add to hashtable, * or take other appropriate action. */ switch (root->node_type) { case SEQ_N: // change main level when see a new sequence break; case FORMAL_PARAMS_N: break; case FUNC_DECLARATION_N: // function declaraions break; case FUNCTION_N: hash = find_hashtable(symtab->root, root->curr_level, root->curr_sib); assert(hash != NULL); for(;hash != NULL && snode == NULL; hash = hash->parent) { snode = lookup_symhashtable(hash, root->value_string, NOHASHSLOT); } assert(snode != NULL); root->snode = snode; break; case ID_N: /* print the id */ hash = find_hashtable(symtab->root, root->curr_level, root->curr_sib); assert(hash != NULL); for(;hash != NULL && snode == NULL; hash = hash->parent) { snode = lookup_symhashtable(hash, root->value_string, NOHASHSLOT); } assert(snode != NULL); root->snode = snode; break; case ARRAY_TYPE_N: // check for return types! hash = find_hashtable(symtab->root, root->curr_level, root->curr_sib); assert(hash != NULL); for(;hash != NULL && snode == NULL; hash = hash->parent) { snode = lookup_symhashtable(hash, root->value_string, NOHASHSLOT); } assert(snode != NULL); root->snode = snode; break; case INT_LITERAL_N: hash = symtab->literal_collection; assert(hash != NULL); assert(root->value_string != NULL); snode = lookup_symhashtable(hash, root->value_string, NOHASHSLOT); root->snode = snode; break; case STRING_LITERAL_N: hash = symtab->literal_collection; assert(hash != NULL); assert(root->value_string != NULL); snode = lookup_symhashtable(hash, root->value_string, NOHASHSLOT); root->snode = snode; break; case RETURN_N: hash = symtab->literal_collection; assert(hash != NULL); if(root->left_child->node_type == VOID_TYPE_N){ snode = lookup_symhashtable(hash, root->left_child->value_string, NOHASHSLOT); root->left_child->snode = snode; } break; default: break; } /* Recurse on each child of the subtree root */ ast_node child; for (child = root->left_child; child != NULL; child = child->right_sibling) link_ast_to_symnode(child, symtab); }
void collect_literals(ast_node root, symboltable_t *symtab){ ast_node child; symnode_t *node; symhashtable_t *collection = symtab->literal_collection; assert(collection != NULL); char* name; int slot = 0; /* Recursively call the function to traverse the tree in a preorder way */ for(child = root->left_child; child != NULL; child = child->right_sibling){ collect_literals(child, symtab); } switch (root->node_type) { case STRING_LITERAL_N: name = root->value_string; // Calculate slot for this node, try to find the current node in the symbol table slot = hashPJW(name, collection->size); node = lookup_symhashtable(collection, name, slot); if(node == NULL){ insert_into_symhashtable(collection, root); } break; /* Need to hash the value differently so as to not to mistake strings and ints, (e.g. 1 vs "1") */ case INT_LITERAL_N: name = calloc(DEFAULTSTRSIZE, sizeof(char)); sprintf(name, "__%d", root->value_int); root->value_string = strdup(name); slot = hashPJW(name, collection->size); node = lookup_symhashtable(collection, name, slot); if(node == NULL){ insert_into_symhashtable(collection, root); } break; case RETURN_N: // Empty return. Create a new symnode to add to // the collection because otherwise it will give us // trouble later when trying to create quads, since // the function to create quads takes symnodes and there // is currently no symnode for this empty return. if(root->left_child != NULL){ if(root->left_child->node_type == VOID_TYPE_N){ name = calloc(DEFAULTSTRSIZE, sizeof(char)); sprintf(name, "__%s", "void"); root->left_child->value_string = calloc(DEFAULTSTRSIZE, sizeof(char)); strcpy(root->left_child->value_string, name); slot = hashPJW(name, collection->size); node = lookup_symhashtable(collection, name, slot); if(node == NULL){ insert_into_symhashtable(collection, root->left_child); } } } default: break; } }
/*declaration of func and identifiers is already checked during build_symbol_table * so here, we just check for paramter inputs into functions */ int check_function(ast_node root, symboltable_t *symtab) { symhashtable_t *hash = NULL; symnode_t *node = NULL; ast_node anode = NULL; switch (root->node_type) { case FUNCTION_N: hash = find_hashtable(symtab->root, root->curr_level, root->curr_sib); for(;hash != NULL && node == NULL; hash = hash->parent) { node = lookup_symhashtable(hash, root->value_string, NOHASHSLOT); //node is the original declaration stored in symbol table } assert(node != NULL); //as hashtable was built previously, it must be found for func_n // Count the number of parameters passed to the function int i = 0; for(anode = root->left_child; anode != NULL; anode = anode->right_sibling) { i++; } if(node->num_parameters != i) { funcError = 1; fprintf(stderr, "line: %d | Error: Number of parameters to function %s does not match number of parameters in declaration at line %d\n", root->line_num, root->value_string, root->line_declared); } else { int k = 0; for(anode = root->left_child; anode != NULL; anode = anode->right_sibling) { if(!((anode->return_type == INT_TYPE_N && node->parameters[k] == VAR_INT_T) || (anode->return_type == ARRAY_TYPE_N && node->parameters[k] == VAR_ARRAY_INT_T)) ) { // if(!(anode->return_type == INT_TYPE_N && node->parameters[k] == VAR_INT_T)) { funcError = 1; //printf("\n\n parm type is: %s return_type is: %s \n\n", TYPE_NAME(node->parameters[k]), NODE_NAME(anode->return_type)); // fprintf(stderr, "\n\n %s return_type: %s but should be %s \n\n",anode->value_string ,NODE_NAME(anode->return_type), TYPE_NAME(node->parameters[k])); assert(anode != NULL); //assert(anode->snode //assert(anode->snode); fprintf(stderr, "%dth param. Expecting %s, got (%s, %s)\n", k, TYPE_NAME(node->parameters[k]), NODE_NAME(anode->return_type), NODE_NAME(anode->node_type)); //fprintf(stderr, "snode of ^ is %s ", anode->snode->name); fprintf(stderr, "line: %d | Error: Input parameters to function %s do not match the declaration at line %d\n", root->line_num, root->value_string, root->line_declared); return 1; } k++; } } break; default: // printf("at default of switch\n"); assert(symtab->root != NULL); break; } /* Recurse on each child of the subtree root, with a depth one greater than the root's depth. */ ast_node child; for (child = root->left_child; child != NULL; child = child->right_sibling) check_function(child, symtab); return 0; }
/* * Works on an assumption that build hashtable as already been run. (i.e. no errors generated from building hashtable) */ void record_var_type_in_ast(ast_node root, symboltable_t *symtab) { symhashtable_t *hash = NULL; symnode_t *node = NULL; /* Depending on node types, go deeper, create sibling scopes, add to hashtable, * or take other appropriate action. */ switch (root->node_type) { case FUNC_DECLARATION_N: hash = find_hashtable(symtab->root, root->curr_level, root->curr_sib); for(;hash != NULL && node == NULL; hash = hash->parent) { node = lookup_symhashtable(hash, root->value_string, NOHASHSLOT); } assert(node != NULL); //as hashtable was built prev, it must be found for func_n if(node->type == FUNC_VOID_T) { root->return_type = VOID_TYPE_N; } else if(node->type == FUNC_INT_T) { root->return_type = INT_TYPE_N; } root->line_declared = node->abnode->line_num; break; case FUNCTION_N: //all function_n nodes are calls not declarations hash = find_hashtable(symtab->root, root->curr_level, root->curr_sib); for(;hash != NULL && node == NULL; hash = hash->parent) { node = lookup_symhashtable(hash, root->value_string, NOHASHSLOT); } assert(node != NULL); //as hashtable was built prev, it must be found for func_n if(node->type == FUNC_VOID_T) { root->return_type = VOID_TYPE_N; } else if(node->type == FUNC_INT_T) { root->return_type = INT_TYPE_N; } root->line_declared = node->abnode->line_num; break; case ID_N: hash = find_hashtable(symtab->root, root->curr_level, root->curr_sib); assert(hash != NULL); for(;hash != NULL && node == NULL; hash = hash->parent) { //printf(" \n\n value string is %s\n\n", root->value_string); node = lookup_symhashtable(hash, root->value_string, NOHASHSLOT); } assert(node != NULL); //as hashtable was built prev, it must be found for ID_N if(root->return_type == 0) { // a zero value means that it is not a declaration, since only declarations // are assigned a return type when building the abstract syntax tree. if(node->type == VAR_INT_T) { root->return_type = INT_TYPE_N; } } root->line_declared = node->abnode->line_num; break; case ARRAY_TYPE_N: // check for return types! hash = find_hashtable(symtab->root, root->curr_level, root->curr_sib); for(;hash != NULL && node == NULL; hash = hash->parent) { node = lookup_symhashtable(hash, root->value_string, NOHASHSLOT); } assert(node != NULL); //as hashtable was built prev, it must be found for array_type_n if(root->return_type == 0) { if(node->type == VAR_ARRAY_INT_T){ if(root->left_child == NULL){ root->return_type = ARRAY_TYPE_N; } else{ root->return_type = INT_TYPE_N; } } } root->line_declared = node->abnode->line_num; break; case INT_LITERAL_N: root->return_type = INT_TYPE_N; break; case RETURN_N: //not sure if we deal with this here... assert(symtab->root != NULL); break; default: // printf("at default of switch\n"); assert(symtab->root != NULL); break; } /* Recurse on each child of the subtree root, with a depth one */ ast_node child; for (child = root->left_child; child != NULL; child = child->right_sibling) record_var_type_in_ast(child, symtab); }
/* Insert a new entry into a symhashtable, but only if it is not already present. Return*/ symnode_t *insert_into_symhashtable(symhashtable_t *hashtable, ast_node astnode) { char* name = astnode->value_string; assert(hashtable); int slot = hashPJW(name, hashtable->size); symnode_t *node = lookup_symhashtable(hashtable, name, slot); /* error check if node already existed! */ if (node == NULL) { node = create_symnode(name, hashtable); node->abnode = astnode; astnode->snode = node; if(astnode->node_type == INT_LITERAL_N){ node->num_val = astnode->value_int; } if(astnode->node_type == ARRAY_TYPE_N) { if(astnode->left_child != NULL ){ astnode->array_length = astnode->left_child->value_int; node->array_length = astnode->array_length; } } if(astnode->node_type == STRING_LITERAL_N){ node->type = STRING_T; } if(astnode->node_type == FUNC_DECLARATION_N) { //printf("FUNC_DEC detected!"); if(astnode->return_type == INT_TYPE_N) { node->type = FUNC_INT_T; //printf(" %s\n", TYPE_NAME(node->type)); } else if(astnode->return_type == VOID_TYPE_N) { node->type = FUNC_VOID_T; //printf(" %s\n", TYPE_NAME(node->type)); } ast_node anode; int i = 0; assert(astnode->left_child != NULL); for(anode = astnode->left_child->left_child; anode != NULL; anode = anode->right_sibling) { i++; } node->num_parameters = i; node->parameters = calloc(sizeof(decl_type), i); assert(node->parameters); i = 0; for(anode = astnode->left_child->left_child; anode != NULL; anode = anode->right_sibling) { if(anode->return_type == INT_TYPE_N) { node->parameters[i] = VAR_INT_T; } else if(anode->return_type == ARRAY_TYPE_N){ node->parameters[i] = VAR_ARRAY_INT_T; } i++; } } else if(astnode->node_type == ID_N) { //printf("VAR detected!"); if(astnode->return_type == INT_TYPE_N) { node->type = VAR_INT_T; //printf(" %s\n", TYPE_NAME(node->type)); } } else if(astnode->node_type == ARRAY_TYPE_N){ if(astnode->return_type == INT_TYPE_N) { node->type = VAR_ARRAY_INT_T; //printf(" %s\n", TYPE_NAME(node->type)); } } node->next = hashtable->table[slot]; hashtable->table[slot] = node; } else{ if(node->abnode->node_type == ARRAY_TYPE_N || node->abnode->return_type == ARRAY_TYPE_N) { node->abnode->array_length = node->array_length; } } return node; }