aboutsummaryrefslogtreecommitdiff
path: root/code/tools/lcc/src/init.c
diff options
context:
space:
mode:
Diffstat (limited to 'code/tools/lcc/src/init.c')
-rw-r--r--code/tools/lcc/src/init.c318
1 files changed, 318 insertions, 0 deletions
diff --git a/code/tools/lcc/src/init.c b/code/tools/lcc/src/init.c
new file mode 100644
index 0000000..172d7c0
--- /dev/null
+++ b/code/tools/lcc/src/init.c
@@ -0,0 +1,318 @@
+#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<<fieldright(p);
+ if (IR->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;
+}