added alignof and typeof - better sizeof support - fixed get_tok_str() for TOK_PPNUM

This commit is contained in:
bellard 2002-11-02 20:45:52 +00:00
parent c0180c4e5f
commit 43f30315f9

390
tcc.c
View file

@ -270,6 +270,7 @@ int rsym, anon_sym,
prog, ind, loc; prog, ind, loc;
/* expression generation modifiers */ /* expression generation modifiers */
int const_wanted; /* true if constant wanted */ int const_wanted; /* true if constant wanted */
int nocode_wanted; /* true if no code generation wanted for an expression */
int global_expr; /* true if compound literals must be allocated int global_expr; /* true if compound literals must be allocated
globally (used during initializers parsing */ globally (used during initializers parsing */
int func_vt, func_vc; /* current function return type (used by int func_vt, func_vc; /* current function return type (used by
@ -490,83 +491,20 @@ static char tok_two_chars[] = "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<
#define TOK_IDENT 256 #define TOK_IDENT 256
enum { enum {
TOK_INT = TOK_IDENT, TOK_LAST = TOK_IDENT - 1,
TOK_VOID,
TOK_CHAR,
TOK_IF,
TOK_ELSE,
TOK_WHILE,
TOK_BREAK,
TOK_RETURN,
TOK_FOR,
TOK_EXTERN,
TOK_STATIC,
TOK_UNSIGNED,
TOK_GOTO,
TOK_DO,
TOK_CONTINUE,
TOK_SWITCH,
TOK_CASE,
/* ignored types Must have contiguous values */
TOK_CONST,
TOK_VOLATILE,
TOK_LONG,
TOK_REGISTER,
TOK_SIGNED,
TOK___SIGNED__, /* gcc keyword */
TOK_AUTO,
TOK_INLINE,
TOK___INLINE__, /* gcc keyword */
TOK_RESTRICT,
/* unsupported type */
TOK_FLOAT,
TOK_DOUBLE,
TOK_BOOL,
TOK_SHORT,
TOK_STRUCT,
TOK_UNION,
TOK_TYPEDEF,
TOK_DEFAULT,
TOK_ENUM,
TOK_SIZEOF,
TOK___ATTRIBUTE__,
/* preprocessor only */
TOK_UIDENT, /* first "user" ident (not keyword) */
TOK_DEFINE = TOK_UIDENT,
TOK_INCLUDE,
TOK_IFDEF,
TOK_IFNDEF,
TOK_ELIF,
TOK_ENDIF,
TOK_DEFINED,
TOK_UNDEF,
TOK_ERROR,
TOK_LINE,
#define DEF(id, str) id, #define DEF(id, str) id,
#include "tcctok.h" #include "tcctok.h"
#undef DEF #undef DEF
}; };
char *tcc_keywords = static const char *tcc_keywords =
"int\0void\0char\0if\0else\0while\0break\0return\0for\0extern\0static\0"
"unsigned\0goto\0do\0continue\0switch\0case\0const\0volatile\0long\0"
"register\0signed\0__signed__\0auto\0inline\0__inline__\0restrict\0"
"float\0double\0_Bool\0short\0struct\0union\0typedef\0default\0enum\0"
"sizeof\0__attribute__\0"
/* the following are not keywords. They are included to ease parsing */
"define\0include\0ifdef\0ifndef\0elif\0endif\0"
"defined\0undef\0error\0line\0"
/* builtin functions */
#define DEF(id, str) str "\0" #define DEF(id, str) str "\0"
#include "tcctok.h" #include "tcctok.h"
#undef DEF #undef DEF
; ;
#define TOK_UIDENT TOK_DEFINE
#ifdef WIN32 #ifdef WIN32
#define snprintf _snprintf #define snprintf _snprintf
#endif #endif
@ -590,13 +528,16 @@ extern long double strtold (const char *__nptr, char **__endptr);
static char *pstrcpy(char *buf, int buf_size, const char *s); static char *pstrcpy(char *buf, int buf_size, const char *s);
static char *pstrcat(char *buf, int buf_size, const char *s); static char *pstrcat(char *buf, int buf_size, const char *s);
void sum(int l); static void sum(int l);
void next(void); static void next(void);
void next_nomacro(void); static void next_nomacro(void);
static int parse_expr_type(void);
static int expr_type(void);
static int unary_type(void);
static int expr_const(void); static int expr_const(void);
void expr_eq(void); static void expr_eq(void);
void gexpr(void); static void gexpr(void);
void decl(int l); static void decl(int l);
static void decl_initializer(int t, Section *sec, unsigned long c, static void decl_initializer(int t, Section *sec, unsigned long c,
int first, int size_only); int first, int size_only);
static void decl_initializer_alloc(int t, AttributeDef *ad, int r, static void decl_initializer_alloc(int t, AttributeDef *ad, int r,
@ -1301,12 +1242,12 @@ char *get_tok_str(int v, CValue *cv)
switch(v) { switch(v) {
case TOK_CINT: case TOK_CINT:
case TOK_CUINT: case TOK_CUINT:
/* XXX: not quite exact, but useful for ## in macros */ /* XXX: not quite exact, but only useful for testing */
sprintf(p, "%u", cv->ui); sprintf(p, "%u", cv->ui);
break; break;
case TOK_CLLONG: case TOK_CLLONG:
case TOK_CULLONG: case TOK_CULLONG:
/* XXX: not quite exact, but useful for ## in macros */ /* XXX: not quite exact, but only useful for testing */
sprintf(p, "%Lu", cv->ull); sprintf(p, "%Lu", cv->ull);
break; break;
case TOK_CCHAR: case TOK_CCHAR:
@ -1321,6 +1262,7 @@ char *get_tok_str(int v, CValue *cv)
len = cstr->size - 1; len = cstr->size - 1;
for(i=0;i<len;i++) for(i=0;i<len;i++)
add_char(&cstr_buf, ((unsigned char *)cstr->data)[i]); add_char(&cstr_buf, ((unsigned char *)cstr->data)[i]);
cstr_ccat(&cstr_buf, '\0');
break; break;
case TOK_STR: case TOK_STR:
case TOK_LSTR: case TOK_LSTR:
@ -2754,7 +2696,7 @@ static inline void next_nomacro1(void)
/* return next token without macro substitution. Can read input from /* return next token without macro substitution. Can read input from
macro_ptr buffer */ macro_ptr buffer */
void next_nomacro() static void next_nomacro(void)
{ {
if (macro_ptr) { if (macro_ptr) {
redo: redo:
@ -2772,7 +2714,7 @@ void next_nomacro()
} }
/* substitute args in macro_str and return allocated string */ /* substitute args in macro_str and return allocated string */
int *macro_arg_subst(Sym **nested_list, int *macro_str, Sym *args) static int *macro_arg_subst(Sym **nested_list, int *macro_str, Sym *args)
{ {
int *st, last_tok, t, notfirst; int *st, last_tok, t, notfirst;
Sym *s; Sym *s;
@ -2894,7 +2836,7 @@ static int *macro_twosharps(void)
p2 = get_tok_str(t, &cval); p2 = get_tok_str(t, &cval);
cstr_cat(&cstr, p2); cstr_cat(&cstr, p2);
cstr_ccat(&cstr, '\0'); cstr_ccat(&cstr, '\0');
if ((tok >= TOK_IDENT || tok == TOK_PPNUM) && if ((tok >= TOK_IDENT || tok == TOK_PPNUM) &&
(t >= TOK_IDENT || t == TOK_PPNUM)) { (t >= TOK_IDENT || t == TOK_PPNUM)) {
if (tok == TOK_PPNUM) { if (tok == TOK_PPNUM) {
@ -3130,7 +3072,7 @@ static void macro_subst(TokenString *tok_str,
} }
/* return next token with macro substitution */ /* return next token with macro substitution */
void next(void) static void next(void)
{ {
Sym *nested_list, *s; Sym *nested_list, *s;
TokenString str; TokenString str;
@ -3670,7 +3612,7 @@ void vpop(void)
v = vtop->r & VT_VALMASK; 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 (v == REG_ST0) { if (v == REG_ST0 && !nocode_wanted) {
o(0xd9dd); /* fstp %st(1) */ o(0xd9dd); /* fstp %st(1) */
} else } else
#endif #endif
@ -4045,8 +3987,12 @@ void gen_opic(int op)
vtop->c.i += fc; vtop->c.i += fc;
} else { } else {
general_case: general_case:
/* call low level op generator */ if (!nocode_wanted) {
gen_opi(op); /* call low level op generator */
gen_opi(op);
} else {
vtop--;
}
} }
} }
} }
@ -4107,7 +4053,11 @@ void gen_opif(int op)
vtop--; vtop--;
} else { } else {
general_case: general_case:
gen_opf(op); if (!nocode_wanted) {
gen_opf(op);
} else {
vtop--;
}
} }
} }
@ -4355,7 +4305,7 @@ void gen_cast(int t)
dbt = t & (VT_BTYPE | VT_UNSIGNED); dbt = t & (VT_BTYPE | VT_UNSIGNED);
sbt = vtop->t & (VT_BTYPE | VT_UNSIGNED); sbt = vtop->t & (VT_BTYPE | VT_UNSIGNED);
if (sbt != dbt) { if (sbt != dbt && !nocode_wanted) {
sf = is_float(sbt); sf = is_float(sbt);
df = is_float(dbt); df = is_float(dbt);
c = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; c = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST;
@ -4749,25 +4699,30 @@ 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(); if (!nocode_wanted) {
gfunc_start(&gf, FUNC_CDECL); vdup();
/* type size */ gfunc_start(&gf, FUNC_CDECL);
size = type_size(vtop->t, &align); /* type size */
vpushi(size); size = type_size(vtop->t, &align);
gfunc_param(&gf); vpushi(size);
/* source */ gfunc_param(&gf);
vtop->t = VT_INT; /* source */
gaddrof(); vtop->t = VT_INT;
gfunc_param(&gf); gaddrof();
/* destination */ gfunc_param(&gf);
vswap(); /* destination */
vtop->t = VT_INT; vswap();
gaddrof(); vtop->t = VT_INT;
gfunc_param(&gf); gaddrof();
gfunc_param(&gf);
save_regs(0);
vpush_global_sym(func_old_type, TOK_memcpy); save_regs(0);
gfunc_call(&gf); vpush_global_sym(func_old_type, TOK_memcpy);
gfunc_call(&gf);
} else {
vswap();
vpop();
}
/* leave source on stack */ /* leave source on stack */
} else if (ft & VT_BITFIELD) { } else if (ft & VT_BITFIELD) {
/* bitfield store handling */ /* bitfield store handling */
@ -4801,33 +4756,35 @@ void vstore(void)
vswap(); vswap();
} }
#endif #endif
rc = RC_INT; if (!nocode_wanted) {
if (is_float(ft)) rc = RC_INT;
rc = RC_FLOAT; if (is_float(ft))
r = gv(rc); /* generate value */ rc = RC_FLOAT;
/* if lvalue was saved on stack, must read it */ r = gv(rc); /* generate value */
if ((vtop[-1].r & VT_VALMASK) == VT_LLOCAL) { /* if lvalue was saved on stack, must read it */
SValue sv; if ((vtop[-1].r & VT_VALMASK) == VT_LLOCAL) {
t = get_reg(RC_INT); SValue sv;
sv.t = VT_INT; t = get_reg(RC_INT);
sv.r = VT_LOCAL | VT_LVAL; sv.t = VT_INT;
sv.c.ul = vtop[-1].c.ul; sv.r = VT_LOCAL | VT_LVAL;
load(t, &sv); sv.c.ul = vtop[-1].c.ul;
vtop[-1].r = t | VT_LVAL; load(t, &sv);
} vtop[-1].r = t | VT_LVAL;
store(r, vtop - 1); }
/* two word case handling : store second register at word + 4 */ store(r, vtop - 1);
if ((ft & VT_BTYPE) == VT_LLONG) { /* two word case handling : store second register at word + 4 */
vswap(); if ((ft & VT_BTYPE) == VT_LLONG) {
/* convert to int to increment easily */ vswap();
vtop->t = VT_INT; /* convert to int to increment easily */
gaddrof(); vtop->t = VT_INT;
vpushi(4); gaddrof();
gen_op('+'); vpushi(4);
vtop->r |= VT_LVAL; gen_op('+');
vswap(); vtop->r |= VT_LVAL;
/* XXX: it works because r2 is spilled last ! */ vswap();
store(vtop->r2, vtop - 1); /* XXX: it works because r2 is spilled last ! */
store(vtop->r2, vtop - 1);
}
} }
vswap(); vswap();
vtop--; /* NOT vpop() because on x86 it would flush the fp stack */ vtop--; /* NOT vpop() because on x86 it would flush the fp stack */
@ -5188,6 +5145,11 @@ int parse_btype(int *type_ptr, AttributeDef *ad)
case TOK___ATTRIBUTE__: case TOK___ATTRIBUTE__:
parse_attribute(ad); parse_attribute(ad);
break; break;
/* GNUC typeof */
case TOK_TYPEOF:
next();
u = parse_expr_type();
goto basic_type1;
default: default:
s = sym_find(tok); s = sym_find(tok);
if (!s || !(s->t & VT_TYPEDEF)) if (!s || !(s->t & VT_TYPEDEF))
@ -5367,7 +5329,7 @@ static void indir(void)
{ {
if ((vtop->t & VT_BTYPE) != VT_PTR) if ((vtop->t & VT_BTYPE) != VT_PTR)
expect("pointer"); expect("pointer");
if (vtop->r & VT_LVAL) if ((vtop->r & VT_LVAL) && !nocode_wanted)
gv(RC_INT); gv(RC_INT);
vtop->t = pointed_type(vtop->t); vtop->t = pointed_type(vtop->t);
/* an array is never an lvalue */ /* an array is never an lvalue */
@ -5394,10 +5356,31 @@ void gfunc_param_typed(GFuncContext *gf, Sym *func, Sym *arg)
} else { } else {
gen_assign_cast(arg->t); gen_assign_cast(arg->t);
} }
gfunc_param(gf); if (!nocode_wanted) {
gfunc_param(gf);
} else {
vpop();
}
} }
void unary(void) /* parse an expression of the form '(type)' or '(expr)' and return its
type */
static int parse_expr_type(void)
{
int ft, n;
AttributeDef ad;
skip('(');
if (parse_btype(&ft, &ad)) {
ft = type_decl(&ad, &n, ft, TYPE_ABSTRACT);
} else {
ft = expr_type();
}
skip(')');
return ft;
}
static void unary(void)
{ {
int n, t, ft, align, size, r; int n, t, ft, align, size, r;
Sym *s; Sym *s;
@ -5515,25 +5498,17 @@ void unary(void)
vpushi(0); vpushi(0);
gen_op('+'); gen_op('+');
} else } else
if (t == TOK_SIZEOF) { if (t == TOK_SIZEOF || t == TOK_ALIGNOF) {
if (tok == '(') { if (tok == '(') {
next(); ft = parse_expr_type();
if (parse_btype(&t, &ad)) {
t = type_decl(&ad, &n, t, TYPE_ABSTRACT);
} else {
/* XXX: some code could be generated: add eval
flag */
gexpr();
t = vtop->t;
vpop();
}
skip(')');
} else { } else {
unary(); ft = unary_type();
t = vtop->t;
vpop();
} }
vpushi(type_size(t, &t)); size = type_size(ft, &align);
if (t == TOK_SIZEOF)
vpushi(size);
else
vpushi(align);
} else } else
if (t == TOK_INC || t == TOK_DEC) { if (t == TOK_INC || t == TOK_DEC) {
unary(); unary();
@ -5627,8 +5602,10 @@ void unary(void)
} }
/* get return type */ /* get return type */
s = sym_find((unsigned)vtop->t >> VT_STRUCT_SHIFT); s = sym_find((unsigned)vtop->t >> VT_STRUCT_SHIFT);
save_regs(0); /* save used temporary registers */ if (!nocode_wanted) {
gfunc_start(&gf, s->r); save_regs(0); /* save used temporary registers */
gfunc_start(&gf, s->r);
}
next(); next();
sa = s->next; /* first parameter */ sa = s->next; /* first parameter */
#ifdef INVERT_FUNC_PARAMS #ifdef INVERT_FUNC_PARAMS
@ -5693,7 +5670,10 @@ void unary(void)
problems */ problems */
vset(VT_INT, VT_LOCAL, loc); vset(VT_INT, VT_LOCAL, loc);
ret.c = vtop->c; ret.c = vtop->c;
gfunc_param(&gf); if (!nocode_wanted)
gfunc_param(&gf);
else
vtop--;
} else { } else {
ret.t = s->t; ret.t = s->t;
ret.r2 = VT_CONST; ret.r2 = VT_CONST;
@ -5723,7 +5703,10 @@ void unary(void)
if (sa) if (sa)
error("too few arguments to function"); error("too few arguments to function");
skip(')'); skip(')');
gfunc_call(&gf); if (!nocode_wanted)
gfunc_call(&gf);
else
vtop--;
/* return value */ /* return value */
vsetc(ret.t, ret.r, &ret.c); vsetc(ret.t, ret.r, &ret.c);
vtop->r2 = ret.r2; vtop->r2 = ret.r2;
@ -5733,7 +5716,7 @@ void unary(void)
} }
} }
void uneq(void) static void uneq(void)
{ {
int t; int t;
@ -5756,7 +5739,7 @@ void uneq(void)
} }
} }
void sum(int l) static void sum(int l)
{ {
int t; int t;
@ -5784,7 +5767,7 @@ void sum(int l)
} }
/* only used if non constant */ /* only used if non constant */
void eand(void) static void eand(void)
{ {
int t; int t;
@ -5804,7 +5787,7 @@ void eand(void)
} }
} }
void eor(void) static void eor(void)
{ {
int t; int t;
@ -5825,7 +5808,7 @@ void eor(void)
} }
/* XXX: better constant handling */ /* XXX: better constant handling */
void expr_eq(void) static void expr_eq(void)
{ {
int tt, u, r1, r2, rc, t1, t2, t, bt1, bt2; int tt, u, r1, r2, rc, t1, t2, t, bt1, bt2;
SValue sv; SValue sv;
@ -5925,7 +5908,7 @@ void expr_eq(void)
} }
} }
void gexpr(void) static void gexpr(void)
{ {
while (1) { while (1) {
expr_eq(); expr_eq();
@ -5936,6 +5919,35 @@ void gexpr(void)
} }
} }
/* parse an expression and return its type without any side effect. */
static int expr_type(void)
{
int a, t;
a = nocode_wanted;
nocode_wanted = 1;
gexpr();
t = vtop->t;
vpop();
nocode_wanted = a;
return t;
}
/* parse a unary expression and return its type without any side
effect. */
static int unary_type(void)
{
int a, t;
a = nocode_wanted;
nocode_wanted = 1;
unary();
t = vtop->t;
vpop();
nocode_wanted = a;
return t;
}
/* parse a constant expression and return value in vtop. */ /* parse a constant expression and return value in vtop. */
static void expr_const1(void) static void expr_const1(void)
{ {
@ -5960,7 +5972,7 @@ static int expr_const(void)
/* return the label token if current token is a label, otherwise /* return the label token if current token is a label, otherwise
return zero */ return zero */
int is_label(void) static int is_label(void)
{ {
int t; int t;
CValue c; CValue c;
@ -5985,7 +5997,7 @@ int is_label(void)
} }
} }
void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_reg) static void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_reg)
{ {
int a, b, c, d; int a, b, c, d;
Sym *s; Sym *s;
@ -6819,8 +6831,52 @@ void analyse_function(void)
} }
#endif #endif
/* parse an old style function declaration list */
/* XXX: check multiple parameter */
static void func_decl_list(Sym *func_sym)
{
AttributeDef ad;
int b, v, t;
Sym *s;
/* parse each declaration */
while (tok != '{' && tok != ';' && tok != TOK_EOF) {
if (!parse_btype(&b, &ad))
expect("declaration list");
if (((b & VT_BTYPE) == VT_ENUM ||
(b & VT_BTYPE) == VT_STRUCT) &&
tok == ';') {
/* we accept no variable after */
} else {
for(;;) {
t = type_decl(&ad, &v, b, TYPE_DIRECT);
/* find parameter in function parameter list */
s = func_sym->next;
while (s != NULL) {
if ((s->v & ~SYM_FIELD) == v)
goto found;
s = s->next;
}
error("declaration for parameter '%s' but no such parameter",
get_tok_str(v, NULL));
found:
/* check that no storage specifier except 'register' was given */
if (t & (VT_EXTERN | VT_STATIC | VT_TYPEDEF))
error("storage class specified for '%s'", get_tok_str(v, NULL));
/* we can add the type (NOTE: it could be local to the function) */
s->t = t;
/* accept other parameters */
if (tok == ',')
next();
else
break;
}
}
skip(';');
}
}
/* 'l' is VT_LOCAL or VT_CONST to define default storage type */ /* 'l' is VT_LOCAL or VT_CONST to define default storage type */
void decl(int l) static void decl(int l)
{ {
int t, b, v, has_init, r; int t, b, v, has_init, r;
Sym *sym; Sym *sym;
@ -6856,6 +6912,14 @@ void decl(int l)
printf("type = '%s'\n", buf); printf("type = '%s'\n", buf);
} }
#endif #endif
if ((t & VT_BTYPE) == VT_FUNC) {
/* if old style function prototype, we accept a
declaration list */
sym = sym_find(((unsigned)t >> VT_STRUCT_SHIFT));
if (sym->c == FUNC_OLD)
func_decl_list(sym);
}
if (tok == '{') { if (tok == '{') {
#ifdef CONFIG_REG_VARS #ifdef CONFIG_REG_VARS
TokenString func_str; TokenString func_str;
@ -7392,7 +7456,7 @@ int tcc_run(TCCState *s1, int argc, char **argv)
TCCState *tcc_new(void) TCCState *tcc_new(void)
{ {
char *p, *r; const char *p, *r;
TCCState *s; TCCState *s;
s = tcc_mallocz(sizeof(TCCState)); s = tcc_mallocz(sizeof(TCCState));