358 lines
		
	
	
	
		
			6.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			358 lines
		
	
	
	
		
			6.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* $Id$ */
 | |
| 
 | |
| /* 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"
 | |
| #include	"misc.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 *strrchr();
 | |
| 
 | |
| 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 = strrchr(s, '.');
 | |
|   if (p) {
 | |
| 	char c = *p;
 | |
| 	p_symbol sym1;
 | |
| 
 | |
| 	*p = 0;
 | |
| 	s = Salloc(s, (unsigned) strlen(s)+1);
 | |
| 	*p = c;
 | |
| 	sym1 = NewSymbol(s,
 | |
| 		  	 PervasiveScope,
 | |
| 		 	 FILELINK,
 | |
| 			 (struct outname *) 0);
 | |
| 	sym1->sy_filelink = sym;
 | |
| 	sym->sy_file->f_base = sym1;
 | |
|   }
 | |
|   return sym;
 | |
| }
 | |
| 
 | |
| static 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'.
 | |
| */
 | |
| 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|LBOUND|UBOUND)
 | |
| 	sym = Lookfromscope(p->t_idf, CLASS, sc->sc_static_encl);
 | |
| 	if (sym) {
 | |
| 		int precise = 1;
 | |
| 
 | |
| 		target_sc = def_scope(sym);
 | |
| 		while (sc && sc != target_sc) {
 | |
| 			precise = 0;
 | |
| 			sc = sc->sc_static_encl;
 | |
| 		}
 | |
| 		return sc == 0 ? 0 : precise + 1 ;
 | |
| 	}
 | |
| 	return 0;
 | |
| 
 | |
|   case OP_SELECT:
 | |
| 	arg = p->t_args[1];
 | |
| 	sym = Lookfromscope(arg->t_idf, CLASS, sc->sc_static_encl);
 | |
| 	if (sym) {
 | |
| 		int precise = 1;
 | |
| 
 | |
| 		target_sc = def_scope(sym);
 | |
| 		while (sc && sc != target_sc) {
 | |
| 			precise = 0;
 | |
| 			sc = sc->sc_static_encl;
 | |
| 		}
 | |
| 		if (sc == 0) return 0;
 | |
| 		if (precise) return consistent(p, sym->sy_scope);
 | |
| 		return consistent(p, sym->sy_scope) != 0;
 | |
| 	}
 | |
| 	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, sym1 = 0;
 | |
|   register p_symbol s;
 | |
|   p_tree	arg;
 | |
|   int precise = 0;
 | |
| 
 | |
|   switch(p->t_oper) {
 | |
|   case OP_NAME:
 | |
| 	sym = Lookfromscope(p->t_idf, class_set, CurrentScope);
 | |
| 	if (sym) {
 | |
| 		/* Found it. */
 | |
| 		break;
 | |
| 	}
 | |
| 
 | |
| 	/* We could not find it using the current scope; 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;
 | |
| 	while (s) {
 | |
| 		int temp;
 | |
| 		if ((s->sy_class & class_set) &&
 | |
| 		    (temp = consistent(p, s->sy_scope))) {
 | |
| 			if (temp > precise) {
 | |
| 				sym = s;
 | |
| 				precise = temp;
 | |
| 				sym1 = 0;
 | |
| 			}
 | |
| 			else if (sym && temp == precise) sym1 = s;
 | |
| 		}
 | |
| 		s = s->sy_next;
 | |
| 	}
 | |
| 	if (sym && sym1) {
 | |
| 		error("could not identify \"%s\"", arg->t_str);
 | |
| 		return 0;
 | |
| 	}
 | |
| 	if (!sym && !s) {
 | |
| 		error("could not find \"%s\"", arg->t_str);
 | |
| 		return 0;
 | |
| 	}
 | |
| 	break;
 | |
| 
 | |
|   default:
 | |
| 	assert(0);
 | |
|   }
 | |
|   return sym;
 | |
| }
 | |
| 
 | |
| static
 | |
| pr_scopes(sc)
 | |
|   p_scope	sc;
 | |
| {
 | |
|   if (! sc) return;
 | |
|   pr_scopes(sc->sc_static_encl);
 | |
|   if (sc->sc_definedby) {
 | |
|   	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);
 | |
|   }
 | |
| }
 | |
| 
 | |
| 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:
 | |
|   case LBOUND:
 | |
|   case UBOUND:
 | |
| 	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);
 | |
| }
 | |
| 
 | |
| resolve_cross(tp)
 | |
|   p_type	tp;
 | |
| {
 | |
|   register p_symbol	sym = tp->ty_sym->sy_idf->id_def;
 | |
| 
 | |
|   while (sym) {
 | |
| 	if (sym->sy_class == TAG &&
 | |
| 	    sym->sy_type->ty_class == T_CROSS &&
 | |
| 	    sym->sy_type->ty_cross == (p_type) 0 &&
 | |
| 	    sym->sy_type->ty_size == tp->ty_class &&
 | |
| 	    scope_encloses(tp->ty_sym->sy_scope, sym->sy_scope)) {
 | |
| 		sym->sy_type->ty_cross = tp;
 | |
| 		sym->sy_type->ty_size = tp->ty_size;
 | |
| 	}
 | |
| 	sym = sym->sy_next;
 | |
|   }
 | |
| }
 |