added wide char and string parsing - added zero init of auto initializers

tcc-xref
bellard 2001-11-28 22:48:43 +00:00
parent 0c6b2dcdfe
commit 4298fccb0c
1 changed files with 117 additions and 44 deletions

161
tcc.c
View File

@ -126,6 +126,7 @@ int nb_include_paths;
(only used for functions) */
/* types */
#define VT_INT 0
#define VT_VOID 0x00040
#define VT_BYTE 0x00080 /* signed byte type */
#define VT_PTR 0x00100 /* pointer increment */
@ -173,8 +174,9 @@ int nb_include_paths;
#define TOK_NUM 0xb3 /* number in tokc */
#define TOK_CCHAR 0xb4 /* char constant in tokc */
#define TOK_STR 0xb5 /* pointer to string in tokc */
#define TOK_TWOSHARPS 0xb6 /* ## preprocessing token */
#define TOK_LCHAR 0xb7
#define TOK_LSTR 0xb8
#define TOK_SHL 0x01 /* shift left */
#define TOK_SAR 0x02 /* signed shift right */
@ -425,14 +427,14 @@ char *get_tok_str(int v, int c)
if (v == TOK_NUM) {
sprintf(buf, "%d", c);
return buf;
} else if (v == TOK_CCHAR) {
} else if (v == TOK_CCHAR || v == TOK_LCHAR) {
p = buf;
*p++ = '\'';
add_char(&p, c);
*p++ = '\'';
*p = '\0';
return buf;
} else if (v == TOK_STR) {
} else if (v == TOK_STR || v == TOK_LSTR) {
ts = (TokenSym *)c;
p = buf;
*p++ = '\"';
@ -649,6 +651,13 @@ void preprocess_skip()
}
}
inline int is_long_tok(int t)
{
return (t == TOK_NUM ||
t == TOK_CCHAR || t == TOK_LCHAR ||
t == TOK_STR || t == TOK_LSTR);
}
void tok_add(int **tok_str, int *tok_len, int t)
{
int len, *str;
@ -667,7 +676,7 @@ void tok_add(int **tok_str, int *tok_len, int t)
void tok_add2(int **tok_str, int *tok_len, int t, int c)
{
tok_add(tok_str, tok_len, t);
if (t == TOK_NUM || t == TOK_CCHAR || t == TOK_STR)
if (is_long_tok(t))
tok_add(tok_str, tok_len, c);
}
@ -721,7 +730,7 @@ void tok_print(int *str)
if (!t)
break;
c = 0;
if (t == TOK_NUM || t == TOK_CCHAR || t == TOK_STR)
if (is_long_tok(t))
c = *str++;
printf(" %s", get_tok_str(t, c));
}
@ -1018,10 +1027,14 @@ void next_nomacro1()
if (q[-1] == 'L') {
/* XXX: not supported entirely (needs different
preprocessor architecture) */
if (ch == '\'')
if (ch == '\'') {
tok = TOK_LCHAR;
goto char_const;
if (ch == '\"')
}
if (ch == '\"') {
tok = TOK_LSTR;
goto str_const;
}
}
while (isid(ch) | isnum(ch)) {
if (q >= token_buf + STRING_MAX_SIZE)
@ -1052,14 +1065,15 @@ void next_nomacro1()
cinp();
tok = TOK_NUM;
} else if (ch == '\'') {
tok = TOK_CCHAR;
char_const:
minp();
tokc = getq();
tok = TOK_CCHAR;
if (ch != '\'')
expect("\'");
minp();
} else if (ch == '\"') {
tok = TOK_STR;
str_const:
minp();
q = token_buf;
@ -1073,7 +1087,6 @@ void next_nomacro1()
}
*q = '\0';
tokc = (int)tok_alloc(token_buf, q - token_buf);
tok = TOK_STR;
minp();
} else {
q = "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<<\1>>\2+=\253-=\255*=\252/=\257%=\245&=\246^=\336|=\374->\247..\250##\266";
@ -1115,7 +1128,7 @@ void next_nomacro()
tok = *macro_ptr;
if (tok) {
macro_ptr++;
if (tok == TOK_NUM || tok == TOK_CCHAR || tok == TOK_STR)
if (is_long_tok(tok))
tokc = *macro_ptr++;
}
} else {
@ -1153,7 +1166,7 @@ int *macro_arg_subst(Sym **nested_list, int *macro_str, Sym *args)
strcat(token_buf, " ");
t = *st++;
c = 0;
if (t == TOK_NUM || t == TOK_CCHAR || t == TOK_STR)
if (is_long_tok(t))
c = *st++;
strcat(token_buf, get_tok_str(t, c));
notfirst = 1;
@ -1167,7 +1180,7 @@ int *macro_arg_subst(Sym **nested_list, int *macro_str, Sym *args)
} else {
tok_add(&str, &len, t);
}
} else if (t == TOK_NUM || t == TOK_CCHAR || t == TOK_STR) {
} else if (is_long_tok(t)) {
tok_add2(&str, &len, t, *macro_str++);
} else {
s = sym_find2(args, t);
@ -1212,7 +1225,7 @@ int *macro_twosharps(int *macro_str)
if (t) {
macro_ptr++;
c = 0;
if (t == TOK_NUM || t == TOK_CCHAR || t == TOK_STR)
if (is_long_tok(t))
c = *macro_ptr++;
/* XXX: we handle only most common cases:
ident + ident or ident + number */
@ -2314,10 +2327,10 @@ void indir()
void unary()
{
int n, t, ft, fc, p, r;
int n, t, ft, fc, p, r, align;
Sym *s;
if (tok == TOK_NUM || tok == TOK_CCHAR) {
if (tok == TOK_NUM || tok == TOK_CCHAR || tok == TOK_LCHAR) {
vset(VT_CONST, tokc);
next();
} else if (tok == TOK___FUNC__) {
@ -2326,17 +2339,22 @@ void unary()
vset(VT_CONST | mk_pointer(VT_BYTE), glo);
strcpy((void *)glo, funcname);
glo += strlen(funcname) + 1;
} else if (tok == TOK_LSTR) {
t = VT_INT;
goto str_init;
} else if (tok == TOK_STR) {
TokenSym *ts;
/* generate (char *) type */
vset(VT_CONST | mk_pointer(VT_BYTE), glo);
while (tok == TOK_STR) {
ts = (TokenSym *)tokc;
memcpy((void *)glo, ts->str, ts->len);
glo += ts->len;
next();
}
*(char *)glo++ = 0;
/* string parsing */
t = VT_BYTE;
str_init:
type_size(t, &align);
glo = (glo + align - 1) & -align;
fc = glo;
/* we must declare it as an array first to use initializer parser */
t = VT_CONST | VT_ARRAY | mk_pointer(t);
decl_initializer(t, glo, 1, 0);
glo += type_size(t, &align);
/* put it as pointer */
vset(t & ~VT_ARRAY, fc);
} else {
t = tok;
next();
@ -2909,7 +2927,9 @@ void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_reg)
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)
void decl_designator(int t, int c,
int *cur_index, Sym **cur_field,
int size_only)
{
Sym *s, *f;
int notfirst, index, align;
@ -2994,13 +3014,37 @@ void init_putv(int t, int c, int v, int is_expr)
}
}
/* put zeros for variable based init */
void init_putz(int t, int c, int size)
{
int memset_addr, r;
if ((t & VT_VALMASK) == VT_CONST) {
/* nothing to do because global are already set to zero */
} else {
vset(VT_CONST, size);
r = gv();
o(0x50 + r);
vset(VT_CONST, 0);
r = gv();
o(0x50 + r);
vset(VT_LOCAL, c);
r = gv();
o(0x50 + r);
memset_addr = (int)&memset;
oad(0xe8, memset_addr - ind - 5);
oad(0xc481, 3 * 4);
}
}
/* '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). '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 index, array_length, t1, n, no_oblock, nb, parlevel, i;
int index, array_length, n, no_oblock, nb, parlevel, i;
int t1, size1, align1;
Sym *s, *f;
TokenSym *ts;
@ -3008,12 +3052,18 @@ void decl_initializer(int t, int c, int first, int size_only)
s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT));
n = s->c;
array_length = 0;
if (tok == TOK_STR) {
t1 = pointed_type(t);
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:
/* XXX: move multiple string parsing in parser ? */
while (tok == TOK_STR) {
while (tok == TOK_STR || tok == TOK_LSTR) {
ts = (TokenSym *)tokc;
/* compute maximum number of chars wanted */
nb = ts->len;
@ -3023,8 +3073,8 @@ void decl_initializer(int t, int c, int first, int 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++;
init_putv(t1, c + (array_length + i) * size1,
ts->str[i], 0);
}
}
array_length += nb;
@ -3034,8 +3084,7 @@ void decl_initializer(int t, int c, int first, int size_only)
warning in this case since it is standard) */
if (n < 0 || array_length < n) {
if (!size_only) {
init_putv(t1, c, 0, 0);
c++;
init_putv(t1, c + (array_length * size1), 0, 0);
}
array_length++;
}
@ -3050,6 +3099,12 @@ void decl_initializer(int t, int c, int first, int size_only)
decl_designator(t, c, &index, NULL, size_only);
if (n >= 0 && index >= n)
error("index too large");
/* must put zero in holes (note that doing it that way
ensures that it even works with designators) */
if (!size_only && array_length < index) {
init_putz(t1, c + array_length * size1,
(index - array_length) * size1);
}
index++;
if (index > array_length)
array_length = index;
@ -3065,6 +3120,11 @@ void decl_initializer(int t, int c, int first, int size_only)
if (!no_oblock)
skip('}');
}
/* put zeros at the end */
if (!size_only && n >= 0 && array_length < n) {
init_putz(t1, c + array_length * size1,
(n - array_length) * size1);
}
/* patch type size if needed */
if (n < 0)
s->c = array_length;
@ -3073,13 +3133,34 @@ void decl_initializer(int t, int c, int first, int size_only)
skip('{');
s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT) | SYM_STRUCT);
f = s->next;
array_length = 0;
index = 0;
n = s->c;
while (tok != '}') {
decl_designator(t, c, NULL, &f, size_only);
/* fill with zero between fields */
index = f->c;
if (!size_only && array_length < index) {
init_putz(t, c + array_length,
index - array_length);
}
index = index + type_size(f->t, &align1);
if (index > array_length)
array_length = index;
if (tok == '}')
break;
skip(',');
f = f->next;
}
/* put zeros at the end */
if (!size_only && array_length < n) {
init_putz(t, c + array_length,
n - array_length);
}
skip('}');
} else if (tok == '{') {
next();
decl_initializer(t, c, first, size_only);
skip('}');
} else if (size_only) {
/* just skip expression */
@ -3091,7 +3172,7 @@ void decl_initializer(int t, int c, int first, int size_only)
else if (tok == ')')
parlevel--;
next();
}
}
} else {
init_putv(t, c, 0, 1);
}
@ -3114,7 +3195,7 @@ void decl(l)
t = type_decl(&v, b, TYPE_DIRECT);
if (tok == '{') {
if (!(t & VT_FUNC))
expect("function defintion");
expect("function definition");
/* patch forward references */
if ((sym = sym_find(v)) && (sym->t & VT_FORWARD)) {
gsym(sym->c);
@ -3234,15 +3315,7 @@ void decl(l)
}
if (tok == '=') {
next();
/* special case for non array types */
n = 0;
if (tok == '{' && (u & (VT_ARRAY | VT_STRUCT)) == 0) {
n = 1;
next();
}
decl_initializer(u, addr, 1, 0);
if (n)
skip('}');
/* restore parse state if needed */
if (init_str) {
free(init_str);