void vari_def (void) { firstentry = symtab_nextentry; match (VAR); { symtab_add (lexeme); } match (ID); while (lookahead == ',') { match (','); { symtab_add (lexeme); } match (ID); } match (':'); vartype (); match (';'); while (lookahead == ID) { match (ID); while (lookahead == ',') { match (','); match (ID); } match (':'); vartype (); match (';'); } }
void check_declr(SymTab *st, Declr* d) { switch(d->tag) { case DECLR_VAR: { if(st->prev) check_array_sizes(d->type); else check_array_empty(d->type); if(!symtab_add(st, d)) print_error("double declaration of variable", d->line); break; } case DECLR_FUNC: { check_array_empty(d->type); if(d->u.func.block) { Declr *proto; SymTab *param; proto = symtab_find(st, d->u.func.name); if(!proto) { symtab_add(st, d); proto = d; } else if(proto->u.func.block) { print_error("double declaration of function", d->line); } else { proto->u.func.block = d->u.func.block; } return_type = d->type; param = symtab_new(st); check_paramlist(param, proto->u.func.params, d->line); check_block(param, proto->u.func.block); symtab_free(param); } else { if(!symtab_add(st, d)) print_error("double declaration of function prototype", d->line); } break; } default: print_error("bug in compiler!", 0); } }
void varspecs(void) { /**/ int initial, final /**/; while (lookahead == VAR) { match(VAR); do { /**/ initial = symtab_nextentry /**/; /**/ final = symtab_add(lexeme) /**/; match(ID); while (lookahead == ',') { match(','); /**/ final = symtab_add(lexeme) /**/; match(ID); } match(':'); typespec(VARIABLE, initial, final); match(';'); } while (lookahead == ID);
bool ffi_get_decl(typecheck_t* t, ast_t* ast, ast_t** out_decl, pass_opt_t* opt) { pony_assert(t != NULL); pony_assert(ast != NULL); pony_assert(out_decl != NULL); const char* ffi_name = ast_name(ast_child(ast)); // Get the symbol table for our containing ifdef (if any) directly. We can't // just search up through scopes as normal since FFI declarations in outer // scopes may not be valid within our ifdef. ast_t* ifdef = t->frame->ifdef_clause; pony_assert(ifdef != NULL); symtab_t* symtab = ast_get_symtab(ifdef); sym_status_t status; ast_t* decl = symtab_find(symtab, ffi_name, &status); if(status == SYM_ERROR) // We've already found an error with that FFI name in this context. return false; if(status == SYM_NONE) { // We've not looked that up yet. pony_assert(decl == NULL); if(!find_ffi_decl(ast, t->frame->package, t->frame->ifdef_cond, &decl, opt)) { // That went wrong. Record that so we don't try again. symtab_add(symtab, ffi_name, NULL, SYM_ERROR); return false; } // Store declaration found for next time, including if we found nothing. symtab_add(symtab, ffi_name, decl, SYM_FFIDECL); } *out_decl = decl; return true; }
void check_paramlist(SymTab *st, DeclrListNode* pln, int line) { while(pln) { if(pln->declr == NULL) { if(pln->next != NULL) print_error("... must be the last parameter of a function", line); break; } else { check_array_empty(pln->declr->type); if(!symtab_add(st, pln->declr)) print_error("parameter declared twice", line); pln = pln->next; } } }
// Add a sub-tree name definition static bool add_subtree_name(build_parser_t* builder, const char* name, ast_t* subtree) { assert(builder != NULL); assert(builder->defs != NULL); if(!symtab_add(builder->defs, name, subtree, SYM_NONE)) { build_error(builder, "Multiple {def %s} attributes", name); return false; } return true; }
bool symtab_merge_public(symtab_t* dst, symtab_t* src) { size_t i = HASHMAP_BEGIN; symbol_t* sym; while((sym = symtab_next(src, &i)) != NULL) { if((sym->name[0] == '_') || (sym->status == SYM_NOCASE)) continue; if(!symtab_add(dst, sym->name, sym->value, sym->status)) return false; } return true; }
bool symtab_merge_public(symtab_t* dst, symtab_t* src) { size_t i = HASHMAP_BEGIN; symbol_t* sym; while((sym = symtab_next(src, &i)) != NULL) { if(is_name_private(sym->name) || (sym->status == SYM_NOCASE) || !strcmp(sym->name, "Main")) continue; if(!symtab_add(dst, sym->name, sym->def, sym->status)) return false; } return true; }
// Add the given method to the relevant name list in the given symbol table static bool add_method_to_list(ast_t* method, methods_t* method_info, const char *entity_name) { assert(method != NULL); assert(method_info != NULL); assert(entity_name != NULL); const char* name = ast_name(ast_childidx(method, 1)); assert(name != NULL); symtab_t* symtab = method_info->symtab; assert(symtab != NULL); // Entity doesn't yet have method, add it to our list for later ast_t* list = (ast_t*)symtab_find(symtab, name, NULL); if(list == NULL) { ast_t* case_clash = (ast_t*)symtab_find_case(symtab, name, NULL); if(case_clash != NULL) { ast_error(case_clash, "in %s method name differs only in case", entity_name); ast_error(method, "previous definition is here"); return false; } // First instance of this name list = ast_blank(TK_ID); ast_set_name(list, name); symtab_add(symtab, name, (void*)list, SYM_NONE); if(method_info->last_list == NULL) ast_add(method_info->name_lists, list); else ast_add_sibling(method_info->last_list, list); method_info->last_list = list; } ast_add(list, method); return true; }
bool ast_set(ast_t* ast, const char* name, ast_t* value, sym_status_t status, bool allow_shadowing) { while(ast->symtab == NULL) ast = ast->parent; if(allow_shadowing) { // Only check the local scope. if(symtab_find_case(ast->symtab, name, NULL) != NULL) return false; } else { // Check the local scope and all parent scopes. if(ast_get_case(ast, name, NULL) != NULL) return false; } return symtab_add(ast->symtab, name, value, status); }
// Process all our sub-tree references static bool process_refs(build_parser_t* builder) { assert(builder != NULL); assert(builder->defs != NULL); for(builder_ref_t* p = builder->refs; p != NULL; p = p->next) { assert(p->name != NULL); assert(p->node != NULL); ast_t* subtree = (ast_t*)symtab_find(builder->defs, p->name, NULL); if(subtree == NULL) { build_error(builder, "Attribute {def %s} not found", p->name); return false; } if(p->symtab == NULL) { // Set node data ast_setdata(p->node, subtree); } else { // Add subtree to node's symtab symtab_t* symtab = ast_get_symtab(p->node); assert(symtab != NULL); if(!symtab_add(symtab, p->symtab, subtree, SYM_NONE)) { build_error(builder, "Duplicate name %s in symbol table", p->name); return false; } } } return true; }
/* * XXX: btrie插入操作有其特殊性 * 对rule匹配规则而言,它是松散的,count表示了str[]的总项数,valids表示有效的str项,end_index * 则表示最后一个有效str项的索引值,end_index可能大于valids。 * 对host匹配规则而言,它是连续的,count依然表示str[]的总项数,但由于是连续,end_index总是等于 * valids-1。 * valids用于指导分配btrie_node,end_index则用于最后的检查工作。 */ btrie_node_t *btrie_insert(btrie_ctx_t *ctx, btrie_node_t **ptr_root, unsigned long count, string_t str[], unsigned long valids, int end_index) { int node_cnt = 0, node_used = 0; btrie_node_t *new_node_array, *node, *wildcard; int i, found = 0; btrie_node_t **proot, *root, *ret = NULL; btrie_node_t **pcurr, *curr; /* 注意: 用于算法内部临时查找,而非当前处理节点 */ if (ctx == NULL || ptr_root == NULL || count == 0 || str == NULL || valids > count || valids == 0) { return NULL; } if (end_index < 0 || end_index >= count) { return NULL; } node_cnt = valids * 2; /* 预留通配符节点,节点分配数量翻倍 */ /* 注意: new_node_array必须是连续分配的,且严格的从头开始连续使用,以便连续释放空闲的 */ new_node_array = btrie_node_alloc(ctx, node_cnt); if (new_node_array == NULL) { NOTICE(); return NULL; } proot = ptr_root; /* 存放root的位置,方便修改root的值 */ root = *proot; for (i = 0; i < count; i++) { if (str[i].len == 0) { continue; } if (str[i].len == BTRIE_NO_VALUE_MAGIC_LEN) { /* 对str是no val型,恢复其正确值0。 */ str[i].len = 0; } again: if (node_used >= node_cnt) { /* BUG: 使用量已经超过分配的数量 */ BUG(); return NULL; } if (root == NULL) { node = &new_node_array[node_used]; node->index = i; if (str[i].len == BTRIE_WILDCARD_MAGIC_LEN) { node->flags = BTRIE_FLAG_WILDCARD; } else { if ((str[i].len > 0) && (symtab_add(ctx->symtab, &str[i], &node->str) != 0)) { goto err_out; } } node_used++; *proot = node; ret = node; proot = &node->child; root = node->child; } else if (root->index == i) { for (pcurr = proot, curr = root; (curr != NULL) && (curr->flags != BTRIE_FLAG_WILDCARD); pcurr = &curr->sibling, curr = curr->sibling) { if (string_is_equal(&curr->str, &str[i])) { found = 1; break; } } if (found) { found = 0; proot = &curr->child; root = curr->child; ret = curr; continue; } if (str[i].len == BTRIE_WILDCARD_MAGIC_LEN) { if (curr == NULL) { /* 通配符节点不存在,首先创建通配符节点 */ node = &new_node_array[node_used]; node->index = i; node->flags = BTRIE_FLAG_WILDCARD; node_used++; /* 然后将通配符节点加入树中 */ node->sibling = curr; *pcurr = node; curr = node; } proot = &curr->child; root = curr->child; ret = curr; continue; } else { node = &new_node_array[node_used]; node->index = i; if ((str[i].len > 0) && (symtab_add(ctx->symtab, &str[i], &node->str) != 0)) { goto err_out; } node_used++; node->sibling = curr; *pcurr = node; proot = &node->child; root = node->child; ret = node; continue; } } else if (root->index > i) { /* root节点等级比待加入节点低 */ if (str[i].len == BTRIE_WILDCARD_MAGIC_LEN) { /* XXX: 目前只有host涉及到通配符,其不可能进入本分支 */ BUG(); goto err_out; } node = &new_node_array[node_used]; node->index = i; if ((str[i].len > 0) && (symtab_add(ctx->symtab, &str[i], &node->str) != 0)) { goto err_out; } node_used++; wildcard = &new_node_array[node_used++]; wildcard->flags = BTRIE_FLAG_WILDCARD; wildcard->index = i; node->sibling = wildcard; wildcard->child = root; *proot = node; ret = node; proot = &node->child; root = node->child; } else { /* root节点等级比待加入节点高 root->index < i */ if (str[i].len == BTRIE_WILDCARD_MAGIC_LEN) { /* XXX: 目前只有host涉及到通配符,其不可能进入本分支 */ BUG(); goto err_out; } for (pcurr = proot, curr = root; (curr != NULL) && (curr->flags != BTRIE_FLAG_WILDCARD); pcurr = &curr->sibling, curr = curr->sibling) { (void)0; } if (curr == NULL) { wildcard = &new_node_array[node_used++]; wildcard->flags = BTRIE_FLAG_WILDCARD; wildcard->index = root->index; *pcurr = wildcard; curr = wildcard; } proot = &curr->child; root = curr->child; goto again; } } /* 对ret的有效性做检查 */ if ((ret != NULL) && (ret->index != end_index)) { /* BUG: 竟然有ret,但还未到末尾的节点 */ BUG(); goto err_out; } /* XXX: 如果添加相同的RULE或者HOST,则ret中data不为NULL,认定为出错 */ if ((ret != NULL) && (ret->data != NULL)) { NOTICE(); goto err_out; } /* 释放未使用的mnode */ btrie_node_free(ctx, (node_cnt - node_used)); return ret; err_out: /* 释放掉还未加入查找树中的节点,已加入的就不删除了 */ btrie_node_free(ctx, (node_cnt - node_used)); return NULL; }
void fold_expr_funcall(expr *e, symtable *stab) { decl *df; funcargs *args_exp; if(expr_kind(e->expr, identifier) && e->expr->spel){ char *const sp = e->expr->spel; e->sym = symtab_search(stab, sp); if(!e->sym){ df = decl_new_where(&e->where); df->type->primitive = type_int; df->type->spec |= spec_extern; cc1_warn_at(&e->where, 0, WARN_IMPLICIT_FUNC, "implicit declaration of function \"%s\"", sp); df->spel = sp; df->funcargs = funcargs_new(); if(e->funcargs) /* set up the funcargs as if it's "x()" - i.e. any args */ function_empty_args(df->funcargs); e->sym = symtab_add(symtab_root(stab), df, sym_global, SYMTAB_WITH_SYM, SYMTAB_PREPEND); }else{ df = e->sym->decl; } fold_expr(e->expr, stab); }else{ fold_expr(e->expr, stab); /* * convert int (*)() to remove the deref */ if(decl_is_func_ptr(e->expr->tree_type)){ /* XXX: memleak */ e->expr = e->expr->lhs; fprintf(stderr, "FUNCPTR\n"); }else{ fprintf(stderr, "decl %s\n", decl_to_str(e->expr->tree_type)); } df = e->expr->tree_type; if(!decl_is_callable(df)){ die_at(&e->expr->where, "expression %s (%s) not callable", e->expr->f_str(), decl_to_str(df)); } } e->tree_type = decl_copy(df); /* * int (*x)(); * (*x)(); * evaluates to tree_type = int; */ decl_func_deref(e->tree_type); if(e->funcargs){ expr **iter; for(iter = e->funcargs; *iter; iter++) fold_expr(*iter, stab); } /* func count comparison, only if the func has arg-decls, or the func is f(void) */ args_exp = decl_funcargs(e->tree_type); UCC_ASSERT(args_exp, "no funcargs for decl %s", df->spel); if(args_exp->arglist || args_exp->args_void){ expr **iter_arg; decl **iter_decl; int count_decl, count_arg; count_decl = count_arg = 0; for(iter_arg = e->funcargs; iter_arg && *iter_arg; iter_arg++, count_arg++); for(iter_decl = args_exp->arglist; iter_decl && *iter_decl; iter_decl++, count_decl++); if(count_decl != count_arg && (args_exp->variadic ? count_arg < count_decl : 1)){ die_at(&e->where, "too %s arguments to function %s (got %d, need %d)", count_arg > count_decl ? "many" : "few", df->spel, count_arg, count_decl); } if(e->funcargs){ funcargs *argument_decls = funcargs_new(); for(iter_arg = e->funcargs; *iter_arg; iter_arg++) dynarray_add((void ***)&argument_decls->arglist, (*iter_arg)->tree_type); fold_funcargs_equal(args_exp, argument_decls, 1, &e->where, "argument", df->spel); funcargs_free(argument_decls, 0); } } }
/* * processmodule() * * step through each segment, determine what exactly we're doing with * it, and if we intend to keep it, determine (a) which segment to * put it in and (b) whereabouts in that segment it will end up. * (b) is fairly easy, because we're now keeping track of how big each * segment in our output file is... */ void processmodule(const char *filename, struct modulenode *mod) { struct segconfig sconf; int seg, outseg; void *header; rdfheaderrec *hr; long bssamount = 0; int bss_was_referenced = 0; for (seg = 0; seg < mod->f.nsegs; seg++) { /* * get the segment configuration for this type from the segment * table. getsegconfig() is a macro, defined in ldsegs.h. */ getsegconfig(sconf, mod->f.seg[seg].type); if (options.verbose > 1) { printf("%s %04x [%04x:%10s] ", filename, mod->f.seg[seg].number, mod->f.seg[seg].type, sconf.typedesc); } /* * sconf->dowhat tells us what to do with a segment of this type. */ switch (sconf.dowhat) { case SEG_IGNORE: /* * Set destination segment to -1, to indicate that this segment * should be ignored for the purpose of output, ie it is left * out of the linked executable. */ mod->seginfo[seg].dest_seg = -1; if (options.verbose > 1) printf("IGNORED\n"); break; case SEG_NEWSEG: /* * The configuration tells us to create a new segment for * each occurrence of this segment type. */ outseg = allocnewseg(sconf.mergetype, mod->f.seg[seg].reserved); mod->seginfo[seg].dest_seg = outseg; mod->seginfo[seg].reloc = 0; outputseg[outseg].length = mod->f.seg[seg].length; if (options.verbose > 1) printf("=> %04x:%08lx (+%04lx)\n", outseg, mod->seginfo[seg].reloc, mod->f.seg[seg].length); break; case SEG_MERGE: /* * The configuration tells us to merge the segment with * a previously existing segment of type 'sconf.mergetype', * if one exists. Otherwise a new segment is created. * This is handled transparently by 'findsegment()'. */ outseg = findsegment(sconf.mergetype, mod->f.seg[seg].reserved); mod->seginfo[seg].dest_seg = outseg; /* * We need to add alignment to these segments. */ if (outputseg[outseg].length % options.align != 0) outputseg[outseg].length += options.align - (outputseg[outseg].length % options.align); mod->seginfo[seg].reloc = outputseg[outseg].length; outputseg[outseg].length += mod->f.seg[seg].length; if (options.verbose > 1) printf("=> %04x:%08lx (+%04lx)\n", outseg, mod->seginfo[seg].reloc, mod->f.seg[seg].length); } } /* * extract symbols from the header, and dump them into the * symbol table */ header = malloc(mod->f.header_len); if (!header) { fprintf(stderr, "ldrdf: not enough memory\n"); exit(1); } if (rdfloadseg(&mod->f, RDOFF_HEADER, header)) { rdfperror("ldrdf", filename); exit(1); } while ((hr = rdfgetheaderrec(&mod->f))) { switch (hr->type) { case RDFREC_IMPORT: /* imported symbol */ case RDFREC_FARIMPORT: /* Define with seg = -1 */ symtab_add(hr->i.label, -1, 0); break; case RDFREC_GLOBAL:{ /* exported symbol */ int destseg; long destreloc; if (hr->e.segment == 2) { bss_was_referenced = 1; destreloc = bss_length; if (destreloc % options.align != 0) destreloc += options.align - (destreloc % options.align); destseg = 2; } else { if ((destseg = mod->seginfo[(int)hr->e.segment].dest_seg) == -1) continue; destreloc = mod->seginfo[(int)hr->e.segment].reloc; } symtab_add(hr->e.label, destseg, destreloc + hr->e.offset); break; } case RDFREC_BSS: /* BSS reservation */ /* * first, amalgamate all BSS reservations in this module * into one, because we allow this in the output format. */ bssamount += hr->b.amount; break; case RDFREC_COMMON:{ /* Common variable */ symtabEnt *ste = symtabFind(symtab, hr->c.label); /* Is the symbol already in the table? */ if (ste) break; /* Align the variable */ if (bss_length % hr->c.align != 0) bss_length += hr->c.align - (bss_length % hr->c.align); if (options.verbose > 1) { printf("%s %04x common '%s' => 0002:%08lx (+%04lx)\n", filename, hr->c.segment, hr->c.label, bss_length, hr->c.size); } symtab_add(hr->c.label, 2, bss_length); mod->bss_reloc = bss_length; bss_length += hr->c.size; break; } } } if (bssamount != 0 || bss_was_referenced) { /* * handle the BSS segment - first pad the existing bss length * to the correct alignment, then store the length in bss_reloc * for this module. Then add this module's BSS length onto * bss_length. */ if (bss_length % options.align != 0) bss_length += options.align - (bss_length % options.align); mod->bss_reloc = bss_length; if (options.verbose > 1) { printf("%s 0002 [ BSS] => 0002:%08lx (+%04lx)\n", filename, bss_length, bssamount); } bss_length += bssamount; } #ifdef STINGY_MEMORY /* * we free the header buffer here, to save memory later. * this isn't efficient, but probably halves the memory usage * of this program... */ mod->f.header_loc = NULL; free(header); #endif }