init.c - scc - simple c99 compiler
 (HTM) git clone git://git.simple-cc.org/scc
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Submodules
 (DIR) README
 (DIR) LICENSE
       ---
       init.c (7200B)
       ---
            1 #include <stdint.h>
            2 #include <stdlib.h>
            3 #include <string.h>
            4 
            5 #include <scc/cstd.h>
            6 #include <scc/scc.h>
            7 #include "cc1.h"
            8 
            9 #define NOLIST 0
           10 #define INLIST 1
           11 
           12 
           13 typedef struct init Init;
           14 
           15 struct designator {
           16         TINT pos;
           17         Node *expr;
           18         struct designator *next;
           19 };
           20 
           21 struct init {
           22         TUINT pos;
           23         TUINT max;
           24         struct designator *tail;
           25         struct designator *head;
           26 };
           27 
           28 static TINT
           29 arydesig(Type *tp, Init *ip)
           30 {
           31         TINT npos;
           32         Node *np;
           33 
           34         if (tp->op != ARY)
           35                 errorp("array index in non-array initializer");
           36         next();
           37         np = constexpr();
           38         npos = np->sym->u.i;
           39         if (npos < 0 || (tp->prop & TDEFINED) && npos >= tp->n.elem) {
           40                 errorp("array index in initializer exceeds array bounds");
           41                 npos = 0;
           42         }
           43         freetree(np);
           44         expect(']');
           45         return npos;
           46 }
           47 
           48 static TINT
           49 fielddesig(Type *tp, Init *ip)
           50 {
           51         int ons;
           52         Symbol *sym, **p;
           53 
           54         if (!(tp->prop & TAGGREG))
           55                 errorp("field name not in record or union initializer");
           56         ons = namespace;
           57         namespace = tp->ns;
           58         next();
           59         namespace = ons;
           60         if (yytoken != IDEN)
           61                 unexpected();
           62         sym = yylval.sym;
           63         next();
           64         if ((sym->flags & SDECLARED) == 0) {
           65                 errorp("unknown field '%s' specified in initializer",
           66                       sym->name);
           67                 return -1;
           68         }
           69         for (p = tp->p.fields; *p != sym; ++p)
           70                 ;
           71         return p - tp->p.fields;
           72 }
           73 
           74 static Init *
           75 init(Init *ip)
           76 {
           77         ip->tail = ip->head = NULL;
           78         ip->pos = ip->max = 0;
           79         return ip;
           80 }
           81 
           82 static Node *
           83 str2ary(Type *tp)
           84 {
           85         Node *np;
           86         Type *btp = tp->type;
           87         Symbol *sym;
           88         size_t len;
           89         char *s;
           90 
           91         np = assign();
           92         sym = np->left->sym;
           93         if (btp != chartype && btp != uchartype && btp != schartype) {
           94                 errorp("array of inappropriate type initialized from string constant");
           95                 return constnode(zero);
           96         }
           97 
           98         len = sym->type->n.elem-1;
           99         if (!(tp->prop & TDEFINED)) {
          100                 tp->n.elem = len+1;
          101                 deftype(tp);
          102         } else if (tp->n.elem < len) {
          103                 warn("initializer-string for array of chars is too long");
          104         }
          105 
          106         len = tp->n.elem;
          107         s = sym->u.s;
          108         sym = newstring(NULL, len);
          109         strncpy(sym->u.s, s, len);
          110         np->sym = sym;
          111         np->type = sym->type;
          112 
          113         return np;
          114 }
          115 
          116 static Node *
          117 initialize(Type *tp, int inlist)
          118 {
          119         Node *np;
          120         Symbol *sym;
          121 
          122         if (tp->op == ARY && yytoken == STRING)
          123                 return str2ary(tp);
          124 
          125         if (yytoken == '{' || inlist && (tp->op == STRUCT || tp->op == ARY))
          126                 return initlist(tp);
          127 
          128         np = assign();
          129         if (!eqtype(tp, np->type, EQUIV)) {
          130                 np = convert(decay(np), tp, 0);
          131                 if (!np) {
          132                         errorp("incorrect initializer");
          133                         return constnode(zero);
          134                 }
          135         }
          136 
          137         return simplify(np);
          138 }
          139 
          140 static Node *
          141 mkcompound(Init *ip, Type *tp)
          142 {
          143         Node **v, **p, *np;
          144         size_t n;
          145         struct designator *dp, *next;
          146         Symbol *sym;
          147         int isconst = 1;
          148 
          149         if (tp->op == UNION) {
          150                 np = NULL;
          151                 v = xmalloc(sizeof(*v));
          152                 for (dp = ip->head; dp; dp = next) {
          153                         freetree(np);
          154                         np = dp->expr;
          155                         next = dp->next;
          156                         free(dp);
          157                 }
          158                 if ((np->flags & NCONST) == 0)
          159                         isconst = 0;
          160                 *v = np;
          161         } else {
          162                 n = (tp->prop&TDEFINED) ? tp->n.elem : ip->max;
          163                 if (n == 0) {
          164                         v = NULL;
          165                 } else if (n > SIZE_MAX / sizeof(*v)) {
          166                         errorp("compound literal too big");
          167                         return constnode(zero);
          168                 } else {
          169                         n *= sizeof(*v);
          170                         v = memset(xmalloc(n), 0, n);
          171 
          172                         for (dp = ip->head; dp; dp = next) {
          173                                 p = &v[dp->pos];
          174                                 freetree(*p);
          175                                 np = dp->expr;
          176                                 *p = np;
          177                                 if ((np->flags & NCONST) == 0)
          178                                         isconst = 0;
          179                                 next = dp->next;
          180                                 free(dp);
          181                         }
          182                 }
          183         }
          184 
          185         sym = newsym(NS_IDEN, NULL);
          186         sym->u.init = v;
          187         sym->type = tp;
          188         sym->flags |= SINITLST;
          189 
          190         return (isconst ? constnode : varnode)(sym);
          191 }
          192 
          193 static void
          194 newdesig(Init *ip, Node *np)
          195 {
          196         struct designator *dp;
          197 
          198         dp = xmalloc(sizeof(*dp));
          199         dp->pos = ip->pos;
          200         dp->expr = np;
          201         dp->next = NULL;
          202 
          203         if (ip->head == NULL) {
          204                 ip->head = ip->tail = dp;
          205         } else {
          206                 ip->tail->next = dp;
          207                 ip->tail = dp;
          208         }
          209 
          210         if (ip->pos+1 > ip->max)
          211                 ip->max = ip->pos+1;
          212 }
          213 
          214 static Node *
          215 initlist_helper(Type *tp)
          216 {
          217         Init in;
          218         Node *np;
          219         Type *curtp;
          220         int braces, scalar, toomany, outbound;
          221         TINT nelem = tp->n.elem;
          222 
          223         init(&in);
          224         braces = scalar = toomany = 0;
          225 
          226         if (accept('{'))
          227                 braces = 1;
          228 
          229         for (;;) {
          230                 curtp = inttype;
          231                 switch (yytoken) {
          232                 case '[':
          233                         in.pos = arydesig(tp, &in);
          234                         curtp = tp->type;
          235                         goto desig_list;
          236                 case '.':
          237                         in.pos = fielddesig(tp, &in);
          238                         if (in.pos >= 0 && in.pos < nelem)
          239                                 curtp = tp->p.fields[in.pos]->type;
          240                 desig_list:
          241                         if (yytoken == '[' || yytoken == '.') {
          242                                 np = initlist(curtp);
          243                                 goto new_desig;
          244                         }
          245                         expect('=');
          246                 default:
          247                         outbound = 0;
          248 
          249                         switch (tp->op) {
          250                         case ARY:
          251                                 curtp = tp->type;
          252                                 if (!(tp->prop & TDEFINED) || in.pos < tp->n.elem)
          253                                         break;
          254                                 if (!toomany)
          255                                         warn("excess elements in array initializer");
          256                                 toomany = 1;
          257                                 outbound = 1;
          258                                 break;
          259                         case UNION:
          260                         case STRUCT:
          261                                 if (in.pos < nelem) {
          262                                         curtp = tp->p.fields[in.pos]->type;
          263                                         break;
          264                                 }
          265                                 if (!toomany)
          266                                         warn("excess elements in struct initializer");
          267                                 toomany = 1;
          268                                 outbound = 1;
          269                                 break;
          270                         default:
          271                                 curtp = tp;
          272                                 if (!scalar)
          273                                         warn("braces around scalar initializer");
          274                                 scalar = 1;
          275                                 if (in.pos == 0)
          276                                         break;
          277                                 if (!toomany)
          278                                         warn("excess elements in scalar initializer");
          279                                 toomany = 1;
          280                                 outbound = 1;
          281                                 break;
          282                         }
          283                         np = initialize(curtp, INLIST);
          284                         if (outbound) {
          285                                 freetree(np);
          286                                 np = NULL;
          287                         }
          288                 }
          289 
          290 new_desig:
          291                 if (np)
          292                         newdesig(&in, np);
          293                 if (++in.pos == 0)
          294                         errorp("compound literal too big");
          295                 if (nelem == in.pos && !braces)
          296                         break;
          297                 if (!accept(','))
          298                         break;
          299                 if (yytoken == '}')
          300                         break;
          301         }
          302 
          303         if (braces)
          304                 expect('}');
          305 
          306 
          307         if (tp->op == ARY && !(tp->prop & TDEFINED)) {
          308                 tp->n.elem = in.max;
          309                 deftype(tp);
          310         }
          311         if (in.max == 0) {
          312                 errorp("empty braced initializer");
          313                 return constnode(zero);
          314         }
          315 
          316         return mkcompound(&in, tp);
          317 }
          318 
          319 Node *
          320 initlist(Type *tp)
          321 {
          322         Node *np;
          323         static int depth;
          324 
          325         if (depth == NR_SUBTYPE)
          326                 error("too many nested initializers");
          327 
          328         ++depth;
          329         np = initlist_helper(tp);
          330         --depth;
          331 
          332         return np;
          333 }
          334 
          335 static void
          336 autoinit(Symbol *sym, Node *np)
          337 {
          338         Symbol *hidden;
          339         Type *tp = sym->type;
          340 
          341 repeat:
          342         switch (tp->op) {
          343         case UNION:
          344                 np = np->sym->u.init[0];
          345                 tp = np->type;
          346                 goto repeat;
          347         case ARY:
          348         case STRUCT:
          349                 if (np->op == OSYM && np->sym->flags & SINITLST) {
          350                         if (!(np->flags & NCONST))
          351                                 abort(); /* TODO */
          352                         hidden = newsym(NS_IDEN, NULL);
          353                         hidden->id = newid();
          354                         hidden->type = sym->type;
          355                         hidden->flags |= SLOCAL | SHASINIT;
          356                         emit(ODECL, hidden);
          357                         emit(OINIT, np);
          358                         np = varnode(hidden);
          359                 }
          360         default:
          361                 emit(ODECL, sym);
          362                 np = node(OASSIGN, tp, varnode(sym), np);
          363                 emit(OEXPR, np);
          364                 break;
          365         }
          366 }
          367 
          368 void
          369 initializer(Symbol *sym, Type *tp)
          370 {
          371         Node *np;
          372         int flags = sym->flags;
          373 
          374         if (tp->op == FTN) {
          375                 errorp("function '%s' initialized like a variable",
          376                        sym->name);
          377                 tp = inttype;
          378         }
          379         np = initialize(tp, NOLIST);
          380 
          381         if (flags & SDEFINED) {
          382                 errorp("redeclaration of '%s'", sym->name);
          383         } else if ((flags & (SGLOBAL|SLOCAL|SPRIVATE)) != 0) {
          384                 if ((np->flags & NCONST) == 0) {
          385                         errorp("initializer element is not constant");
          386                         return;
          387                 }
          388                 sym->flags |= SHASINIT;
          389                 sym->flags &= ~SEMITTED;
          390                 emit(ODECL, sym);
          391                 emit(OINIT, np);
          392                 sym->flags |= SDEFINED;
          393         } else if ((flags & (SEXTERN|STYPEDEF)) != 0) {
          394                 errorp("'%s' has both '%s' and initializer",
          395                        sym->name, (flags&SEXTERN) ? "extern" : "typedef");
          396         } else {
          397                 autoinit(sym, np);
          398         }
          399 }