added char/short types in lvalues to fix cast problems - added gcc style variadic macros - fixed zero arg macros - refuse extra comma at end of function call - fixed unused logical operation result case

tcc-xref
bellard 2002-07-13 11:17:19 +00:00
parent 4e5a85292b
commit 3d3e2372c5
1 changed files with 177 additions and 101 deletions

190
tcc.c
View File

@ -135,7 +135,6 @@ typedef struct Reloc {
/* section definition */ /* section definition */
typedef struct Section { typedef struct Section {
char name[64]; /* section name */
unsigned char *data; /* section data */ unsigned char *data; /* section data */
unsigned char *data_ptr; /* current data pointer */ unsigned char *data_ptr; /* current data pointer */
int sh_num; /* elf section number */ int sh_num; /* elf section number */
@ -144,6 +143,7 @@ typedef struct Section {
int sh_entsize; /* elf entry size */ int sh_entsize; /* elf entry size */
struct Section *link; /* link to another section */ struct Section *link; /* link to another section */
struct Section *next; struct Section *next;
char name[64]; /* section name */
} Section; } Section;
/* GNUC attribute definition */ /* GNUC attribute definition */
@ -289,6 +289,7 @@ struct TCCState {
#define VT_LVAL_BYTE 0x1000 /* lvalue is a byte */ #define VT_LVAL_BYTE 0x1000 /* lvalue is a byte */
#define VT_LVAL_SHORT 0x2000 /* lvalue is a short */ #define VT_LVAL_SHORT 0x2000 /* lvalue is a short */
#define VT_LVAL_UNSIGNED 0x4000 /* lvalue is unsigned */ #define VT_LVAL_UNSIGNED 0x4000 /* lvalue is unsigned */
#define VT_LVAL_TYPE (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED)
/* types */ /* types */
#define VT_STRUCT_SHIFT 16 /* structure/enum name shift (16 bits left) */ #define VT_STRUCT_SHIFT 16 /* structure/enum name shift (16 bits left) */
@ -1466,7 +1467,7 @@ void tok_print(int *str)
void parse_define(void) void parse_define(void)
{ {
Sym *s, *first, **ps; Sym *s, *first, **ps;
int v, t; int v, t, varg, is_vaargs;
TokenString str; TokenString str;
v = tok; v = tok;
@ -1479,12 +1480,21 @@ void parse_define(void)
next_nomacro(); next_nomacro();
ps = &first; ps = &first;
while (tok != ')') { while (tok != ')') {
if (tok == TOK_DOTS) varg = tok;
tok = TOK___VA_ARGS__; next_nomacro();
s = sym_push1(&define_stack, tok | SYM_FIELD, 0, 0); is_vaargs = 0;
if (varg == TOK_DOTS) {
varg = TOK___VA_ARGS__;
is_vaargs = 1;
} else if (tok == TOK_DOTS && gnu_ext) {
is_vaargs = 1;
next_nomacro();
}
if (varg < TOK_IDENT)
error("badly punctuated parameter list");
s = sym_push1(&define_stack, varg | SYM_FIELD, is_vaargs, 0);
*ps = s; *ps = s;
ps = &s->next; ps = &s->next;
next_nomacro();
if (tok != ',') if (tok != ',')
break; break;
next_nomacro(); next_nomacro();
@ -2199,8 +2209,20 @@ int *macro_arg_subst(Sym **nested_list, int *macro_str, Sym *args)
st = (int *)s->c; st = (int *)s->c;
/* if '##' is present before or after, no arg substitution */ /* if '##' is present before or after, no arg substitution */
if (*macro_str == TOK_TWOSHARPS || last_tok == TOK_TWOSHARPS) { if (*macro_str == TOK_TWOSHARPS || last_tok == TOK_TWOSHARPS) {
/* special case for var arg macros : ## eats the
',' if empty VA_ARGS riable. */
/* XXX: test of the ',' is not 100%
reliable. should fix it to avoid security
problems */
if (gnu_ext && s->t && *st == 0 &&
last_tok == TOK_TWOSHARPS &&
str.len >= 2&& str.str[str.len - 2] == ',') {
/* suppress ',' '##' */
str.len -= 2;
} else {
while (*st) while (*st)
tok_str_add(&str, *st++); tok_str_add(&str, *st++);
}
} else { } else {
macro_subst(&str, nested_list, st); macro_subst(&str, nested_list, st);
} }
@ -2335,10 +2357,10 @@ void macro_subst(TokenString *tok_str,
get_tok_str(s->v, 0)); get_tok_str(s->v, 0));
tok_str_new(&str); tok_str_new(&str);
parlevel = 0; parlevel = 0;
/* NOTE: non zero sa->t indicates VA_ARGS */
while ((parlevel > 0 || while ((parlevel > 0 ||
(tok != ')' && (tok != ')' &&
(tok != ',' || (tok != ',' || sa->t))) &&
sa->v == (TOK___VA_ARGS__ | SYM_FIELD)))) &&
tok != -1) { tok != -1) {
if (tok == '(') if (tok == '(')
parlevel++; parlevel++;
@ -2348,17 +2370,24 @@ void macro_subst(TokenString *tok_str,
next_nomacro(); next_nomacro();
} }
tok_str_add(&str, 0); tok_str_add(&str, 0);
sym_push2(&args, sa->v & ~SYM_FIELD, 0, (int)str.str); sym_push2(&args, sa->v & ~SYM_FIELD, sa->t, (int)str.str);
if (tok == ')') sa = sa->next;
if (tok == ')') {
/* special case for gcc var args: add an empty
var arg argument if it is omitted */
if (sa && sa->t && gnu_ext)
continue;
else
break; break;
}
if (tok != ',') if (tok != ',')
expect(","); expect(",");
next_nomacro(); next_nomacro();
sa = sa->next;
} }
if (sa->next) if (sa) {
error("macro '%s' used with too few args", error("macro '%s' used with too few args",
get_tok_str(s->v, 0)); get_tok_str(s->v, 0));
}
/* now subst each arg */ /* now subst each arg */
mstr = macro_arg_subst(nested_list, mstr, args); mstr = macro_arg_subst(nested_list, mstr, args);
@ -2626,14 +2655,17 @@ void gaddrof(void)
/* generate lvalue bound code */ /* generate lvalue bound code */
void gbound(void) void gbound(void)
{ {
int lval_type;
vtop->r &= ~VT_MUSTBOUND; vtop->r &= ~VT_MUSTBOUND;
/* if lvalue, then use checking code before dereferencing */ /* if lvalue, then use checking code before dereferencing */
if (vtop->r & VT_LVAL) { if (vtop->r & VT_LVAL) {
lval_type = vtop->r & (VT_LVAL_TYPE | VT_LVAL);
gaddrof(); gaddrof();
vpushi(0); vpushi(0);
gen_bounded_ptr_add1(); gen_bounded_ptr_add1();
gen_bounded_ptr_add2(1); gen_bounded_ptr_add2(1);
vtop->r |= VT_LVAL; vtop->r |= lval_type;
} }
} }
#endif #endif
@ -2730,6 +2762,23 @@ int gv(int rc)
vpop(); vpop();
/* write second register */ /* write second register */
vtop->r2 = r2; vtop->r2 = r2;
} else if ((vtop->r & VT_LVAL) && !is_float(vtop->t)) {
int t1, t;
/* lvalue of scalar type : need to use lvalue type
because of possible cast */
t = vtop->t;
t1 = t;
/* compute memory access type */
if (vtop->r & VT_LVAL_BYTE)
t = VT_BYTE;
else if (vtop->r & VT_LVAL_SHORT)
t = VT_SHORT;
if (vtop->r & VT_LVAL_UNSIGNED)
t |= VT_UNSIGNED;
vtop->t = t;
load(r, vtop);
/* restore wanted type */
vtop->t = t1;
} else { } else {
/* one register type load */ /* one register type load */
load(r, vtop); load(r, vtop);
@ -2806,12 +2855,18 @@ void vrotb(int n)
/* pop stack value */ /* pop stack value */
void vpop(void) void vpop(void)
{ {
int v;
v = vtop->r & VT_VALMASK;
#ifdef TCC_TARGET_I386 #ifdef TCC_TARGET_I386
/* for x86, we need to pop the FP stack */ /* for x86, we need to pop the FP stack */
if ((vtop->r & VT_VALMASK) == REG_ST0) { if (v == REG_ST0) {
o(0xd9dd); /* fstp %st(1) */ o(0xd9dd); /* fstp %st(1) */
} } else
#endif #endif
if (v == VT_JMP || v == VT_JMPI) {
/* need to put correct jump if && or || without test */
gsym(vtop->c.ul);
}
vtop--; vtop--;
} }
@ -3467,7 +3522,7 @@ void force_charshort_cast(int t)
/* cast 'vtop' to 't' type */ /* cast 'vtop' to 't' type */
void gen_cast(int t) void gen_cast(int t)
{ {
int sbt, dbt, sf, df, c, st1, dt1; int sbt, dbt, sf, df, c;
/* special delayed cast for char/short */ /* special delayed cast for char/short */
/* XXX: in some cases (multiple cascaded casts), it may still /* XXX: in some cases (multiple cascaded casts), it may still
@ -3477,8 +3532,8 @@ void gen_cast(int t)
force_charshort_cast(vtop->t); force_charshort_cast(vtop->t);
} }
dbt = t & VT_BTYPE; dbt = t & (VT_BTYPE | VT_UNSIGNED);
sbt = vtop->t & VT_BTYPE; sbt = vtop->t & (VT_BTYPE | VT_UNSIGNED);
if (sbt != dbt) { if (sbt != dbt) {
sf = is_float(sbt); sf = is_float(sbt);
@ -3507,9 +3562,8 @@ void gen_cast(int t)
} }
} else if (df) { } else if (df) {
/* convert int to fp */ /* convert int to fp */
st1 = vtop->t & (VT_BTYPE | VT_UNSIGNED);
if (c) { if (c) {
switch(st1) { switch(sbt) {
case VT_LLONG | VT_UNSIGNED: case VT_LLONG | VT_UNSIGNED:
case VT_LLONG: case VT_LLONG:
/* XXX: add const cases for long long */ /* XXX: add const cases for long long */
@ -3535,14 +3589,13 @@ void gen_cast(int t)
} }
} else if (sf) { } else if (sf) {
/* convert fp to int */ /* convert fp to int */
dt1 = t & (VT_BTYPE | VT_UNSIGNED);
/* we handle char/short/etc... with generic code */ /* we handle char/short/etc... with generic code */
if (dt1 != (VT_INT | VT_UNSIGNED) && if (dbt != (VT_INT | VT_UNSIGNED) &&
dt1 != (VT_LLONG | VT_UNSIGNED) && dbt != (VT_LLONG | VT_UNSIGNED) &&
dt1 != VT_LLONG) dbt != VT_LLONG)
dt1 = VT_INT; dbt = VT_INT;
if (c) { if (c) {
switch(dt1) { switch(dbt) {
case VT_LLONG | VT_UNSIGNED: case VT_LLONG | VT_UNSIGNED:
case VT_LLONG: case VT_LLONG:
/* XXX: add const cases for long long */ /* XXX: add const cases for long long */
@ -3565,17 +3618,18 @@ void gen_cast(int t)
} }
} else { } else {
do_ftoi: do_ftoi:
gen_cvt_ftoi1(dt1); gen_cvt_ftoi1(dbt);
} }
if (dt1 == VT_INT && (t & (VT_BTYPE | VT_UNSIGNED)) != dt1) { if (dbt == VT_INT && (t & (VT_BTYPE | VT_UNSIGNED)) != dbt) {
/* additionnal cast for char/short/bool... */ /* additionnal cast for char/short/bool... */
vtop->t = dt1; vtop->t = dbt;
gen_cast(t); gen_cast(t);
} }
} else if (dbt == VT_LLONG) { } else if ((dbt & VT_BTYPE) == VT_LLONG) {
if ((sbt & VT_BTYPE) != VT_LLONG) {
/* scalar to long long */ /* scalar to long long */
if (c) { if (c) {
if ((vtop->t & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED)) if (sbt == (VT_INT | VT_UNSIGNED))
vtop->c.ll = vtop->c.ui; vtop->c.ll = vtop->c.ui;
else else
vtop->c.ll = vtop->c.i; vtop->c.ll = vtop->c.i;
@ -3583,7 +3637,7 @@ void gen_cast(int t)
/* machine independant conversion */ /* machine independant conversion */
gv(RC_INT); gv(RC_INT);
/* generate high word */ /* generate high word */
if ((vtop->t & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED)) { if (sbt == (VT_INT | VT_UNSIGNED)) {
vpushi(0); vpushi(0);
gv(RC_INT); gv(RC_INT);
} else { } else {
@ -3595,29 +3649,27 @@ void gen_cast(int t)
vtop[-1].r2 = vtop->r; vtop[-1].r2 = vtop->r;
vpop(); vpop();
} }
}
} else if (dbt == VT_BOOL) { } else if (dbt == VT_BOOL) {
/* scalar to bool */ /* scalar to bool */
vpushi(0); vpushi(0);
gen_op(TOK_NE); gen_op(TOK_NE);
} else if (dbt == VT_BYTE || dbt == VT_SHORT) { } else if ((dbt & VT_BTYPE) == VT_BYTE ||
(dbt & VT_BTYPE) == VT_SHORT) {
force_charshort_cast(t); force_charshort_cast(t);
} else if (dbt == VT_INT) { } else if ((dbt & VT_BTYPE) == VT_INT) {
/* scalar to int */ /* scalar to int */
if (sbt == VT_LLONG) { if (sbt == VT_LLONG) {
/* from long long: just take low order word */ /* from long long: just take low order word */
lexpand(); lexpand();
vpop(); vpop();
} else if (sbt == VT_PTR) {
/* ok to cast */
} else if (vtop->r & VT_LVAL) {
/* if lvalue and single word type, nothing to do (XXX:
maybe incorrect for sizeof op) */
goto no_cast;
} }
/* if lvalue and single word type, nothing to do because
the lvalue already contains the real type size (see
VT_LVAL_xxx constants) */
} }
} }
vtop->t = t; vtop->t = t;
no_cast: ;
} }
/* return type size. Put alignment at 'a' */ /* return type size. Put alignment at 'a' */
@ -3698,7 +3750,7 @@ int is_compatible_types(int t1, int t2)
if (t1 == VT_VOID || t2 == VT_VOID) if (t1 == VT_VOID || t2 == VT_VOID)
return 1; return 1;
return is_compatible_types(t1, t2); return is_compatible_types(t1, t2);
} else if (bt1 == VT_STRUCT) { } else if (bt1 == VT_STRUCT || bt2 == VT_STRUCT) {
return (t2 == t1); return (t2 == t1);
} else if (bt1 == VT_FUNC) { } else if (bt1 == VT_FUNC) {
if (bt2 != VT_FUNC) if (bt2 != VT_FUNC)
@ -3877,7 +3929,6 @@ void vstore(void)
/* if structure, only generate pointer */ /* if structure, only generate pointer */
/* structure assignment : generate memcpy */ /* structure assignment : generate memcpy */
/* XXX: optimize if small size */ /* XXX: optimize if small size */
vdup(); vdup();
gfunc_start(&gf, FUNC_CDECL); gfunc_start(&gf, FUNC_CDECL);
/* type size */ /* type size */
@ -4488,7 +4539,25 @@ Sym *external_sym(int v, int u, int r)
return s; return s;
} }
void indir(void) /* compute the lvalue VT_LVAL_xxx needed to match type t. */
static int lvalue_type(int t)
{
int bt, r;
r = VT_LVAL;
bt = t & VT_BTYPE;
if (bt == VT_BYTE)
r |= VT_LVAL_BYTE;
else if (bt == VT_SHORT)
r |= VT_LVAL_SHORT;
else
return r;
if (t & VT_UNSIGNED)
r |= VT_LVAL_UNSIGNED;
return r;
}
/* indirection with full error checking and bound check */
static void indir(void)
{ {
if ((vtop->t & VT_BTYPE) != VT_PTR) if ((vtop->t & VT_BTYPE) != VT_PTR)
expect("pointer"); expect("pointer");
@ -4497,7 +4566,7 @@ void indir(void)
vtop->t = pointed_type(vtop->t); vtop->t = pointed_type(vtop->t);
/* an array is never an lvalue */ /* an array is never an lvalue */
if (!(vtop->t & VT_ARRAY)) { if (!(vtop->t & VT_ARRAY)) {
vtop->r |= VT_LVAL; vtop->r |= lvalue_type(vtop->t);
/* if bound checking, the referenced pointer must be checked */ /* if bound checking, the referenced pointer must be checked */
if (do_bounds_check) if (do_bounds_check)
vtop->r |= VT_MUSTBOUND; vtop->r |= VT_MUSTBOUND;
@ -4594,7 +4663,7 @@ void unary(void)
r = VT_LOCAL; r = VT_LOCAL;
/* all except arrays are lvalues */ /* all except arrays are lvalues */
if (!(ft & VT_ARRAY)) if (!(ft & VT_ARRAY))
r |= VT_LVAL; r |= lvalue_type(ft);
memset(&ad, 0, sizeof(AttributeDef)); memset(&ad, 0, sizeof(AttributeDef));
fc = decl_initializer_alloc(ft, &ad, r, 1); fc = decl_initializer_alloc(ft, &ad, r, 1);
vset(ft, r, fc); vset(ft, r, fc);
@ -4615,7 +4684,9 @@ void unary(void)
except for unary '&' and sizeof. Since we consider that except for unary '&' and sizeof. Since we consider that
functions are not lvalues, we only have to handle it functions are not lvalues, we only have to handle it
there and in function calls. */ there and in function calls. */
if ((vtop->t & VT_BTYPE) != VT_FUNC) /* arrays can also be used although they are not lvalues */
if ((vtop->t & VT_BTYPE) != VT_FUNC &&
!(vtop->t & VT_ARRAY))
test_lvalue(); test_lvalue();
vtop->t = mk_pointer(vtop->t); vtop->t = mk_pointer(vtop->t);
gaddrof(); gaddrof();
@ -4666,6 +4737,8 @@ void unary(void)
gen_op('-'); gen_op('-');
} else } else
{ {
if (t < TOK_UIDENT)
expect("identifier");
s = sym_find(t); s = sym_find(t);
if (!s) { if (!s) {
if (tok != '(') if (tok != '(')
@ -4716,7 +4789,7 @@ void unary(void)
vtop->t = s->t; vtop->t = s->t;
/* an array is never an lvalue */ /* an array is never an lvalue */
if (!(vtop->t & VT_ARRAY)) if (!(vtop->t & VT_ARRAY))
vtop->r |= VT_LVAL; vtop->r |= lvalue_type(vtop->t);
next(); next();
} else if (tok == '[') { } else if (tok == '[') {
next(); next();
@ -4758,7 +4831,8 @@ void unary(void)
/* read each argument and store it on a stack */ /* read each argument and store it on a stack */
/* XXX: merge it with macro args ? */ /* XXX: merge it with macro args ? */
args = NULL; args = NULL;
while (tok != ')') { if (tok != ')') {
for(;;) {
tok_str_new(&str); tok_str_new(&str);
parlevel = 0; parlevel = 0;
while ((parlevel > 0 || (tok != ')' && tok != ',')) && while ((parlevel > 0 || (tok != ')' && tok != ',')) &&
@ -4776,12 +4850,11 @@ void unary(void)
s1->next = sa; /* add reference to argument */ s1->next = sa; /* add reference to argument */
if (sa) if (sa)
sa = sa->next; sa = sa->next;
if (tok != ',') if (tok == ')')
break; break;
next(); skip(',');
}
} }
if (tok != ')')
expect(")");
/* now generate code in reverse order by reading the stack */ /* now generate code in reverse order by reading the stack */
save_parse_state(&saved_parse_state); save_parse_state(&saved_parse_state);
@ -4826,13 +4899,16 @@ void unary(void)
ret.c.i = 0; ret.c.i = 0;
} }
#ifndef INVERT_FUNC_PARAMS #ifndef INVERT_FUNC_PARAMS
while (tok != ')') { if (tok != ')') {
for(;;) {
expr_eq(); expr_eq();
gfunc_param_typed(&gf, s, sa); gfunc_param_typed(&gf, s, sa);
if (sa) if (sa)
sa = sa->next; sa = sa->next;
if (tok == ',') if (tok == ')')
next(); break;
skip(',');
}
} }
#endif #endif
if (sa) if (sa)
@ -5934,7 +6010,7 @@ void decl(int l)
/* not lvalue if array */ /* not lvalue if array */
r = 0; r = 0;
if (!(t & VT_ARRAY)) if (!(t & VT_ARRAY))
r |= VT_LVAL; r |= lvalue_type(t);
if (b & VT_EXTERN) { if (b & VT_EXTERN) {
/* external variable */ /* external variable */
external_sym(v, t, r); external_sym(v, t, r);