#include "c.h" static int curseg; /* current segment */ /* defpointer - initialize a pointer to p or to 0 if p==0 */ void defpointer(Symbol p) { if (p) { (*IR->defaddress)(p); p->ref++; } else { static Value v; (*IR->defconst)(P, voidptype->size, v); } } /* genconst - generate/check constant expression e; return size */ static int genconst(Tree e, int def) { for (;;) switch (generic(e->op)) { case ADDRG: if (def) (*IR->defaddress)(e->u.sym); return e->type->size; case CNST: if (e->op == CNST+P && isarray(e->type)) { e = cvtconst(e); continue; } if (def) (*IR->defconst)(e->type->op, e->type->size, e->u.v); return e->type->size; case RIGHT: assert(e->kids[0] || e->kids[1]); if (e->kids[1] && e->kids[0]) error("initializer must be constant\n"); e = e->kids[1] ? e->kids[1] : e->kids[0]; continue; case CVP: if (isarith(e->type)) error("cast from `%t' to `%t' is illegal in constant expressions\n", e->kids[0]->type, e->type); /* fall thru */ case CVI: case CVU: case CVF: e = e->kids[0]; continue; default: error("initializer must be constant\n"); if (def) genconst(consttree(0, inttype), def); return inttype->size; } } /* initvalue - evaluate a constant expression for a value of integer type ty */ static Tree initvalue(Type ty) { Type aty; Tree e; needconst++; e = expr1(0); if ((aty = assign(ty, e)) != NULL) e = cast(e, aty); else { error("invalid initialization type; found `%t' expected `%t'\n", e->type, ty); e = retype(consttree(0, inttype), ty); } needconst--; if (generic(e->op) != CNST) { error("initializer must be constant\n"); e = retype(consttree(0, inttype), ty); } return e; } /* initarray - initialize array of ty of <= len bytes; if len == 0, go to } */ static int initarray(int len, Type ty, int lev) { int n = 0; do { initializer(ty, lev); n += ty->size; if (len > 0 && n >= len || t != ',') break; t = gettok(); } while (t != '}'); return n; } /* initchar - initialize array of <= len ty characters; if len == 0, go to } */ static int initchar(int len, Type ty) { int n = 0; char buf[16], *s = buf; do { *s++ = initvalue(ty)->u.v.i; if (++n%inttype->size == 0) { (*IR->defstring)(inttype->size, buf); s = buf; } if (len > 0 && n >= len || t != ',') break; t = gettok(); } while (t != '}'); if (s > buf) (*IR->defstring)(s - buf, buf); return n; } /* initend - finish off an initialization at level lev; accepts trailing comma */ static void initend(int lev, char follow[]) { if (lev == 0 && t == ',') t = gettok(); test('}', follow); } /* initfields - initialize <= an unsigned's worth of bit fields in fields p to q */ static int initfields(Field p, Field q) { unsigned int bits = 0; int i, n = 0; do { i = initvalue(inttype)->u.v.i; if (fieldsize(p) < 8*p->type->size) { if (p->type == inttype && (i < -(int)(fieldmask(p)>>1)-1 || i > (int)(fieldmask(p)>>1)) || p->type == unsignedtype && (i&~fieldmask(p)) != 0) warning("initializer exceeds bit-field width\n"); i &= fieldmask(p); } bits |= i<little_endian) { if (fieldsize(p) + fieldright(p) > n) n = fieldsize(p) + fieldright(p); } else { if (fieldsize(p) + fieldleft(p) > n) n = fieldsize(p) + fieldleft(p); } if (p->link == q) break; p = p->link; } while (t == ',' && (t = gettok()) != 0); n = (n + 7)/8; for (i = 0; i < n; i++) { Value v; if (IR->little_endian) { v.u = (unsigned char)bits; bits >>= 8; } else { /* a big endian */ v.u = (unsigned char)(bits>>(8*(unsignedtype->size - 1))); bits <<= 8; } (*IR->defconst)(U, unsignedchar->size, v); } return n; } /* initstruct - initialize a struct ty of <= len bytes; if len == 0, go to } */ static int initstruct(int len, Type ty, int lev) { int a, n = 0; Field p = ty->u.sym->u.s.flist; do { if (p->offset > n) { (*IR->space)(p->offset - n); n += p->offset - n; } if (p->lsb) { Field q = p; while (q->link && q->link->offset == p->offset) q = q->link; n += initfields(p, q->link); p = q; } else { initializer(p->type, lev); n += p->type->size; } if (p->link) { p = p->link; a = p->type->align; } else a = ty->align; if (a && n%a) { (*IR->space)(a - n%a); n = roundup(n, a); } if (len > 0 && n >= len || t != ',') break; t = gettok(); } while (t != '}'); return n; } /* initializer - constexpr | { constexpr ( , constexpr )* [ , ] } */ Type initializer(Type ty, int lev) { int n = 0; Tree e; Type aty = NULL; static char follow[] = { IF, CHAR, STATIC, 0 }; ty = unqual(ty); if (isscalar(ty)) { needconst++; if (t == '{') { t = gettok(); e = expr1(0); initend(lev, follow); } else e = expr1(0); e = pointer(e); if ((aty = assign(ty, e)) != NULL) e = cast(e, aty); else error("invalid initialization type; found `%t' expected `%t'\n", e->type, ty); n = genconst(e, 1); deallocate(STMT); needconst--; } if ((isunion(ty) || isstruct(ty)) && ty->size == 0) { static char follow[] = { CHAR, STATIC, 0 }; error("cannot initialize undefined `%t'\n", ty); skipto(';', follow); return ty; } else if (isunion(ty)) { if (t == '{') { t = gettok(); n = initstruct(ty->u.sym->u.s.flist->type->size, ty, lev + 1); initend(lev, follow); } else { if (lev == 0) error("missing { in initialization of `%t'\n", ty); n = initstruct(ty->u.sym->u.s.flist->type->size, ty, lev + 1); } } else if (isstruct(ty)) { if (t == '{') { t = gettok(); n = initstruct(0, ty, lev + 1); test('}', follow); } else if (lev > 0) n = initstruct(ty->size, ty, lev + 1); else { error("missing { in initialization of `%t'\n", ty); n = initstruct(ty->u.sym->u.s.flist->type->size, ty, lev + 1); } } if (isarray(ty)) aty = unqual(ty->type); if (isarray(ty) && ischar(aty)) { if (t == SCON) { if (ty->size > 0 && ty->size == tsym->type->size - 1) tsym->type = array(chartype, ty->size, 0); n = tsym->type->size; (*IR->defstring)(tsym->type->size, tsym->u.c.v.p); t = gettok(); } else if (t == '{') { t = gettok(); if (t == SCON) { ty = initializer(ty, lev + 1); initend(lev, follow); return ty; } n = initchar(0, aty); test('}', follow); } else if (lev > 0 && ty->size > 0) n = initchar(ty->size, aty); else { /* eg, char c[] = 0; */ error("missing { in initialization of `%t'\n", ty); n = initchar(1, aty); } } else if (isarray(ty)) { if (t == SCON && aty == widechar) { int i; unsigned int *s = tsym->u.c.v.p; if (ty->size > 0 && ty->size == tsym->type->size - widechar->size) tsym->type = array(widechar, ty->size/widechar->size, 0); n = tsym->type->size; for (i = 0; i < n; i += widechar->size) { Value v; v.u = *s++; (*IR->defconst)(widechar->op, widechar->size, v); } t = gettok(); } else if (t == '{') { t = gettok(); if (t == SCON && aty == widechar) { ty = initializer(ty, lev + 1); initend(lev, follow); return ty; } n = initarray(0, aty, lev + 1); test('}', follow); } else if (lev > 0 && ty->size > 0) n = initarray(ty->size, aty, lev + 1); else { error("missing { in initialization of `%t'\n", ty); n = initarray(aty->size, aty, lev + 1); } } if (ty->size) { if (n > ty->size) error("too many initializers\n"); else if (n < ty->size) (*IR->space)(ty->size - n); } else if (isarray(ty) && ty->type->size > 0) ty = array(ty->type, n/ty->type->size, 0); else ty->size = n; return ty; } /* swtoseg - switch to segment seg, if necessary */ void swtoseg(int seg) { if (curseg != seg) (*IR->segment)(seg); curseg = seg; }