scc

simple c99 compiler
git clone git://git.simple-cc.org/scc
Log | Files | Refs | Submodules | README | LICENSE

init.c (7200B)


      1 #include <stdint.h>
      2 #include <stdlib.h>
      3 #include <string.h>
      4 
      5 #include <scc/cstd.h>
      6 #include <scc/scc.h>
      7 #include "cc1.h"
      8 
      9 #define NOLIST 0
     10 #define INLIST 1
     11 
     12 
     13 typedef struct init Init;
     14 
     15 struct designator {
     16 	TINT pos;
     17 	Node *expr;
     18 	struct designator *next;
     19 };
     20 
     21 struct init {
     22 	TUINT pos;
     23 	TUINT max;
     24 	struct designator *tail;
     25 	struct designator *head;
     26 };
     27 
     28 static TINT
     29 arydesig(Type *tp, Init *ip)
     30 {
     31 	TINT npos;
     32 	Node *np;
     33 
     34 	if (tp->op != ARY)
     35 		errorp("array index in non-array initializer");
     36 	next();
     37 	np = constexpr();
     38 	npos = np->sym->u.i;
     39 	if (npos < 0 || (tp->prop & TDEFINED) && npos >= tp->n.elem) {
     40 		errorp("array index in initializer exceeds array bounds");
     41 		npos = 0;
     42 	}
     43 	freetree(np);
     44 	expect(']');
     45 	return npos;
     46 }
     47 
     48 static TINT
     49 fielddesig(Type *tp, Init *ip)
     50 {
     51 	int ons;
     52 	Symbol *sym, **p;
     53 
     54 	if (!(tp->prop & TAGGREG))
     55 		errorp("field name not in record or union initializer");
     56 	ons = namespace;
     57 	namespace = tp->ns;
     58 	next();
     59 	namespace = ons;
     60 	if (yytoken != IDEN)
     61 		unexpected();
     62 	sym = yylval.sym;
     63 	next();
     64 	if ((sym->flags & SDECLARED) == 0) {
     65 		errorp("unknown field '%s' specified in initializer",
     66 		      sym->name);
     67 		return -1;
     68 	}
     69 	for (p = tp->p.fields; *p != sym; ++p)
     70 		;
     71 	return p - tp->p.fields;
     72 }
     73 
     74 static Init *
     75 init(Init *ip)
     76 {
     77 	ip->tail = ip->head = NULL;
     78 	ip->pos = ip->max = 0;
     79 	return ip;
     80 }
     81 
     82 static Node *
     83 str2ary(Type *tp)
     84 {
     85 	Node *np;
     86 	Type *btp = tp->type;
     87 	Symbol *sym;
     88 	size_t len;
     89 	char *s;
     90 
     91 	np = assign();
     92 	sym = np->left->sym;
     93 	if (btp != chartype && btp != uchartype && btp != schartype) {
     94 		errorp("array of inappropriate type initialized from string constant");
     95 		return constnode(zero);
     96 	}
     97 
     98 	len = sym->type->n.elem-1;
     99 	if (!(tp->prop & TDEFINED)) {
    100 		tp->n.elem = len+1;
    101 		deftype(tp);
    102 	} else if (tp->n.elem < len) {
    103 		warn("initializer-string for array of chars is too long");
    104 	}
    105 
    106 	len = tp->n.elem;
    107 	s = sym->u.s;
    108 	sym = newstring(NULL, len);
    109 	strncpy(sym->u.s, s, len);
    110 	np->sym = sym;
    111 	np->type = sym->type;
    112 
    113 	return np;
    114 }
    115 
    116 static Node *
    117 initialize(Type *tp, int inlist)
    118 {
    119 	Node *np;
    120 	Symbol *sym;
    121 
    122 	if (tp->op == ARY && yytoken == STRING)
    123 		return str2ary(tp);
    124 
    125 	if (yytoken == '{' || inlist && (tp->op == STRUCT || tp->op == ARY))
    126 		return initlist(tp);
    127 
    128 	np = assign();
    129 	if (!eqtype(tp, np->type, EQUIV)) {
    130 		np = convert(decay(np), tp, 0);
    131 		if (!np) {
    132 			errorp("incorrect initializer");
    133 			return constnode(zero);
    134 		}
    135 	}
    136 
    137 	return simplify(np);
    138 }
    139 
    140 static Node *
    141 mkcompound(Init *ip, Type *tp)
    142 {
    143 	Node **v, **p, *np;
    144 	size_t n;
    145 	struct designator *dp, *next;
    146 	Symbol *sym;
    147 	int isconst = 1;
    148 
    149 	if (tp->op == UNION) {
    150 		np = NULL;
    151 		v = xmalloc(sizeof(*v));
    152 		for (dp = ip->head; dp; dp = next) {
    153 			freetree(np);
    154 			np = dp->expr;
    155 			next = dp->next;
    156 			free(dp);
    157 		}
    158 		if ((np->flags & NCONST) == 0)
    159 			isconst = 0;
    160 		*v = np;
    161 	} else {
    162 		n = (tp->prop&TDEFINED) ? tp->n.elem : ip->max;
    163 		if (n == 0) {
    164 			v = NULL;
    165 		} else if (n > SIZE_MAX / sizeof(*v)) {
    166 			errorp("compound literal too big");
    167 			return constnode(zero);
    168 		} else {
    169 			n *= sizeof(*v);
    170 			v = memset(xmalloc(n), 0, n);
    171 
    172 			for (dp = ip->head; dp; dp = next) {
    173 				p = &v[dp->pos];
    174 				freetree(*p);
    175 				np = dp->expr;
    176 				*p = np;
    177 				if ((np->flags & NCONST) == 0)
    178 					isconst = 0;
    179 				next = dp->next;
    180 				free(dp);
    181 			}
    182 		}
    183 	}
    184 
    185 	sym = newsym(NS_IDEN, NULL);
    186 	sym->u.init = v;
    187 	sym->type = tp;
    188 	sym->flags |= SINITLST;
    189 
    190 	return (isconst ? constnode : varnode)(sym);
    191 }
    192 
    193 static void
    194 newdesig(Init *ip, Node *np)
    195 {
    196 	struct designator *dp;
    197 
    198 	dp = xmalloc(sizeof(*dp));
    199 	dp->pos = ip->pos;
    200 	dp->expr = np;
    201 	dp->next = NULL;
    202 
    203 	if (ip->head == NULL) {
    204 		ip->head = ip->tail = dp;
    205 	} else {
    206 		ip->tail->next = dp;
    207 		ip->tail = dp;
    208 	}
    209 
    210 	if (ip->pos+1 > ip->max)
    211 		ip->max = ip->pos+1;
    212 }
    213 
    214 static Node *
    215 initlist_helper(Type *tp)
    216 {
    217 	Init in;
    218 	Node *np;
    219 	Type *curtp;
    220 	int braces, scalar, toomany, outbound;
    221 	TINT nelem = tp->n.elem;
    222 
    223 	init(&in);
    224 	braces = scalar = toomany = 0;
    225 
    226 	if (accept('{'))
    227 		braces = 1;
    228 
    229 	for (;;) {
    230 		curtp = inttype;
    231 		switch (yytoken) {
    232 		case '[':
    233 			in.pos = arydesig(tp, &in);
    234 			curtp = tp->type;
    235 			goto desig_list;
    236 		case '.':
    237 			in.pos = fielddesig(tp, &in);
    238 			if (in.pos >= 0 && in.pos < nelem)
    239 				curtp = tp->p.fields[in.pos]->type;
    240 		desig_list:
    241 			if (yytoken == '[' || yytoken == '.') {
    242 				np = initlist(curtp);
    243 				goto new_desig;
    244 			}
    245 			expect('=');
    246 		default:
    247 			outbound = 0;
    248 
    249 			switch (tp->op) {
    250 			case ARY:
    251 				curtp = tp->type;
    252 				if (!(tp->prop & TDEFINED) || in.pos < tp->n.elem)
    253 					break;
    254 				if (!toomany)
    255 					warn("excess elements in array initializer");
    256 				toomany = 1;
    257 				outbound = 1;
    258 				break;
    259 			case UNION:
    260 			case STRUCT:
    261 				if (in.pos < nelem) {
    262 					curtp = tp->p.fields[in.pos]->type;
    263 					break;
    264 				}
    265 				if (!toomany)
    266 					warn("excess elements in struct initializer");
    267 				toomany = 1;
    268 				outbound = 1;
    269 				break;
    270 			default:
    271 				curtp = tp;
    272 				if (!scalar)
    273 					warn("braces around scalar initializer");
    274 				scalar = 1;
    275 				if (in.pos == 0)
    276 					break;
    277 				if (!toomany)
    278 					warn("excess elements in scalar initializer");
    279 				toomany = 1;
    280 				outbound = 1;
    281 				break;
    282 			}
    283 			np = initialize(curtp, INLIST);
    284 			if (outbound) {
    285 				freetree(np);
    286 				np = NULL;
    287 			}
    288 		}
    289 
    290 new_desig:
    291 		if (np)
    292 			newdesig(&in, np);
    293 		if (++in.pos == 0)
    294 			errorp("compound literal too big");
    295 		if (nelem == in.pos && !braces)
    296 			break;
    297 		if (!accept(','))
    298 			break;
    299 		if (yytoken == '}')
    300 			break;
    301 	}
    302 
    303 	if (braces)
    304 		expect('}');
    305 
    306 
    307 	if (tp->op == ARY && !(tp->prop & TDEFINED)) {
    308 		tp->n.elem = in.max;
    309 		deftype(tp);
    310 	}
    311 	if (in.max == 0) {
    312 		errorp("empty braced initializer");
    313 		return constnode(zero);
    314 	}
    315 
    316 	return mkcompound(&in, tp);
    317 }
    318 
    319 Node *
    320 initlist(Type *tp)
    321 {
    322 	Node *np;
    323 	static int depth;
    324 
    325 	if (depth == NR_SUBTYPE)
    326 		error("too many nested initializers");
    327 
    328 	++depth;
    329 	np = initlist_helper(tp);
    330 	--depth;
    331 
    332 	return np;
    333 }
    334 
    335 static void
    336 autoinit(Symbol *sym, Node *np)
    337 {
    338 	Symbol *hidden;
    339 	Type *tp = sym->type;
    340 
    341 repeat:
    342 	switch (tp->op) {
    343 	case UNION:
    344 		np = np->sym->u.init[0];
    345 		tp = np->type;
    346 		goto repeat;
    347 	case ARY:
    348 	case STRUCT:
    349 		if (np->op == OSYM && np->sym->flags & SINITLST) {
    350 			if (!(np->flags & NCONST))
    351 				abort(); /* TODO */
    352 			hidden = newsym(NS_IDEN, NULL);
    353 			hidden->id = newid();
    354 			hidden->type = sym->type;
    355 			hidden->flags |= SLOCAL | SHASINIT;
    356 			emit(ODECL, hidden);
    357 			emit(OINIT, np);
    358 			np = varnode(hidden);
    359 		}
    360 	default:
    361 		emit(ODECL, sym);
    362 		np = node(OASSIGN, tp, varnode(sym), np);
    363 		emit(OEXPR, np);
    364 		break;
    365 	}
    366 }
    367 
    368 void
    369 initializer(Symbol *sym, Type *tp)
    370 {
    371 	Node *np;
    372 	int flags = sym->flags;
    373 
    374 	if (tp->op == FTN) {
    375 		errorp("function '%s' initialized like a variable",
    376 		       sym->name);
    377 		tp = inttype;
    378 	}
    379 	np = initialize(tp, NOLIST);
    380 
    381 	if (flags & SDEFINED) {
    382 		errorp("redeclaration of '%s'", sym->name);
    383 	} else if ((flags & (SGLOBAL|SLOCAL|SPRIVATE)) != 0) {
    384 		if ((np->flags & NCONST) == 0) {
    385 			errorp("initializer element is not constant");
    386 			return;
    387 		}
    388 		sym->flags |= SHASINIT;
    389 		sym->flags &= ~SEMITTED;
    390 		emit(ODECL, sym);
    391 		emit(OINIT, np);
    392 		sym->flags |= SDEFINED;
    393 	} else if ((flags & (SEXTERN|STYPEDEF)) != 0) {
    394 		errorp("'%s' has both '%s' and initializer",
    395 		       sym->name, (flags&SEXTERN) ? "extern" : "typedef");
    396 	} else {
    397 		autoinit(sym, np);
    398 	}
    399 }