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