diff options
Diffstat (limited to 'src/cmd/cc/dcl.c')
-rw-r--r-- | src/cmd/cc/dcl.c | 1669 |
1 files changed, 1669 insertions, 0 deletions
diff --git a/src/cmd/cc/dcl.c b/src/cmd/cc/dcl.c new file mode 100644 index 000000000..d624bf247 --- /dev/null +++ b/src/cmd/cc/dcl.c @@ -0,0 +1,1669 @@ +// Inferno utils/cc/dcl.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/dcl.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include <u.h> +#include "cc.h" + +Node* +dodecl(void (*f)(int,Type*,Sym*), int c, Type *t, Node *n) +{ + Sym *s; + Node *n1; + int32 v; + + nearln = lineno; + lastfield = 0; + +loop: + if(n != Z) + switch(n->op) { + default: + diag(n, "unknown declarator: %O", n->op); + break; + + case OARRAY: + t = typ(TARRAY, t); + t->width = 0; + n1 = n->right; + n = n->left; + if(n1 != Z) { + complex(n1); + v = -1; + if(n1->op == OCONST) + v = n1->vconst; + if(v <= 0) { + diag(n, "array size must be a positive constant"); + v = 1; + } + t->width = v * t->link->width; + } + goto loop; + + case OIND: + t = typ(TIND, t); + t->garb = n->garb; + n = n->left; + goto loop; + + case OFUNC: + t = typ(TFUNC, t); + t->down = fnproto(n); + n = n->left; + goto loop; + + case OBIT: + n1 = n->right; + complex(n1); + lastfield = -1; + if(n1->op == OCONST) + lastfield = n1->vconst; + if(lastfield < 0) { + diag(n, "field width must be non-negative constant"); + lastfield = 1; + } + if(lastfield == 0) { + lastbit = 0; + firstbit = 1; + if(n->left != Z) { + diag(n, "zero width named field"); + lastfield = 1; + } + } + if(!typei[t->etype]) { + diag(n, "field type must be int-like"); + t = types[TINT]; + lastfield = 1; + } + if(lastfield > tfield->width*8) { + diag(n, "field width larger than field unit"); + lastfield = 1; + } + lastbit += lastfield; + if(lastbit > tfield->width*8) { + lastbit = lastfield; + firstbit = 1; + } + n = n->left; + goto loop; + + case ONAME: + if(f == NODECL) + break; + s = n->sym; + (*f)(c, t, s); + if(s->class == CLOCAL) + s = mkstatic(s); + firstbit = 0; + n->sym = s; + n->type = s->type; + n->xoffset = s->offset; + n->class = s->class; + n->etype = TVOID; + if(n->type != T) + n->etype = n->type->etype; + if(debug['d']) + dbgdecl(s); + acidvar(s); + godefvar(s); + s->varlineno = lineno; + break; + } + lastdcl = t; + return n; +} + +Sym* +mkstatic(Sym *s) +{ + Sym *s1; + + if(s->class != CLOCAL) + return s; + snprint(symb, NSYMB, "%s$%d", s->name, s->block); + s1 = lookup(); + if(s1->class != CSTATIC) { + s1->type = s->type; + s1->offset = s->offset; + s1->block = s->block; + s1->class = CSTATIC; + } + return s1; +} + +/* + * make a copy of a typedef + * the problem is to split out incomplete + * arrays so that it is in the variable + * rather than the typedef. + */ +Type* +tcopy(Type *t) +{ + Type *tl, *tx; + int et; + + if(t == T) + return t; + et = t->etype; + if(typesu[et]) + return t; + tl = tcopy(t->link); + if(tl != t->link || + (et == TARRAY && t->width == 0)) { + tx = copytyp(t); + tx->link = tl; + return tx; + } + return t; +} + +Node* +doinit(Sym *s, Type *t, int32 o, Node *a) +{ + Node *n; + + if(t == T) + return Z; + if(s->class == CEXTERN) { + s->class = CGLOBL; + if(debug['d']) + dbgdecl(s); + } + if(debug['i']) { + print("t = %T; o = %d; n = %s\n", t, o, s->name); + prtree(a, "doinit value"); + } + + + n = initlist; + if(a->op == OINIT) + a = a->left; + initlist = a; + + a = init1(s, t, o, 0); + if(initlist != Z) + diag(initlist, "more initializers than structure: %s", + s->name); + initlist = n; + + return a; +} + +/* + * get next major operator, + * dont advance initlist. + */ +Node* +peekinit(void) +{ + Node *a; + + a = initlist; + +loop: + if(a == Z) + return a; + if(a->op == OLIST) { + a = a->left; + goto loop; + } + return a; +} + +/* + * consume and return next element on + * initlist. expand strings. + */ +Node* +nextinit(void) +{ + Node *a, *b, *n; + + a = initlist; + n = Z; + + if(a == Z) + return a; + if(a->op == OLIST) { + n = a->right; + a = a->left; + } + if(a->op == OUSED) { + a = a->left; + b = new(OCONST, Z, Z); + b->type = a->type->link; + if(a->op == OSTRING) { + b->vconst = convvtox(*a->cstring, TCHAR); + a->cstring++; + } + if(a->op == OLSTRING) { + b->vconst = convvtox(*a->rstring, TUSHORT); + a->rstring++; + } + a->type->width -= b->type->width; + if(a->type->width <= 0) + initlist = n; + return b; + } + initlist = n; + return a; +} + +int +isstruct(Node *a, Type *t) +{ + Node *n; + + switch(a->op) { + case ODOTDOT: + n = a->left; + if(n && n->type && sametype(n->type, t)) + return 1; + case OSTRING: + case OLSTRING: + case OCONST: + case OINIT: + case OELEM: + return 0; + } + + n = new(ODOTDOT, Z, Z); + *n = *a; + + /* + * ODOTDOT is a flag for tcom + * a second tcom will not be performed + */ + a->op = ODOTDOT; + a->left = n; + a->right = Z; + + if(tcom(n)) + return 0; + + if(sametype(n->type, t)) + return 1; + return 0; +} + +Node* +init1(Sym *s, Type *t, int32 o, int exflag) +{ + Node *a, *l, *r, nod; + Type *t1; + int32 e, w, so, mw; + + a = peekinit(); + if(a == Z) + return Z; + + if(debug['i']) { + print("t = %T; o = %d; n = %s\n", t, o, s->name); + prtree(a, "init1 value"); + } + + if(exflag && a->op == OINIT) + return doinit(s, t, o, nextinit()); + + switch(t->etype) { + default: + diag(Z, "unknown type in initialization: %T to: %s", t, s->name); + return Z; + + case TCHAR: + case TUCHAR: + case TINT: + case TUINT: + case TSHORT: + case TUSHORT: + case TLONG: + case TULONG: + case TVLONG: + case TUVLONG: + case TFLOAT: + case TDOUBLE: + case TIND: + single: + if(a->op == OARRAY || a->op == OELEM) + return Z; + + a = nextinit(); + if(a == Z) + return Z; + + if(t->nbits) + diag(Z, "cannot initialize bitfields"); + if(s->class == CAUTO) { + l = new(ONAME, Z, Z); + l->sym = s; + l->type = t; + l->etype = TVOID; + if(s->type) + l->etype = s->type->etype; + l->xoffset = s->offset + o; + l->class = s->class; + + l = new(OASI, l, a); + return l; + } + + complex(a); + if(a->type == T) + return Z; + + if(a->op == OCONST) { + if(vconst(a) && t->etype == TIND && a->type && a->type->etype != TIND){ + diag(a, "initialize pointer to an integer: %s", s->name); + return Z; + } + if(!sametype(a->type, t)) { + /* hoop jumping to save malloc */ + if(nodcast == Z) + nodcast = new(OCAST, Z, Z); + nod = *nodcast; + nod.left = a; + nod.type = t; + nod.lineno = a->lineno; + complex(&nod); + if(nod.type) + *a = nod; + } + if(a->op != OCONST) { + diag(a, "initializer is not a constant: %s", + s->name); + return Z; + } + if(vconst(a) == 0) + return Z; + goto gext; + } + if(t->etype == TIND) { + while(a->op == OCAST) { + warn(a, "CAST in initialization ignored"); + a = a->left; + } + if(!sametype(t, a->type)) { + diag(a, "initialization of incompatible pointers: %s\n%T and %T", + s->name, t, a->type); + } + if(a->op == OADDR) + a = a->left; + goto gext; + } + + while(a->op == OCAST) + a = a->left; + if(a->op == OADDR) { + warn(a, "initialize pointer to an integer: %s", s->name); + a = a->left; + goto gext; + } + diag(a, "initializer is not a constant: %s", s->name); + return Z; + + gext: + gextern(s, a, o, t->width); + + return Z; + + case TARRAY: + w = t->link->width; + if(a->op == OSTRING || a->op == OLSTRING) + if(typei[t->link->etype]) { + /* + * get rid of null if sizes match exactly + */ + a = nextinit(); + mw = t->width/w; + so = a->type->width/a->type->link->width; + if(mw && so > mw) { + if(so != mw+1) + diag(a, "string initialization larger than array"); + a->type->width -= a->type->link->width; + } + + /* + * arrange strings to be expanded + * inside OINIT braces. + */ + a = new(OUSED, a, Z); + return doinit(s, t, o, a); + } + + mw = -w; + l = Z; + for(e=0;;) { + /* + * peek ahead for element initializer + */ + a = peekinit(); + if(a == Z) + break; + if(a->op == OELEM && t->link->etype != TSTRUCT) + break; + if(a->op == OARRAY) { + if(e && exflag) + break; + a = nextinit(); + r = a->left; + complex(r); + if(r->op != OCONST) { + diag(r, "initializer subscript must be constant"); + return Z; + } + e = r->vconst; + if(t->width != 0) + if(e < 0 || e*w >= t->width) { + diag(a, "initialization index out of range: %d", e); + continue; + } + } + + so = e*w; + if(so > mw) + mw = so; + if(t->width != 0) + if(mw >= t->width) + break; + r = init1(s, t->link, o+so, 1); + l = newlist(l, r); + e++; + } + if(t->width == 0) + t->width = mw+w; + return l; + + case TUNION: + case TSTRUCT: + /* + * peek ahead to find type of rhs. + * if its a structure, then treat + * this element as a variable + * rather than an aggregate. + */ + if(isstruct(a, t)) + goto single; + + if(t->width <= 0) { + diag(Z, "incomplete structure: %s", s->name); + return Z; + } + l = Z; + + again: + for(t1 = t->link; t1 != T; t1 = t1->down) { + if(a->op == OARRAY && t1->etype != TARRAY) + break; + if(a->op == OELEM) { + if(t1->sym != a->sym) + continue; + nextinit(); + } + r = init1(s, t1, o+t1->offset, 1); + l = newlist(l, r); + a = peekinit(); + if(a == Z) + break; + if(a->op == OELEM) + goto again; + } + if(a && a->op == OELEM) + diag(a, "structure element not found %F", a); + return l; + } +} + +Node* +newlist(Node *l, Node *r) +{ + if(r == Z) + return l; + if(l == Z) + return r; + return new(OLIST, l, r); +} + +void +sualign(Type *t) +{ + Type *l; + int32 o, w, maxal; + + o = 0; + maxal = 0; + switch(t->etype) { + + case TSTRUCT: + t->offset = 0; + w = 0; + for(l = t->link; l != T; l = l->down) { + if(l->nbits) { + if(l->shift <= 0) { + l->shift = -l->shift; + w = xround(w, tfield->width); + o = w; + w += tfield->width; + } + l->offset = o; + } else { + if(l->width <= 0) + if(l->down != T) + if(l->sym) + diag(Z, "incomplete structure element: %s", + l->sym->name); + else + diag(Z, "incomplete structure element"); + w = align(w, l, Ael1, &maxal); + l->offset = w; + w = align(w, l, Ael2, &maxal); + } + } + w = align(w, t, Asu2, &maxal); + t->width = w; + t->align = maxal; + acidtype(t); + godeftype(t); + return; + + case TUNION: + t->offset = 0; + w = 0; + for(l = t->link; l != T; l = l->down) { + if(l->width <= 0) + if(l->sym) + diag(Z, "incomplete union element: %s", + l->sym->name); + else + diag(Z, "incomplete union element"); + l->offset = 0; + l->shift = 0; + o = align(align(0, l, Ael1, &maxal), l, Ael2, &maxal); + if(o > w) + w = o; + } + w = align(w, t, Asu2, &maxal); + t->width = w; + t->align = maxal; + acidtype(t); + godeftype(t); + return; + + default: + diag(Z, "unknown type in sualign: %T", t); + break; + } +} + +int32 +xround(int32 v, int w) +{ + int r; + + if(w <= 0 || w > 8) { + diag(Z, "rounding by %d", w); + w = 1; + } + r = v%w; + if(r) + v += w-r; + return v; +} + +Type* +ofnproto(Node *n) +{ + Type *tl, *tr, *t; + + if(n == Z) + return T; + switch(n->op) { + case OLIST: + tl = ofnproto(n->left); + tr = ofnproto(n->right); + if(tl == T) + return tr; + tl->down = tr; + return tl; + + case ONAME: + t = copytyp(n->sym->type); + t->down = T; + return t; + } + return T; +} + +#define ANSIPROTO 1 +#define OLDPROTO 2 + +void +argmark(Node *n, int pass) +{ + Type *t; + + autoffset = align(0, thisfn->link, Aarg0, nil); + stkoff = 0; + for(; n->left != Z; n = n->left) { + if(n->op != OFUNC || n->left->op != ONAME) + continue; + walkparam(n->right, pass); + if(pass != 0 && anyproto(n->right) == OLDPROTO) { + t = typ(TFUNC, n->left->sym->type->link); + t->down = typ(TOLD, T); + t->down->down = ofnproto(n->right); + tmerge(t, n->left->sym); + n->left->sym->type = t; + } + break; + } + autoffset = 0; + stkoff = 0; +} + +void +walkparam(Node *n, int pass) +{ + Sym *s; + Node *n1; + + if(n != Z && n->op == OPROTO && n->left == Z && n->type == types[TVOID]) + return; + +loop: + if(n == Z) + return; + switch(n->op) { + default: + diag(n, "argument not a name/prototype: %O", n->op); + break; + + case OLIST: + walkparam(n->left, pass); + n = n->right; + goto loop; + + case OPROTO: + for(n1 = n; n1 != Z; n1=n1->left) + if(n1->op == ONAME) { + if(pass == 0) { + s = n1->sym; + push1(s); + s->offset = -1; + break; + } + dodecl(pdecl, CPARAM, n->type, n->left); + break; + } + if(n1) + break; + if(pass == 0) { + /* + * extension: + * allow no name in argument declaration + diag(Z, "no name in argument declaration"); + */ + break; + } + dodecl(NODECL, CPARAM, n->type, n->left); + pdecl(CPARAM, lastdcl, S); + break; + + case ODOTDOT: + break; + + case ONAME: + s = n->sym; + if(pass == 0) { + push1(s); + s->offset = -1; + break; + } + if(s->offset != -1) { + if(autoffset == 0) { + firstarg = s; + firstargtype = s->type; + } + autoffset = align(autoffset, s->type, Aarg1, nil); + s->offset = autoffset; + autoffset = align(autoffset, s->type, Aarg2, nil); + } else + dodecl(pdecl, CXXX, types[TINT], n); + break; + } +} + +void +markdcl(void) +{ + Decl *d; + + blockno++; + d = push(); + d->val = DMARK; + d->offset = autoffset; + d->block = autobn; + autobn = blockno; +} + +Node* +revertdcl(void) +{ + Decl *d; + Sym *s; + Node *n, *n1; + + n = Z; + for(;;) { + d = dclstack; + if(d == D) { + diag(Z, "pop off dcl stack"); + break; + } + dclstack = d->link; + s = d->sym; + switch(d->val) { + case DMARK: + autoffset = d->offset; + autobn = d->block; + return n; + + case DAUTO: + if(debug['d']) + print("revert1 \"%s\"\n", s->name); + if(s->aused == 0) { + nearln = s->varlineno; + if(s->class == CAUTO) + warn(Z, "auto declared and not used: %s", s->name); + if(s->class == CPARAM) + warn(Z, "param declared and not used: %s", s->name); + } + if(s->type && (s->type->garb & GVOLATILE)) { + n1 = new(ONAME, Z, Z); + n1->sym = s; + n1->type = s->type; + n1->etype = TVOID; + if(n1->type != T) + n1->etype = n1->type->etype; + n1->xoffset = s->offset; + n1->class = s->class; + + n1 = new(OADDR, n1, Z); + n1 = new(OUSED, n1, Z); + if(n == Z) + n = n1; + else + n = new(OLIST, n1, n); + } + s->type = d->type; + s->class = d->class; + s->offset = d->offset; + s->block = d->block; + s->varlineno = d->varlineno; + s->aused = d->aused; + break; + + case DSUE: + if(debug['d']) + print("revert2 \"%s\"\n", s->name); + s->suetag = d->type; + s->sueblock = d->block; + break; + + case DLABEL: + if(debug['d']) + print("revert3 \"%s\"\n", s->name); + if(s->label && s->label->addable == 0) + warn(s->label, "label declared and not used \"%s\"", s->name); + s->label = Z; + break; + } + } + return n; +} + +Type* +fnproto(Node *n) +{ + int r; + + r = anyproto(n->right); + if(r == 0 || (r & OLDPROTO)) { + if(r & ANSIPROTO) + diag(n, "mixed ansi/old function declaration: %F", n->left); + return T; + } + return fnproto1(n->right); +} + +int +anyproto(Node *n) +{ + int r; + + r = 0; + +loop: + if(n == Z) + return r; + switch(n->op) { + case OLIST: + r |= anyproto(n->left); + n = n->right; + goto loop; + + case ODOTDOT: + case OPROTO: + return r | ANSIPROTO; + } + return r | OLDPROTO; +} + +Type* +fnproto1(Node *n) +{ + Type *t; + + if(n == Z) + return T; + switch(n->op) { + case OLIST: + t = fnproto1(n->left); + if(t != T) + t->down = fnproto1(n->right); + return t; + + case OPROTO: + lastdcl = T; + dodecl(NODECL, CXXX, n->type, n->left); + t = typ(TXXX, T); + if(lastdcl != T) + *t = *paramconv(lastdcl, 1); + return t; + + case ONAME: + diag(n, "incomplete argument prototype"); + return typ(TINT, T); + + case ODOTDOT: + return typ(TDOT, T); + } + diag(n, "unknown op in fnproto"); + return T; +} + +void +dbgdecl(Sym *s) +{ + print("decl \"%s\": C=%s [B=%d:O=%d] T=%T\n", + s->name, cnames[s->class], s->block, s->offset, s->type); +} + +Decl* +push(void) +{ + Decl *d; + + d = alloc(sizeof(*d)); + d->link = dclstack; + dclstack = d; + return d; +} + +Decl* +push1(Sym *s) +{ + Decl *d; + + d = push(); + d->sym = s; + d->val = DAUTO; + d->type = s->type; + d->class = s->class; + d->offset = s->offset; + d->block = s->block; + d->varlineno = s->varlineno; + d->aused = s->aused; + return d; +} + +int +sametype(Type *t1, Type *t2) +{ + + if(t1 == t2) + return 1; + return rsametype(t1, t2, 5, 1); +} + +int +rsametype(Type *t1, Type *t2, int n, int f) +{ + int et; + + n--; + for(;;) { + if(t1 == t2) + return 1; + if(t1 == T || t2 == T) + return 0; + if(n <= 0) + return 1; + et = t1->etype; + if(et != t2->etype) + return 0; + if(et == TFUNC) { + if(!rsametype(t1->link, t2->link, n, 0)) + return 0; + t1 = t1->down; + t2 = t2->down; + while(t1 != T && t2 != T) { + if(t1->etype == TOLD) { + t1 = t1->down; + continue; + } + if(t2->etype == TOLD) { + t2 = t2->down; + continue; + } + while(t1 != T || t2 != T) { + if(!rsametype(t1, t2, n, 0)) + return 0; + t1 = t1->down; + t2 = t2->down; + } + break; + } + return 1; + } + if(et == TARRAY) + if(t1->width != t2->width && t1->width != 0 && t2->width != 0) + return 0; + if(typesu[et]) { + if(t1->link == T) + snap(t1); + if(t2->link == T) + snap(t2); + t1 = t1->link; + t2 = t2->link; + for(;;) { + if(t1 == t2) + return 1; + if(!rsametype(t1, t2, n, 0)) + return 0; + t1 = t1->down; + t2 = t2->down; + } + } + t1 = t1->link; + t2 = t2->link; + if((f || !debug['V']) && et == TIND) { + if(t1 != T && t1->etype == TVOID) + return 1; + if(t2 != T && t2->etype == TVOID) + return 1; + } + } +} + +typedef struct Typetab Typetab; + +struct Typetab{ + int n; + Type **a; +}; + +static int +sigind(Type *t, Typetab *tt) +{ + int n; + Type **a, **na, **p, **e; + + n = tt->n; + a = tt->a; + e = a+n; + /* linear search seems ok */ + for(p = a ; p < e; p++) + if(sametype(*p, t)) + return p-a; + if((n&15) == 0){ + na = malloc((n+16)*sizeof(Type*)); + memmove(na, a, n*sizeof(Type*)); + free(a); + a = tt->a = na; + } + a[tt->n++] = t; + return -1; +} + +static uint32 +signat(Type *t, Typetab *tt) +{ + int i; + Type *t1; + int32 s; + + s = 0; + for(; t; t=t->link) { + s = s*thash1 + thash[t->etype]; + if(t->garb&GINCOMPLETE) + return s; + switch(t->etype) { + default: + return s; + case TARRAY: + s = s*thash2 + 0; /* was t->width */ + break; + case TFUNC: + for(t1=t->down; t1; t1=t1->down) + s = s*thash3 + signat(t1, tt); + break; + case TSTRUCT: + case TUNION: + if((i = sigind(t, tt)) >= 0){ + s = s*thash2 + i; + return s; + } + for(t1=t->link; t1; t1=t1->down) + s = s*thash3 + signat(t1, tt); + return s; + case TIND: + break; + } + } + return s; +} + +uint32 +signature(Type *t) +{ + uint32 s; + Typetab tt; + + tt.n = 0; + tt.a = nil; + s = signat(t, &tt); + free(tt.a); + return s; +} + +uint32 +sign(Sym *s) +{ + uint32 v; + Type *t; + + if(s->sig == SIGINTERN) + return SIGNINTERN; + if((t = s->type) == T) + return 0; + v = signature(t); + if(v == 0) + v = SIGNINTERN; + return v; +} + +void +snap(Type *t) +{ + if(typesu[t->etype]) + if(t->link == T && t->tag && t->tag->suetag) { + t->link = t->tag->suetag->link; + t->width = t->tag->suetag->width; + } +} + +Type* +dotag(Sym *s, int et, int bn) +{ + Decl *d; + + if(bn != 0 && bn != s->sueblock) { + d = push(); + d->sym = s; + d->val = DSUE; + d->type = s->suetag; + d->block = s->sueblock; + s->suetag = T; + } + if(s->suetag == T) { + s->suetag = typ(et, T); + s->sueblock = autobn; + } + if(s->suetag->etype != et) + diag(Z, "tag used for more than one type: %s", + s->name); + if(s->suetag->tag == S) + s->suetag->tag = s; + return s->suetag; +} + +Node* +dcllabel(Sym *s, int f) +{ + Decl *d, d1; + Node *n; + + n = s->label; + if(n != Z) { + if(f) { + if(n->complex) + diag(Z, "label reused: %s", s->name); + n->complex = 1; // declared + } else + n->addable = 1; // used + return n; + } + + d = push(); + d->sym = s; + d->val = DLABEL; + dclstack = d->link; + + d1 = *firstdcl; + *firstdcl = *d; + *d = d1; + + firstdcl->link = d; + firstdcl = d; + + n = new(OXXX, Z, Z); + n->sym = s; + n->complex = f; + n->addable = !f; + s->label = n; + + if(debug['d']) + dbgdecl(s); + return n; +} + +Type* +paramconv(Type *t, int f) +{ + + switch(t->etype) { + case TUNION: + case TSTRUCT: + if(t->width <= 0) + diag(Z, "incomplete structure: %s", t->tag->name); + break; + + case TARRAY: + t = typ(TIND, t->link); + t->width = types[TIND]->width; + break; + + case TFUNC: + t = typ(TIND, t); + t->width = types[TIND]->width; + break; + + case TFLOAT: + if(!f) + t = types[TDOUBLE]; + break; + + case TCHAR: + case TSHORT: + if(!f) + t = types[TINT]; + break; + + case TUCHAR: + case TUSHORT: + if(!f) + t = types[TUINT]; + break; + } + return t; +} + +void +adecl(int c, Type *t, Sym *s) +{ + + if(c == CSTATIC) + c = CLOCAL; + if(t->etype == TFUNC) { + if(c == CXXX) + c = CEXTERN; + if(c == CLOCAL) + c = CSTATIC; + if(c == CAUTO || c == CEXREG) + diag(Z, "function cannot be %s %s", cnames[c], s->name); + } + if(c == CXXX) + c = CAUTO; + if(s) { + if(s->class == CSTATIC) + if(c == CEXTERN || c == CGLOBL) { + warn(Z, "just say static: %s", s->name); + c = CSTATIC; + } + if(s->class == CAUTO || s->class == CPARAM || s->class == CLOCAL) + if(s->block == autobn) + diag(Z, "auto redeclaration of: %s", s->name); + if(c != CPARAM) + push1(s); + s->block = autobn; + s->offset = 0; + s->type = t; + s->class = c; + s->aused = 0; + } + switch(c) { + case CAUTO: + autoffset = align(autoffset, t, Aaut3, nil); + stkoff = maxround(stkoff, autoffset); + s->offset = -autoffset; + break; + + case CPARAM: + if(autoffset == 0) { + firstarg = s; + firstargtype = t; + } + autoffset = align(autoffset, t, Aarg1, nil); + if(s) + s->offset = autoffset; + autoffset = align(autoffset, t, Aarg2, nil); + break; + } +} + +void +pdecl(int c, Type *t, Sym *s) +{ + if(s && s->offset != -1) { + diag(Z, "not a parameter: %s", s->name); + return; + } + t = paramconv(t, c==CPARAM); + if(c == CXXX) + c = CPARAM; + if(c != CPARAM) { + diag(Z, "parameter cannot have class: %s", s->name); + c = CPARAM; + } + adecl(c, t, s); +} + +void +xdecl(int c, Type *t, Sym *s) +{ + int32 o; + + o = 0; + switch(c) { + case CEXREG: + o = exreg(t); + if(o == 0) + c = CEXTERN; + if(s->class == CGLOBL) + c = CGLOBL; + break; + + case CEXTERN: + if(s->class == CGLOBL) + c = CGLOBL; + break; + + case CXXX: + c = CGLOBL; + if(s->class == CEXTERN) + s->class = CGLOBL; + break; + + case CAUTO: + diag(Z, "overspecified class: %s %s %s", s->name, cnames[c], cnames[s->class]); + c = CEXTERN; + break; + + case CTYPESTR: + if(!typesuv[t->etype]) { + diag(Z, "typestr must be struct/union: %s", s->name); + break; + } + dclfunct(t, s); + break; + } + + if(s->class == CSTATIC) + if(c == CEXTERN || c == CGLOBL) { + warn(Z, "overspecified class: %s %s %s", s->name, cnames[c], cnames[s->class]); + c = CSTATIC; + } + if(s->type != T) + if(s->class != c || !sametype(t, s->type) || t->etype == TENUM) { + diag(Z, "external redeclaration of: %s", s->name); + Bprint(&diagbuf, " %s %T %L\n", cnames[c], t, nearln); + Bprint(&diagbuf, " %s %T %L\n", cnames[s->class], s->type, s->varlineno); + } + tmerge(t, s); + s->type = t; + s->class = c; + s->block = 0; + s->offset = o; +} + +void +tmerge(Type *t1, Sym *s) +{ + Type *ta, *tb, *t2; + + t2 = s->type; + for(;;) { + if(t1 == T || t2 == T || t1 == t2) + break; + if(t1->etype != t2->etype) + break; + switch(t1->etype) { + case TFUNC: + ta = t1->down; + tb = t2->down; + if(ta == T) { + t1->down = tb; + break; + } + if(tb == T) + break; + while(ta != T && tb != T) { + if(ta == tb) + break; + /* ignore old-style flag */ + if(ta->etype == TOLD) { + ta = ta->down; + continue; + } + if(tb->etype == TOLD) { + tb = tb->down; + continue; + } + /* checking terminated by ... */ + if(ta->etype == TDOT && tb->etype == TDOT) { + ta = T; + tb = T; + break; + } + if(!sametype(ta, tb)) + break; + ta = ta->down; + tb = tb->down; + } + if(ta != tb) + diag(Z, "function inconsistently declared: %s", s->name); + + /* take new-style over old-style */ + ta = t1->down; + tb = t2->down; + if(ta != T && ta->etype == TOLD) + if(tb != T && tb->etype != TOLD) + t1->down = tb; + break; + + case TARRAY: + /* should we check array size change? */ + if(t2->width > t1->width) + t1->width = t2->width; + break; + + case TUNION: + case TSTRUCT: + return; + } + t1 = t1->link; + t2 = t2->link; + } +} + +void +edecl(int c, Type *t, Sym *s) +{ + Type *t1; + + if(s == S) { + if(!typesu[t->etype]) + diag(Z, "unnamed structure element must be struct/union"); + if(c != CXXX) + diag(Z, "unnamed structure element cannot have class"); + } else + if(c != CXXX) + diag(Z, "structure element cannot have class: %s", s->name); + t1 = t; + t = copytyp(t1); + t->sym = s; + t->down = T; + if(lastfield) { + t->shift = lastbit - lastfield; + t->nbits = lastfield; + if(firstbit) + t->shift = -t->shift; + if(typeu[t->etype]) + t->etype = tufield->etype; + else + t->etype = tfield->etype; + } + if(strf == T) + strf = t; + else + strl->down = t; + strl = t; +} + +/* + * this routine is very suspect. + * ansi requires the enum type to + * be represented as an 'int' + * this means that 0x81234567 + * would be illegal. this routine + * makes signed and unsigned go + * to unsigned. + */ +Type* +maxtype(Type *t1, Type *t2) +{ + + if(t1 == T) + return t2; + if(t2 == T) + return t1; + if(t1->etype > t2->etype) + return t1; + return t2; +} + +void +doenum(Sym *s, Node *n) +{ + + if(n) { + complex(n); + if(n->op != OCONST) { + diag(n, "enum not a constant: %s", s->name); + return; + } + en.cenum = n->type; + en.tenum = maxtype(en.cenum, en.tenum); + + if(!typefd[en.cenum->etype]) + en.lastenum = n->vconst; + else + en.floatenum = n->fconst; + } + if(dclstack) + push1(s); + xdecl(CXXX, types[TENUM], s); + + if(en.cenum == T) { + en.tenum = types[TINT]; + en.cenum = types[TINT]; + en.lastenum = 0; + } + s->tenum = en.cenum; + + if(!typefd[s->tenum->etype]) { + s->vconst = convvtox(en.lastenum, s->tenum->etype); + en.lastenum++; + } else { + s->fconst = en.floatenum; + en.floatenum++; + } + + if(debug['d']) + dbgdecl(s); + acidvar(s); + godefvar(s); +} + +void +symadjust(Sym *s, Node *n, int32 del) +{ + + switch(n->op) { + default: + if(n->left) + symadjust(s, n->left, del); + if(n->right) + symadjust(s, n->right, del); + return; + + case ONAME: + if(n->sym == s) + n->xoffset -= del; + return; + + case OCONST: + case OSTRING: + case OLSTRING: + case OINDREG: + case OREGISTER: + return; + } +} + +Node* +contig(Sym *s, Node *n, int32 v) +{ + Node *p, *r, *q, *m; + int32 w; + Type *zt; + + if(debug['i']) { + print("contig v = %d; s = %s\n", v, s->name); + prtree(n, "doinit value"); + } + + if(n == Z) + goto no; + w = s->type->width; + + /* + * nightmare: an automatic array whose size + * increases when it is initialized + */ + if(v != w) { + if(v != 0) + diag(n, "automatic adjustable array: %s", s->name); + v = s->offset; + autoffset = align(autoffset, s->type, Aaut3, nil); + s->offset = -autoffset; + stkoff = maxround(stkoff, autoffset); + symadjust(s, n, v - s->offset); + } + if(w <= ewidth[TIND]) + goto no; + if(n->op == OAS) + diag(Z, "oops in contig"); +/*ZZZ this appears incorrect +need to check if the list completely covers the data. +if not, bail + */ + if(n->op == OLIST) + goto no; + if(n->op == OASI) + if(n->left->type) + if(n->left->type->width == w) + goto no; + while(w & (ewidth[TIND]-1)) + w++; +/* + * insert the following code, where long becomes vlong if pointers are fat + * + *(long**)&X = (long*)((char*)X + sizeof(X)); + do { + *(long**)&X -= 1; + **(long**)&X = 0; + } while(*(long**)&X); + */ + + for(q=n; q->op != ONAME; q=q->left) + ; + + zt = ewidth[TIND] > ewidth[TLONG]? types[TVLONG]: types[TLONG]; + + p = new(ONAME, Z, Z); + *p = *q; + p->type = typ(TIND, zt); + p->xoffset = s->offset; + + r = new(ONAME, Z, Z); + *r = *p; + r = new(OPOSTDEC, r, Z); + + q = new(ONAME, Z, Z); + *q = *p; + q = new(OIND, q, Z); + + m = new(OCONST, Z, Z); + m->vconst = 0; + m->type = zt; + + q = new(OAS, q, m); + + r = new(OLIST, r, q); + + q = new(ONAME, Z, Z); + *q = *p; + r = new(ODWHILE, q, r); + + q = new(ONAME, Z, Z); + *q = *p; + q->type = q->type->link; + q->xoffset += w; + q = new(OADDR, q, 0); + + q = new(OASI, p, q); + r = new(OLIST, q, r); + + n = new(OLIST, r, n); + +no: + return n; +} |