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

278
tcc.c
View File

@ -135,7 +135,6 @@ typedef struct Reloc {
/* section definition */
typedef struct Section {
char name[64]; /* section name */
unsigned char *data; /* section data */
unsigned char *data_ptr; /* current data pointer */
int sh_num; /* elf section number */
@ -144,6 +143,7 @@ typedef struct Section {
int sh_entsize; /* elf entry size */
struct Section *link; /* link to another section */
struct Section *next;
char name[64]; /* section name */
} Section;
/* GNUC attribute definition */
@ -283,12 +283,13 @@ struct TCCState {
#define VT_LVAL 0x0100 /* var is an lvalue */
#define VT_FORWARD 0x0200 /* value is forward reference */
#define VT_MUSTCAST 0x0400 /* value must be casted to be correct (used for
char/short stored in integer registers) */
char/short stored in integer registers) */
#define VT_MUSTBOUND 0x0800 /* bound checking must be done before
dereferencing value */
#define VT_LVAL_BYTE 0x1000 /* lvalue is a byte */
#define VT_LVAL_SHORT 0x2000 /* lvalue is a short */
#define VT_LVAL_UNSIGNED 0x4000 /* lvalue is unsigned */
#define VT_LVAL_TYPE (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED)
/* types */
#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)
{
Sym *s, *first, **ps;
int v, t;
int v, t, varg, is_vaargs;
TokenString str;
v = tok;
@ -1479,12 +1480,21 @@ void parse_define(void)
next_nomacro();
ps = &first;
while (tok != ')') {
if (tok == TOK_DOTS)
tok = TOK___VA_ARGS__;
s = sym_push1(&define_stack, tok | SYM_FIELD, 0, 0);
varg = tok;
next_nomacro();
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->next;
next_nomacro();
if (tok != ',')
break;
next_nomacro();
@ -2197,10 +2207,22 @@ int *macro_arg_subst(Sym **nested_list, int *macro_str, Sym *args)
s = sym_find2(args, t);
if (s) {
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) {
while (*st)
tok_str_add(&str, *st++);
/* 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)
tok_str_add(&str, *st++);
}
} else {
macro_subst(&str, nested_list, st);
}
@ -2335,10 +2357,10 @@ void macro_subst(TokenString *tok_str,
get_tok_str(s->v, 0));
tok_str_new(&str);
parlevel = 0;
/* NOTE: non zero sa->t indicates VA_ARGS */
while ((parlevel > 0 ||
(tok != ')' &&
(tok != ',' ||
sa->v == (TOK___VA_ARGS__ | SYM_FIELD)))) &&
(tok != ',' || sa->t))) &&
tok != -1) {
if (tok == '(')
parlevel++;
@ -2348,17 +2370,24 @@ void macro_subst(TokenString *tok_str,
next_nomacro();
}
tok_str_add(&str, 0);
sym_push2(&args, sa->v & ~SYM_FIELD, 0, (int)str.str);
if (tok == ')')
break;
sym_push2(&args, sa->v & ~SYM_FIELD, sa->t, (int)str.str);
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;
}
if (tok != ',')
expect(",");
next_nomacro();
sa = sa->next;
}
if (sa->next)
if (sa) {
error("macro '%s' used with too few args",
get_tok_str(s->v, 0));
}
/* now subst each arg */
mstr = macro_arg_subst(nested_list, mstr, args);
@ -2626,14 +2655,17 @@ void gaddrof(void)
/* generate lvalue bound code */
void gbound(void)
{
int lval_type;
vtop->r &= ~VT_MUSTBOUND;
/* if lvalue, then use checking code before dereferencing */
if (vtop->r & VT_LVAL) {
lval_type = vtop->r & (VT_LVAL_TYPE | VT_LVAL);
gaddrof();
vpushi(0);
gen_bounded_ptr_add1();
gen_bounded_ptr_add2(1);
vtop->r |= VT_LVAL;
vtop->r |= lval_type;
}
}
#endif
@ -2730,6 +2762,23 @@ int gv(int rc)
vpop();
/* write second register */
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 {
/* one register type load */
load(r, vtop);
@ -2806,12 +2855,18 @@ void vrotb(int n)
/* pop stack value */
void vpop(void)
{
int v;
v = vtop->r & VT_VALMASK;
#ifdef TCC_TARGET_I386
/* 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) */
}
} else
#endif
if (v == VT_JMP || v == VT_JMPI) {
/* need to put correct jump if && or || without test */
gsym(vtop->c.ul);
}
vtop--;
}
@ -3467,7 +3522,7 @@ void force_charshort_cast(int t)
/* cast 'vtop' to 't' type */
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 */
/* XXX: in some cases (multiple cascaded casts), it may still
@ -3477,8 +3532,8 @@ void gen_cast(int t)
force_charshort_cast(vtop->t);
}
dbt = t & VT_BTYPE;
sbt = vtop->t & VT_BTYPE;
dbt = t & (VT_BTYPE | VT_UNSIGNED);
sbt = vtop->t & (VT_BTYPE | VT_UNSIGNED);
if (sbt != dbt) {
sf = is_float(sbt);
@ -3507,9 +3562,8 @@ void gen_cast(int t)
}
} else if (df) {
/* convert int to fp */
st1 = vtop->t & (VT_BTYPE | VT_UNSIGNED);
if (c) {
switch(st1) {
switch(sbt) {
case VT_LLONG | VT_UNSIGNED:
case VT_LLONG:
/* XXX: add const cases for long long */
@ -3535,14 +3589,13 @@ void gen_cast(int t)
}
} else if (sf) {
/* convert fp to int */
dt1 = t & (VT_BTYPE | VT_UNSIGNED);
/* we handle char/short/etc... with generic code */
if (dt1 != (VT_INT | VT_UNSIGNED) &&
dt1 != (VT_LLONG | VT_UNSIGNED) &&
dt1 != VT_LLONG)
dt1 = VT_INT;
if (dbt != (VT_INT | VT_UNSIGNED) &&
dbt != (VT_LLONG | VT_UNSIGNED) &&
dbt != VT_LLONG)
dbt = VT_INT;
if (c) {
switch(dt1) {
switch(dbt) {
case VT_LLONG | VT_UNSIGNED:
case VT_LLONG:
/* XXX: add const cases for long long */
@ -3565,59 +3618,58 @@ void gen_cast(int t)
}
} else {
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... */
vtop->t = dt1;
vtop->t = dbt;
gen_cast(t);
}
} else if (dbt == VT_LLONG) {
/* scalar to long long */
if (c) {
if ((vtop->t & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED))
vtop->c.ll = vtop->c.ui;
else
vtop->c.ll = vtop->c.i;
} else {
/* machine independant conversion */
gv(RC_INT);
/* generate high word */
if ((vtop->t & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED)) {
vpushi(0);
gv(RC_INT);
} else if ((dbt & VT_BTYPE) == VT_LLONG) {
if ((sbt & VT_BTYPE) != VT_LLONG) {
/* scalar to long long */
if (c) {
if (sbt == (VT_INT | VT_UNSIGNED))
vtop->c.ll = vtop->c.ui;
else
vtop->c.ll = vtop->c.i;
} else {
gv_dup();
vpushi(31);
gen_op(TOK_SAR);
/* machine independant conversion */
gv(RC_INT);
/* generate high word */
if (sbt == (VT_INT | VT_UNSIGNED)) {
vpushi(0);
gv(RC_INT);
} else {
gv_dup();
vpushi(31);
gen_op(TOK_SAR);
}
/* patch second register */
vtop[-1].r2 = vtop->r;
vpop();
}
/* patch second register */
vtop[-1].r2 = vtop->r;
vpop();
}
} else if (dbt == VT_BOOL) {
/* scalar to bool */
vpushi(0);
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);
} else if (dbt == VT_INT) {
} else if ((dbt & VT_BTYPE) == VT_INT) {
/* scalar to int */
if (sbt == VT_LLONG) {
/* from long long: just take low order word */
lexpand();
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;
no_cast: ;
}
/* 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)
return 1;
return is_compatible_types(t1, t2);
} else if (bt1 == VT_STRUCT) {
} else if (bt1 == VT_STRUCT || bt2 == VT_STRUCT) {
return (t2 == t1);
} else if (bt1 == VT_FUNC) {
if (bt2 != VT_FUNC)
@ -3877,7 +3929,6 @@ void vstore(void)
/* if structure, only generate pointer */
/* structure assignment : generate memcpy */
/* XXX: optimize if small size */
vdup();
gfunc_start(&gf, FUNC_CDECL);
/* type size */
@ -4488,7 +4539,25 @@ Sym *external_sym(int v, int u, int r)
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)
expect("pointer");
@ -4497,7 +4566,7 @@ void indir(void)
vtop->t = pointed_type(vtop->t);
/* an array is never an lvalue */
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 (do_bounds_check)
vtop->r |= VT_MUSTBOUND;
@ -4594,7 +4663,7 @@ void unary(void)
r = VT_LOCAL;
/* all except arrays are lvalues */
if (!(ft & VT_ARRAY))
r |= VT_LVAL;
r |= lvalue_type(ft);
memset(&ad, 0, sizeof(AttributeDef));
fc = decl_initializer_alloc(ft, &ad, r, 1);
vset(ft, r, fc);
@ -4615,7 +4684,9 @@ void unary(void)
except for unary '&' and sizeof. Since we consider that
functions are not lvalues, we only have to handle it
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();
vtop->t = mk_pointer(vtop->t);
gaddrof();
@ -4666,6 +4737,8 @@ void unary(void)
gen_op('-');
} else
{
if (t < TOK_UIDENT)
expect("identifier");
s = sym_find(t);
if (!s) {
if (tok != '(')
@ -4716,7 +4789,7 @@ void unary(void)
vtop->t = s->t;
/* an array is never an lvalue */
if (!(vtop->t & VT_ARRAY))
vtop->r |= VT_LVAL;
vtop->r |= lvalue_type(vtop->t);
next();
} else if (tok == '[') {
next();
@ -4758,30 +4831,30 @@ void unary(void)
/* read each argument and store it on a stack */
/* XXX: merge it with macro args ? */
args = NULL;
while (tok != ')') {
tok_str_new(&str);
parlevel = 0;
while ((parlevel > 0 || (tok != ')' && tok != ',')) &&
tok != -1) {
if (tok == '(')
parlevel++;
else if (tok == ')')
parlevel--;
tok_str_add_tok(&str);
next();
if (tok != ')') {
for(;;) {
tok_str_new(&str);
parlevel = 0;
while ((parlevel > 0 || (tok != ')' && tok != ',')) &&
tok != -1) {
if (tok == '(')
parlevel++;
else if (tok == ')')
parlevel--;
tok_str_add_tok(&str);
next();
}
tok_str_add(&str, -1); /* end of file added */
tok_str_add(&str, 0);
s1 = sym_push2(&args, 0, 0, (int)str.str);
s1->next = sa; /* add reference to argument */
if (sa)
sa = sa->next;
if (tok == ')')
break;
skip(',');
}
tok_str_add(&str, -1); /* end of file added */
tok_str_add(&str, 0);
s1 = sym_push2(&args, 0, 0, (int)str.str);
s1->next = sa; /* add reference to argument */
if (sa)
sa = sa->next;
if (tok != ',')
break;
next();
}
if (tok != ')')
expect(")");
/* now generate code in reverse order by reading the stack */
save_parse_state(&saved_parse_state);
@ -4826,13 +4899,16 @@ void unary(void)
ret.c.i = 0;
}
#ifndef INVERT_FUNC_PARAMS
while (tok != ')') {
expr_eq();
gfunc_param_typed(&gf, s, sa);
if (sa)
sa = sa->next;
if (tok == ',')
next();
if (tok != ')') {
for(;;) {
expr_eq();
gfunc_param_typed(&gf, s, sa);
if (sa)
sa = sa->next;
if (tok == ')')
break;
skip(',');
}
}
#endif
if (sa)
@ -5934,7 +6010,7 @@ void decl(int l)
/* not lvalue if array */
r = 0;
if (!(t & VT_ARRAY))
r |= VT_LVAL;
r |= lvalue_type(t);
if (b & VT_EXTERN) {
/* external variable */
external_sym(v, t, r);