ack/util/grind/symbol.c
1990-09-21 16:58:20 +00:00

368 lines
6.3 KiB
C

/* $Header$ */
/* Symbol handling */
#include <stdio.h>
#include <alloc.h>
#include <out.h>
#include <stb.h>
#include <assert.h>
#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);
}