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); } }
/* * 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; }
/* * This function creates a hashtable and then appropriately attaches it to its parent, * whose identifier is given to us in the form of its identifier (parent_lvl, parent_sibno) */ symhashtable_t *make_insert_hashtable(symhashtable_t *root, int lvl, int sibno, int parent_lvl, int parent_sibno) { symhashtable_t *hashtable, *parent_hashtable, *temp; hashtable = create_symhashtable(HASHSIZE); assert(hashtable != NULL); parent_hashtable = find_hashtable(root, parent_lvl, parent_sibno); //parent must have been created assert(parent_hashtable != NULL); // Fill the appropriate values for our hash table. hashtable->parent = parent_hashtable; hashtable->level = lvl; hashtable->sibno = sibno; //insert as rightmost child of parent if(parent_hashtable->child != NULL) { for(temp = parent_hashtable->child ; temp->rightsib != NULL; temp = temp->rightsib) { ;} temp->rightsib = hashtable; } else { parent_hashtable->child = hashtable; } return hashtable; }
/* Lookup a hashtable with given lvl and sibno in a symbol table. If found return a pointer to it. Otherwise, return NULL */ symhashtable_t *find_hashtable(symhashtable_t *root, int lvl, int sib) { if(root != NULL) { if (lvl == root->level && sib == root->sibno) { return(root); } } symhashtable_t *res, *child; res = NULL; for(child = root->child; child != NULL && res == NULL; child = child->rightsib) { //if(child != NULL) {printf("in find) lvl: %d, sibno: %d\n", child->level,child->sibno);} res = find_hashtable(child, lvl, sib); } return res; }
char const * strget(char const *s) { poolelem e, *ep; if (strpool == NULL) strpool = new_hashtable(&poolinfo); e.str = s; if (!find_hashtable(strpool, (hashelt *)&e)) insert_hashtable(strpool, (hashelt *)&e); ep = (poolelem *)cur_hashtable(strpool); ep->ref++; return ep->str; }
void strdrop(char const *s) { poolelem e, *ep; if (strpool == NULL) return; e.str = s; if (!find_hashtable(strpool, &e)) return; ep = (poolelem *)cur_hashtable(strpool); if (--ep->ref <= 0) remove_hashtable(strpool, ep); }
/* * Tests to see if the given directory has already been visited. */ static int already_visited(char *mandir, char *dir, int count_visit) { struct stat st; if (stat(dir, &st) < 0) { if (mandir != NULL) warn("%s/%s", mandir, dir); else warn("%s", dir); exit_code = 1; return 1; } if (find_hashtable(visited, st.st_ino, st.st_dev) != NULL) { if (mandir != NULL) warnx("already visited %s/%s", mandir, dir); else warnx("already visited %s", dir); return 1; } if (count_visit) insert_hashtable(visited, st.st_ino, st.st_dev, ""); return 0; }
/* * 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; } }
/* * Processes a single man page source by using nroff to create * the preformatted cat page. */ static void process_page(char *mandir, char *src, char *cat, enum Ziptype zipped) { int src_test, cat_test; time_t src_mtime, cat_mtime; char cmd[MAXPATHLEN]; dev_t src_dev; ino_t src_ino; const char *link_name; src_test = test_path(src, &src_mtime); if (!(src_test & (TEST_FILE|TEST_READABLE))) { if (!(src_test & TEST_DIR)) { warnx("%s/%s: unreadable", mandir, src); exit_code = 1; if (rm_junk && is_symlink(src)) junk(mandir, src, "bogus symlink"); } return; } src_dev = test_st.st_dev; src_ino = test_st.st_ino; cat_test = test_path(cat, &cat_mtime); if (cat_test & (TEST_FILE|TEST_READABLE)) { if (!force && cat_mtime >= src_mtime) { if (verbose) { fprintf(stderr, "\t%s/%s: up to date\n", mandir, src); } return; } } /* * Is the man page a link to one we've already processed? */ if ((link_name = find_hashtable(links, src_ino, src_dev)) != NULL) { if (verbose || pretend) { fprintf(stderr, "%slink %s -> %s\n", verbose ? "\t" : "", cat, link_name); } if (!pretend) link(link_name, cat); return; } insert_hashtable(links, src_ino, src_dev, strdup(cat)); if (verbose || pretend) { fprintf(stderr, "%sformat %s -> %s\n", verbose ? "\t" : "", src, cat); if (pretend) return; } snprintf(tmp_file, sizeof tmp_file, "%s.tmp", cat); snprintf(cmd, sizeof cmd, "%scat %s | tbl | nroff -c -T%s -man | %s > %s.tmp", zipped == BZIP ? BZ2CAT_CMD : zipped == GZIP ? GZCAT_CMD : "", src, nroff_device, zipped == BZIP ? BZ2_CMD : zipped == GZIP ? GZ_CMD : "cat", cat); if (system(cmd) != 0) err(1, "formatting pipeline"); if (rename(tmp_file, cat) < 0) warn("%s", cat); tmp_file[0] = '\0'; }
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); }
/*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); }
/* * Builds the symbol table, creating scopes as needed, and linking them together. * Adds variable and function identifiers to scopes appropriately. */ void build_symbol_table(ast_node root, int level, int sibno, symboltable_t *symtab) { //calculate the scope for the variable/func declaration //calculate the parent for that variable/func declaration //need function to take as input //printf("here \n"); symhashtable_t *hash; /* Depending on node types, go deeper, create sibling scopes, add to hashtable, * or take other appropriate action. */ switch (root->node_type) { ast_node param; int param_offset = 4; int param_count = 0; case SEQ_N: // change main level when see a new sequence level++; break; case FORMAL_PARAMS_N: level++; param_count = 0; insert_scope_info(root, level, sibno, MAX(level - 1, 0), getSibling(level) ); // for(param = root->left_child; param != NULL; param = param->right_sibling){ // if(param->node_type == ARRAY_TYPE_N || param->return_type == ARRAY_TYPE_N){ // param_count += DEFAULT_ARRAY_PARAM_SIZE; // } // else{ // param_count++; // } // } // printf("PARAM COUNT!!!!! = %d\n", param_count); // // for(param = root->left_child; param != NULL; param = param->right_sibling){ // if(param->node_type == ARRAY_TYPE_N || param->return_type == ARRAY_TYPE_N){ // param->snode->offset = param_count * 4; // param->snode->offset -= DEFAULT_ARRAY_PARAM_SIZE; // } // else{ // param->snode->offset = param_count-- * 4; // } // } break; case FUNC_DECLARATION_N: // function declaraions //does hashtable exist with given lvl, siblvl (use find_hashtable) check_if_redef(root, symtab ,level, sibno); hash = find_hashtable(symtab->root, level, sibno); if(hash == NULL) { hash = make_insert_hashtable(symtab->root, level, sibno, MAX(level - 1, 0), getSibling(level) ); } insert_into_symhashtable(hash, root); // will only insert if it is empty. insert_scope_info(root, level, sibno, MAX(level - 1, 0), getSibling(level) ); break; case FUNCTION_N: check_if_declared(root, symtab ,level, sibno); insert_scope_info(root, level, sibno, MAX(level - 1, 0), getSibling(level) ); break; case ID_N: /* print the id */ check_if_redef(root, symtab ,level, sibno); //if(root->return_type != 0) { // a non-zero value means that it is a declaration, since only declarations // are assigned a return type when building the abstract syntax tree. if(root->isDecl){ hash = find_hashtable(symtab->root, level, sibno); if(hash == NULL) { hash = make_insert_hashtable(symtab->root, level, sibno, MAX(level - 1, 0), getSibling(level) ); } insert_into_symhashtable(hash, root); } else { // don't know if previously declared check_if_declared(root, symtab , level, sibno); } insert_scope_info(root, level, sibno, MAX(level - 1, 0), getSibling(level) ); break; case ARRAY_TYPE_N: // check for return types! check_if_redef(root, symtab ,level, sibno); //cif(root->return_type != 0) { if(root->isDecl){ hash = find_hashtable(symtab->root, level, sibno); if(hash == NULL) { hash = make_insert_hashtable(symtab->root, level, sibno, MAX(level - 1, 0), getSibling(level) ); } insert_into_symhashtable(hash, root); } else { check_if_declared(root, symtab , level, sibno); } insert_scope_info(root, level, sibno, MAX(level - 1, 0), getSibling(level) ); break; case RETURN_N: insert_scope_info(root, level, sibno, MAX(level - 1, 0), getSibling(level) ); break; default: // printf("at default of switch\n"); assert(symtab->root != NULL); hash = find_hashtable(symtab->root, level, sibno); if(hash == NULL) { hash = make_insert_hashtable(symtab->root, level, sibno, MAX(level - 1, 0), getSibling(level) ); } //note: cannot use insert_scope_info here because siblings[level - 1] causes invalid read as level-1 can go negative break; } if(arraylen == level) { arraylen = arraylen + DELTA; siblings = realloc(siblings, sizeof(int) * arraylen); assert(siblings != NULL); for(int k=0; k < DELTA; k++) { siblings[arraylen - (DELTA-k)] = 0; } } /* 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) build_symbol_table(child, level, siblings[level], symtab); if(root->node_type == SEQ_N){//} || root->node_type == FORMAL_PARAMS_N){ siblings[level]++; // change sibling level after you're done printing all // subtrees, i.e., after done recursing. } }