From 0c6b2dcdfe297486aec7835a822b33bd5b2a67f2 Mon Sep 17 00:00:00 2001
From: bellard <bellard>
Date: Mon, 26 Nov 2001 22:57:27 +0000
Subject: [PATCH] completed initializer handlign (compute size before storing
 initializers if unknown size - macro subst fix

---
 tcc.c | 200 ++++++++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 144 insertions(+), 56 deletions(-)

diff --git a/tcc.c b/tcc.c
index 53d0d9f7..ca22f839 100644
--- a/tcc.c
+++ b/tcc.c
@@ -264,7 +264,7 @@ int expr_const();
 void expr_eq();
 void expr();
 void decl();
-void decl_assign(int t, int c, int first);
+void decl_initializer(int t, int c, int first, int size_only);
 int gv();
 void move_reg();
 void save_reg();
@@ -1168,7 +1168,7 @@ int *macro_arg_subst(Sym **nested_list, int *macro_str, Sym *args)
                 tok_add(&str, &len, t);
             }
         } else if (t == TOK_NUM || t == TOK_CCHAR || t == TOK_STR) {
-            tok_add2(&str, &len, t, *macro_ptr++);
+            tok_add2(&str, &len, t, *macro_str++);
         } else {
             s = sym_find2(args, t);
             if (s) {
@@ -2906,8 +2906,10 @@ void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_reg)
 }
 
 /* t is the array or struct type. c is the array or struct
-   address. cur_index/cur_field is the pointer to the current value */
-void decl_designator(int t, int c, int *cur_index, Sym **cur_field)
+   address. cur_index/cur_field is the pointer to the current
+   value. 'size_only' is true if only size info is needed (only used
+   in arrays) */
+void decl_designator(int t, int c, int *cur_index, Sym **cur_field, int size_only)
 {
     Sym *s, *f;
     int notfirst, index, align;
@@ -2964,39 +2966,79 @@ void decl_designator(int t, int c, int *cur_index, Sym **cur_field)
             c += f->c;
         }
     }
-    decl_assign(t, c, 0);
+    decl_initializer(t, c, 0, size_only);
+}
+
+/* store a value or an expression directly in global data or in local array */
+
+void init_putv(int t, int c, int v, int is_expr)
+{
+    if ((t & VT_VALMASK) == VT_CONST) {
+        if (is_expr)
+            v = expr_const();
+        if (t & VT_BYTE)
+            *(char *)c = v;
+        else if (t & VT_SHORT)
+            *(short *)c = v;
+        else
+            *(int *)c = v;
+    } else {
+        vt = t;
+        vc = c;
+        vpush();
+        if (is_expr)
+            expr_eq();
+        else
+            vset(VT_CONST, v);
+        vstore();
+    }
 }
 
 /* 't' contains the type and storage info. c is the address of the
    object. 'first' is true if array '{' must be read (multi dimension
-   implicit array init handling). */
-void decl_assign(int t, int c, int first)
+   implicit array init handling). 'size_only' is true if size only
+   evaluation is wanted (only for arrays). */
+void decl_initializer(int t, int c, int first, int size_only)
 {
-    int v, index, index_max, t1, n, no_oblock;
+    int index, array_length, t1, n, no_oblock, nb, parlevel, i;
     Sym *s, *f;
     TokenSym *ts;
 
     if (t & VT_ARRAY) {
         s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT));
         n = s->c;
-        index_max = 0;
+        array_length = 0;
         if (tok == TOK_STR) {
             t1 = pointed_type(t);
             if (!(t1 & VT_BYTE))
                 error("invalid type");
-            if ((t & VT_VALMASK) == VT_CONST) {
-                while (tok == TOK_STR) {
-                    ts = (TokenSym *)tokc;
-                    memcpy((void *)c, ts->str, ts->len);
-                    c += ts->len;
-                    index_max += ts->len;
-                    next();
+            /* XXX: move multiple string parsing in parser ? */
+            while (tok == TOK_STR) {
+                ts = (TokenSym *)tokc;
+                /* compute maximum number of chars wanted */
+                nb = ts->len;
+                if (n >= 0 && nb > (n - array_length))
+                    nb = n - array_length;
+                if (!size_only) {
+                    if (ts->len > nb)
+                        warning("initializer-string for array is too long");
+                    for(i=0;i<nb;i++) {
+                        init_putv(t1, c, ts->str[i], 0);
+                        c++;
+                    }
                 }
-                *(char *)c++ = 0;
-            } else {
-                error("local string init not handled");
+                array_length += nb;
+                next();
+            }
+            /* only add trailing zero if enough storage (no
+               warning in this case since it is standard) */
+            if (n < 0 || array_length < n) {
+                if (!size_only) {
+                    init_putv(t1, c, 0, 0);
+                    c++;
+                }
+                array_length++;
             }
-            /* string init */
         } else {
             no_oblock = 0;
             if (!first && tok != '{')
@@ -3005,12 +3047,12 @@ void decl_assign(int t, int c, int first)
                 skip('{');
             index = 0;
             while (tok != '}') {
-                decl_designator(t, c, &index, NULL);
+                decl_designator(t, c, &index, NULL, size_only);
                 if (n >= 0 && index >= n)
                     error("index too large");
-                if (index > index_max)
-                    index_max = index;
                 index++;
+                if (index > array_length)
+                    array_length = index;
                 /* special test for multi dimensional arrays (may not
                    be strictly correct if designators are used at the
                    same time) */
@@ -3025,45 +3067,43 @@ void decl_assign(int t, int c, int first)
         }
         /* patch type size if needed */
         if (n < 0)
-            s->c = index_max + 1;
+            s->c = array_length;
     } else if (t & VT_STRUCT) {
         /* XXX: union needs only one init */
         skip('{');
         s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT) | SYM_STRUCT);
         f = s->next;
         while (tok != '}') {
-            decl_designator(t, c, NULL, &f);
+            decl_designator(t, c, NULL, &f, size_only);
             if (tok == '}')
                 break;
             skip(',');
             f = f->next;
         }
         skip('}');
+    } else if (size_only) {
+        /* just skip expression */
+        parlevel = 0;
+        while ((parlevel > 0 || (tok != '}' && tok != ',')) && 
+               tok != -1) {
+            if (tok == '(')
+                parlevel++;
+            else if (tok == ')')
+                parlevel--;
+            next();
+       }
     } else {
-        if ((t & VT_VALMASK) == VT_CONST) {
-            v = expr_const();
-            if (t & VT_BYTE)
-                *(char *)c = v;
-            else if (t & VT_SHORT)
-                *(short *)c = v;
-            else
-                *(int *)c = v;
-        } else {
-            vt = t;
-            vc = c;
-            vpush();
-            expr_eq();
-            vstore();
-        }
+        init_putv(t, c, 0, 1);
     }
 }
 
 /* 'l' is VT_LOCAL or VT_CONST to define default storage type */
 void decl(l)
 {
-    int *a, t, b, size, align, v, u, n, addr;
+    int *a, t, b, size, align, v, u, n, addr, tok1;
     Sym *sym;
-
+    int *init_str, init_len, level, *saved_macro_ptr;
+    
     while (b = ist()) {
         if ((b & (VT_ENUM | VT_STRUCT)) && tok == ';') {
             /* we accept no variable after */
@@ -3130,16 +3170,67 @@ void decl(l)
                             u = VT_CONST;
                         u |= t;
                         size = type_size(t, &align);
+                        /* If unknown size, we must evaluate it before
+                           evaluating initializers because
+                           initializers can generate global data too
+                           (e.g. string pointers or ISOC99 compound
+                           literals). It also simplifies local
+                           initializers handling */
+                        init_len = 0;
+                        init_str = NULL;
+                        saved_macro_ptr = NULL; /* avoid warning */
+                        tok1 = 0;
+                        if (size < 0) {
+                            if (tok != '=') 
+                                error("unknown size for '%s'", get_tok_str(v, 0));
+                            tok_add2(&init_str, &init_len, tok, tokc);
+                            next();
+                            /* get all init string */
+                            level = 0;
+                            while (level > 0 || (tok != ',' && tok != ';')) {
+                                if (tok < 0)
+                                    error("unexpect end of file in initializer for '%s'",
+                                          get_tok_str(v, 0));
+                                tok_add2(&init_str, &init_len, tok, tokc);
+                                if (tok == '{')
+                                    level++;
+                                else if (tok == '}') {
+                                    if (level == 0)
+                                        break;
+                                    level--;
+                                }
+                                next();
+                            }
+                            tok1 = tok;
+                            tok_add(&init_str, &init_len, -1);
+                            tok_add(&init_str, &init_len, 0);
+
+                            /* compute size */
+                            saved_macro_ptr = macro_ptr;
+                            macro_ptr = init_str;
+                            next();
+                            skip('=');
+                            decl_initializer(u, 0, 1, 1);
+                            /* prepare second initializer parsing */
+                            macro_ptr = init_str;
+                            next();
+                            
+                            /* if still unknown size, error */
+                            size = type_size(t, &align);
+                            if (size < 0) 
+                                error("unknown size for '%s'", get_tok_str(v, 0));
+                        }
                         if ((u & VT_VALMASK) == VT_LOCAL) {
-                            /* XXX: cannot use implicit size for local
-                               storage */
-                            if (size < 0)
-                                error("size must be known for locals");
                             loc = (loc - size) & -align;
                             addr = loc;
                         } else {
                             glo = (glo + align - 1) & -align;
                             addr = glo;
+                            /* very important to increment global
+                               pointer at this time because
+                               initializers themselves can create new
+                               initializers */
+                            glo += size;
                         }
                         if (tok == '=') {
                             next();
@@ -3149,20 +3240,17 @@ void decl(l)
                                 n = 1;
                                 next();
                             }
-                            decl_assign(u, addr, 1);
+                            decl_initializer(u, addr, 1, 0);
                             if (n)
                                 skip('}');
+                            /* restore parse state if needed */
+                            if (init_str) {
+                                free(init_str);
+                                macro_ptr = saved_macro_ptr;
+                                tok = tok1;
+                            }
                         }
                         sym_push(v, u, addr);
-                        /* if global, add size */
-                        if ((u & VT_VALMASK) == VT_CONST) {
-                            /* must recompute size if it was an array
-                               with implicit size */
-                            size = type_size(t, &align);
-                            if (size < 0)
-                                error("invalid size");
-                            glo += size;
-                        }
                     }
                 }
                 if (tok != ',') {