1#include <assert.h>2#include <stdint.h>3#include <stdlib.h>4#include <string.h>56#include <scc/cstd.h>7#include <scc/scc.h>8#include "cc1.h"910#define NOLIST 011#define INLIST 1121314typedef struct init Init;1516struct designator {17 long long pos;18 Node *expr;19 struct designator *next;20};2122struct init {23 unsigned long long pos;24 unsigned long long max;25 struct designator *tail;26 struct designator *head;27};2829int disstring;3031static long long32arydesig(Type *tp, Init *ip)33{3435 long long npos;36 Node *np;3738 if (tp->op != ARY)39 errorp("array index in non-array initializer");4041 next();42 if ((np = iconstexpr()) == NULL) {43 errorp("array index in initializer not of integer type");44 npos = 0;45 } else {46 npos = np->sym->u.i;47 }4849 if (npos < 0 || (tp->prop & TDEFINED) && npos >= tp->n.elem) {50 errorp("array index in initializer exceeds array bounds");51 npos = 0;52 }53 freetree(np);54 expect(']');55 return npos;56}5758static long long59fielddesig(Type *tp, Init *ip)60{61 int ons;62 Symbol *sym, **p;6364 if (!(tp->prop & TAGGREG))65 errorp("field name not in record or union initializer");66 ons = namespace;67 namespace = tp->ns;68 next();69 namespace = ons;70 if (yytoken != IDEN)71 unexpected();72 sym = yylval.sym;73 next();74 if ((sym->flags & SDECLARED) == 0) {75 errorp("unknown field '%s' specified in initializer",76 sym->name);77 return -1;78 }79 for (p = tp->p.fields; *p != sym; ++p)80 ;81 return p - tp->p.fields;82}8384static Init *85init(Init *ip)86{87 ip->tail = ip->head = NULL;88 ip->pos = ip->max = 0;89 return ip;90}9192static Node *93str2ary(Type *tp)94{95 char *s;96 Rune *rs;97 Node *np;98 Type *btp = tp->type;99 Symbol *str, *sym;100 long long i, olen, len;101102 disstring = 1;103 np = assign();104 disstring = 0;105 str = np->left->sym;106107 len = tp->n.elem;108 olen = str->type->n.elem-1;109 if (!(tp->prop & TDEFINED)) {110 len = tp->n.elem = olen+1;111 deftype(tp);112 } else if (len < olen) {113 warn("initializer-string for array of chars is too long");114 }115116 if (str->flags & SSTRING) {117 if (btp != chartype && btp != uchartype && btp != schartype)118 goto wrong;119 s = str->u.s;120 sym = newstring(NULL, len);121 } else {122 if (btp->size != wchartype->size)123 goto wrong;124 rs = str->u.rs;125 sym = newrstring(NULL, len);126 }127128 for (i = 0; i < len; i++) {129 if (str->flags & SSTRING)130 sym->u.s[i] = (i < olen) ? *s++ : '\0';131 else132 sym->u.rs[i] = (i < olen) ? *rs++ : L'\0';133 }134135 assert(np->op == OADDR);136 np->left->sym = sym;137 np->left->type = sym->type;138 np->sym = sym;139 np->type = sym->type;140141 return np;142143wrong:144 errorp("array of inappropriate type initialized from string constant");145 return constnode(zero);146}147148static Node *initlist(Type *);149150static Node *151initialize(Type *tp, int inlist)152{153 Node *np;154 Symbol *sym;155156 if (tp->op == ARY && yytoken == STRING)157 return str2ary(tp);158159 if (yytoken == '{' || inlist && (tp->op == STRUCT || tp->op == ARY))160 return initlist(tp);161162 np = assign();163 if (!eqtype(tp, np->type, EQUIV)) {164 np = convert(decay(np), tp, 0);165 if (!np) {166 errorp("incorrect initializer");167 return constnode(zero);168 }169 }170171 return simplify(np);172}173174static Node *175mkcompound(Init *ip, Type *tp)176{177 Node **v, **p, *np;178 size_t n;179 struct designator *dp, *next;180 Symbol *sym;181 int isconst = 1;182183 if (tp->op == UNION) {184 np = NULL;185 v = xmalloc(sizeof(*v));186 for (dp = ip->head; dp; dp = next) {187 freetree(np);188 np = dp->expr;189 next = dp->next;190 free(dp);191 }192 if ((np->flags & NCONST) == 0)193 isconst = 0;194 *v = np;195 } else {196 n = (tp->prop&TDEFINED) ? tp->n.elem : ip->max;197 if (n == 0) {198 v = NULL;199 } else if (n > SIZE_MAX / sizeof(*v)) {200 errorp("compound literal too big");201 return constnode(zero);202 } else {203 n *= sizeof(*v);204 v = memset(xmalloc(n), 0, n);205206 for (dp = ip->head; dp; dp = next) {207 p = &v[dp->pos];208 freetree(*p);209 np = dp->expr;210 *p = np;211 if ((np->flags & NCONST) == 0)212 isconst = 0;213 next = dp->next;214 free(dp);215 }216 }217 }218219 sym = newsym(NS_IDEN, NULL);220 sym->u.init = v;221 sym->type = tp;222 sym->flags |= SINITLST;223224 return (isconst ? constnode : varnode)(sym);225}226227static void228newdesig(Init *ip, Node *np)229{230 struct designator *dp;231232 dp = xmalloc(sizeof(*dp));233 dp->pos = ip->pos;234 dp->expr = np;235 dp->next = NULL;236237 if (ip->head == NULL) {238 ip->head = ip->tail = dp;239 } else {240 ip->tail->next = dp;241 ip->tail = dp;242 }243244 if (ip->pos+1 > ip->max)245 ip->max = ip->pos+1;246}247248static Node *249initlist_helper(Type *tp)250{251 Init in;252 Node *np;253 Type *curtp, *btp;254 int braces, scalar, toomany, outbound;255 long long nelem = tp->n.elem;256257 braces = scalar = toomany = 0;258259 if (accept('{'))260 braces = 1;261262 if (yytoken == STRING && tp->op == ARY) {263 btp = tp->type;264 if (btp == chartype || btp == uchartype || btp == schartype) {265 np = str2ary(tp);266 if (braces)267 expect('}');268 return np;269 }270 }271272 init(&in);273 for (;;) {274 curtp = inttype;275 switch (yytoken) {276 case '[':277 in.pos = arydesig(tp, &in);278 curtp = tp->type;279 goto desig_list;280 case '.':281 in.pos = fielddesig(tp, &in);282 if (in.pos >= 0 && in.pos < nelem)283 curtp = tp->p.fields[in.pos]->type;284 desig_list:285 if (yytoken == '[' || yytoken == '.') {286 np = initlist(curtp);287 goto new_desig;288 }289 expect('=');290 default:291 outbound = 0;292293 switch (tp->op) {294 case ARY:295 curtp = tp->type;296 if (!(tp->prop & TDEFINED) || in.pos < tp->n.elem)297 break;298 if (!toomany)299 warn("excess elements in array initializer");300 toomany = 1;301 outbound = 1;302 break;303 case UNION:304 case STRUCT:305 if (in.pos < nelem) {306 curtp = tp->p.fields[in.pos]->type;307 break;308 }309 if (!toomany)310 warn("excess elements in struct initializer");311 toomany = 1;312 outbound = 1;313 break;314 default:315 curtp = tp;316 if (!scalar)317 warn("braces around scalar initializer");318 scalar = 1;319 if (in.pos == 0)320 break;321 if (!toomany)322 warn("excess elements in scalar initializer");323 toomany = 1;324 outbound = 1;325 break;326 }327 np = initialize(curtp, INLIST);328 if (outbound) {329 freetree(np);330 np = NULL;331 }332 }333334new_desig:335 if (np)336 newdesig(&in, np);337 if (++in.pos == 0)338 errorp("compound literal too big");339 if (nelem == in.pos && !braces)340 break;341 if (!accept(','))342 break;343 if (yytoken == '}')344 break;345 }346347 if (braces)348 expect('}');349350351 if (tp->op == ARY && !(tp->prop & TDEFINED)) {352 tp->n.elem = in.max;353 deftype(tp);354 }355 if (in.max == 0) {356 errorp("empty braced initializer");357 return constnode(zero);358 }359360 return mkcompound(&in, tp);361}362363static Node *364initlist(Type *tp)365{366 Node *np;367 static int depth;368369 if (depth == NR_SUBTYPE)370 error("too many nested initializers");371372 ++depth;373 np = initlist_helper(tp);374 --depth;375376 return np;377}378379static void380autofield(Symbol *sym, Node *np, Type *tp, unsigned long long *addr)381{382 int align;383 Node *aux;384 unsigned long long na;385386 align = tp->align - 1;387 na = *addr;388 na = (na + align) & ~align;389 *addr = na;390391 aux = node(OADDR, pvoidtype, varnode(sym), NULL);392 aux = node(OADD, pvoidtype, aux, addrnode(na));393 aux = node(OPTR, tp, aux, NULL);394 aux = node(OASSIGN, tp, aux, np);395396 emit(OEXPR, aux);397 *addr += tp->size;398}399400static void401autocomp(Symbol *sym, Node *np, Type *tp, unsigned long long *addr)402{403 Type *p;404 Node *aux;405 Symbol *init;406 unsigned long long n;407408 if (!np) {409 init = NULL;410 } else {411 if (!np->sym)412 goto expression;413 init = np->sym;414 if ((init->flags & SINITLST) == 0)415 goto expression;416 }417418 switch (tp->op) {419 case PTR:420 case INT:421 case ENUM:422 aux = init ? *init->u.init : zeronode(tp);423 autofield(sym, aux, aux->type, addr);424 break;425 case UNION:426 aux = (init) ? init->u.init[0] : NULL;427 p = (aux) ? aux->type : tp->p.fields[0]->type;428 autocomp(sym, aux, p, addr);429 break;430 case STRUCT:431 case ARY:432 if (np && (np->flags & NCONST) != 0) {433 Symbol *hidden = newsym(NS_IDEN, NULL);434 hidden->id = newid();435 hidden->type = init->type;436 hidden->flags |= SLOCAL | SHASINIT;437 emit(ODECL, hidden);438 emit(OINIT, np);439 np = varnode(hidden);440 goto expression;441 }442 for (n = 0; n < tp->n.elem; ++n) {443 aux = (init) ? init->u.init[n] : NULL;444 p = (tp->op == ARY) ? tp->type : tp->p.fields[n]->type;445 autocomp(sym, aux, p, addr);446 }447 break;448 default:449 abort();450 }451452 if (init) {453 free(init->u.init);454 init->u.init = NULL;455 }456 freetree(np);457 return;458459expression:460 autofield(sym, np, tp, addr);461}462463static void464emitstrings(Node *np)465{466 unsigned f;467 Symbol *sym;468 long long i, n;469470 if (!np)471 return;472473 if (np->op == OSYM) {474 sym = np->sym;475 f = sym->flags & (SSTRING|SRSTRING|SEMITTED|SINITLST);476 if (f == SSTRING || f == SRSTRING) {477 sym->flags |= SHASINIT;478 emit(ODECL, sym);479 emit(OINIT, constnode(sym));480 } else if (f == SINITLST) {481 n = (np->type->op == UNION) ? 1 : np->type->n.elem;482 for (i = 0; i < n; ++i)483 emitstrings(sym->u.init[i]);484 }485 }486487 emitstrings(np->left);488 emitstrings(np->right);489}490491static void492autoinit(Symbol *sym, Node *np)493{494 unsigned long long a;495 Symbol *hidden;496 Type *tp = np->type;497498repeat:499 switch (tp->op) {500 case UNION:501 np = np->sym->u.init[0];502 tp = np->type;503 goto repeat;504 case ARY:505 if (np->op == OADDR && np->sym->flags & SSTRING)506 goto hidden_data;507 case STRUCT:508 if (np->op != OSYM || (np->sym->flags & SINITLST) == 0)509 goto expr;510 hidden_data:511 if (!(np->flags & NCONST)) {512 a = 0;513 emitstrings(np);514 emit(ODECL, sym);515 autocomp(sym, np, np->type, &a);516 break;517 }518 hidden = newsym(NS_IDEN, NULL);519 hidden->id = newid();520 hidden->type = sym->type;521 hidden->flags |= SLOCAL | SHASINIT;522 emit(ODECL, hidden);523 emit(OINIT, np);524 np = varnode(hidden);525 default:526 expr:527 emitstrings(np);528 emit(ODECL, sym);529 np = node(OASSIGN, tp, varnode(sym), np);530 emit(OEXPR, np);531 break;532 }533}534535void536initializer(Symbol *sym)537{538 Node *np;539 Type *tp = sym->type;540 int flags = sym->flags;541542 if (tp->op == FTN) {543 errorp("function '%s' initialized like a variable",544 sym->name);545 tp = inttype;546 }547 np = initialize(tp, NOLIST);548549 if (flags & SDEFINED) {550 errorp("redeclaration of '%s'", sym->name);551 } else if ((flags & (SGLOBAL|SLOCAL|SPRIVATE)) != 0) {552 if ((np->flags & NCONST) == 0) {553 errorp("initializer element is not constant");554 return;555 }556 sym->flags |= SHASINIT;557 sym->flags &= ~SEMITTED;558 emit(ODECL, sym);559 emit(OINIT, np);560 sym->flags |= SDEFINED;561 } else if ((flags & (SEXTERN|STYPEDEF)) != 0) {562 errorp("'%s' has both '%s' and initializer",563 sym->name, (flags&SEXTERN) ? "extern" : "typedef");564 } else {565 autoinit(sym, np);566 }567}