scc

Simple C99 Compiler
Log | Files | Refs | README | LICENSE

commit 7ba972cc2abea4cb7399b463d22f5dae705d2aa6
parent ca4dc0e4231ef4fa8cd322fd21beb4a99e6a0fac
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Mon, 14 Sep 2015 16:03:33 +0200

Add designated initializers syntax

At this point we accept designated initializer but we are not emiting them.
The reason is because we have to build a full tree with the information of
the initializer list, and emit first the nested elements.

Diffstat:
cc1/cc1.h | 2+-
cc1/expr.c | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 86 insertions(+), 3 deletions(-)

diff --git a/cc1/cc1.h b/cc1/cc1.h @@ -52,7 +52,7 @@ struct type { } p; union { unsigned char rank; /* convertion rank */ - short elem; /* number of type parameters */ + TINT elem; /* number of type parameters */ } n; }; diff --git a/cc1/expr.c b/cc1/expr.c @@ -978,13 +978,95 @@ condexpr(void) return np; } +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->op != STRUCT || tp->op != UNION) + 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 n, toomany = 0; 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 && !toomany) { @@ -1043,6 +1125,9 @@ initializer(Symbol *sym, Type *tp, int nelem) /* if !sym it means there are too much initializers */ if (!sym) return; + if (nelem >= 0) + return; + np = assignop(OINIT, varnode(sym), np); if ((flags & (ISEXTERN|ISTYPEDEF)) != 0) { @@ -1052,8 +1137,6 @@ initializer(Symbol *sym, Type *tp, int nelem) } else if ((flags & (ISEXTERN|ISTYPEDEF)) != 0) { errorp("'%s' has both '%s' and initializer", sym->name, (flags&ISEXTERN) ? "extern" : "typedef"); - } else if (flags & ISFIELD) { - ; } else { np->op = OASSIGN; emit(OEXPR, np);