ref: 6e980d9048da9c1aaaafa68ee7835ad83423a07a
dir: /cc1/init.c/
#include <stdio.h> #include <stdlib.h> #include "../inc/cc.h" #include "../inc/sizes.h" #include "cc1.h" struct designator { TINT pos; Node *expr; struct designator *next; }; static TINT arydesig(Init *ip) { TINT npos; Node *np; if (ip->type->op != ARY) errorp("array index in non-array initializer"); next(); np = iconstexpr(); npos = np->sym->u.i; freetree(np); expect(']'); return npos; } static TINT fielddesig(Init *ip) { TINT npos; int ons; Symbol *sym, **p; Type *tp = ip->type; if (!tp->aggreg) 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 & ISDECLARED) == 0) { errorp(" unknown field '%s' specified in initializer", sym->name); return 0; } for (p = tp->p.fields; *p != sym; ++p) /* nothing */; return p - tp->p.fields; } static Init * designation(Init *ip) { struct designator *dp; TINT (*fun)(Init *); dp = xmalloc(sizeof(*dp)); dp->next = ip->head; ip->head = dp; switch (yytoken) { case '[': fun = arydesig; break; case '.': fun = fielddesig; break; default: return ip; } ip->pos = (*fun)(ip); expect('='); return ip; } static Node * initlist(Symbol *sym, Type *tp) { Init *ip; Symbol *nsym; struct designator *dp; int toomany = 0; Type *newtp; ip = xmalloc(sizeof(*ip)); ip->head = NULL; ip->pos = 0; ip->type = tp; if (accept('}')) goto end_of_initializer; for (ip->pos = 1; ; ++ip->pos) { designation(ip); switch (tp->op) { case ARY: newtp = tp->type; if (!tp->defined || ip->pos < tp->n.elem) break; if (!toomany) warn("excess elements in array initializer"); toomany = 1; break; case STRUCT: if (ip->pos < tp->n.elem) { sym = tp->p.fields[ip->pos]; newtp = sym->type; break; } if (!toomany) warn("excess elements in struct initializer"); toomany = 1; break; default: newtp = tp; warn("braces around scalar initializer"); if (ip->pos <= 0) break; if (!toomany) warn("excess elements in scalar initializer"); toomany = 1; break; } dp = ip->head; dp->pos = ip->pos; /* TODO: pass the correct parameters to initlist */ dp->expr = (accept('{')) ? initlist(sym, tp) : assign(NULL); if (!accept(',')) break; } expect('}'); end_of_initializer: if (tp->op == ARY && !tp->defined) { tp->n.elem = ip->pos; tp->defined = 1; } nsym = newsym(NS_IDEN); nsym->u.init = ip; return constnode(nsym); } void initializer(Symbol *sym, Type *tp, int nelem) { Node *np; int flags = sym->flags; if (tp->op == FTN) errorp("function '%s' is initialized like a variable", sym->name); switch (yytoken) { case '{': initlist(sym, tp); return; case '=': np = assign(varnode(sym)); break; } if (flags & ISDEFINED) { errorp("redeclaration of '%s'", sym->name); } else if ((flags & (ISGLOBAL|ISLOCAL|ISPRIVATE)) != 0) { if (!np->right->constant) errorp("initializer element is not constant"); emit(OINIT, np); sym->flags |= ISDEFINED; } else if ((flags & (ISEXTERN|ISTYPEDEF)) != 0) { errorp("'%s' has both '%s' and initializer", sym->name, (flags&ISEXTERN) ? "extern" : "typedef"); } else { np->op = OASSIGN; emit(OEXPR, np); } }