#include "cc.h" Node* dodecl(void (*f)(int,Type*,Sym*), int c, Type *t, Node *n) { Sym *s; Node *n1; long 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->offset; 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); 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->offset; 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(!typechl[t->etype]) { diag(n, "field type must be int-like"); t = 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->offset = s->offset; n->class = s->class; n->etype = TVOID; if(n->type != T) n->etype = n->type->etype; if(debug['d']) dbgdecl(s); s->varlineno = lineno; if(n->ref) if(f == edecl) { n->ref->class = CSELEM+CLAST; strl->lineno = n->ref->lineno; } else { n->ref->class = s->class+CLAST; if(s->class == CGLOBL && s->varlineno != 0) n->ref->dlineno = s->varlineno; else s->varlineno = n->ref->lineno; } break; } lastdcl = t; return n; } Sym* mkstatic(Sym *s) { Sym *s1; if(s->class != CLOCAL) return s; sprint(symb, "%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 imcomplete * 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 = typ(TXXX, 0); *tx = *t; tx->link = tl; return tx; } return t; } Node* doinit(Sym *s, Type *t, long 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 = %ld; 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; loop: 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->offset = castto(*a->us, TCHAR); a->us++; } if(a->op == OLSTRING) { b->offset = castto(*a->rs, TUSHORT); a->rs++; } 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: 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, long o, int exflag) { Node *a, *l, *r; long e, w, so, mw; a = peekinit(); if(a == Z) return Z; if(debug['i']) { print("t = %T; o = %ld; 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 TSHORT: case TUSHORT: case TLONG: case TULONG: case TVLONG: case TFLOAT: case TDOUBLE: case TIND: single: if(a->op == OARRAY) 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->offset = s->offset + o; l->class = s->class; l = new(OAS, l, a); return l; } complex(a); if(a->type == T) return Z; if(a->op == OCONST) { if(!sametype(a->type, t)) { e = a->lineno; a = new(OCAST, a, Z); a->lineno = e; a->type = t; complex(a); } 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", s->name); print("%T and %T\n", t, a->type); } if(a->op == OADDR) a = a->left; goto gext; } if(typelp[t->etype]) { while(a->op == OCAST) a = a->left; if(a->op == OADDR) { warn(a, "initialize pointer to an integer", 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(typechl[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 == OARRAY) { a = nextinit(); r = a->left; complex(r); if(r->op != OCONST) { diag(r, "initializer subscript must be constant"); return Z; } e = r->offset; if(t->width != 0) if(e < 0 || e*w >= t->width) { diag(a, "initilization index out of range: %ld", e); e = 0; } 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: return init1(s, t->link, o, exflag); 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; for(t = t->link; t != T; t = t->down) { a = peekinit(); if(a == Z) break; if(a->op == OARRAY) break; r = init1(s, t, o+t->offset, 1); l = newlist(l, r); } return l; } } Node* newlist(Node *l, Node *r) { if(r == Z) return l; if(l == Z) return r; return new(OLIST, l, r); } void suallign(Type *t) { Type *l; long o, w; o = 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 += round(w, tfield->width); o = w; w += tfield->width; } l->offset = o; } else { if(l->width <= 0) if(l->sym) diag(Z, "incomplete structure element: %s", l->sym->name); else diag(Z, "incomplete structure element"); w += round(w, allign(l)); l->offset = w; w += l->width; } } w += round(w, supad); t->width = w; 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; if(l->width > w) w = l->width; } w += round(w, supad); t->width = w; return; default: diag(Z, "unknown type in suallign: %T", t); break; } } int allign(Type *t) { int w; while(t->etype == TARRAY) t = t->link; w = ewidth[t->etype]; if(w <= 0 || w > suround) w = suround; return w; } int round(long v, long w) { int r; if(w <= 0) { diag(Z, "rounding by %d", w); w = 1; } if(w > types[TLONG]->width) w = types[TLONG]->width; r = v%w; if(r) r = w-r; return r; } Type* ofnproto(Node *n) { Type *tl, *tr, *t; loop: 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 = typ(TXXX, T); *t = *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 = 0; if(typesu[thisfn->link->etype]) { autoffset += types[TIND]->width; autoffset += round(autoffset, tint->width); } 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; 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: if(pass == 0) { for(; n != Z; n=n->left) if(n->op == ONAME) { s = n->sym; push1(s); s->offset = -1; break; } if(n == Z) diag(Z, "no name in argument declaration"); break; } dodecl(pdecl, CPARAM, n->type, n->left); 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; } s->offset = autoffset; autoffset += s->type->width; autoffset += round(autoffset, tint->width); } else dodecl(pdecl, CXXX, tint, n); break; } } void markdcl(void) { Decl *d; blockno++; d = push(); d->val = DMARK; d->offset = autoffset; d->block = autobn; autobn = blockno; } void revertdcl(void) { Decl *d; Sym *s; 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; 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); } 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); s->label = Z; break; } } } 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->etype, T); case ODOTDOT: return typ(TDOT, T); } diag(n, "unknown op in fnproto"); return T; } void dbgdecl(Sym *s) { print("decl \"%s\": %s ", s->name, cnames[s->class]); if(s->class == CAUTO) print("[%d:%ld] ", s->block, s->offset); print("%T\n", s->type); } Decl* push(void) { Decl *d; ALLOC(d, Decl); 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); } int rsametype(Type *t1, Type *t2, int n) { 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)) 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)) return 0; t1 = t1->down; t2 = t2->down; } break; } return 1; } t1 = t1->link; t2 = t2->link; if(typesu[et]) for(;;) { if(t1 == t2) return 1; if(!rsametype(t1, t2, n)) return 0; t1 = t1->down; t2 = t2->down; } if(et == TIND) if(t1->etype == TVOID || t2->etype == TVOID) return 1; } } void 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; } 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; } 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; s->label = n; if(debug['d']) dbgdecl(s); return n; } Type* paramconv(Type *t, int f) { switch(t->etype) { 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 = tint; break; case TUCHAR: case TUSHORT: if(!f) t = 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->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; if(c != CAUTO && c != CPARAM) return; if(c == CPARAM && autoffset == 0) { firstarg = s; firstargtype = t; } if(t->width < tint->width) autoffset += endian(t->width); s->offset = autoffset; autoffset += t->width; autoffset += round(autoffset, tint->width); if(c == CAUTO) s->offset = -autoffset; if(autoffset > stkoff) { stkoff = autoffset; stkoff += round(stkoff, types[TLONG]->width); } } void pdecl(int c, Type *t, Sym *s) { if(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) { long o; o = 0; if(c == CEXREG) { o = exreg(t); if(o == 0) c = CEXTERN; } if(c == CXXX) { c = CGLOBL; if(s->class == CEXTERN) s->class = c; } if(c == CEXTERN) if(s->class == CGLOBL) c = CGLOBL; if(c == CAUTO) { diag(Z, "external declaration cannot be auto: %s", s->name); c = CEXTERN; } if(s->class == CSTATIC) if(c == CEXTERN || c == CGLOBL) 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); print(" %T; %T\n", t, s->type); } 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; /*print("merge %T; %T\n", t1, t2);/**/ 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; int n; 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 = typ(TXXX, T); *t = *t1; t->sym = s; t->down = T; if(lastfield) { t->shift = lastbit - lastfield; t->nbits = lastfield; if(firstbit) t->shift = -t->shift; /* real bitfields or not */ if(0) { n = t->nbits; lastfield = 0; firstbit = 0; lastbit = 0; t->nbits = 0; t->shift = 0; if(typeu[t->etype]) { /* BUG */ if(n <= 8) t->etype = TUCHAR; else if(n <= 16) t->etype = TUSHORT; else t->etype = TULONG; } else { if(n <= 8) t->etype = TCHAR; else if(n <= 16) t->etype = TSHORT; else t->etype = TLONG; } } } if(strf == T) strf = t; else strl->down = t; strl = t; } Type* maxtype(long v) { char c; short s; /* * BUG this tests the compile, not the target */ c = v; if(c == v) return types[TCHAR]; s = v; if(s == v) return types[TSHORT]; return types[TLONG]; } void doenum(Sym *s, Node *n) { if(n) { complex(n); if(n->op != OCONST || !typechl[n->type->etype]) { diag(n, "constant integer expected in enum: %s", s->name); return; } if(tint != types[TLONG] && typel[n->type->etype]) diag(n, "enum constant cannot be long"); lastenum = n->offset; } if(dclstack) push1(s); xdecl(CXXX, types[TENUM], s); if(ovflo(lastenum, tint->etype)) diag(n, "enum constant exceeds an integer: %s", s->name); s->offset = lastenum; if(debug['d']) dbgdecl(s); if(lastenum > maxenum) maxenum = lastenum; if(-lastenum > maxenum) maxenum = -lastenum; lastenum++; } void dbgprint(Sym *s, Type *t) { Type *l; if(suedebug == 0) return; if(strcmp(s->name, suedebug) != 0) return; print("%s %ld %T\n", s->name, t->width, t); for(l = t->link; l != T; l = l->down) { if(l->sym) print("%s %ld %T\n", l->sym->name, l->offset, l); else print("<> %ld %T\n", l->offset, l); } } void symadjust(Sym *s, Node *n, long 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->offset -= del; return; case OCONST: case OSTRING: case OLSTRING: case OINDREG: case OREGISTER: return; } } Node* contig(Sym *s, Node *n, long v) { Node *p, *r, *q, *m; long w; 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 += w; autoffset += round(autoffset, tint->width); s->offset = -autoffset; if(autoffset > stkoff) { stkoff = autoffset; stkoff += round(stkoff, types[TLONG]->width); } symadjust(s, n, v - s->offset); } if(w <= 4) goto no; if(n->op == OAS) if(n->left->type) if(n->left->type->width == w) goto no; while(w & 3) w++; /* is this a bug?? */ /* * insert the following code * *(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) ; p = new(ONAME, Z, Z); *p = *q; p->type = typ(TIND, types[TLONG]); p->offset = 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->offset = 0; m->type = types[TLONG]; 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->offset += w; q = new(OADDR, q, 0); q = new(OAS, p, q); r = new(OLIST, q, r); n = new(OLIST, r, n); no: return n; }