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