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
This commit is contained in:
parent
4e5a85292b
commit
3d3e2372c5
1 changed files with 177 additions and 101 deletions
192
tcc.c
192
tcc.c
|
@ -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();
|
||||||
|
@ -2197,10 +2207,22 @@ int *macro_arg_subst(Sym **nested_list, int *macro_str, Sym *args)
|
||||||
s = sym_find2(args, t);
|
s = sym_find2(args, t);
|
||||||
if (s) {
|
if (s) {
|
||||||
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);
|
||||||
|
|
Loading…
Reference in a new issue