xref: /csrg-svn/old/dbx/symbols.c (revision 16620)
19657Slinton /* Copyright (c) 1982 Regents of the University of California */
29657Slinton 
3*16620Ssam static char sccsid[] = "@(#)symbols.c 1.10 8/10/83";
49657Slinton 
5*16620Ssam static char rcsid[] = "$Header: symbols.c,v 1.4 84/03/27 10:24:18 linton Exp $";
6*16620Ssam 
79657Slinton /*
89657Slinton  * Symbol management.
99657Slinton  */
109657Slinton 
119657Slinton #include "defs.h"
129657Slinton #include "symbols.h"
139657Slinton #include "languages.h"
149657Slinton #include "printsym.h"
159657Slinton #include "tree.h"
169657Slinton #include "operators.h"
179657Slinton #include "eval.h"
189657Slinton #include "mappings.h"
199657Slinton #include "events.h"
209657Slinton #include "process.h"
219657Slinton #include "runtime.h"
229657Slinton #include "machine.h"
239657Slinton #include "names.h"
249657Slinton 
259657Slinton #ifndef public
269657Slinton typedef struct Symbol *Symbol;
279657Slinton 
289657Slinton #include "machine.h"
299657Slinton #include "names.h"
309657Slinton #include "languages.h"
319657Slinton 
329657Slinton /*
339657Slinton  * Symbol classes
349657Slinton  */
359657Slinton 
369657Slinton typedef enum {
379657Slinton     BADUSE, CONST, TYPE, VAR, ARRAY, PTRFILE, RECORD, FIELD,
3812547Scsvaf     PROC, FUNC, FVAR, REF, PTR, FILET, SET, RANGE,
399657Slinton     LABEL, WITHPTR, SCAL, STR, PROG, IMPROPER, VARNT,
40*16620Ssam     FPROC, FFUNC, MODULE, TAG, COMMON, EXTREF, TYPEREF
419657Slinton } Symclass;
429657Slinton 
4312547Scsvaf typedef enum { R_CONST, R_TEMP, R_ARG, R_ADJUST } Rangetype;
4412547Scsvaf 
459657Slinton struct Symbol {
469657Slinton     Name name;
479657Slinton     Language language;
489657Slinton     Symclass class : 8;
499657Slinton     Integer level : 8;
509657Slinton     Symbol type;
519657Slinton     Symbol chain;
529657Slinton     union {
539657Slinton 	int offset;		/* variable address */
549657Slinton 	long iconval;		/* integer constant value */
559657Slinton 	double fconval;		/* floating constant value */
569657Slinton 	struct {		/* field offset and size (both in bits) */
579657Slinton 	    int offset;
589657Slinton 	    int length;
599657Slinton 	} field;
6012547Scsvaf 	struct {		/* common offset and chain; used to relocate */
6112547Scsvaf 	    int offset;         /* vars in global BSS */
6212547Scsvaf 	    Symbol chain;
6312547Scsvaf 	} common;
649657Slinton 	struct {		/* range bounds */
6512547Scsvaf             Rangetype lowertype : 16;
6612547Scsvaf             Rangetype uppertype : 16;
679657Slinton 	    long lower;
689657Slinton 	    long upper;
699657Slinton 	} rangev;
7011865Slinton 	struct {
7111865Slinton 	    int offset : 16;	/* offset for of function value */
72*16620Ssam 	    Boolean src : 1;	/* true if there is source line info */
73*16620Ssam 	    Boolean inline : 1;	/* true if no separate act. rec. */
74*16620Ssam 	    Boolean intern : 1; /* internal calling sequence */
75*16620Ssam 	    int unused : 13;
7611865Slinton 	    Address beginaddr;	/* address of function code */
779657Slinton 	} funcv;
789657Slinton 	struct {		/* variant record info */
799657Slinton 	    int size;
809657Slinton 	    Symbol vtorec;
819657Slinton 	    Symbol vtag;
829657Slinton 	} varnt;
83*16620Ssam 	String typeref;		/* type defined by "<module>:<type>" */
84*16620Ssam 	Symbol extref;		/* indirect symbol for external reference */
859657Slinton     } symvalue;
869657Slinton     Symbol block;		/* symbol containing this symbol */
879657Slinton     Symbol next_sym;		/* hash chain */
889657Slinton };
899657Slinton 
909657Slinton /*
919657Slinton  * Basic types.
929657Slinton  */
939657Slinton 
949657Slinton Symbol t_boolean;
959657Slinton Symbol t_char;
969657Slinton Symbol t_int;
979657Slinton Symbol t_real;
989657Slinton Symbol t_nil;
99*16620Ssam Symbol t_open;
1009657Slinton 
1019657Slinton Symbol program;
1029657Slinton Symbol curfunc;
1039657Slinton 
1049657Slinton #define symname(s) ident(s->name)
1059657Slinton #define codeloc(f) ((f)->symvalue.funcv.beginaddr)
1069657Slinton #define isblock(s) (Boolean) ( \
1079657Slinton     s->class == FUNC or s->class == PROC or \
1089657Slinton     s->class == MODULE or s->class == PROG \
1099657Slinton )
110*16620Ssam #define isroutine(s) (Boolean) ( \
111*16620Ssam     s->class == FUNC or s->class == PROC \
112*16620Ssam )
1139657Slinton 
11411865Slinton #define nosource(f) (not (f)->symvalue.funcv.src)
11514441Slinton #define isinline(f) ((f)->symvalue.funcv.inline)
11611865Slinton 
1179657Slinton #include "tree.h"
1189657Slinton 
1199657Slinton /*
1209657Slinton  * Some macros to make finding a symbol with certain attributes.
1219657Slinton  */
1229657Slinton 
1239657Slinton #define find(s, withname) \
1249657Slinton { \
1259657Slinton     s = lookup(withname); \
1269657Slinton     while (s != nil and not (s->name == (withname) and
1279657Slinton 
1289657Slinton #define where /* qualification */
1299657Slinton 
1309657Slinton #define endfind(s) )) { \
1319657Slinton 	s = s->next_sym; \
1329657Slinton     } \
1339657Slinton }
1349657Slinton 
1359657Slinton #endif
1369657Slinton 
1379657Slinton /*
1389657Slinton  * Symbol table structure currently does not support deletions.
1399657Slinton  */
1409657Slinton 
1419657Slinton #define HASHTABLESIZE 2003
1429657Slinton 
1439657Slinton private Symbol hashtab[HASHTABLESIZE];
1449657Slinton 
1459657Slinton #define hash(name) ((((unsigned) name) >> 2) mod HASHTABLESIZE)
1469657Slinton 
1479657Slinton /*
1489657Slinton  * Allocate a new symbol.
1499657Slinton  */
1509657Slinton 
15111171Slinton #define SYMBLOCKSIZE 100
1529657Slinton 
1539657Slinton typedef struct Sympool {
1549657Slinton     struct Symbol sym[SYMBLOCKSIZE];
1559657Slinton     struct Sympool *prevpool;
1569657Slinton } *Sympool;
1579657Slinton 
1589657Slinton private Sympool sympool = nil;
1599657Slinton private Integer nleft = 0;
1609657Slinton 
1619657Slinton public Symbol symbol_alloc()
1629657Slinton {
1639657Slinton     register Sympool newpool;
1649657Slinton 
1659657Slinton     if (nleft <= 0) {
1669657Slinton 	newpool = new(Sympool);
16711171Slinton 	bzero(newpool, sizeof(newpool));
1689657Slinton 	newpool->prevpool = sympool;
1699657Slinton 	sympool = newpool;
1709657Slinton 	nleft = SYMBLOCKSIZE;
1719657Slinton     }
1729657Slinton     --nleft;
1739657Slinton     return &(sympool->sym[nleft]);
1749657Slinton }
1759657Slinton 
17612547Scsvaf 
17712547Scsvaf public symbol_dump(func)
17812547Scsvaf Symbol func;
17912547Scsvaf {
180*16620Ssam   register Symbol s;
181*16620Ssam   register Integer i;
18212547Scsvaf 
183*16620Ssam 	printf(" symbols in %s \n",symname(func));
184*16620Ssam 	for(i=0; i< HASHTABLESIZE; i++)
185*16620Ssam 	   for(s=hashtab[i]; s != nil; s=s->next_sym)  {
186*16620Ssam 		if (s->block == func) psym(s);
187*16620Ssam 		}
18812547Scsvaf }
18912547Scsvaf 
1909657Slinton /*
1919657Slinton  * Free all the symbols currently allocated.
1929657Slinton  */
1939657Slinton public symbol_free()
1949657Slinton {
1959657Slinton     Sympool s, t;
1969657Slinton     register Integer i;
1979657Slinton 
1989657Slinton     s = sympool;
1999657Slinton     while (s != nil) {
2009657Slinton 	t = s->prevpool;
2019657Slinton 	dispose(s);
2029657Slinton 	s = t;
2039657Slinton     }
2049657Slinton     for (i = 0; i < HASHTABLESIZE; i++) {
2059657Slinton 	hashtab[i] = nil;
2069657Slinton     }
2079657Slinton     sympool = nil;
2089657Slinton     nleft = 0;
2099657Slinton }
2109657Slinton 
2119657Slinton /*
2129657Slinton  * Create a new symbol with the given attributes.
2139657Slinton  */
2149657Slinton 
2159657Slinton public Symbol newSymbol(name, blevel, class, type, chain)
2169657Slinton Name name;
2179657Slinton Integer blevel;
2189657Slinton Symclass class;
2199657Slinton Symbol type;
2209657Slinton Symbol chain;
2219657Slinton {
2229657Slinton     register Symbol s;
2239657Slinton 
2249657Slinton     s = symbol_alloc();
2259657Slinton     s->name = name;
2269657Slinton     s->level = blevel;
2279657Slinton     s->class = class;
2289657Slinton     s->type = type;
2299657Slinton     s->chain = chain;
2309657Slinton     return s;
2319657Slinton }
2329657Slinton 
2339657Slinton /*
2349657Slinton  * Insert a symbol into the hash table.
2359657Slinton  */
2369657Slinton 
2379657Slinton public Symbol insert(name)
2389657Slinton Name name;
2399657Slinton {
2409657Slinton     register Symbol s;
2419657Slinton     register unsigned int h;
2429657Slinton 
2439657Slinton     h = hash(name);
2449657Slinton     s = symbol_alloc();
2459657Slinton     s->name = name;
2469657Slinton     s->next_sym = hashtab[h];
2479657Slinton     hashtab[h] = s;
2489657Slinton     return s;
2499657Slinton }
2509657Slinton 
2519657Slinton /*
2529657Slinton  * Symbol lookup.
2539657Slinton  */
2549657Slinton 
2559657Slinton public Symbol lookup(name)
2569657Slinton Name name;
2579657Slinton {
2589657Slinton     register Symbol s;
2599657Slinton     register unsigned int h;
2609657Slinton 
2619657Slinton     h = hash(name);
2629657Slinton     s = hashtab[h];
2639657Slinton     while (s != nil and s->name != name) {
2649657Slinton 	s = s->next_sym;
2659657Slinton     }
2669657Slinton     return s;
2679657Slinton }
2689657Slinton 
2699657Slinton /*
270*16620Ssam  * Delete a symbol from the symbol table.
271*16620Ssam  */
272*16620Ssam 
273*16620Ssam public delete (s)
274*16620Ssam Symbol s;
275*16620Ssam {
276*16620Ssam     register Symbol t;
277*16620Ssam     register unsigned int h;
278*16620Ssam 
279*16620Ssam     h = hash(s->name);
280*16620Ssam     t = hashtab[h];
281*16620Ssam     if (t == nil) {
282*16620Ssam 	panic("delete of non-symbol '%s'", symname(s));
283*16620Ssam     } else if (t == s) {
284*16620Ssam 	hashtab[h] = s->next_sym;
285*16620Ssam     } else {
286*16620Ssam 	while (t->next_sym != s) {
287*16620Ssam 	    t = t->next_sym;
288*16620Ssam 	    if (t == nil) {
289*16620Ssam 		panic("delete of non-symbol '%s'", symname(s));
290*16620Ssam 	    }
291*16620Ssam 	}
292*16620Ssam 	t->next_sym = s->next_sym;
293*16620Ssam     }
294*16620Ssam }
295*16620Ssam 
296*16620Ssam /*
2979657Slinton  * Dump out all the variables associated with the given
2989657Slinton  * procedure, function, or program at the given recursive level.
2999657Slinton  *
3009657Slinton  * This is quite inefficient.  We traverse the entire symbol table
3019657Slinton  * each time we're called.  The assumption is that this routine
3029657Slinton  * won't be called frequently enough to merit improved performance.
3039657Slinton  */
3049657Slinton 
3059657Slinton public dumpvars(f, frame)
3069657Slinton Symbol f;
3079657Slinton Frame frame;
3089657Slinton {
3099657Slinton     register Integer i;
3109657Slinton     register Symbol s;
3119657Slinton 
3129657Slinton     for (i = 0; i < HASHTABLESIZE; i++) {
3139657Slinton 	for (s = hashtab[i]; s != nil; s = s->next_sym) {
3149657Slinton 	    if (container(s) == f) {
3159657Slinton 		if (should_print(s)) {
3169657Slinton 		    printv(s, frame);
3179657Slinton 		    putchar('\n');
3189657Slinton 		} else if (s->class == MODULE) {
3199657Slinton 		    dumpvars(s, frame);
3209657Slinton 		}
3219657Slinton 	    }
3229657Slinton 	}
3239657Slinton     }
3249657Slinton }
3259657Slinton 
3269657Slinton /*
3279657Slinton  * Create a builtin type.
3289657Slinton  * Builtin types are circular in that btype->type->type = btype.
3299657Slinton  */
3309657Slinton 
3319657Slinton public Symbol maketype(name, lower, upper)
3329657Slinton String name;
3339657Slinton long lower;
3349657Slinton long upper;
3359657Slinton {
3369657Slinton     register Symbol s;
3379657Slinton 
3389657Slinton     s = newSymbol(identname(name, true), 0, TYPE, nil, nil);
339*16620Ssam     s->language = primlang;
3409657Slinton     s->type = newSymbol(nil, 0, RANGE, s, nil);
341*16620Ssam     s->type->language = s->language;
3429657Slinton     s->type->symvalue.rangev.lower = lower;
3439657Slinton     s->type->symvalue.rangev.upper = upper;
3449657Slinton     return s;
3459657Slinton }
3469657Slinton 
3479657Slinton /*
3489657Slinton  * These functions are now compiled inline.
3499657Slinton  *
3509657Slinton  * public String symname(s)
3519657Slinton Symbol s;
3529657Slinton {
3539657Slinton     checkref(s);
3549657Slinton     return ident(s->name);
3559657Slinton }
3569657Slinton 
3579657Slinton  *
3589657Slinton  * public Address codeloc(f)
3599657Slinton Symbol f;
3609657Slinton {
3619657Slinton     checkref(f);
3629657Slinton     if (not isblock(f)) {
3639657Slinton 	panic("codeloc: \"%s\" is not a block", ident(f->name));
3649657Slinton     }
3659657Slinton     return f->symvalue.funcv.beginaddr;
3669657Slinton }
3679657Slinton  *
3689657Slinton  */
3699657Slinton 
3709657Slinton /*
3719657Slinton  * Reduce type to avoid worrying about type names.
3729657Slinton  */
3739657Slinton 
3749657Slinton public Symbol rtype(type)
3759657Slinton Symbol type;
3769657Slinton {
3779657Slinton     register Symbol t;
3789657Slinton 
3799657Slinton     t = type;
3809657Slinton     if (t != nil) {
38112547Scsvaf 	if (t->class == VAR or t->class == FIELD or t->class == REF ) {
3829657Slinton 	    t = t->type;
3839657Slinton 	}
384*16620Ssam 	if (t->class == TYPEREF) {
385*16620Ssam 	    resolveRef(t);
386*16620Ssam 	}
3879657Slinton 	while (t->class == TYPE or t->class == TAG) {
3889657Slinton 	    t = t->type;
389*16620Ssam 	    if (t->class == TYPEREF) {
390*16620Ssam 		resolveRef(t);
391*16620Ssam 	    }
3929657Slinton 	}
3939657Slinton     }
3949657Slinton     return t;
3959657Slinton }
3969657Slinton 
397*16620Ssam /*
398*16620Ssam  * Find the end of a module name.  Return nil if there is none
399*16620Ssam  * in the given string.
400*16620Ssam  */
401*16620Ssam 
402*16620Ssam private String findModuleMark (s)
403*16620Ssam String s;
404*16620Ssam {
405*16620Ssam     register char *p, *r;
406*16620Ssam     register boolean done;
407*16620Ssam 
408*16620Ssam     p = s;
409*16620Ssam     done = false;
410*16620Ssam     do {
411*16620Ssam 	if (*p == ':') {
412*16620Ssam 	    done = true;
413*16620Ssam 	    r = p;
414*16620Ssam 	} else if (*p == '\0') {
415*16620Ssam 	    done = true;
416*16620Ssam 	    r = nil;
417*16620Ssam 	} else {
418*16620Ssam 	    ++p;
419*16620Ssam 	}
420*16620Ssam     } while (not done);
421*16620Ssam     return r;
422*16620Ssam }
423*16620Ssam 
424*16620Ssam /*
425*16620Ssam  * Resolve a type reference by modifying to be the appropriate type.
426*16620Ssam  *
427*16620Ssam  * If the reference has a name, then it refers to an opaque type and
428*16620Ssam  * the actual type is directly accessible.  Otherwise, we must use
429*16620Ssam  * the type reference string, which is of the form "module:{module:}name".
430*16620Ssam  */
431*16620Ssam 
432*16620Ssam public resolveRef (t)
433*16620Ssam Symbol t;
434*16620Ssam {
435*16620Ssam     register char *p;
436*16620Ssam     char *start;
437*16620Ssam     Symbol s, m, outer;
438*16620Ssam     Name n;
439*16620Ssam 
440*16620Ssam     if (t->name != nil) {
441*16620Ssam 	s = t;
442*16620Ssam     } else {
443*16620Ssam 	start = t->symvalue.typeref;
444*16620Ssam 	outer = program;
445*16620Ssam 	p = findModuleMark(start);
446*16620Ssam 	while (p != nil) {
447*16620Ssam 	    *p = '\0';
448*16620Ssam 	    n = identname(start, true);
449*16620Ssam 	    find(m, n) where m->block == outer endfind(m);
450*16620Ssam 	    if (m == nil) {
451*16620Ssam 		p = nil;
452*16620Ssam 		outer = nil;
453*16620Ssam 		s = nil;
454*16620Ssam 	    } else {
455*16620Ssam 		outer = m;
456*16620Ssam 		start = p + 1;
457*16620Ssam 		p = findModuleMark(start);
458*16620Ssam 	    }
459*16620Ssam 	}
460*16620Ssam 	if (outer != nil) {
461*16620Ssam 	    n = identname(start, true);
462*16620Ssam 	    find(s, n) where s->block == outer endfind(s);
463*16620Ssam 	}
464*16620Ssam     }
465*16620Ssam     if (s != nil and s->type != nil) {
466*16620Ssam 	t->name = s->type->name;
467*16620Ssam 	t->class = s->type->class;
468*16620Ssam 	t->type = s->type->type;
469*16620Ssam 	t->chain = s->type->chain;
470*16620Ssam 	t->symvalue = s->type->symvalue;
471*16620Ssam 	t->block = s->type->block;
472*16620Ssam     }
473*16620Ssam }
474*16620Ssam 
4759657Slinton public Integer level(s)
4769657Slinton Symbol s;
4779657Slinton {
4789657Slinton     checkref(s);
4799657Slinton     return s->level;
4809657Slinton }
4819657Slinton 
4829657Slinton public Symbol container(s)
4839657Slinton Symbol s;
4849657Slinton {
4859657Slinton     checkref(s);
4869657Slinton     return s->block;
4879657Slinton }
4889657Slinton 
4899657Slinton /*
4909657Slinton  * Return the object address of the given symbol.
4919657Slinton  *
4929657Slinton  * There are the following possibilities:
4939657Slinton  *
4949657Slinton  *	globals		- just take offset
4959657Slinton  *	locals		- take offset from locals base
4969657Slinton  *	arguments	- take offset from argument base
4979657Slinton  *	register	- offset is register number
4989657Slinton  */
4999657Slinton 
500*16620Ssam #define isglobal(s)		(s->level == 1)
501*16620Ssam #define islocaloff(s)		(s->level >= 2 and s->symvalue.offset < 0)
502*16620Ssam #define isparamoff(s)		(s->level >= 2 and s->symvalue.offset >= 0)
5039657Slinton #define isreg(s)		(s->level < 0)
5049657Slinton 
5059657Slinton public Address address(s, frame)
5069657Slinton Symbol s;
5079657Slinton Frame frame;
5089657Slinton {
5099657Slinton     register Frame frp;
5109657Slinton     register Address addr;
5119657Slinton     register Symbol cur;
5129657Slinton 
5139657Slinton     checkref(s);
5149657Slinton     if (not isactive(s->block)) {
5159657Slinton 	error("\"%s\" is not currently defined", symname(s));
5169657Slinton     } else if (isglobal(s)) {
5179657Slinton 	addr = s->symvalue.offset;
5189657Slinton     } else {
5199657Slinton 	frp = frame;
5209657Slinton 	if (frp == nil) {
5219657Slinton 	    cur = s->block;
5229657Slinton 	    while (cur != nil and cur->class == MODULE) {
5239657Slinton 		cur = cur->block;
5249657Slinton 	    }
5259657Slinton 	    if (cur == nil) {
5269657Slinton 		cur = whatblock(pc);
5279657Slinton 	    }
5289657Slinton 	    frp = findframe(cur);
5299657Slinton 	    if (frp == nil) {
5309657Slinton 		panic("unexpected nil frame for \"%s\"", symname(s));
5319657Slinton 	    }
5329657Slinton 	}
5339657Slinton 	if (islocaloff(s)) {
5349657Slinton 	    addr = locals_base(frp) + s->symvalue.offset;
5359657Slinton 	} else if (isparamoff(s)) {
5369657Slinton 	    addr = args_base(frp) + s->symvalue.offset;
5379657Slinton 	} else if (isreg(s)) {
5389657Slinton 	    addr = savereg(s->symvalue.offset, frp);
5399657Slinton 	} else {
5409657Slinton 	    panic("address: bad symbol \"%s\"", symname(s));
5419657Slinton 	}
5429657Slinton     }
5439657Slinton     return addr;
5449657Slinton }
5459657Slinton 
5469657Slinton /*
5479657Slinton  * Define a symbol used to access register values.
5489657Slinton  */
5499657Slinton 
5509657Slinton public defregname(n, r)
5519657Slinton Name n;
5529657Slinton Integer r;
5539657Slinton {
5549657Slinton     register Symbol s, t;
5559657Slinton 
5569657Slinton     s = insert(n);
5579657Slinton     t = newSymbol(nil, 0, PTR, t_int, nil);
558*16620Ssam     t->language = primlang;
5599657Slinton     s->language = t->language;
5609657Slinton     s->class = VAR;
5619657Slinton     s->level = -3;
5629657Slinton     s->type = t;
5639657Slinton     s->block = program;
5649657Slinton     s->symvalue.offset = r;
5659657Slinton }
5669657Slinton 
5679657Slinton /*
5689657Slinton  * Resolve an "abstract" type reference.
5699657Slinton  *
5709657Slinton  * It is possible in C to define a pointer to a type, but never define
5719657Slinton  * the type in a particular source file.  Here we try to resolve
5729657Slinton  * the type definition.  This is problematic, it is possible to
5739657Slinton  * have multiple, different definitions for the same name type.
5749657Slinton  */
5759657Slinton 
5769657Slinton public findtype(s)
5779657Slinton Symbol s;
5789657Slinton {
5799657Slinton     register Symbol t, u, prev;
5809657Slinton 
5819657Slinton     u = s;
5829657Slinton     prev = nil;
5839657Slinton     while (u != nil and u->class != BADUSE) {
5849657Slinton 	if (u->name != nil) {
5859657Slinton 	    prev = u;
5869657Slinton 	}
5879657Slinton 	u = u->type;
5889657Slinton     }
5899657Slinton     if (prev == nil) {
5909657Slinton 	error("couldn't find link to type reference");
5919657Slinton     }
5929657Slinton     find(t, prev->name) where
593*16620Ssam 	t != prev and t->block->class == MODULE and t->class == prev->class and
594*16620Ssam 	t->type != nil and t->type->type != nil and
595*16620Ssam 	t->type->type->class != BADUSE
5969657Slinton     endfind(t);
5979657Slinton     if (t == nil) {
5989657Slinton 	error("couldn't resolve reference");
5999657Slinton     } else {
6009657Slinton 	prev->type = t->type;
6019657Slinton     }
6029657Slinton }
6039657Slinton 
6049657Slinton /*
6059657Slinton  * Find the size in bytes of the given type.
6069657Slinton  *
6079657Slinton  * This is probably the WRONG thing to do.  The size should be kept
6089657Slinton  * as an attribute in the symbol information as is done for structures
6099657Slinton  * and fields.  I haven't gotten around to cleaning this up yet.
6109657Slinton  */
6119657Slinton 
61212547Scsvaf #define MAXUCHAR 255
61312547Scsvaf #define MAXUSHORT 65535L
6149657Slinton #define MINCHAR -128
6159657Slinton #define MAXCHAR 127
6169657Slinton #define MINSHORT -32768
6179657Slinton #define MAXSHORT 32767
6189657Slinton 
619*16620Ssam /*
620*16620Ssam  * When necessary, compute the upper bound for an open array (Modula-2 style).
621*16620Ssam  */
622*16620Ssam 
623*16620Ssam public chkOpenArray (sym)
6249657Slinton Symbol sym;
6259657Slinton {
626*16620Ssam     Symbol t;
627*16620Ssam     Address a;
628*16620Ssam     integer n;
629*16620Ssam 
630*16620Ssam     if (sym->class == REF or sym->class == VAR) {
631*16620Ssam 	t = rtype(sym->type);
632*16620Ssam 	if (t->class == ARRAY and t->chain == t_open) {
633*16620Ssam 	    a = address(sym, nil);
634*16620Ssam 	    dread(&n, a + sizeof(Word), sizeof(n));
635*16620Ssam 	    t->chain->type->symvalue.rangev.upper = n - 1;
636*16620Ssam 	}
637*16620Ssam     }
638*16620Ssam }
639*16620Ssam 
640*16620Ssam public findbounds (u, lower, upper)
641*16620Ssam Symbol u;
642*16620Ssam long *lower, *upper;
643*16620Ssam {
644*16620Ssam     Rangetype lbt, ubt;
645*16620Ssam     long lb, ub;
646*16620Ssam 
647*16620Ssam     if (u->class == RANGE) {
648*16620Ssam 	lbt = u->symvalue.rangev.lowertype;
649*16620Ssam 	ubt = u->symvalue.rangev.uppertype;
650*16620Ssam 	lb = u->symvalue.rangev.lower;
651*16620Ssam 	ub = u->symvalue.rangev.upper;
652*16620Ssam 	if (lbt == R_ARG or lbt == R_TEMP) {
653*16620Ssam 	    if (not getbound(u, lb, lbt, lower)) {
654*16620Ssam 		error("dynamic bounds not currently available");
655*16620Ssam 	    }
656*16620Ssam 	} else {
657*16620Ssam 	    *lower = lb;
658*16620Ssam 	}
659*16620Ssam 	if (ubt == R_ARG or ubt == R_TEMP) {
660*16620Ssam 	    if (not getbound(u, ub, ubt, upper)) {
661*16620Ssam 		error("dynamic bounds not currently available");
662*16620Ssam 	    }
663*16620Ssam 	} else {
664*16620Ssam 	    *upper = ub;
665*16620Ssam 	}
666*16620Ssam     } else if (u->class == SCAL) {
667*16620Ssam 	*lower = 0;
668*16620Ssam 	*upper = u->symvalue.iconval - 1;
669*16620Ssam     } else {
670*16620Ssam 	panic("unexpected array bound type");
671*16620Ssam     }
672*16620Ssam }
673*16620Ssam 
674*16620Ssam public integer size(sym)
675*16620Ssam Symbol sym;
676*16620Ssam {
677*16620Ssam     register Symbol s, t, u;
678*16620Ssam     register integer nel, elsize;
6799657Slinton     long lower, upper;
680*16620Ssam     integer r, off, len;
6819657Slinton 
6829657Slinton     t = sym;
6839657Slinton     checkref(t);
684*16620Ssam     if (t->class == TYPEREF) {
685*16620Ssam 	resolveRef(t);
686*16620Ssam     }
6879657Slinton     switch (t->class) {
6889657Slinton 	case RANGE:
6899657Slinton 	    lower = t->symvalue.rangev.lower;
6909657Slinton 	    upper = t->symvalue.rangev.upper;
691*16620Ssam 	    if (upper == 0 and lower > 0) {
692*16620Ssam 		/* real */
6939657Slinton 		r = lower;
694*16620Ssam 	    } else if (lower > upper) {
695*16620Ssam 		/* unsigned long */
696*16620Ssam 		r = sizeof(long);
69712045Slinton 	    } else if (
69812547Scsvaf   		(lower >= MINCHAR and upper <= MAXCHAR) or
69912547Scsvaf   		(lower >= 0 and upper <= MAXUCHAR)
70012547Scsvaf   	      ) {
7019657Slinton 		r = sizeof(char);
70212547Scsvaf   	    } else if (
70312547Scsvaf   		(lower >= MINSHORT and upper <= MAXSHORT) or
70412547Scsvaf   		(lower >= 0 and upper <= MAXUSHORT)
70512547Scsvaf   	      ) {
7069657Slinton 		r = sizeof(short);
7079657Slinton 	    } else {
7089657Slinton 		r = sizeof(long);
7099657Slinton 	    }
7109657Slinton 	    break;
7119657Slinton 
7129657Slinton 	case ARRAY:
7139657Slinton 	    elsize = size(t->type);
7149657Slinton 	    nel = 1;
7159657Slinton 	    for (t = t->chain; t != nil; t = t->chain) {
716*16620Ssam 		u = rtype(t);
717*16620Ssam 		findbounds(u, &lower, &upper);
7189657Slinton 		nel *= (upper-lower+1);
7199657Slinton 	    }
7209657Slinton 	    r = nel*elsize;
7219657Slinton 	    break;
7229657Slinton 
72312547Scsvaf 	case REF:
7249657Slinton 	case VAR:
7259657Slinton 	case FVAR:
726*16620Ssam 	    chkOpenArray(t);
7279657Slinton 	    r = size(t->type);
72812127Slinton 	    /*
72912127Slinton 	     *
73012045Slinton 	    if (r < sizeof(Word) and isparam(t)) {
7319657Slinton 		r = sizeof(Word);
7329657Slinton 	    }
73312547Scsvaf 	    */
7349657Slinton 	    break;
7359657Slinton 
7369657Slinton 	case CONST:
7379657Slinton 	    r = size(t->type);
7389657Slinton 	    break;
7399657Slinton 
7409657Slinton 	case TYPE:
7419657Slinton 	    if (t->type->class == PTR and t->type->type->class == BADUSE) {
7429657Slinton 		findtype(t);
7439657Slinton 	    }
7449657Slinton 	    r = size(t->type);
7459657Slinton 	    break;
7469657Slinton 
7479657Slinton 	case TAG:
7489657Slinton 	    r = size(t->type);
7499657Slinton 	    break;
7509657Slinton 
7519657Slinton 	case FIELD:
752*16620Ssam 	    off = t->symvalue.field.offset;
753*16620Ssam 	    len = t->symvalue.field.length;
754*16620Ssam 	    r = (off + len + 7) div 8 - (off div 8);
755*16620Ssam 	    /* r = (t->symvalue.field.length + 7) div 8; */
7569657Slinton 	    break;
7579657Slinton 
7589657Slinton 	case RECORD:
7599657Slinton 	case VARNT:
7609657Slinton 	    r = t->symvalue.offset;
7619657Slinton 	    if (r == 0 and t->chain != nil) {
7629657Slinton 		panic("missing size information for record");
7639657Slinton 	    }
7649657Slinton 	    break;
7659657Slinton 
7669657Slinton 	case PTR:
7679657Slinton 	case FILET:
7689657Slinton 	    r = sizeof(Word);
7699657Slinton 	    break;
7709657Slinton 
7719657Slinton 	case SCAL:
77212609Slinton 	    r = sizeof(Word);
77312609Slinton 	    /*
77412609Slinton 	     *
7759657Slinton 	    if (t->symvalue.iconval > 255) {
7769657Slinton 		r = sizeof(short);
7779657Slinton 	    } else {
7789657Slinton 		r = sizeof(char);
7799657Slinton 	    }
78012609Slinton 	     *
78112609Slinton 	     */
7829657Slinton 	    break;
7839657Slinton 
7849657Slinton 	case FPROC:
7859657Slinton 	case FFUNC:
7869657Slinton 	    r = sizeof(Word);
7879657Slinton 	    break;
7889657Slinton 
7899657Slinton 	case PROC:
7909657Slinton 	case FUNC:
7919657Slinton 	case MODULE:
7929657Slinton 	case PROG:
7939657Slinton 	    r = sizeof(Symbol);
7949657Slinton 	    break;
7959657Slinton 
796*16620Ssam 	case SET:
797*16620Ssam 	    u = rtype(t->type);
798*16620Ssam 	    switch (u->class) {
799*16620Ssam 		case RANGE:
800*16620Ssam 		    r = u->symvalue.rangev.upper - u->symvalue.rangev.lower + 1;
801*16620Ssam 		    break;
802*16620Ssam 
803*16620Ssam 		case SCAL:
804*16620Ssam 		    r = u->symvalue.iconval;
805*16620Ssam 		    break;
806*16620Ssam 
807*16620Ssam 		default:
808*16620Ssam 		    error("expected range for set base type");
809*16620Ssam 		    break;
810*16620Ssam 	    }
811*16620Ssam 	    r = (r + BITSPERBYTE - 1) div BITSPERBYTE;
812*16620Ssam 	    break;
813*16620Ssam 
8149657Slinton 	default:
8159657Slinton 	    if (ord(t->class) > ord(TYPEREF)) {
8169657Slinton 		panic("size: bad class (%d)", ord(t->class));
8179657Slinton 	    } else {
818*16620Ssam 		fprintf(stderr, "!! size(%s) ??", classname(t));
8199657Slinton 	    }
820*16620Ssam 	    r = 0;
821*16620Ssam 	    break;
8229657Slinton     }
8239657Slinton     return r;
8249657Slinton }
8259657Slinton 
8269657Slinton /*
8279657Slinton  * Test if a symbol is a parameter.  This is true if there
8289657Slinton  * is a cycle from s->block to s via chain pointers.
8299657Slinton  */
8309657Slinton 
8319657Slinton public Boolean isparam(s)
8329657Slinton Symbol s;
8339657Slinton {
8349657Slinton     register Symbol t;
8359657Slinton 
8369657Slinton     t = s->block;
8379657Slinton     while (t != nil and t != s) {
8389657Slinton 	t = t->chain;
8399657Slinton     }
8409657Slinton     return (Boolean) (t != nil);
8419657Slinton }
8429657Slinton 
8439657Slinton /*
844*16620Ssam  * Test if a type is an open array parameter type.
8459657Slinton  */
8469657Slinton 
847*16620Ssam public Boolean isopenarray (t)
848*16620Ssam Symbol t;
849*16620Ssam {
850*16620Ssam     return (Boolean) (t->class == ARRAY and t->chain == t_open);
851*16620Ssam }
852*16620Ssam 
853*16620Ssam /*
854*16620Ssam  * Test if a symbol is a var parameter, i.e. has class REF but
855*16620Ssam  * is not an open array parameter (those are treated special).
856*16620Ssam  */
857*16620Ssam 
8589657Slinton public Boolean isvarparam(s)
8599657Slinton Symbol s;
8609657Slinton {
8619657Slinton     return (Boolean) (s->class == REF);
8629657Slinton }
8639657Slinton 
8649657Slinton /*
8659657Slinton  * Test if a symbol is a variable (actually any addressible quantity
8669657Slinton  * with do).
8679657Slinton  */
8689657Slinton 
8699657Slinton public Boolean isvariable(s)
8709657Slinton register Symbol s;
8719657Slinton {
8729657Slinton     return (Boolean) (s->class == VAR or s->class == FVAR or s->class == REF);
8739657Slinton }
8749657Slinton 
8759657Slinton /*
8769657Slinton  * Test if a symbol is a block, e.g. function, procedure, or the
8779657Slinton  * main program.
8789657Slinton  *
8799657Slinton  * This function is now expanded inline for efficiency.
8809657Slinton  *
8819657Slinton  * public Boolean isblock(s)
8829657Slinton register Symbol s;
8839657Slinton {
8849657Slinton     return (Boolean) (
8859657Slinton 	s->class == FUNC or s->class == PROC or
8869657Slinton 	s->class == MODULE or s->class == PROG
8879657Slinton     );
8889657Slinton }
8899657Slinton  *
8909657Slinton  */
8919657Slinton 
8929657Slinton /*
8939657Slinton  * Test if a symbol is a module.
8949657Slinton  */
8959657Slinton 
8969657Slinton public Boolean ismodule(s)
8979657Slinton register Symbol s;
8989657Slinton {
8999657Slinton     return (Boolean) (s->class == MODULE);
9009657Slinton }
9019657Slinton 
9029657Slinton /*
9039657Slinton  * Test if a symbol is builtin, that is, a predefined type or
9049657Slinton  * reserved word.
9059657Slinton  */
9069657Slinton 
9079657Slinton public Boolean isbuiltin(s)
9089657Slinton register Symbol s;
9099657Slinton {
9109657Slinton     return (Boolean) (s->level == 0 and s->class != PROG and s->class != VAR);
9119657Slinton }
9129657Slinton 
9139657Slinton /*
914*16620Ssam  * Mark a procedure or function as internal, meaning that it is called
915*16620Ssam  * with a different calling sequence.
916*16620Ssam  */
917*16620Ssam 
918*16620Ssam public markInternal (s)
919*16620Ssam Symbol s;
920*16620Ssam {
921*16620Ssam     s->symvalue.funcv.intern = true;
922*16620Ssam }
923*16620Ssam 
924*16620Ssam public boolean isinternal (s)
925*16620Ssam Symbol s;
926*16620Ssam {
927*16620Ssam     return s->symvalue.funcv.intern;
928*16620Ssam }
929*16620Ssam 
930*16620Ssam /*
9319657Slinton  * Test if two types match.
9329657Slinton  * Equivalent names implies a match in any language.
9339657Slinton  *
9349657Slinton  * Special symbols must be handled with care.
9359657Slinton  */
9369657Slinton 
9379657Slinton public Boolean compatible(t1, t2)
9389657Slinton register Symbol t1, t2;
9399657Slinton {
9409657Slinton     Boolean b;
941*16620Ssam     Symbol rt1, rt2;
9429657Slinton 
9439657Slinton     if (t1 == t2) {
9449657Slinton 	b = true;
9459657Slinton     } else if (t1 == nil or t2 == nil) {
9469657Slinton 	b = false;
9479657Slinton     } else if (t1 == procsym) {
9489657Slinton 	b = isblock(t2);
9499657Slinton     } else if (t2 == procsym) {
9509657Slinton 	b = isblock(t1);
951*16620Ssam     } else if (t1->language == primlang) {
952*16620Ssam 	if (t2->language == primlang) {
953*16620Ssam 	    rt1 = rtype(t1);
954*16620Ssam 	    rt2 = rtype(t2);
955*16620Ssam 	    b = (boolean) (
956*16620Ssam 		(rt1->type == t_open and rt2->type == t_int) or
957*16620Ssam 		(rt2->type == t_open and rt1->type == t_int) or
958*16620Ssam 		rt1 == rt2
959*16620Ssam 	    );
960*16620Ssam 	} else {
961*16620Ssam 	    b = (boolean) (*language_op(t2->language, L_TYPEMATCH))(t1, t2);
962*16620Ssam 	}
963*16620Ssam     } else if (t2->language == primlang) {
964*16620Ssam 	b = (boolean) (*language_op(t1->language, L_TYPEMATCH))(t1, t2);
9659657Slinton     } else if (t1->language == nil) {
966*16620Ssam 	if (t2->language == nil) {
967*16620Ssam 	    b = false;
968*16620Ssam 	} else {
969*16620Ssam 	    b = (boolean) (*language_op(t2->language, L_TYPEMATCH))(t1, t2);
970*16620Ssam 	}
97112547Scsvaf     } else if (t2->language == nil) {
972*16620Ssam 	b = (boolean) (*language_op(t1->language, L_TYPEMATCH))(t1, t2);
973*16620Ssam     } else if (isbuiltin(t1) or isbuiltin(t1->type)) {
974*16620Ssam 	b = (boolean) (*language_op(t2->language, L_TYPEMATCH))(t1, t2);
9759657Slinton     } else {
976*16620Ssam 	b = (boolean) (*language_op(t1->language, L_TYPEMATCH))(t1, t2);
9779657Slinton     }
9789657Slinton     return b;
9799657Slinton }
9809657Slinton 
9819657Slinton /*
9829657Slinton  * Check for a type of the given name.
9839657Slinton  */
9849657Slinton 
9859657Slinton public Boolean istypename(type, name)
9869657Slinton Symbol type;
9879657Slinton String name;
9889657Slinton {
9899657Slinton     Symbol t;
9909657Slinton     Boolean b;
9919657Slinton 
9929657Slinton     t = type;
9939657Slinton     checkref(t);
9949657Slinton     b = (Boolean) (
995*16620Ssam 	t->class == TYPE and streq(ident(t->name), name)
9969657Slinton     );
9979657Slinton     return b;
9989657Slinton }
9999657Slinton 
10009657Slinton /*
1001*16620Ssam  * Determine if a (value) parameter should actually be passed by address.
1002*16620Ssam  */
1003*16620Ssam 
1004*16620Ssam public boolean passaddr (p, exprtype)
1005*16620Ssam Symbol p, exprtype;
1006*16620Ssam {
1007*16620Ssam     boolean b;
1008*16620Ssam     Language def;
1009*16620Ssam 
1010*16620Ssam     if (p == nil) {
1011*16620Ssam 	def = findlanguage(".c");
1012*16620Ssam 	b = (boolean) (*language_op(def, L_PASSADDR))(p, exprtype);
1013*16620Ssam     } else if (p->language == nil or p->language == primlang) {
1014*16620Ssam 	b = false;
1015*16620Ssam     } else if (isopenarray(p->type)) {
1016*16620Ssam 	b = true;
1017*16620Ssam     } else {
1018*16620Ssam 	b = (boolean) (*language_op(p->language, L_PASSADDR))(p, exprtype);
1019*16620Ssam     }
1020*16620Ssam     return b;
1021*16620Ssam }
1022*16620Ssam 
1023*16620Ssam /*
10249657Slinton  * Test if the name of a symbol is uniquely defined or not.
10259657Slinton  */
10269657Slinton 
10279657Slinton public Boolean isambiguous(s)
10289657Slinton register Symbol s;
10299657Slinton {
10309657Slinton     register Symbol t;
10319657Slinton 
10329657Slinton     find(t, s->name) where t != s endfind(t);
10339657Slinton     return (Boolean) (t != nil);
10349657Slinton }
10359657Slinton 
10369657Slinton typedef char *Arglist;
10379657Slinton 
10389657Slinton #define nextarg(type)  ((type *) (ap += sizeof(type)))[-1]
10399657Slinton 
10409657Slinton private Symbol mkstring();
10419657Slinton private Symbol namenode();
10429657Slinton 
10439657Slinton /*
10449657Slinton  * Determine the type of a parse tree.
10459657Slinton  * Also make some symbol-dependent changes to the tree such as
10469657Slinton  * changing removing RVAL nodes for constant symbols.
10479657Slinton  */
10489657Slinton 
10499657Slinton public assigntypes(p)
10509657Slinton register Node p;
10519657Slinton {
10529657Slinton     register Node p1;
10539657Slinton     register Symbol s;
10549657Slinton 
10559657Slinton     switch (p->op) {
10569657Slinton 	case O_SYM:
10579657Slinton 	    p->nodetype = namenode(p);
10589657Slinton 	    break;
10599657Slinton 
10609657Slinton 	case O_LCON:
10619657Slinton 	    p->nodetype = t_int;
10629657Slinton 	    break;
10639657Slinton 
10649657Slinton 	case O_FCON:
10659657Slinton 	    p->nodetype = t_real;
10669657Slinton 	    break;
10679657Slinton 
10689657Slinton 	case O_SCON:
10699657Slinton 	    p->value.scon = strdup(p->value.scon);
10709657Slinton 	    s = mkstring(p->value.scon);
10719657Slinton 	    if (s == t_char) {
10729657Slinton 		p->op = O_LCON;
10739657Slinton 		p->value.lcon = p->value.scon[0];
10749657Slinton 	    }
10759657Slinton 	    p->nodetype = s;
10769657Slinton 	    break;
10779657Slinton 
10789657Slinton 	case O_INDIR:
10799657Slinton 	    p1 = p->value.arg[0];
10809657Slinton 	    chkclass(p1, PTR);
10819657Slinton 	    p->nodetype = rtype(p1->nodetype)->type;
10829657Slinton 	    break;
10839657Slinton 
10849657Slinton 	case O_DOT:
10859657Slinton 	    p->nodetype = p->value.arg[1]->value.sym;
10869657Slinton 	    break;
10879657Slinton 
10889657Slinton 	case O_RVAL:
10899657Slinton 	    p1 = p->value.arg[0];
10909657Slinton 	    p->nodetype = p1->nodetype;
10919657Slinton 	    if (p1->op == O_SYM) {
10929657Slinton 		if (p1->nodetype->class == FUNC) {
10939657Slinton 		    p->op = O_CALL;
10949657Slinton 		    p->value.arg[1] = nil;
10959657Slinton 		} else if (p1->value.sym->class == CONST) {
10969657Slinton 		    if (compatible(p1->value.sym->type, t_real)) {
10979657Slinton 			p->op = O_FCON;
10989657Slinton 			p->value.fcon = p1->value.sym->symvalue.fconval;
10999657Slinton 			p->nodetype = t_real;
11009657Slinton 			dispose(p1);
11019657Slinton 		    } else {
11029657Slinton 			p->op = O_LCON;
11039657Slinton 			p->value.lcon = p1->value.sym->symvalue.iconval;
11049657Slinton 			p->nodetype = p1->value.sym->type;
11059657Slinton 			dispose(p1);
11069657Slinton 		    }
11079657Slinton 		} else if (isreg(p1->value.sym)) {
11089657Slinton 		    p->op = O_SYM;
11099657Slinton 		    p->value.sym = p1->value.sym;
11109657Slinton 		    dispose(p1);
11119657Slinton 		}
11129657Slinton 	    } else if (p1->op == O_INDIR and p1->value.arg[0]->op == O_SYM) {
11139657Slinton 		s = p1->value.arg[0]->value.sym;
11149657Slinton 		if (isreg(s)) {
11159657Slinton 		    p1->op = O_SYM;
11169657Slinton 		    dispose(p1->value.arg[0]);
11179657Slinton 		    p1->value.sym = s;
11189657Slinton 		    p1->nodetype = s;
11199657Slinton 		}
11209657Slinton 	    }
11219657Slinton 	    break;
11229657Slinton 
1123*16620Ssam 	/*
1124*16620Ssam 	 * Perform a cast if the call is of the form "type(expr)".
1125*16620Ssam 	 */
11269657Slinton 	case O_CALL:
11279657Slinton 	    p1 = p->value.arg[0];
112811171Slinton 	    p->nodetype = rtype(p1->nodetype)->type;
11299657Slinton 	    break;
11309657Slinton 
113111171Slinton 	case O_TYPERENAME:
113211171Slinton 	    p->nodetype = p->value.arg[1]->nodetype;
113311171Slinton 	    break;
113411171Slinton 
11359657Slinton 	case O_ITOF:
11369657Slinton 	    p->nodetype = t_real;
11379657Slinton 	    break;
11389657Slinton 
11399657Slinton 	case O_NEG:
11409657Slinton 	    s = p->value.arg[0]->nodetype;
11419657Slinton 	    if (not compatible(s, t_int)) {
11429657Slinton 		if (not compatible(s, t_real)) {
11439657Slinton 		    beginerrmsg();
1144*16620Ssam 		    fprintf(stderr, "\"");
11459657Slinton 		    prtree(stderr, p->value.arg[0]);
1146*16620Ssam 		    fprintf(stderr, "\" is improper type");
11479657Slinton 		    enderrmsg();
11489657Slinton 		} else {
11499657Slinton 		    p->op = O_NEGF;
11509657Slinton 		}
11519657Slinton 	    }
11529657Slinton 	    p->nodetype = s;
11539657Slinton 	    break;
11549657Slinton 
11559657Slinton 	case O_ADD:
11569657Slinton 	case O_SUB:
11579657Slinton 	case O_MUL:
1158*16620Ssam 	    binaryop(p, nil);
1159*16620Ssam 	    break;
1160*16620Ssam 
11619657Slinton 	case O_LT:
11629657Slinton 	case O_LE:
11639657Slinton 	case O_GT:
11649657Slinton 	case O_GE:
11659657Slinton 	case O_EQ:
11669657Slinton 	case O_NE:
1167*16620Ssam 	    binaryop(p, t_boolean);
11689657Slinton 	    break;
11699657Slinton 
11709657Slinton 	case O_DIVF:
11719657Slinton 	    convert(&(p->value.arg[0]), t_real, O_ITOF);
11729657Slinton 	    convert(&(p->value.arg[1]), t_real, O_ITOF);
11739657Slinton 	    p->nodetype = t_real;
11749657Slinton 	    break;
11759657Slinton 
11769657Slinton 	case O_DIV:
11779657Slinton 	case O_MOD:
11789657Slinton 	    convert(&(p->value.arg[0]), t_int, O_NOP);
11799657Slinton 	    convert(&(p->value.arg[1]), t_int, O_NOP);
11809657Slinton 	    p->nodetype = t_int;
11819657Slinton 	    break;
11829657Slinton 
11839657Slinton 	case O_AND:
11849657Slinton 	case O_OR:
11859657Slinton 	    chkboolean(p->value.arg[0]);
11869657Slinton 	    chkboolean(p->value.arg[1]);
11879657Slinton 	    p->nodetype = t_boolean;
11889657Slinton 	    break;
11899657Slinton 
11909657Slinton 	case O_QLINE:
11919657Slinton 	    p->nodetype = t_int;
11929657Slinton 	    break;
11939657Slinton 
11949657Slinton 	default:
11959657Slinton 	    p->nodetype = nil;
11969657Slinton 	    break;
11979657Slinton     }
11989657Slinton }
11999657Slinton 
12009657Slinton /*
1201*16620Ssam  * Process a binary arithmetic or relational operator.
1202*16620Ssam  * Convert from integer to real if necessary.
1203*16620Ssam  */
1204*16620Ssam 
1205*16620Ssam private binaryop (p, t)
1206*16620Ssam Node p;
1207*16620Ssam Symbol t;
1208*16620Ssam {
1209*16620Ssam     Node p1, p2;
1210*16620Ssam     Boolean t1real, t2real;
1211*16620Ssam     Symbol t1, t2;
1212*16620Ssam 
1213*16620Ssam     p1 = p->value.arg[0];
1214*16620Ssam     p2 = p->value.arg[1];
1215*16620Ssam     t1 = rtype(p1->nodetype);
1216*16620Ssam     t2 = rtype(p2->nodetype);
1217*16620Ssam     t1real = compatible(t1, t_real);
1218*16620Ssam     t2real = compatible(t2, t_real);
1219*16620Ssam     if (t1real or t2real) {
1220*16620Ssam 	p->op = (Operator) (ord(p->op) + 1);
1221*16620Ssam 	if (not t1real) {
1222*16620Ssam 	    p->value.arg[0] = build(O_ITOF, p1);
1223*16620Ssam 	} else if (not t2real) {
1224*16620Ssam 	    p->value.arg[1] = build(O_ITOF, p2);
1225*16620Ssam 	}
1226*16620Ssam 	p->nodetype = t_real;
1227*16620Ssam     } else {
1228*16620Ssam 	if (size(p1->nodetype) > sizeof(integer)) {
1229*16620Ssam 	    beginerrmsg();
1230*16620Ssam 	    fprintf(stderr, "operation not defined on \"");
1231*16620Ssam 	    prtree(stderr, p1);
1232*16620Ssam 	    fprintf(stderr, "\"");
1233*16620Ssam 	    enderrmsg();
1234*16620Ssam 	} else if (size(p2->nodetype) > sizeof(integer)) {
1235*16620Ssam 	    beginerrmsg();
1236*16620Ssam 	    fprintf(stderr, "operation not defined on \"");
1237*16620Ssam 	    prtree(stderr, p2);
1238*16620Ssam 	    fprintf(stderr, "\"");
1239*16620Ssam 	    enderrmsg();
1240*16620Ssam 	}
1241*16620Ssam 	p->nodetype = t_int;
1242*16620Ssam     }
1243*16620Ssam     if (t != nil) {
1244*16620Ssam 	p->nodetype = t;
1245*16620Ssam     }
1246*16620Ssam }
1247*16620Ssam 
1248*16620Ssam /*
12499657Slinton  * Create a node for a name.  The symbol for the name has already
12509657Slinton  * been chosen, either implicitly with "which" or explicitly from
12519657Slinton  * the dot routine.
12529657Slinton  */
12539657Slinton 
12549657Slinton private Symbol namenode(p)
12559657Slinton Node p;
12569657Slinton {
12579657Slinton     register Symbol r, s;
12589657Slinton     register Node np;
12599657Slinton 
12609657Slinton     s = p->value.sym;
12619657Slinton     if (s->class == REF) {
12629657Slinton 	np = new(Node);
12639657Slinton 	np->op = p->op;
12649657Slinton 	np->nodetype = s;
12659657Slinton 	np->value.sym = s;
12669657Slinton 	p->op = O_INDIR;
12679657Slinton 	p->value.arg[0] = np;
12689657Slinton     }
12699657Slinton /*
12709657Slinton  * Old way
12719657Slinton  *
12729657Slinton     if (s->class == CONST or s->class == VAR or s->class == FVAR) {
12739657Slinton 	r = s->type;
12749657Slinton     } else {
12759657Slinton 	r = s;
12769657Slinton     }
12779657Slinton  *
12789657Slinton  */
12799657Slinton     return s;
12809657Slinton }
12819657Slinton 
12829657Slinton /*
12839657Slinton  * Convert a tree to a type via a conversion operator;
12849657Slinton  * if this isn't possible generate an error.
12859657Slinton  *
12869657Slinton  * Note the tree is call by address, hence the #define below.
12879657Slinton  */
12889657Slinton 
12899657Slinton private convert(tp, typeto, op)
12909657Slinton Node *tp;
12919657Slinton Symbol typeto;
12929657Slinton Operator op;
12939657Slinton {
1294*16620Ssam     Node tree;
1295*16620Ssam     Symbol s, t;
12969657Slinton 
1297*16620Ssam     tree = *tp;
12989657Slinton     s = rtype(tree->nodetype);
1299*16620Ssam     t = rtype(typeto);
1300*16620Ssam     if (compatible(t, t_real) and compatible(s, t_int)) {
13019657Slinton 	tree = build(op, tree);
1302*16620Ssam     } else if (not compatible(s, t)) {
13039657Slinton 	beginerrmsg();
1304*16620Ssam 	fprintf(stderr, "expected integer or real, found \"");
1305*16620Ssam 	prtree(stderr, tree);
1306*16620Ssam 	fprintf(stderr, "\"");
13079657Slinton 	enderrmsg();
1308*16620Ssam     } else if (op != O_NOP and s != t) {
13099657Slinton 	tree = build(op, tree);
13109657Slinton     }
1311*16620Ssam     *tp = tree;
13129657Slinton }
13139657Slinton 
13149657Slinton /*
13159657Slinton  * Construct a node for the dot operator.
13169657Slinton  *
13179657Slinton  * If the left operand is not a record, but rather a procedure
13189657Slinton  * or function, then we interpret the "." as referencing an
13199657Slinton  * "invisible" variable; i.e. a variable within a dynamically
13209657Slinton  * active block but not within the static scope of the current procedure.
13219657Slinton  */
13229657Slinton 
13239657Slinton public Node dot(record, fieldname)
13249657Slinton Node record;
13259657Slinton Name fieldname;
13269657Slinton {
13279657Slinton     register Node p;
13289657Slinton     register Symbol s, t;
13299657Slinton 
13309657Slinton     if (isblock(record->nodetype)) {
13319657Slinton 	find(s, fieldname) where
13329657Slinton 	    s->block == record->nodetype and
13339657Slinton 	    s->class != FIELD and s->class != TAG
13349657Slinton 	endfind(s);
13359657Slinton 	if (s == nil) {
13369657Slinton 	    beginerrmsg();
13379657Slinton 	    fprintf(stderr, "\"%s\" is not defined in ", ident(fieldname));
13389657Slinton 	    printname(stderr, record->nodetype);
13399657Slinton 	    enderrmsg();
13409657Slinton 	}
13419657Slinton 	p = new(Node);
13429657Slinton 	p->op = O_SYM;
13439657Slinton 	p->value.sym = s;
13449657Slinton 	p->nodetype = namenode(p);
13459657Slinton     } else {
13469657Slinton 	p = record;
13479657Slinton 	t = rtype(p->nodetype);
13489657Slinton 	if (t->class == PTR) {
13499657Slinton 	    s = findfield(fieldname, t->type);
13509657Slinton 	} else {
13519657Slinton 	    s = findfield(fieldname, t);
13529657Slinton 	}
13539657Slinton 	if (s == nil) {
13549657Slinton 	    beginerrmsg();
13559657Slinton 	    fprintf(stderr, "\"%s\" is not a field in ", ident(fieldname));
13569657Slinton 	    prtree(stderr, record);
13579657Slinton 	    enderrmsg();
13589657Slinton 	}
13599657Slinton 	if (t->class == PTR and not isreg(record->nodetype)) {
13609657Slinton 	    p = build(O_INDIR, record);
13619657Slinton 	}
13629657Slinton 	p = build(O_DOT, p, build(O_SYM, s));
13639657Slinton     }
13649657Slinton     return p;
13659657Slinton }
13669657Slinton 
13679657Slinton /*
13689657Slinton  * Return a tree corresponding to an array reference and do the
13699657Slinton  * error checking.
13709657Slinton  */
13719657Slinton 
13729657Slinton public Node subscript(a, slist)
13739657Slinton Node a, slist;
13749657Slinton {
1375*16620Ssam     Symbol t;
13769657Slinton 
1377*16620Ssam     t = rtype(a->nodetype);
1378*16620Ssam     if (t->language == nil) {
137912547Scsvaf 	error("unknown language");
1380*16620Ssam     } else {
1381*16620Ssam 	return (Node) (*language_op(t->language, L_BUILDAREF))(a, slist);
1382*16620Ssam     }
13839657Slinton }
13849657Slinton 
13859657Slinton /*
13869657Slinton  * Evaluate a subscript index.
13879657Slinton  */
13889657Slinton 
13899657Slinton public int evalindex(s, i)
13909657Slinton Symbol s;
13919657Slinton long i;
13929657Slinton {
1393*16620Ssam     Symbol t;
13949657Slinton 
1395*16620Ssam     t = rtype(s);
1396*16620Ssam     if (t->language == nil) {
139712547Scsvaf 	error("unknown language");
1398*16620Ssam     } else {
1399*16620Ssam 	return ((*language_op(t->language, L_EVALAREF)) (s, i));
1400*16620Ssam     }
14019657Slinton }
14029657Slinton 
14039657Slinton /*
14049657Slinton  * Check to see if a tree is boolean-valued, if not it's an error.
14059657Slinton  */
14069657Slinton 
14079657Slinton public chkboolean(p)
14089657Slinton register Node p;
14099657Slinton {
14109657Slinton     if (p->nodetype != t_boolean) {
14119657Slinton 	beginerrmsg();
14129657Slinton 	fprintf(stderr, "found ");
14139657Slinton 	prtree(stderr, p);
14149657Slinton 	fprintf(stderr, ", expected boolean expression");
14159657Slinton 	enderrmsg();
14169657Slinton     }
14179657Slinton }
14189657Slinton 
14199657Slinton /*
14209657Slinton  * Check to make sure the given tree has a type of the given class.
14219657Slinton  */
14229657Slinton 
14239657Slinton private chkclass(p, class)
14249657Slinton Node p;
14259657Slinton Symclass class;
14269657Slinton {
14279657Slinton     struct Symbol tmpsym;
14289657Slinton 
14299657Slinton     tmpsym.class = class;
14309657Slinton     if (rtype(p->nodetype)->class != class) {
14319657Slinton 	beginerrmsg();
14329657Slinton 	fprintf(stderr, "\"");
14339657Slinton 	prtree(stderr, p);
14349657Slinton 	fprintf(stderr, "\" is not a %s", classname(&tmpsym));
14359657Slinton 	enderrmsg();
14369657Slinton     }
14379657Slinton }
14389657Slinton 
14399657Slinton /*
1440*16620Ssam  * Construct a node for the type of a string.
14419657Slinton  */
14429657Slinton 
14439657Slinton private Symbol mkstring(str)
14449657Slinton String str;
14459657Slinton {
14469657Slinton     register char *p, *q;
14479657Slinton     register Symbol s;
1448*16620Ssam     integer len;
14499657Slinton 
14509657Slinton     p = str;
14519657Slinton     q = str;
14529657Slinton     while (*p != '\0') {
14539657Slinton 	if (*p == '\\') {
14549657Slinton 	    ++p;
14559657Slinton 	}
14569657Slinton 	*q = *p;
14579657Slinton 	++p;
14589657Slinton 	++q;
14599657Slinton     }
14609657Slinton     *q = '\0';
1461*16620Ssam     len = p - str;
1462*16620Ssam     if (len == 1) {
1463*16620Ssam 	s = t_char;
1464*16620Ssam     } else {
1465*16620Ssam 	s = newSymbol(nil, 0, ARRAY, t_char, nil);
1466*16620Ssam 	s->language = primlang;
1467*16620Ssam 	s->chain = newSymbol(nil, 0, RANGE, t_int, nil);
1468*16620Ssam 	s->chain->language = s->language;
1469*16620Ssam 	s->chain->symvalue.rangev.lower = 1;
1470*16620Ssam 	s->chain->symvalue.rangev.upper = len + 1;
1471*16620Ssam     }
14729657Slinton     return s;
14739657Slinton }
14749657Slinton 
14759657Slinton /*
14769657Slinton  * Free up the space allocated for a string type.
14779657Slinton  */
14789657Slinton 
14799657Slinton public unmkstring(s)
14809657Slinton Symbol s;
14819657Slinton {
14829657Slinton     dispose(s->chain);
14839657Slinton }
14849657Slinton 
14859657Slinton /*
14869657Slinton  * Figure out the "current" variable or function being referred to,
14879657Slinton  * this is either the active one or the most visible from the
14889657Slinton  * current scope.
14899657Slinton  */
14909657Slinton 
14919657Slinton public Symbol which(n)
14929657Slinton Name n;
14939657Slinton {
14949657Slinton     register Symbol s, p, t, f;
14959657Slinton 
1496*16620Ssam     find(s, n) where s->class != FIELD and s->class != TAG endfind(s);
14979657Slinton     if (s == nil) {
14989657Slinton 	s = lookup(n);
14999657Slinton     }
15009657Slinton     if (s == nil) {
15019657Slinton 	error("\"%s\" is not defined", ident(n));
15029657Slinton     } else if (s == program or isbuiltin(s)) {
15039657Slinton 	t = s;
15049657Slinton     } else {
1505*16620Ssam     /*
1506*16620Ssam      * Old way
1507*16620Ssam      *
1508*16620Ssam 	if (not isactive(program)) {
1509*16620Ssam 	    f = program;
1510*16620Ssam 	} else {
1511*16620Ssam 	    f = whatblock(pc);
1512*16620Ssam 	    if (f == nil) {
1513*16620Ssam 		panic("no block for addr 0x%x", pc);
1514*16620Ssam 	    }
1515*16620Ssam 	}
1516*16620Ssam      *
1517*16620Ssam      * Now start with curfunc.
1518*16620Ssam      */
15199657Slinton 	p = curfunc;
15209657Slinton 	do {
15219657Slinton 	    find(t, n) where
1522*16620Ssam 		t->block == p and t->class != FIELD and t->class != TAG
15239657Slinton 	    endfind(t);
15249657Slinton 	    p = p->block;
15259657Slinton 	} while (t == nil and p != nil);
15269657Slinton 	if (t == nil) {
15279657Slinton 	    t = s;
15289657Slinton 	}
15299657Slinton     }
15309657Slinton     return t;
15319657Slinton }
15329657Slinton 
15339657Slinton /*
15349657Slinton  * Find the symbol which is has the same name and scope as the
15359657Slinton  * given symbol but is of the given field.  Return nil if there is none.
15369657Slinton  */
15379657Slinton 
15389657Slinton public Symbol findfield(fieldname, record)
15399657Slinton Name fieldname;
15409657Slinton Symbol record;
15419657Slinton {
15429657Slinton     register Symbol t;
15439657Slinton 
15449657Slinton     t = rtype(record)->chain;
15459657Slinton     while (t != nil and t->name != fieldname) {
15469657Slinton 	t = t->chain;
15479657Slinton     }
15489657Slinton     return t;
15499657Slinton }
155012547Scsvaf 
155112547Scsvaf public Boolean getbound(s,off,type,valp)
155212547Scsvaf Symbol s;
155312547Scsvaf int off;
155412547Scsvaf Rangetype type;
155512547Scsvaf int *valp;
155612547Scsvaf {
155712547Scsvaf     Frame frp;
155812547Scsvaf     Address addr;
155912547Scsvaf     Symbol cur;
156012547Scsvaf 
156112547Scsvaf     if (not isactive(s->block)) {
156212547Scsvaf 	return(false);
156312547Scsvaf     }
156412547Scsvaf     cur = s->block;
156512547Scsvaf     while (cur != nil and cur->class == MODULE) {  /* WHY*/
156612547Scsvaf     		cur = cur->block;
156712547Scsvaf     }
156812547Scsvaf     if(cur == nil) {
156912547Scsvaf 		cur = whatblock(pc);
157012547Scsvaf     }
157112547Scsvaf     frp = findframe(cur);
157212547Scsvaf     if (frp == nil) {
157312547Scsvaf 	return(false);
157412547Scsvaf     }
157512547Scsvaf     if(type == R_TEMP) addr = locals_base(frp) + off;
157612547Scsvaf     else if (type == R_ARG) addr = args_base(frp) + off;
157712547Scsvaf     else return(false);
157812547Scsvaf     dread(valp,addr,sizeof(long));
157912547Scsvaf     return(true);
158012547Scsvaf }
1581