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