/* $Header$ */ /* Symbol handling */ #include #include #include #include #include #include "position.h" #include "file.h" #include "idf.h" #include "type.h" #include "symbol.h" #include "scope.h" #include "tree.h" #include "operator.h" p_symbol currfile, listfile; extern FILE *db_out; p_symbol NewSymbol(s, scope, class, nam) char *s; register p_scope scope; struct outname *nam; { register p_symbol sym; sym = new_symbol(); sym->sy_idf = str2idf(s, 0); sym->sy_scope = scope; sym->sy_prev_sc = scope->sc_symbs; scope->sc_symbs = sym; sym->sy_next = sym->sy_idf->id_def; sym->sy_idf->id_def = sym; sym->sy_class = class; switch(class) { case MODULE: case PROC: case FUNCTION: case VAR: case REGVAR: case LOCVAR: case VARPAR: sym->sy_name.nm_value = nam->on_valu; break; default: break; } return sym; } /* Lookup a definition for 'id' in scope 'scope' with class in the 'class' bitset. */ p_symbol Lookup(id, scope, class) struct idf *id; p_scope scope; int class; { register p_symbol p = id ? id->id_def : 0; while (p) { if (p->sy_scope == scope && (p->sy_class & class)) { return p; } p = p->sy_next; } return (p_symbol) 0; } /* Lookup a definition for 'id' with class in the 'class' bitset, starting in scope 'sc' and also looking in enclosing scopes. */ p_symbol Lookfromscope(id, class, sc) register struct idf *id; int class; register p_scope sc; { if (! id) return (p_symbol) 0; while (sc) { register p_symbol sym = id->id_def; while (sym) { if (sym->sy_scope == sc && (sym->sy_class & class)) { return sym; } sym = sym->sy_next; } sc = sc->sc_static_encl; } return (p_symbol) 0; } extern char *strrindex(); p_symbol add_file(s) char *s; { register p_symbol sym = NewSymbol(s, PervasiveScope, FILESYM, (struct outname *) 0); register char *p; sym->sy_file = new_file(); sym->sy_file->f_sym = sym; p = strrindex(s, '.'); if (p) { char c = *p; p_symbol sym1; *p = 0; sym1 = NewSymbol(Salloc(s, (unsigned) strlen(s)+1), PervasiveScope, FILELINK, (struct outname *) 0); *p = c; sym1->sy_filelink = sym; sym->sy_file->f_base = sym1; } return sym; } p_scope def_scope(s) p_symbol s; { switch(s->sy_class) { case FILELINK: s = s->sy_filelink; /* fall through */ case FILESYM: return s->sy_file->f_scope; case PROC: case FUNCTION: case MODULE: case TYPE: case VAR: case REGVAR: case LOCVAR: case VARPAR: return s->sy_name.nm_scope; } return 0; } /* Determine if the OP_SELECT tree indicated by 'p' could lead to scope 'sc'. */ static int consistent(p, sc) p_tree p; p_scope sc; { p_tree arg; p_symbol sym; p_scope target_sc; assert(p->t_oper == OP_SELECT); p = p->t_args[0]; switch(p->t_oper) { case OP_NAME: #define CLASS (FILELINK|FILESYM|PROC|FUNCTION|MODULE|TYPE|VAR|REGVAR|LOCVAR|VARPAR) sym = Lookfromscope(p->t_idf, CLASS, sc->sc_static_encl); if (sym) { target_sc = def_scope(sym); while (sc && sc != target_sc) { sc = sc->sc_static_encl; } return sc != 0; } return 0; case OP_SELECT: arg = p->t_args[1]; sym = Lookfromscope(arg->t_idf, CLASS, sc->sc_static_encl); if (sym) { target_sc = def_scope(sym); while (sc && sc != target_sc) { sc = sc->sc_static_encl; } return sc != 0 && consistent(p, sym->sy_scope); } return 0; default: assert(0); } return 0; /* notreached? */ } /* Try to find the name referred to in the node indicated by 'p', and try to be just a little bit intelligent about it. */ p_symbol identify(p, class_set) p_tree p; int class_set; { p_symbol sym = 0; register p_symbol s; p_tree arg; switch(p->t_oper) { case OP_NAME: if (! p->t_sc) p->t_sc = CurrentScope; sym = Lookfromscope(p->t_idf, class_set, p->t_sc); if (sym) { /* Found it. */ break; } /* We could not find it using scope p->t_sc; now we try to identify it using class_set. If this results in only one definition, we take this one. */ s = p->t_idf->id_def; while (s) { if (s->sy_class & class_set) { if (sym) { error("could not identify \"%s\"", p->t_str); sym = 0; break; } sym = s; } s = s->sy_next; } if (!sym && !s) { error("could not find \"%s\"", p->t_str); } break; case OP_SELECT: arg = p->t_args[1]; assert(arg->t_oper == OP_NAME); s = arg->t_idf->id_def; sym = 0; while (s) { if ((s->sy_class & class_set) && consistent(p, s->sy_scope)) { if (sym) { error("could not identify \"%s\"", arg->t_str); sym = 0; } sym = s; } s = s->sy_next; } if (!sym && !s) { error("could not find \"%s\"", arg->t_str); } break; default: assert(0); } return sym; } static pr_scopes(sc) p_scope sc; { while (sc && ! sc->sc_definedby) { sc = sc->sc_static_encl; } if (sc) { pr_scopes(sc->sc_static_encl); if (sc->sc_definedby->sy_class == FILESYM && sc->sc_definedby->sy_file->f_base) { fprintf(db_out, "%s`", sc->sc_definedby->sy_file->f_base->sy_idf->id_text); } else fprintf(db_out, "%s`", sc->sc_definedby->sy_idf->id_text); } } static pr_sym(s) p_symbol s; { switch(s->sy_class) { case CONST: fprintf(db_out, "Constant:\t"); break; case TYPE: fprintf(db_out, "Type:\t\t"); break; case TAG: fprintf(db_out, "Tag:\t\t"); break; case MODULE: fprintf(db_out, "Module:\t\t"); break; case PROC: case FUNCTION: fprintf(db_out, "Routine:\t"); break; case VAR: case REGVAR: case LOCVAR: case VARPAR: fprintf(db_out, "Variable:\t"); break; case FIELD: fprintf(db_out, "Field:\t\t"); break; case FILESYM: case FILELINK: fprintf(db_out, "File:\t\t"); break; default: assert(0); } pr_scopes(s->sy_scope); fprintf(db_out, "%s\n", s->sy_idf->id_text); } /* Print all identifications of p->t_args[0]. */ do_find(p) p_tree p; { register p_symbol s; p_tree arg; p = p->t_args[0]; switch(p->t_oper) { case OP_NAME: s = p->t_idf->id_def; while (s) { pr_sym(s); s = s->sy_next; } break; case OP_SELECT: arg = p->t_args[1]; assert(arg->t_oper == OP_NAME); s = arg->t_idf->id_def; while (s) { if (consistent(p, s->sy_scope)) { pr_sym(s); } s = s->sy_next; } break; default: assert(0); } } do_which(p) p_tree p; { p_symbol sym = identify(p->t_args[0], 0xffff); if ( sym) pr_sym(sym); }