ref: f08eafe178160c3dea617d0dd28c50b04b998c8d
dir: /cc1/init.c/
/* See LICENSE file for copyright and license details. */ static char sccsid[] = "@(#) ./cc1/init.c"; #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <cstd.h> #include "../inc/cc.h" #include "cc1.h" typedef struct init Init; struct designator { TINT pos; Node *expr; struct designator *next; }; struct init { Type *type; size_t pos; size_t max; struct designator *tail; struct designator *head; }; static TINT arydesig(Init *ip) { TINT npos; Node *np; Type *tp = ip->type; if (ip->type->op != ARY) errorp("array index in non-array initializer"); next(); np = constexpr(); npos = np->sym->u.i; if (npos < 0 || (tp->prop & TDEFINED) && npos >= tp->n.elem) { errorp("array index in initializer exceeds array bounds"); npos = 0; } freetree(np); expect(']'); return npos; } static TINT fielddesig(Init *ip) { int ons; Symbol *sym, **p; Type *tp = ip->type; if (!(tp->prop & TAGGREG)) errorp("field name not in record or union initializer"); ons = namespace; namespace = tp->ns; next(); namespace = ons; if (yytoken != IDEN) unexpected(); sym = yylval.sym; if ((sym->flags & SDECLARED) == 0) { errorp("unknown field '%s' specified in initializer", sym->name); return 0; } for (p = tp->p.fields; *p != sym; ++p) /* nothing */; next(); return p - tp->p.fields; } static Init * designation(Init *ip) { TINT (*fun)(Init *); switch (yytoken) { case '[': fun = arydesig; break; case '.': fun = fielddesig; break; default: return ip; } ip->pos = (*fun)(ip); expect('='); return ip; } static Node * initialize(Type *tp) { Node *np; Symbol *sym; Type *btp; size_t len; char *s; int isstring; if ((tp->op == ARY || tp->op == STRUCT) && yytoken != '{' && yytoken != STRING) { return initlist(tp); } isstring = yytoken == STRING; np = (yytoken == '{') ? initlist(tp) : assign(); if (isstring && tp->op == ARY) { sym = np->left->sym; btp = tp->type; if (btp != chartype && btp != uchartype && btp != schartype) { errorp("array of inappropriate type initialized from string constant"); goto return_zero; } len = sym->type->n.elem-1; if (!(tp->prop & TDEFINED)) { tp->n.elem = len+1; deftype(tp); } else if (tp->n.elem < len) { warn("initializer-string for array of chars is too long"); } len = tp->n.elem; s = sym->u.s; sym = newstring(NULL, len); strncpy(sym->u.s, s, len); np->sym = sym; np->type = sym->type; return np; } else { if (eqtype(tp, np->type, 1)) return np; np = convert(decay(np), tp, 0); if (!np) { errorp("incorrect initializer"); goto return_zero; } } return simplify(np); return_zero: return constnode(zero); } static Node * mkcompound(Init *ip) { Node **v, **p; size_t n; struct designator *dp, *next; Symbol *sym; if ((n = ip->max) == 0) { v = NULL; } else if (n > SIZE_MAX / sizeof(*v)) { errorp("compound literal too big"); return constnode(zero); } else { n *= sizeof(*v); v = memset(xmalloc(n), 0, n); for (dp = ip->head; dp; dp = next) { p = &v[dp->pos]; freetree(*p); *p = dp->expr; next = dp->next; free(dp); } } sym = newsym(NS_IDEN, NULL); sym->u.init = v; sym->type = ip->type; sym->flags |= SINITLST; return constnode(sym); } static void newdesig(Init *ip, Node *np) { struct designator *dp; dp = xmalloc(sizeof(*dp)); dp->pos = ip->pos; dp->expr = np; dp->next = NULL; if (ip->head == NULL) { ip->head = ip->tail = dp; } else { ip->tail->next = dp; ip->tail = dp; } } Node * initlist(Type *tp) { Init in; int braces, scalar, toomany, outbound; Type *newtp; Node *np; in.tail = in.head = NULL; in.type = tp; in.pos = 0; in.max = 0; braces = scalar = toomany = 0; if (accept('{')) braces = 1; do { if (yytoken == '}') break; outbound = 0; designation(&in); switch (tp->op) { case ARY: newtp = tp->type; if (!(tp->prop & TDEFINED) || in.pos < tp->n.elem) break; if (!toomany) warn("excess elements in array initializer"); outbound = 1; toomany = 1; break; /* TODO: case UNION: */ case STRUCT: if (in.pos < tp->n.elem) { newtp = tp->p.fields[in.pos]->type; break; } newtp = inttype; if (!toomany) warn("excess elements in struct initializer"); toomany = 1; outbound = 1; break; default: newtp = tp; if (!scalar) warn("braces around scalar initializer"); scalar = 1; if (in.pos == 0) break; if (!toomany) warn("excess elements in scalar initializer"); toomany = 1; outbound = 1; break; } np = initialize(newtp); if (outbound) freetree(np); else newdesig(&in, np); if (++in.pos == 0) errorp("compound literal too big"); if (in.pos > in.max) in.max = in.pos; if (tp->n.elem == in.pos && !braces) break; } while (accept(',')); if (braces) expect('}'); if (tp->op == ARY && !(tp->prop & TDEFINED)) { tp->n.elem = in.max; deftype(tp); } if (tp->op == ARY || tp->op == STRUCT) in.max = tp->n.elem; else if (in.max == 0) { errorp("empty scalar initializer"); return constnode(zero); } return mkcompound(&in); } static void autoinit(Symbol *sym, Node *np) { Symbol *hidden; Type *tp = sym->type; size_t n; /* FIXME: It should be SIZET */ if (!(np->flags & NCONST)) abort(); /* TODO: Implement not constant initializers */ repeat: switch (tp->op) { case UNION: n = tp->n.elem-1; tp = tp->p.fields[n]->type; np = np->sym->u.init[n]; goto repeat; case ARY: case STRUCT: hidden = newsym(NS_IDEN, NULL); hidden->type = sym->type; hidden->flags |= SLOCAL | SHASINIT; emit(ODECL, hidden); emit(OINIT, np); emit(ODECL, sym); emit(OEXPR, node(OASSIGN, tp, varnode(sym), varnode(hidden))); break; default: emit(ODECL, sym); np = node(OASSIGN, tp, varnode(sym), np); emit(OEXPR, np); break; } } void initializer(Symbol *sym, Type *tp) { Node *np; int flags = sym->flags; if (tp->op == FTN) { errorp("function '%s' initialized like a variable", sym->name); tp = inttype; } np = initialize(tp); if (flags & SDEFINED) { errorp("redeclaration of '%s'", sym->name); } else if ((flags & (SGLOBAL|SLOCAL|SPRIVATE)) != 0) { if (!(np->flags & NCONST)) { errorp("initializer element is not constant"); return; } sym->flags |= SHASINIT; sym->flags &= ~SEMITTED; emit(ODECL, sym); emit(OINIT, np); sym->flags |= SDEFINED; } else if ((flags & (SEXTERN|STYPEDEF)) != 0) { errorp("'%s' has both '%s' and initializer", sym->name, (flags&SEXTERN) ? "extern" : "typedef"); } else { autoinit(sym, np); } }