📄 dcl.c
字号:
#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->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); 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, 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; 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;}intisstruct(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, long o, int exflag){ Node *a, *l, *r, nod; Type *t1; 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 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: %ld", 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);}voidsuallign(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->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); l->offset = w; w = align(w, l, Ael2); } } w = align(w, t, Asu2); t->width = w; acidtype(t); pickletype(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), l, Ael2); if(o > w) w = o; } w = align(w, t, Asu2); t->width = w; acidtype(t); pickletype(t); return; default: diag(Z, "unknown type in suallign: %T", t); break; }}longround(long 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 2voidargmark(Node *n, int pass){ Type *t; autoffset = align(0, thisfn->link, Aarg0); 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;}voidwalkparam(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); s->offset = autoffset; autoffset = align(autoffset, s->type, Aarg2); } else dodecl(pdecl, CXXX, types[TINT], n); break; }}voidmarkdcl(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){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -