aboutsummaryrefslogtreecommitdiff
path: root/tcc.c
diff options
context:
space:
mode:
Diffstat (limited to 'tcc.c')
-rw-r--r--tcc.c219
1 files changed, 127 insertions, 92 deletions
diff --git a/tcc.c b/tcc.c
index 2eecc0e..9045c3a 100644
--- a/tcc.c
+++ b/tcc.c
@@ -97,6 +97,8 @@ typedef struct {
FILE *file;
int tok, tok1, tokc, rsym, anon_sym,
prog, ind, loc, glo, vt, vc, const_wanted, line_num;
+int global_expr; /* true if compound literals must be allocated
+ globally (used during initializers parsing */
int tok_ident;
TokenSym **table_ident;
TokenSym *hash_ident[521];
@@ -267,6 +269,7 @@ void expr_eq();
void expr();
void decl();
void decl_initializer(int t, int c, int first, int size_only);
+int decl_initializer_alloc(int t, int has_init);
int gv();
void move_reg();
void save_reg();
@@ -2363,8 +2366,22 @@ void unary()
if (t = ist()) {
ft = type_decl(&n, t, TYPE_ABSTRACT);
skip(')');
- unary();
- vt = (vt & VT_TYPEN) | ft;
+ /* check ISOC99 compound literal */
+ if (tok == '{') {
+ /* data is allocated locally by default */
+ if (global_expr)
+ ft |= VT_CONST;
+ else
+ ft |= VT_LOCAL;
+ /* all except arrays are lvalues */
+ if (!(ft & VT_ARRAY))
+ ft |= VT_LVAL;
+ fc = decl_initializer_alloc(ft, 1);
+ vset(ft, fc);
+ } else {
+ unary();
+ vt = (vt & VT_TYPEN) | ft;
+ }
} else {
expr();
skip(')');
@@ -2993,9 +3010,16 @@ void decl_designator(int t, int c,
void init_putv(int t, int c, int v, int is_expr)
{
+ int saved_global_expr;
+
if ((t & VT_VALMASK) == VT_CONST) {
- if (is_expr)
+ if (is_expr) {
+ /* compound literals must be allocated globally in this case */
+ saved_global_expr = global_expr;
+ global_expr = 1;
v = expr_const();
+ global_expr = saved_global_expr;
+ }
if (t & VT_BYTE)
*(char *)c = v;
else if (t & VT_SHORT)
@@ -3054,14 +3078,20 @@ void decl_initializer(int t, int c, int first, int size_only)
array_length = 0;
t1 = pointed_type(t);
size1 = type_size(t1, &align1);
- if (tok == TOK_LSTR) {
- if ((t1 & VT_TYPE & ~VT_UNSIGNED) != VT_INT)
- error("invalid type");
- goto str_init;
- } else if (tok == TOK_STR) {
- if (!(t1 & VT_BYTE))
- error("invalid type");
- str_init:
+
+ no_oblock = 1;
+ if ((first && tok != TOK_LSTR && tok != TOK_STR) ||
+ tok == '{') {
+ skip('{');
+ no_oblock = 0;
+ }
+
+ /* only parse strings here if correct type (otherwise: handle
+ them as ((w)char *) expressions */
+ if ((tok == TOK_LSTR &&
+ (t1 & VT_TYPE & ~VT_UNSIGNED) == VT_INT) ||
+ (tok == TOK_STR &&
+ (t1 & VT_TYPE & ~VT_UNSIGNED) == VT_BYTE)) {
/* XXX: move multiple string parsing in parser ? */
while (tok == TOK_STR || tok == TOK_LSTR) {
ts = (TokenSym *)tokc;
@@ -3089,11 +3119,6 @@ void decl_initializer(int t, int c, int first, int size_only)
array_length++;
}
} else {
- no_oblock = 0;
- if (!first && tok != '{')
- no_oblock = 1;
- else
- skip('{');
index = 0;
while (tok != '}') {
decl_designator(t, c, &index, NULL, size_only);
@@ -3117,9 +3142,9 @@ void decl_initializer(int t, int c, int first, int size_only)
break;
skip(',');
}
- if (!no_oblock)
- skip('}');
}
+ if (!no_oblock)
+ skip('}');
/* put zeros at the end */
if (!size_only && n >= 0 && array_length < n) {
init_putz(t1, c + array_length * size1,
@@ -3178,12 +3203,91 @@ void decl_initializer(int t, int c, int first, int size_only)
}
}
+/* parse an initializer for type 't' if 'has_init' is true, and
+ allocate space in local or global data space. The allocated address
+ in returned */
+int decl_initializer_alloc(int t, int has_init)
+{
+ int size, align, addr, tok1;
+ int *init_str, init_len, level, *saved_macro_ptr;
+
+ 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 (!has_init)
+ error("unknown type size");
+ /* get all init string */
+ level = 0;
+ while (level > 0 || (tok != ',' && tok != ';')) {
+ if (tok < 0)
+ error("unexpect end of file in initializer");
+ 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();
+ decl_initializer(t, 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 type size");
+ }
+ if ((t & VT_VALMASK) == VT_LOCAL) {
+ 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 (has_init) {
+ decl_initializer(t, addr, 1, 0);
+ /* restore parse state if needed */
+ if (init_str) {
+ free(init_str);
+ macro_ptr = saved_macro_ptr;
+ tok = tok1;
+ }
+ }
+ return addr;
+}
+
+
/* '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, tok1;
+ int *a, t, b, v, u, n, addr, has_init;
Sym *sym;
- int *init_str, init_len, level, *saved_macro_ptr;
while (b = ist()) {
if ((b & (VT_ENUM | VT_STRUCT)) && tok == ';') {
@@ -3250,79 +3354,10 @@ void decl(l)
if (t & VT_STATIC)
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) {
- 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 == '=') {
+ has_init = (tok == '=');
+ if (has_init)
next();
- decl_initializer(u, addr, 1, 0);
- /* restore parse state if needed */
- if (init_str) {
- free(init_str);
- macro_ptr = saved_macro_ptr;
- tok = tok1;
- }
- }
+ addr = decl_initializer_alloc(u, has_init);
sym_push(v, u, addr);
}
}