xref: /csrg-svn/old/dbx/symbols.c (revision 12127)
19657Slinton /* Copyright (c) 1982 Regents of the University of California */
29657Slinton 
3*12127Slinton static char sccsid[] = "@(#)symbols.c 1.7 04/29/83";
49657Slinton 
59657Slinton /*
69657Slinton  * Symbol management.
79657Slinton  */
89657Slinton 
99657Slinton #include "defs.h"
109657Slinton #include "symbols.h"
119657Slinton #include "languages.h"
129657Slinton #include "printsym.h"
139657Slinton #include "tree.h"
149657Slinton #include "operators.h"
159657Slinton #include "eval.h"
169657Slinton #include "mappings.h"
179657Slinton #include "events.h"
189657Slinton #include "process.h"
199657Slinton #include "runtime.h"
209657Slinton #include "machine.h"
219657Slinton #include "names.h"
229657Slinton 
239657Slinton #ifndef public
249657Slinton typedef struct Symbol *Symbol;
259657Slinton 
269657Slinton #include "machine.h"
279657Slinton #include "names.h"
289657Slinton #include "languages.h"
299657Slinton 
309657Slinton /*
319657Slinton  * Symbol classes
329657Slinton  */
339657Slinton 
349657Slinton typedef enum {
359657Slinton     BADUSE, CONST, TYPE, VAR, ARRAY, PTRFILE, RECORD, FIELD,
369657Slinton     PROC, FUNC, FVAR, REF, PTR, FILET, SET, RANGE,
379657Slinton     LABEL, WITHPTR, SCAL, STR, PROG, IMPROPER, VARNT,
389657Slinton     FPROC, FFUNC, MODULE, TYPEREF, TAG
399657Slinton } Symclass;
409657Slinton 
419657Slinton struct Symbol {
429657Slinton     Name name;
439657Slinton     Language language;
449657Slinton     Symclass class : 8;
459657Slinton     Integer level : 8;
469657Slinton     Symbol type;
479657Slinton     Symbol chain;
489657Slinton     union {
499657Slinton 	int offset;		/* variable address */
509657Slinton 	long iconval;		/* integer constant value */
519657Slinton 	double fconval;		/* floating constant value */
529657Slinton 	struct {		/* field offset and size (both in bits) */
539657Slinton 	    int offset;
549657Slinton 	    int length;
559657Slinton 	} field;
569657Slinton 	struct {		/* range bounds */
579657Slinton 	    long lower;
589657Slinton 	    long upper;
599657Slinton 	} rangev;
6011865Slinton 	struct {
6111865Slinton 	    int offset : 16;	/* offset for of function value */
6211865Slinton 	    Boolean src : 16;	/* true if there is source line info */
6311865Slinton 	    Address beginaddr;	/* address of function code */
649657Slinton 	} funcv;
659657Slinton 	struct {		/* variant record info */
669657Slinton 	    int size;
679657Slinton 	    Symbol vtorec;
689657Slinton 	    Symbol vtag;
699657Slinton 	} varnt;
709657Slinton     } symvalue;
719657Slinton     Symbol block;		/* symbol containing this symbol */
729657Slinton     Symbol next_sym;		/* hash chain */
739657Slinton };
749657Slinton 
759657Slinton /*
769657Slinton  * Basic types.
779657Slinton  */
789657Slinton 
799657Slinton Symbol t_boolean;
809657Slinton Symbol t_char;
819657Slinton Symbol t_int;
829657Slinton Symbol t_real;
839657Slinton Symbol t_nil;
849657Slinton 
859657Slinton Symbol program;
869657Slinton Symbol curfunc;
879657Slinton 
889657Slinton #define symname(s) ident(s->name)
899657Slinton #define codeloc(f) ((f)->symvalue.funcv.beginaddr)
909657Slinton #define isblock(s) (Boolean) ( \
919657Slinton     s->class == FUNC or s->class == PROC or \
929657Slinton     s->class == MODULE or s->class == PROG \
939657Slinton )
949657Slinton 
9511865Slinton #define nosource(f) (not (f)->symvalue.funcv.src)
9611865Slinton 
979657Slinton #include "tree.h"
989657Slinton 
999657Slinton /*
1009657Slinton  * Some macros to make finding a symbol with certain attributes.
1019657Slinton  */
1029657Slinton 
1039657Slinton #define find(s, withname) \
1049657Slinton { \
1059657Slinton     s = lookup(withname); \
1069657Slinton     while (s != nil and not (s->name == (withname) and
1079657Slinton 
1089657Slinton #define where /* qualification */
1099657Slinton 
1109657Slinton #define endfind(s) )) { \
1119657Slinton 	s = s->next_sym; \
1129657Slinton     } \
1139657Slinton }
1149657Slinton 
1159657Slinton #endif
1169657Slinton 
1179657Slinton /*
1189657Slinton  * Symbol table structure currently does not support deletions.
1199657Slinton  */
1209657Slinton 
1219657Slinton #define HASHTABLESIZE 2003
1229657Slinton 
1239657Slinton private Symbol hashtab[HASHTABLESIZE];
1249657Slinton 
1259657Slinton #define hash(name) ((((unsigned) name) >> 2) mod HASHTABLESIZE)
1269657Slinton 
1279657Slinton /*
1289657Slinton  * Allocate a new symbol.
1299657Slinton  */
1309657Slinton 
13111171Slinton #define SYMBLOCKSIZE 100
1329657Slinton 
1339657Slinton typedef struct Sympool {
1349657Slinton     struct Symbol sym[SYMBLOCKSIZE];
1359657Slinton     struct Sympool *prevpool;
1369657Slinton } *Sympool;
1379657Slinton 
1389657Slinton private Sympool sympool = nil;
1399657Slinton private Integer nleft = 0;
1409657Slinton 
1419657Slinton public Symbol symbol_alloc()
1429657Slinton {
1439657Slinton     register Sympool newpool;
1449657Slinton 
1459657Slinton     if (nleft <= 0) {
1469657Slinton 	newpool = new(Sympool);
14711171Slinton 	bzero(newpool, sizeof(newpool));
1489657Slinton 	newpool->prevpool = sympool;
1499657Slinton 	sympool = newpool;
1509657Slinton 	nleft = SYMBLOCKSIZE;
1519657Slinton     }
1529657Slinton     --nleft;
1539657Slinton     return &(sympool->sym[nleft]);
1549657Slinton }
1559657Slinton 
1569657Slinton /*
1579657Slinton  * Free all the symbols currently allocated.
1589657Slinton  */
1599657Slinton 
1609657Slinton public symbol_free()
1619657Slinton {
1629657Slinton     Sympool s, t;
1639657Slinton     register Integer i;
1649657Slinton 
1659657Slinton     s = sympool;
1669657Slinton     while (s != nil) {
1679657Slinton 	t = s->prevpool;
1689657Slinton 	dispose(s);
1699657Slinton 	s = t;
1709657Slinton     }
1719657Slinton     for (i = 0; i < HASHTABLESIZE; i++) {
1729657Slinton 	hashtab[i] = nil;
1739657Slinton     }
1749657Slinton     sympool = nil;
1759657Slinton     nleft = 0;
1769657Slinton }
1779657Slinton 
1789657Slinton /*
1799657Slinton  * Create a new symbol with the given attributes.
1809657Slinton  */
1819657Slinton 
1829657Slinton public Symbol newSymbol(name, blevel, class, type, chain)
1839657Slinton Name name;
1849657Slinton Integer blevel;
1859657Slinton Symclass class;
1869657Slinton Symbol type;
1879657Slinton Symbol chain;
1889657Slinton {
1899657Slinton     register Symbol s;
1909657Slinton 
1919657Slinton     s = symbol_alloc();
1929657Slinton     s->name = name;
1939657Slinton     s->level = blevel;
1949657Slinton     s->class = class;
1959657Slinton     s->type = type;
1969657Slinton     s->chain = chain;
1979657Slinton     return s;
1989657Slinton }
1999657Slinton 
2009657Slinton /*
2019657Slinton  * Insert a symbol into the hash table.
2029657Slinton  */
2039657Slinton 
2049657Slinton public Symbol insert(name)
2059657Slinton Name name;
2069657Slinton {
2079657Slinton     register Symbol s;
2089657Slinton     register unsigned int h;
2099657Slinton 
2109657Slinton     h = hash(name);
2119657Slinton     s = symbol_alloc();
2129657Slinton     s->name = name;
2139657Slinton     s->next_sym = hashtab[h];
2149657Slinton     hashtab[h] = s;
2159657Slinton     return s;
2169657Slinton }
2179657Slinton 
2189657Slinton /*
2199657Slinton  * Symbol lookup.
2209657Slinton  */
2219657Slinton 
2229657Slinton public Symbol lookup(name)
2239657Slinton Name name;
2249657Slinton {
2259657Slinton     register Symbol s;
2269657Slinton     register unsigned int h;
2279657Slinton 
2289657Slinton     h = hash(name);
2299657Slinton     s = hashtab[h];
2309657Slinton     while (s != nil and s->name != name) {
2319657Slinton 	s = s->next_sym;
2329657Slinton     }
2339657Slinton     return s;
2349657Slinton }
2359657Slinton 
2369657Slinton /*
2379657Slinton  * Dump out all the variables associated with the given
2389657Slinton  * procedure, function, or program at the given recursive level.
2399657Slinton  *
2409657Slinton  * This is quite inefficient.  We traverse the entire symbol table
2419657Slinton  * each time we're called.  The assumption is that this routine
2429657Slinton  * won't be called frequently enough to merit improved performance.
2439657Slinton  */
2449657Slinton 
2459657Slinton public dumpvars(f, frame)
2469657Slinton Symbol f;
2479657Slinton Frame frame;
2489657Slinton {
2499657Slinton     register Integer i;
2509657Slinton     register Symbol s;
2519657Slinton 
2529657Slinton     for (i = 0; i < HASHTABLESIZE; i++) {
2539657Slinton 	for (s = hashtab[i]; s != nil; s = s->next_sym) {
2549657Slinton 	    if (container(s) == f) {
2559657Slinton 		if (should_print(s)) {
2569657Slinton 		    printv(s, frame);
2579657Slinton 		    putchar('\n');
2589657Slinton 		} else if (s->class == MODULE) {
2599657Slinton 		    dumpvars(s, frame);
2609657Slinton 		}
2619657Slinton 	    }
2629657Slinton 	}
2639657Slinton     }
2649657Slinton }
2659657Slinton 
2669657Slinton /*
2679657Slinton  * Create a builtin type.
2689657Slinton  * Builtin types are circular in that btype->type->type = btype.
2699657Slinton  */
2709657Slinton 
2719657Slinton public Symbol maketype(name, lower, upper)
2729657Slinton String name;
2739657Slinton long lower;
2749657Slinton long upper;
2759657Slinton {
2769657Slinton     register Symbol s;
2779657Slinton 
2789657Slinton     s = newSymbol(identname(name, true), 0, TYPE, nil, nil);
2799657Slinton     s->language = findlanguage(".c");
2809657Slinton     s->type = newSymbol(nil, 0, RANGE, s, nil);
2819657Slinton     s->type->symvalue.rangev.lower = lower;
2829657Slinton     s->type->symvalue.rangev.upper = upper;
2839657Slinton     return s;
2849657Slinton }
2859657Slinton 
2869657Slinton /*
2879657Slinton  * These functions are now compiled inline.
2889657Slinton  *
2899657Slinton  * public String symname(s)
2909657Slinton Symbol s;
2919657Slinton {
2929657Slinton     checkref(s);
2939657Slinton     return ident(s->name);
2949657Slinton }
2959657Slinton 
2969657Slinton  *
2979657Slinton  * public Address codeloc(f)
2989657Slinton Symbol f;
2999657Slinton {
3009657Slinton     checkref(f);
3019657Slinton     if (not isblock(f)) {
3029657Slinton 	panic("codeloc: \"%s\" is not a block", ident(f->name));
3039657Slinton     }
3049657Slinton     return f->symvalue.funcv.beginaddr;
3059657Slinton }
3069657Slinton  *
3079657Slinton  */
3089657Slinton 
3099657Slinton /*
3109657Slinton  * Reduce type to avoid worrying about type names.
3119657Slinton  */
3129657Slinton 
3139657Slinton public Symbol rtype(type)
3149657Slinton Symbol type;
3159657Slinton {
3169657Slinton     register Symbol t;
3179657Slinton 
3189657Slinton     t = type;
3199657Slinton     if (t != nil) {
3209657Slinton 	if (t->class == VAR or t->class == FIELD) {
3219657Slinton 	    t = t->type;
3229657Slinton 	}
3239657Slinton 	while (t->class == TYPE or t->class == TAG) {
3249657Slinton 	    t = t->type;
3259657Slinton 	}
3269657Slinton     }
3279657Slinton     return t;
3289657Slinton }
3299657Slinton 
3309657Slinton public Integer level(s)
3319657Slinton Symbol s;
3329657Slinton {
3339657Slinton     checkref(s);
3349657Slinton     return s->level;
3359657Slinton }
3369657Slinton 
3379657Slinton public Symbol container(s)
3389657Slinton Symbol s;
3399657Slinton {
3409657Slinton     checkref(s);
3419657Slinton     return s->block;
3429657Slinton }
3439657Slinton 
3449657Slinton /*
3459657Slinton  * Return the object address of the given symbol.
3469657Slinton  *
3479657Slinton  * There are the following possibilities:
3489657Slinton  *
3499657Slinton  *	globals		- just take offset
3509657Slinton  *	locals		- take offset from locals base
3519657Slinton  *	arguments	- take offset from argument base
3529657Slinton  *	register	- offset is register number
3539657Slinton  */
3549657Slinton 
3559657Slinton #define isglobal(s)		(s->level == 1 or s->level == 2)
3569657Slinton #define islocaloff(s)		(s->level >= 3 and s->symvalue.offset < 0)
3579657Slinton #define isparamoff(s)		(s->level >= 3 and s->symvalue.offset >= 0)
3589657Slinton #define isreg(s)		(s->level < 0)
3599657Slinton 
3609657Slinton public Address address(s, frame)
3619657Slinton Symbol s;
3629657Slinton Frame frame;
3639657Slinton {
3649657Slinton     register Frame frp;
3659657Slinton     register Address addr;
3669657Slinton     register Symbol cur;
3679657Slinton 
3689657Slinton     checkref(s);
3699657Slinton     if (not isactive(s->block)) {
3709657Slinton 	error("\"%s\" is not currently defined", symname(s));
3719657Slinton     } else if (isglobal(s)) {
3729657Slinton 	addr = s->symvalue.offset;
3739657Slinton     } else {
3749657Slinton 	frp = frame;
3759657Slinton 	if (frp == nil) {
3769657Slinton 	    cur = s->block;
3779657Slinton 	    while (cur != nil and cur->class == MODULE) {
3789657Slinton 		cur = cur->block;
3799657Slinton 	    }
3809657Slinton 	    if (cur == nil) {
3819657Slinton 		cur = whatblock(pc);
3829657Slinton 	    }
3839657Slinton 	    frp = findframe(cur);
3849657Slinton 	    if (frp == nil) {
3859657Slinton 		panic("unexpected nil frame for \"%s\"", symname(s));
3869657Slinton 	    }
3879657Slinton 	}
3889657Slinton 	if (islocaloff(s)) {
3899657Slinton 	    addr = locals_base(frp) + s->symvalue.offset;
3909657Slinton 	} else if (isparamoff(s)) {
3919657Slinton 	    addr = args_base(frp) + s->symvalue.offset;
3929657Slinton 	} else if (isreg(s)) {
3939657Slinton 	    addr = savereg(s->symvalue.offset, frp);
3949657Slinton 	} else {
3959657Slinton 	    panic("address: bad symbol \"%s\"", symname(s));
3969657Slinton 	}
3979657Slinton     }
3989657Slinton     return addr;
3999657Slinton }
4009657Slinton 
4019657Slinton /*
4029657Slinton  * Define a symbol used to access register values.
4039657Slinton  */
4049657Slinton 
4059657Slinton public defregname(n, r)
4069657Slinton Name n;
4079657Slinton Integer r;
4089657Slinton {
4099657Slinton     register Symbol s, t;
4109657Slinton 
4119657Slinton     s = insert(n);
4129657Slinton     t = newSymbol(nil, 0, PTR, t_int, nil);
4139657Slinton     t->language = findlanguage(".s");
4149657Slinton     s->language = t->language;
4159657Slinton     s->class = VAR;
4169657Slinton     s->level = -3;
4179657Slinton     s->type = t;
4189657Slinton     s->block = program;
4199657Slinton     s->symvalue.offset = r;
4209657Slinton }
4219657Slinton 
4229657Slinton /*
4239657Slinton  * Resolve an "abstract" type reference.
4249657Slinton  *
4259657Slinton  * It is possible in C to define a pointer to a type, but never define
4269657Slinton  * the type in a particular source file.  Here we try to resolve
4279657Slinton  * the type definition.  This is problematic, it is possible to
4289657Slinton  * have multiple, different definitions for the same name type.
4299657Slinton  */
4309657Slinton 
4319657Slinton public findtype(s)
4329657Slinton Symbol s;
4339657Slinton {
4349657Slinton     register Symbol t, u, prev;
4359657Slinton 
4369657Slinton     u = s;
4379657Slinton     prev = nil;
4389657Slinton     while (u != nil and u->class != BADUSE) {
4399657Slinton 	if (u->name != nil) {
4409657Slinton 	    prev = u;
4419657Slinton 	}
4429657Slinton 	u = u->type;
4439657Slinton     }
4449657Slinton     if (prev == nil) {
4459657Slinton 	error("couldn't find link to type reference");
4469657Slinton     }
4479657Slinton     find(t, prev->name) where
4489657Slinton 	t->type != nil and t->class == prev->class and
4499657Slinton 	t->type->class != BADUSE and t->block->class == MODULE
4509657Slinton     endfind(t);
4519657Slinton     if (t == nil) {
4529657Slinton 	error("couldn't resolve reference");
4539657Slinton     } else {
4549657Slinton 	prev->type = t->type;
4559657Slinton     }
4569657Slinton }
4579657Slinton 
4589657Slinton /*
4599657Slinton  * Find the size in bytes of the given type.
4609657Slinton  *
4619657Slinton  * This is probably the WRONG thing to do.  The size should be kept
4629657Slinton  * as an attribute in the symbol information as is done for structures
4639657Slinton  * and fields.  I haven't gotten around to cleaning this up yet.
4649657Slinton  */
4659657Slinton 
4669657Slinton #define MINCHAR -128
4679657Slinton #define MAXCHAR 127
46812045Slinton #define MAXUCHAR 255
4699657Slinton #define MINSHORT -32768
4709657Slinton #define MAXSHORT 32767
47112045Slinton #define MAXUSHORT 65535L
4729657Slinton 
4739657Slinton public Integer size(sym)
4749657Slinton Symbol sym;
4759657Slinton {
4769657Slinton     register Symbol s, t;
4779657Slinton     register int nel, elsize;
4789657Slinton     long lower, upper;
4799657Slinton     int r;
4809657Slinton 
4819657Slinton     t = sym;
4829657Slinton     checkref(t);
4839657Slinton     switch (t->class) {
4849657Slinton 	case RANGE:
4859657Slinton 	    lower = t->symvalue.rangev.lower;
4869657Slinton 	    upper = t->symvalue.rangev.upper;
4879657Slinton 	    if (upper == 0 and lower > 0) {		/* real */
4889657Slinton 		r = lower;
48912045Slinton 	    } else if (
49012045Slinton 		(lower >= MINCHAR and upper <= MAXCHAR) or
49112045Slinton 		(lower >= 0 and upper <= MAXUCHAR)
49212045Slinton 	      ) {
4939657Slinton 		r = sizeof(char);
49412045Slinton 	    } else if (
49512045Slinton 		(lower >= MINSHORT and upper <= MAXSHORT) or
49612045Slinton 		(lower >= 0 and upper <= MAXUSHORT)
49712045Slinton 	      ) {
4989657Slinton 		r = sizeof(short);
4999657Slinton 	    } else {
5009657Slinton 		r = sizeof(long);
5019657Slinton 	    }
5029657Slinton 	    break;
5039657Slinton 
5049657Slinton 	case ARRAY:
5059657Slinton 	    elsize = size(t->type);
5069657Slinton 	    nel = 1;
5079657Slinton 	    for (t = t->chain; t != nil; t = t->chain) {
5089657Slinton 		s = rtype(t);
5099657Slinton 		lower = s->symvalue.rangev.lower;
5109657Slinton 		upper = s->symvalue.rangev.upper;
5119657Slinton 		nel *= (upper-lower+1);
5129657Slinton 	    }
5139657Slinton 	    r = nel*elsize;
5149657Slinton 	    break;
5159657Slinton 
5169657Slinton 	case VAR:
5179657Slinton 	case FVAR:
5189657Slinton 	    r = size(t->type);
519*12127Slinton 	    /*
520*12127Slinton 	     *
52112045Slinton 	    if (r < sizeof(Word) and isparam(t)) {
5229657Slinton 		r = sizeof(Word);
5239657Slinton 	    }
524*12127Slinton 	     */
5259657Slinton 	    break;
5269657Slinton 
5279657Slinton 	case CONST:
5289657Slinton 	    r = size(t->type);
5299657Slinton 	    break;
5309657Slinton 
5319657Slinton 	case TYPE:
5329657Slinton 	    if (t->type->class == PTR and t->type->type->class == BADUSE) {
5339657Slinton 		findtype(t);
5349657Slinton 	    }
5359657Slinton 	    r = size(t->type);
5369657Slinton 	    break;
5379657Slinton 
5389657Slinton 	case TAG:
5399657Slinton 	    r = size(t->type);
5409657Slinton 	    break;
5419657Slinton 
5429657Slinton 	case FIELD:
5439657Slinton 	    r = (t->symvalue.field.length + 7) div 8;
5449657Slinton 	    break;
5459657Slinton 
5469657Slinton 	case RECORD:
5479657Slinton 	case VARNT:
5489657Slinton 	    r = t->symvalue.offset;
5499657Slinton 	    if (r == 0 and t->chain != nil) {
5509657Slinton 		panic("missing size information for record");
5519657Slinton 	    }
5529657Slinton 	    break;
5539657Slinton 
5549657Slinton 	case PTR:
5559657Slinton 	case REF:
5569657Slinton 	case FILET:
5579657Slinton 	    r = sizeof(Word);
5589657Slinton 	    break;
5599657Slinton 
5609657Slinton 	case SCAL:
5619657Slinton 	    if (t->symvalue.iconval > 255) {
5629657Slinton 		r = sizeof(short);
5639657Slinton 	    } else {
5649657Slinton 		r = sizeof(char);
5659657Slinton 	    }
5669657Slinton 	    break;
5679657Slinton 
5689657Slinton 	case FPROC:
5699657Slinton 	case FFUNC:
5709657Slinton 	    r = sizeof(Word);
5719657Slinton 	    break;
5729657Slinton 
5739657Slinton 	case PROC:
5749657Slinton 	case FUNC:
5759657Slinton 	case MODULE:
5769657Slinton 	case PROG:
5779657Slinton 	    r = sizeof(Symbol);
5789657Slinton 	    break;
5799657Slinton 
5809657Slinton 	default:
5819657Slinton 	    if (ord(t->class) > ord(TYPEREF)) {
5829657Slinton 		panic("size: bad class (%d)", ord(t->class));
5839657Slinton 	    } else {
5849657Slinton 		error("improper operation on a %s", classname(t));
5859657Slinton 	    }
5869657Slinton 	    /* NOTREACHED */
5879657Slinton     }
5889657Slinton     return r;
5899657Slinton }
5909657Slinton 
5919657Slinton /*
5929657Slinton  * Test if a symbol is a parameter.  This is true if there
5939657Slinton  * is a cycle from s->block to s via chain pointers.
5949657Slinton  */
5959657Slinton 
5969657Slinton public Boolean isparam(s)
5979657Slinton Symbol s;
5989657Slinton {
5999657Slinton     register Symbol t;
6009657Slinton 
6019657Slinton     t = s->block;
6029657Slinton     while (t != nil and t != s) {
6039657Slinton 	t = t->chain;
6049657Slinton     }
6059657Slinton     return (Boolean) (t != nil);
6069657Slinton }
6079657Slinton 
6089657Slinton /*
6099657Slinton  * Test if a symbol is a var parameter, i.e. has class REF.
6109657Slinton  */
6119657Slinton 
6129657Slinton public Boolean isvarparam(s)
6139657Slinton Symbol s;
6149657Slinton {
6159657Slinton     return (Boolean) (s->class == REF);
6169657Slinton }
6179657Slinton 
6189657Slinton /*
6199657Slinton  * Test if a symbol is a variable (actually any addressible quantity
6209657Slinton  * with do).
6219657Slinton  */
6229657Slinton 
6239657Slinton public Boolean isvariable(s)
6249657Slinton register Symbol s;
6259657Slinton {
6269657Slinton     return (Boolean) (s->class == VAR or s->class == FVAR or s->class == REF);
6279657Slinton }
6289657Slinton 
6299657Slinton /*
6309657Slinton  * Test if a symbol is a block, e.g. function, procedure, or the
6319657Slinton  * main program.
6329657Slinton  *
6339657Slinton  * This function is now expanded inline for efficiency.
6349657Slinton  *
6359657Slinton  * public Boolean isblock(s)
6369657Slinton register Symbol s;
6379657Slinton {
6389657Slinton     return (Boolean) (
6399657Slinton 	s->class == FUNC or s->class == PROC or
6409657Slinton 	s->class == MODULE or s->class == PROG
6419657Slinton     );
6429657Slinton }
6439657Slinton  *
6449657Slinton  */
6459657Slinton 
6469657Slinton /*
6479657Slinton  * Test if a symbol is a module.
6489657Slinton  */
6499657Slinton 
6509657Slinton public Boolean ismodule(s)
6519657Slinton register Symbol s;
6529657Slinton {
6539657Slinton     return (Boolean) (s->class == MODULE);
6549657Slinton }
6559657Slinton 
6569657Slinton /*
6579657Slinton  * Test if a symbol is builtin, that is, a predefined type or
6589657Slinton  * reserved word.
6599657Slinton  */
6609657Slinton 
6619657Slinton public Boolean isbuiltin(s)
6629657Slinton register Symbol s;
6639657Slinton {
6649657Slinton     return (Boolean) (s->level == 0 and s->class != PROG and s->class != VAR);
6659657Slinton }
6669657Slinton 
6679657Slinton /*
6689657Slinton  * Test if two types match.
6699657Slinton  * Equivalent names implies a match in any language.
6709657Slinton  *
6719657Slinton  * Special symbols must be handled with care.
6729657Slinton  */
6739657Slinton 
6749657Slinton public Boolean compatible(t1, t2)
6759657Slinton register Symbol t1, t2;
6769657Slinton {
6779657Slinton     Boolean b;
6789657Slinton 
6799657Slinton     if (t1 == t2) {
6809657Slinton 	b = true;
6819657Slinton     } else if (t1 == nil or t2 == nil) {
6829657Slinton 	b = false;
6839657Slinton     } else if (t1 == procsym) {
6849657Slinton 	b = isblock(t2);
6859657Slinton     } else if (t2 == procsym) {
6869657Slinton 	b = isblock(t1);
6879657Slinton     } else if (t1->language == nil) {
6889657Slinton 	b = (Boolean) (t2->language == nil or
6899657Slinton 	    (*language_op(t2->language, L_TYPEMATCH))(t1, t2));
6909657Slinton     } else {
6919657Slinton 	b = (Boolean) (*language_op(t1->language, L_TYPEMATCH))(t1, t2);
6929657Slinton     }
6939657Slinton     return b;
6949657Slinton }
6959657Slinton 
6969657Slinton /*
6979657Slinton  * Check for a type of the given name.
6989657Slinton  */
6999657Slinton 
7009657Slinton public Boolean istypename(type, name)
7019657Slinton Symbol type;
7029657Slinton String name;
7039657Slinton {
7049657Slinton     Symbol t;
7059657Slinton     Boolean b;
7069657Slinton 
7079657Slinton     t = type;
7089657Slinton     checkref(t);
7099657Slinton     b = (Boolean) (
7109657Slinton 	t->class == TYPE and t->name == identname(name, true)
7119657Slinton     );
7129657Slinton     return b;
7139657Slinton }
7149657Slinton 
7159657Slinton /*
7169657Slinton  * Test if the name of a symbol is uniquely defined or not.
7179657Slinton  */
7189657Slinton 
7199657Slinton public Boolean isambiguous(s)
7209657Slinton register Symbol s;
7219657Slinton {
7229657Slinton     register Symbol t;
7239657Slinton 
7249657Slinton     find(t, s->name) where t != s endfind(t);
7259657Slinton     return (Boolean) (t != nil);
7269657Slinton }
7279657Slinton 
7289657Slinton typedef char *Arglist;
7299657Slinton 
7309657Slinton #define nextarg(type)  ((type *) (ap += sizeof(type)))[-1]
7319657Slinton 
7329657Slinton private Symbol mkstring();
7339657Slinton private Symbol namenode();
7349657Slinton 
7359657Slinton /*
7369657Slinton  * Determine the type of a parse tree.
7379657Slinton  * Also make some symbol-dependent changes to the tree such as
7389657Slinton  * changing removing RVAL nodes for constant symbols.
7399657Slinton  */
7409657Slinton 
7419657Slinton public assigntypes(p)
7429657Slinton register Node p;
7439657Slinton {
7449657Slinton     register Node p1;
7459657Slinton     register Symbol s;
7469657Slinton 
7479657Slinton     switch (p->op) {
7489657Slinton 	case O_SYM:
7499657Slinton 	    p->nodetype = namenode(p);
7509657Slinton 	    break;
7519657Slinton 
7529657Slinton 	case O_LCON:
7539657Slinton 	    p->nodetype = t_int;
7549657Slinton 	    break;
7559657Slinton 
7569657Slinton 	case O_FCON:
7579657Slinton 	    p->nodetype = t_real;
7589657Slinton 	    break;
7599657Slinton 
7609657Slinton 	case O_SCON:
7619657Slinton 	    p->value.scon = strdup(p->value.scon);
7629657Slinton 	    s = mkstring(p->value.scon);
7639657Slinton 	    if (s == t_char) {
7649657Slinton 		p->op = O_LCON;
7659657Slinton 		p->value.lcon = p->value.scon[0];
7669657Slinton 	    }
7679657Slinton 	    p->nodetype = s;
7689657Slinton 	    break;
7699657Slinton 
7709657Slinton 	case O_INDIR:
7719657Slinton 	    p1 = p->value.arg[0];
7729657Slinton 	    chkclass(p1, PTR);
7739657Slinton 	    p->nodetype = rtype(p1->nodetype)->type;
7749657Slinton 	    break;
7759657Slinton 
7769657Slinton 	case O_DOT:
7779657Slinton 	    p->nodetype = p->value.arg[1]->value.sym;
7789657Slinton 	    break;
7799657Slinton 
7809657Slinton 	case O_RVAL:
7819657Slinton 	    p1 = p->value.arg[0];
7829657Slinton 	    p->nodetype = p1->nodetype;
7839657Slinton 	    if (p1->op == O_SYM) {
7849657Slinton 		if (p1->nodetype->class == FUNC) {
7859657Slinton 		    p->op = O_CALL;
7869657Slinton 		    p->value.arg[1] = nil;
7879657Slinton 		} else if (p1->value.sym->class == CONST) {
7889657Slinton 		    if (compatible(p1->value.sym->type, t_real)) {
7899657Slinton 			p->op = O_FCON;
7909657Slinton 			p->value.fcon = p1->value.sym->symvalue.fconval;
7919657Slinton 			p->nodetype = t_real;
7929657Slinton 			dispose(p1);
7939657Slinton 		    } else {
7949657Slinton 			p->op = O_LCON;
7959657Slinton 			p->value.lcon = p1->value.sym->symvalue.iconval;
7969657Slinton 			p->nodetype = p1->value.sym->type;
7979657Slinton 			dispose(p1);
7989657Slinton 		    }
7999657Slinton 		} else if (isreg(p1->value.sym)) {
8009657Slinton 		    p->op = O_SYM;
8019657Slinton 		    p->value.sym = p1->value.sym;
8029657Slinton 		    dispose(p1);
8039657Slinton 		}
8049657Slinton 	    } else if (p1->op == O_INDIR and p1->value.arg[0]->op == O_SYM) {
8059657Slinton 		s = p1->value.arg[0]->value.sym;
8069657Slinton 		if (isreg(s)) {
8079657Slinton 		    p1->op = O_SYM;
8089657Slinton 		    dispose(p1->value.arg[0]);
8099657Slinton 		    p1->value.sym = s;
8109657Slinton 		    p1->nodetype = s;
8119657Slinton 		}
8129657Slinton 	    }
8139657Slinton 	    break;
8149657Slinton 
8159657Slinton 	/*
8169657Slinton 	 * Perform a cast if the call is of the form "type(expr)".
8179657Slinton 	 */
8189657Slinton 	case O_CALL:
8199657Slinton 	    p1 = p->value.arg[0];
82011171Slinton 	    p->nodetype = rtype(p1->nodetype)->type;
8219657Slinton 	    break;
8229657Slinton 
82311171Slinton 	case O_TYPERENAME:
82411171Slinton 	    p->nodetype = p->value.arg[1]->nodetype;
82511171Slinton 	    break;
82611171Slinton 
8279657Slinton 	case O_ITOF:
8289657Slinton 	    p->nodetype = t_real;
8299657Slinton 	    break;
8309657Slinton 
8319657Slinton 	case O_NEG:
8329657Slinton 	    s = p->value.arg[0]->nodetype;
8339657Slinton 	    if (not compatible(s, t_int)) {
8349657Slinton 		if (not compatible(s, t_real)) {
8359657Slinton 		    beginerrmsg();
8369657Slinton 		    prtree(stderr, p->value.arg[0]);
8379657Slinton 		    fprintf(stderr, "is improper type");
8389657Slinton 		    enderrmsg();
8399657Slinton 		} else {
8409657Slinton 		    p->op = O_NEGF;
8419657Slinton 		}
8429657Slinton 	    }
8439657Slinton 	    p->nodetype = s;
8449657Slinton 	    break;
8459657Slinton 
8469657Slinton 	case O_ADD:
8479657Slinton 	case O_SUB:
8489657Slinton 	case O_MUL:
8499657Slinton 	case O_LT:
8509657Slinton 	case O_LE:
8519657Slinton 	case O_GT:
8529657Slinton 	case O_GE:
8539657Slinton 	case O_EQ:
8549657Slinton 	case O_NE:
8559657Slinton 	{
8569657Slinton 	    Boolean t1real, t2real;
8579657Slinton 	    Symbol t1, t2;
8589657Slinton 
8599657Slinton 	    t1 = rtype(p->value.arg[0]->nodetype);
8609657Slinton 	    t2 = rtype(p->value.arg[1]->nodetype);
8619657Slinton 	    t1real = compatible(t1, t_real);
8629657Slinton 	    t2real = compatible(t2, t_real);
8639657Slinton 	    if (t1real or t2real) {
8649657Slinton 		p->op = (Operator) (ord(p->op) + 1);
8659657Slinton 		if (not t1real) {
8669657Slinton 		    p->value.arg[0] = build(O_ITOF, p->value.arg[0]);
8679657Slinton 		} else if (not t2real) {
8689657Slinton 		    p->value.arg[1] = build(O_ITOF, p->value.arg[1]);
8699657Slinton 		}
8709657Slinton 	    } else {
8719657Slinton 		if (t1real) {
8729657Slinton 		    convert(&(p->value.arg[0]), t_int, O_NOP);
8739657Slinton 		}
8749657Slinton 		if (t2real) {
8759657Slinton 		    convert(&(p->value.arg[1]), t_int, O_NOP);
8769657Slinton 		}
8779657Slinton 	    }
8789657Slinton 	    if (ord(p->op) >= ord(O_LT)) {
8799657Slinton 		p->nodetype = t_boolean;
8809657Slinton 	    } else {
8819657Slinton 		if (t1real or t2real) {
8829657Slinton 		    p->nodetype = t_real;
8839657Slinton 		} else {
8849657Slinton 		    p->nodetype = t_int;
8859657Slinton 		}
8869657Slinton 	    }
8879657Slinton 	    break;
8889657Slinton 	}
8899657Slinton 
8909657Slinton 	case O_DIVF:
8919657Slinton 	    convert(&(p->value.arg[0]), t_real, O_ITOF);
8929657Slinton 	    convert(&(p->value.arg[1]), t_real, O_ITOF);
8939657Slinton 	    p->nodetype = t_real;
8949657Slinton 	    break;
8959657Slinton 
8969657Slinton 	case O_DIV:
8979657Slinton 	case O_MOD:
8989657Slinton 	    convert(&(p->value.arg[0]), t_int, O_NOP);
8999657Slinton 	    convert(&(p->value.arg[1]), t_int, O_NOP);
9009657Slinton 	    p->nodetype = t_int;
9019657Slinton 	    break;
9029657Slinton 
9039657Slinton 	case O_AND:
9049657Slinton 	case O_OR:
9059657Slinton 	    chkboolean(p->value.arg[0]);
9069657Slinton 	    chkboolean(p->value.arg[1]);
9079657Slinton 	    p->nodetype = t_boolean;
9089657Slinton 	    break;
9099657Slinton 
9109657Slinton 	case O_QLINE:
9119657Slinton 	    p->nodetype = t_int;
9129657Slinton 	    break;
9139657Slinton 
9149657Slinton 	default:
9159657Slinton 	    p->nodetype = nil;
9169657Slinton 	    break;
9179657Slinton     }
9189657Slinton }
9199657Slinton 
9209657Slinton /*
9219657Slinton  * Create a node for a name.  The symbol for the name has already
9229657Slinton  * been chosen, either implicitly with "which" or explicitly from
9239657Slinton  * the dot routine.
9249657Slinton  */
9259657Slinton 
9269657Slinton private Symbol namenode(p)
9279657Slinton Node p;
9289657Slinton {
9299657Slinton     register Symbol r, s;
9309657Slinton     register Node np;
9319657Slinton 
9329657Slinton     s = p->value.sym;
9339657Slinton     if (s->class == REF) {
9349657Slinton 	np = new(Node);
9359657Slinton 	np->op = p->op;
9369657Slinton 	np->nodetype = s;
9379657Slinton 	np->value.sym = s;
9389657Slinton 	p->op = O_INDIR;
9399657Slinton 	p->value.arg[0] = np;
9409657Slinton     }
9419657Slinton /*
9429657Slinton  * Old way
9439657Slinton  *
9449657Slinton     if (s->class == CONST or s->class == VAR or s->class == FVAR) {
9459657Slinton 	r = s->type;
9469657Slinton     } else {
9479657Slinton 	r = s;
9489657Slinton     }
9499657Slinton  *
9509657Slinton  */
9519657Slinton     return s;
9529657Slinton }
9539657Slinton 
9549657Slinton /*
9559657Slinton  * Convert a tree to a type via a conversion operator;
9569657Slinton  * if this isn't possible generate an error.
9579657Slinton  *
9589657Slinton  * Note the tree is call by address, hence the #define below.
9599657Slinton  */
9609657Slinton 
9619657Slinton private convert(tp, typeto, op)
9629657Slinton Node *tp;
9639657Slinton Symbol typeto;
9649657Slinton Operator op;
9659657Slinton {
9669657Slinton #define tree    (*tp)
9679657Slinton 
9689657Slinton     Symbol s;
9699657Slinton 
9709657Slinton     s = rtype(tree->nodetype);
9719657Slinton     typeto = rtype(typeto);
9729657Slinton     if (compatible(typeto, t_real) and compatible(s, t_int)) {
9739657Slinton 	tree = build(op, tree);
9749657Slinton     } else if (not compatible(s, typeto)) {
9759657Slinton 	beginerrmsg();
9769657Slinton 	prtree(stderr, s);
9779657Slinton 	fprintf(stderr, " is improper type");
9789657Slinton 	enderrmsg();
9799657Slinton     } else if (op != O_NOP and s != typeto) {
9809657Slinton 	tree = build(op, tree);
9819657Slinton     }
9829657Slinton 
9839657Slinton #undef tree
9849657Slinton }
9859657Slinton 
9869657Slinton /*
9879657Slinton  * Construct a node for the dot operator.
9889657Slinton  *
9899657Slinton  * If the left operand is not a record, but rather a procedure
9909657Slinton  * or function, then we interpret the "." as referencing an
9919657Slinton  * "invisible" variable; i.e. a variable within a dynamically
9929657Slinton  * active block but not within the static scope of the current procedure.
9939657Slinton  */
9949657Slinton 
9959657Slinton public Node dot(record, fieldname)
9969657Slinton Node record;
9979657Slinton Name fieldname;
9989657Slinton {
9999657Slinton     register Node p;
10009657Slinton     register Symbol s, t;
10019657Slinton 
10029657Slinton     if (isblock(record->nodetype)) {
10039657Slinton 	find(s, fieldname) where
10049657Slinton 	    s->block == record->nodetype and
10059657Slinton 	    s->class != FIELD and s->class != TAG
10069657Slinton 	endfind(s);
10079657Slinton 	if (s == nil) {
10089657Slinton 	    beginerrmsg();
10099657Slinton 	    fprintf(stderr, "\"%s\" is not defined in ", ident(fieldname));
10109657Slinton 	    printname(stderr, record->nodetype);
10119657Slinton 	    enderrmsg();
10129657Slinton 	}
10139657Slinton 	p = new(Node);
10149657Slinton 	p->op = O_SYM;
10159657Slinton 	p->value.sym = s;
10169657Slinton 	p->nodetype = namenode(p);
10179657Slinton     } else {
10189657Slinton 	p = record;
10199657Slinton 	t = rtype(p->nodetype);
10209657Slinton 	if (t->class == PTR) {
10219657Slinton 	    s = findfield(fieldname, t->type);
10229657Slinton 	} else {
10239657Slinton 	    s = findfield(fieldname, t);
10249657Slinton 	}
10259657Slinton 	if (s == nil) {
10269657Slinton 	    beginerrmsg();
10279657Slinton 	    fprintf(stderr, "\"%s\" is not a field in ", ident(fieldname));
10289657Slinton 	    prtree(stderr, record);
10299657Slinton 	    enderrmsg();
10309657Slinton 	}
10319657Slinton 	if (t->class == PTR and not isreg(record->nodetype)) {
10329657Slinton 	    p = build(O_INDIR, record);
10339657Slinton 	}
10349657Slinton 	p = build(O_DOT, p, build(O_SYM, s));
10359657Slinton     }
10369657Slinton     return p;
10379657Slinton }
10389657Slinton 
10399657Slinton /*
10409657Slinton  * Return a tree corresponding to an array reference and do the
10419657Slinton  * error checking.
10429657Slinton  */
10439657Slinton 
10449657Slinton public Node subscript(a, slist)
10459657Slinton Node a, slist;
10469657Slinton {
10479657Slinton     register Symbol t;
10489657Slinton     register Node p;
10499657Slinton     Symbol etype, atype, eltype;
105011770Slinton     Node esub, r;
10519657Slinton 
105211770Slinton     r = a;
10539657Slinton     t = rtype(a->nodetype);
105411770Slinton     eltype = t->type;
105511770Slinton     if (t->class == PTR) {
105611770Slinton 	p = slist->value.arg[0];
105711770Slinton 	if (not compatible(p->nodetype, t_int)) {
105811770Slinton 	    beginerrmsg();
105911770Slinton 	    fprintf(stderr, "bad type for subscript of ");
106011770Slinton 	    prtree(stderr, a);
106111770Slinton 	    enderrmsg();
106211770Slinton 	}
106311770Slinton 	r = build(O_MUL, p, build(O_LCON, (long) size(eltype)));
106411770Slinton 	r = build(O_ADD, build(O_RVAL, a), r);
106511770Slinton 	r->nodetype = eltype;
106611770Slinton     } else if (t->class != ARRAY) {
10679657Slinton 	beginerrmsg();
10689657Slinton 	prtree(stderr, a);
10699657Slinton 	fprintf(stderr, " is not an array");
10709657Slinton 	enderrmsg();
107111770Slinton     } else {
107211770Slinton 	p = slist;
107311770Slinton 	t = t->chain;
107411770Slinton 	for (; p != nil and t != nil; p = p->value.arg[1], t = t->chain) {
107511770Slinton 	    esub = p->value.arg[0];
107611770Slinton 	    etype = rtype(esub->nodetype);
107711770Slinton 	    atype = rtype(t);
107811770Slinton 	    if (not compatible(atype, etype)) {
107911770Slinton 		beginerrmsg();
108011770Slinton 		fprintf(stderr, "subscript ");
108111770Slinton 		prtree(stderr, esub);
108211770Slinton 		fprintf(stderr, " is the wrong type");
108311770Slinton 		enderrmsg();
108411770Slinton 	    }
108511770Slinton 	    r = build(O_INDEX, r, esub);
108611770Slinton 	    r->nodetype = eltype;
108711770Slinton 	}
108811770Slinton 	if (p != nil or t != nil) {
10899657Slinton 	    beginerrmsg();
109011770Slinton 	    if (p != nil) {
109111770Slinton 		fprintf(stderr, "too many subscripts for ");
109211770Slinton 	    } else {
109311770Slinton 		fprintf(stderr, "not enough subscripts for ");
109411770Slinton 	    }
109511770Slinton 	    prtree(stderr, a);
10969657Slinton 	    enderrmsg();
10979657Slinton 	}
10989657Slinton     }
109911770Slinton     return r;
11009657Slinton }
11019657Slinton 
11029657Slinton /*
11039657Slinton  * Evaluate a subscript index.
11049657Slinton  */
11059657Slinton 
11069657Slinton public int evalindex(s, i)
11079657Slinton Symbol s;
11089657Slinton long i;
11099657Slinton {
11109657Slinton     long lb, ub;
11119657Slinton 
11129657Slinton     s = rtype(s)->chain;
11139657Slinton     lb = s->symvalue.rangev.lower;
11149657Slinton     ub = s->symvalue.rangev.upper;
11159657Slinton     if (i < lb or i > ub) {
11169657Slinton 	error("subscript out of range");
11179657Slinton     }
11189657Slinton     return (i - lb);
11199657Slinton }
11209657Slinton 
11219657Slinton /*
11229657Slinton  * Check to see if a tree is boolean-valued, if not it's an error.
11239657Slinton  */
11249657Slinton 
11259657Slinton public chkboolean(p)
11269657Slinton register Node p;
11279657Slinton {
11289657Slinton     if (p->nodetype != t_boolean) {
11299657Slinton 	beginerrmsg();
11309657Slinton 	fprintf(stderr, "found ");
11319657Slinton 	prtree(stderr, p);
11329657Slinton 	fprintf(stderr, ", expected boolean expression");
11339657Slinton 	enderrmsg();
11349657Slinton     }
11359657Slinton }
11369657Slinton 
11379657Slinton /*
11389657Slinton  * Check to make sure the given tree has a type of the given class.
11399657Slinton  */
11409657Slinton 
11419657Slinton private chkclass(p, class)
11429657Slinton Node p;
11439657Slinton Symclass class;
11449657Slinton {
11459657Slinton     struct Symbol tmpsym;
11469657Slinton 
11479657Slinton     tmpsym.class = class;
11489657Slinton     if (rtype(p->nodetype)->class != class) {
11499657Slinton 	beginerrmsg();
11509657Slinton 	fprintf(stderr, "\"");
11519657Slinton 	prtree(stderr, p);
11529657Slinton 	fprintf(stderr, "\" is not a %s", classname(&tmpsym));
11539657Slinton 	enderrmsg();
11549657Slinton     }
11559657Slinton }
11569657Slinton 
11579657Slinton /*
11589657Slinton  * Construct a node for the type of a string.  While we're at it,
11599657Slinton  * scan the string for '' that collapse to ', and chop off the ends.
11609657Slinton  */
11619657Slinton 
11629657Slinton private Symbol mkstring(str)
11639657Slinton String str;
11649657Slinton {
11659657Slinton     register char *p, *q;
11669657Slinton     register Symbol s;
11679657Slinton 
11689657Slinton     p = str;
11699657Slinton     q = str;
11709657Slinton     while (*p != '\0') {
11719657Slinton 	if (*p == '\\') {
11729657Slinton 	    ++p;
11739657Slinton 	}
11749657Slinton 	*q = *p;
11759657Slinton 	++p;
11769657Slinton 	++q;
11779657Slinton     }
11789657Slinton     *q = '\0';
11799657Slinton     s = newSymbol(nil, 0, ARRAY, t_char, nil);
11809657Slinton     s->language = findlanguage(".s");
11819657Slinton     s->chain = newSymbol(nil, 0, RANGE, t_int, nil);
11829657Slinton     s->chain->language = s->language;
11839657Slinton     s->chain->symvalue.rangev.lower = 1;
11849657Slinton     s->chain->symvalue.rangev.upper = p - str + 1;
11859657Slinton     return s;
11869657Slinton }
11879657Slinton 
11889657Slinton /*
11899657Slinton  * Free up the space allocated for a string type.
11909657Slinton  */
11919657Slinton 
11929657Slinton public unmkstring(s)
11939657Slinton Symbol s;
11949657Slinton {
11959657Slinton     dispose(s->chain);
11969657Slinton }
11979657Slinton 
11989657Slinton /*
11999657Slinton  * Figure out the "current" variable or function being referred to,
12009657Slinton  * this is either the active one or the most visible from the
12019657Slinton  * current scope.
12029657Slinton  */
12039657Slinton 
12049657Slinton public Symbol which(n)
12059657Slinton Name n;
12069657Slinton {
12079657Slinton     register Symbol s, p, t, f;
12089657Slinton 
12099657Slinton     find(s, n) where s->class != FIELD and s->class != TAG endfind(s);
12109657Slinton     if (s == nil) {
12119657Slinton 	s = lookup(n);
12129657Slinton     }
12139657Slinton     if (s == nil) {
12149657Slinton 	error("\"%s\" is not defined", ident(n));
12159657Slinton     } else if (s == program or isbuiltin(s)) {
12169657Slinton 	t = s;
12179657Slinton     } else {
12189657Slinton     /*
12199657Slinton      * Old way
12209657Slinton      *
12219657Slinton 	if (not isactive(program)) {
12229657Slinton 	    f = program;
12239657Slinton 	} else {
12249657Slinton 	    f = whatblock(pc);
12259657Slinton 	    if (f == nil) {
12269657Slinton 		panic("no block for addr 0x%x", pc);
12279657Slinton 	    }
12289657Slinton 	}
12299657Slinton      *
12309657Slinton      * Now start with curfunc.
12319657Slinton      */
12329657Slinton 	p = curfunc;
12339657Slinton 	do {
12349657Slinton 	    find(t, n) where
12359657Slinton 		t->block == p and t->class != FIELD and t->class != TAG
12369657Slinton 	    endfind(t);
12379657Slinton 	    p = p->block;
12389657Slinton 	} while (t == nil and p != nil);
12399657Slinton 	if (t == nil) {
12409657Slinton 	    t = s;
12419657Slinton 	}
12429657Slinton     }
12439657Slinton     return t;
12449657Slinton }
12459657Slinton 
12469657Slinton /*
12479657Slinton  * Find the symbol which is has the same name and scope as the
12489657Slinton  * given symbol but is of the given field.  Return nil if there is none.
12499657Slinton  */
12509657Slinton 
12519657Slinton public Symbol findfield(fieldname, record)
12529657Slinton Name fieldname;
12539657Slinton Symbol record;
12549657Slinton {
12559657Slinton     register Symbol t;
12569657Slinton 
12579657Slinton     t = rtype(record)->chain;
12589657Slinton     while (t != nil and t->name != fieldname) {
12599657Slinton 	t = t->chain;
12609657Slinton     }
12619657Slinton     return t;
12629657Slinton }
1263