* added compilers lcc and bcc (linux86)
[mascara-docs.git] / compilers / lcc / src / init.c
blob172d7c0473c515afb36873e7eda0c6d796b2d16d
1 #include "c.h"
4 static int curseg; /* current segment */
6 /* defpointer - initialize a pointer to p or to 0 if p==0 */
7 void defpointer(Symbol p) {
8 if (p) {
9 (*IR->defaddress)(p);
10 p->ref++;
11 } else {
12 static Value v;
13 (*IR->defconst)(P, voidptype->size, v);
17 /* genconst - generate/check constant expression e; return size */
18 static int genconst(Tree e, int def) {
19 for (;;)
20 switch (generic(e->op)) {
21 case ADDRG:
22 if (def)
23 (*IR->defaddress)(e->u.sym);
24 return e->type->size;
25 case CNST:
26 if (e->op == CNST+P && isarray(e->type)) {
27 e = cvtconst(e);
28 continue;
30 if (def)
31 (*IR->defconst)(e->type->op, e->type->size, e->u.v);
32 return e->type->size;
33 case RIGHT:
34 assert(e->kids[0] || e->kids[1]);
35 if (e->kids[1] && e->kids[0])
36 error("initializer must be constant\n");
37 e = e->kids[1] ? e->kids[1] : e->kids[0];
38 continue;
39 case CVP:
40 if (isarith(e->type))
41 error("cast from `%t' to `%t' is illegal in constant expressions\n",
42 e->kids[0]->type, e->type);
43 /* fall thru */
44 case CVI: case CVU: case CVF:
45 e = e->kids[0];
46 continue;
47 default:
48 error("initializer must be constant\n");
49 if (def)
50 genconst(consttree(0, inttype), def);
51 return inttype->size;
55 /* initvalue - evaluate a constant expression for a value of integer type ty */
56 static Tree initvalue(Type ty) {
57 Type aty;
58 Tree e;
60 needconst++;
61 e = expr1(0);
62 if ((aty = assign(ty, e)) != NULL)
63 e = cast(e, aty);
64 else {
65 error("invalid initialization type; found `%t' expected `%t'\n",
66 e->type, ty);
67 e = retype(consttree(0, inttype), ty);
69 needconst--;
70 if (generic(e->op) != CNST) {
71 error("initializer must be constant\n");
72 e = retype(consttree(0, inttype), ty);
74 return e;
77 /* initarray - initialize array of ty of <= len bytes; if len == 0, go to } */
78 static int initarray(int len, Type ty, int lev) {
79 int n = 0;
81 do {
82 initializer(ty, lev);
83 n += ty->size;
84 if ((len > 0 && n >= len) || t != ',')
85 break;
86 t = gettok();
87 } while (t != '}');
88 return n;
91 /* initchar - initialize array of <= len ty characters; if len == 0, go to } */
92 static int initchar(int len, Type ty) {
93 int n = 0;
94 char buf[16], *s = buf;
96 do {
97 *s++ = initvalue(ty)->u.v.i;
98 if (++n%inttype->size == 0) {
99 (*IR->defstring)(inttype->size, buf);
100 s = buf;
102 if ((len > 0 && n >= len) || t != ',')
103 break;
104 t = gettok();
105 } while (t != '}');
106 if (s > buf)
107 (*IR->defstring)(s - buf, buf);
108 return n;
111 /* initend - finish off an initialization at level lev; accepts trailing comma */
112 static void initend(int lev, char follow[]) {
113 if (lev == 0 && t == ',')
114 t = gettok();
115 test('}', follow);
118 /* initfields - initialize <= an unsigned's worth of bit fields in fields p to q */
119 static int initfields(Field p, Field q) {
120 unsigned int bits = 0;
121 int i, n = 0;
123 do {
124 i = initvalue(inttype)->u.v.i;
125 if (fieldsize(p) < 8*p->type->size) {
126 if ((p->type == inttype &&
127 (i < -(int)(fieldmask(p)>>1)-1 || i > (int)(fieldmask(p)>>1)))
128 || (p->type == unsignedtype && (i&~fieldmask(p)) != 0))
129 warning("initializer exceeds bit-field width\n");
130 i &= fieldmask(p);
132 bits |= i<<fieldright(p);
133 if (IR->little_endian) {
134 if (fieldsize(p) + fieldright(p) > n)
135 n = fieldsize(p) + fieldright(p);
136 } else {
137 if (fieldsize(p) + fieldleft(p) > n)
138 n = fieldsize(p) + fieldleft(p);
140 if (p->link == q)
141 break;
142 p = p->link;
143 } while (t == ',' && (t = gettok()) != 0);
144 n = (n + 7)/8;
145 for (i = 0; i < n; i++) {
146 Value v;
147 if (IR->little_endian) {
148 v.u = (unsigned char)bits;
149 bits >>= 8;
150 } else { /* a big endian */
151 v.u = (unsigned char)(bits>>(8*(unsignedtype->size - 1)));
152 bits <<= 8;
154 (*IR->defconst)(U, unsignedchar->size, v);
156 return n;
159 /* initstruct - initialize a struct ty of <= len bytes; if len == 0, go to } */
160 static int initstruct(int len, Type ty, int lev) {
161 int a, n = 0;
162 Field p = ty->u.sym->u.s.flist;
164 do {
165 if (p->offset > n) {
166 (*IR->space)(p->offset - n);
167 n += p->offset - n;
169 if (p->lsb) {
170 Field q = p;
171 while (q->link && q->link->offset == p->offset)
172 q = q->link;
173 n += initfields(p, q->link);
174 p = q;
175 } else {
176 initializer(p->type, lev);
177 n += p->type->size;
179 if (p->link) {
180 p = p->link;
181 a = p->type->align;
182 } else
183 a = ty->align;
184 if (a && n%a) {
185 (*IR->space)(a - n%a);
186 n = roundup(n, a);
188 if ((len > 0 && n >= len) || t != ',')
189 break;
190 t = gettok();
191 } while (t != '}');
192 return n;
195 /* initializer - constexpr | { constexpr ( , constexpr )* [ , ] } */
196 Type initializer(Type ty, int lev) {
197 int n = 0;
198 Tree e;
199 Type aty = NULL;
200 static char follow[] = { IF, CHAR, STATIC, 0 };
202 ty = unqual(ty);
203 if (isscalar(ty)) {
204 needconst++;
205 if (t == '{') {
206 t = gettok();
207 e = expr1(0);
208 initend(lev, follow);
209 } else
210 e = expr1(0);
211 e = pointer(e);
212 if ((aty = assign(ty, e)) != NULL)
213 e = cast(e, aty);
214 else
215 error("invalid initialization type; found `%t' expected `%t'\n",
216 e->type, ty);
217 n = genconst(e, 1);
218 deallocate(STMT);
219 needconst--;
221 if ((isunion(ty) || isstruct(ty)) && ty->size == 0) {
222 static char follow[] = { CHAR, STATIC, 0 };
223 error("cannot initialize undefined `%t'\n", ty);
224 skipto(';', follow);
225 return ty;
226 } else if (isunion(ty)) {
227 if (t == '{') {
228 t = gettok();
229 n = initstruct(ty->u.sym->u.s.flist->type->size, ty, lev + 1);
230 initend(lev, follow);
231 } else {
232 if (lev == 0)
233 error("missing { in initialization of `%t'\n", ty);
234 n = initstruct(ty->u.sym->u.s.flist->type->size, ty, lev + 1);
236 } else if (isstruct(ty)) {
237 if (t == '{') {
238 t = gettok();
239 n = initstruct(0, ty, lev + 1);
240 test('}', follow);
241 } else if (lev > 0)
242 n = initstruct(ty->size, ty, lev + 1);
243 else {
244 error("missing { in initialization of `%t'\n", ty);
245 n = initstruct(ty->u.sym->u.s.flist->type->size, ty, lev + 1);
248 if (isarray(ty))
249 aty = unqual(ty->type);
250 if (isarray(ty) && ischar(aty)) {
251 if (t == SCON) {
252 if (ty->size > 0 && ty->size == tsym->type->size - 1)
253 tsym->type = array(chartype, ty->size, 0);
254 n = tsym->type->size;
255 (*IR->defstring)(tsym->type->size, tsym->u.c.v.p);
256 t = gettok();
257 } else if (t == '{') {
258 t = gettok();
259 if (t == SCON) {
260 ty = initializer(ty, lev + 1);
261 initend(lev, follow);
262 return ty;
264 n = initchar(0, aty);
265 test('}', follow);
266 } else if (lev > 0 && ty->size > 0)
267 n = initchar(ty->size, aty);
268 else { /* eg, char c[] = 0; */
269 error("missing { in initialization of `%t'\n", ty);
270 n = initchar(1, aty);
272 } else if (isarray(ty)) {
273 if (t == SCON && aty == widechar) {
274 int i;
275 unsigned int *s = tsym->u.c.v.p;
276 if (ty->size > 0 && ty->size == tsym->type->size - widechar->size)
277 tsym->type = array(widechar, ty->size/widechar->size, 0);
278 n = tsym->type->size;
279 for (i = 0; i < n; i += widechar->size) {
280 Value v;
281 v.u = *s++;
282 (*IR->defconst)(widechar->op, widechar->size, v);
284 t = gettok();
285 } else if (t == '{') {
286 t = gettok();
287 if (t == SCON && aty == widechar) {
288 ty = initializer(ty, lev + 1);
289 initend(lev, follow);
290 return ty;
292 n = initarray(0, aty, lev + 1);
293 test('}', follow);
294 } else if (lev > 0 && ty->size > 0)
295 n = initarray(ty->size, aty, lev + 1);
296 else {
297 error("missing { in initialization of `%t'\n", ty);
298 n = initarray(aty->size, aty, lev + 1);
301 if (ty->size) {
302 if (n > ty->size)
303 error("too many initializers\n");
304 else if (n < ty->size)
305 (*IR->space)(ty->size - n);
306 } else if (isarray(ty) && ty->type->size > 0)
307 ty = array(ty->type, n/ty->type->size, 0);
308 else
309 ty->size = n;
310 return ty;
313 /* swtoseg - switch to segment seg, if necessary */
314 void swtoseg(int seg) {
315 if (curseg != seg)
316 (*IR->segment)(seg);
317 curseg = seg;