ref: 38c240c4f09858a4ce71d70ee7fe16e7df7c9bff
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;
struct designator *next;
};
static TINT
arydesig(Type *tp)
{
TINT npos;
Node *np;
if (tp->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(Type *tp)
{
TINT npos;
int ons;
Symbol *sym, **p;
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 struct designator *
designation(Type *tp)
{
struct designator *des = NULL, *d;
TINT (*fun)(Type *);
for (;;) {
switch (yytoken) {
case '[': fun = arydesig; break;
case '.': fun = fielddesig; break;
default:
if (des)
expect('=');
return des;
}
d = xmalloc(sizeof(*d));
d->next = NULL;
if (!des) {
des = d;
} else {
des->next = d;
des = d;
}
des->pos = (*fun)(tp);
}
}
static void
initlist(Symbol *sym, Type *tp)
{
struct designator *des;
int toomany = 0;
TINT n;
Type *newtp;
for (n = 0; ; ++n) {
if ((des = designation(tp)) == NULL) {
des = xmalloc(sizeof(*des));
des->pos = n;
} else {
n = des->pos;
}
switch (tp->op) {
case ARY:
if (tp->defined && n >= tp->n.elem) {
if (!toomany)
warn("excess elements in array initializer");
toomany = 1;
sym = NULL;
}
newtp = tp->type;
break;
case STRUCT:
if (n >= tp->n.elem) {
if (!toomany)
warn("excess elements in struct initializer");
toomany = 1;
sym = NULL;
} else {
sym = tp->p.fields[n];
newtp = sym->type;
}
break;
default:
newtp = tp;
warn("braces around scalar initializer");
if (n > 0) {
if (!toomany)
warn("excess elements in scalar initializer");
toomany = 1;
sym = NULL;
}
break;
}
initializer(sym, newtp, n);
if (!accept(','))
break;
}
expect('}');
if (tp->op == ARY && !tp->defined) {
tp->n.elem = n + 1;
tp->defined = 1;
}
}
extern Node *assign(Node *np);
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); /* FIXME: This code is not complete */
return;
case '=':
np = assign(varnode(sym));
break;
}
/* FIXME: old code used in the recursive call
* if (!sym)
* return;
* if (nelem >= 0)
* return;
*/
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);
}
}