mirror of
https://github.com/golang/go
synced 2024-11-20 05:44:44 -07:00
b0449c50f7
8c/gc.h: . Added <u.h> header. . Added "lD" pragma for "*Adr" to supplement "D". 8c/swt.c: . Removed unreferenced "thestring" arguments in Bprint() calls. cc/acid.c: cc/com.c: cc/com64.c: cc/dcl.c: cc/scon.c: . Added <u.h>, required by "cc.h". cc/bits.c: . Added <u.h>, required by "cc.h". cc/cc.h: . Removed <u.h> and <ctype.h>. . Added "O" pragma to accept "uint" as well as "int". . Added new "U" pragma (char *). cc/cc.y: . Added <u.h> before <stdio.h> (and "cc.h"). cc/dpchk.c: cc/mac.c: . Added <u.h> and <ctype.h>. cc/funct.c: . Added <u.h>, required by "cc.h". cc/godefs.c . Added <u.h>, required by "cc.h". . Dropped unused "t" argument in Bprint(). cc/lex.c: . Added <u.h> and <ctype.h>. . Removed unnecessary incrementation. . Changed exit() invocations with exits(). cc/omachcap.c: . Added <u.h>, required by "cc.h". . USED(n) for unused argument to machcap(). cc/sub.c: . Added <u.h> and <ctype.h>. R=rsc CC=golang-dev https://golang.org/cl/4629070
1670 lines
28 KiB
C
1670 lines
28 KiB
C
// 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;
|
|
}
|