aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbellard <bellard>2002-11-02 20:45:52 +0000
committerbellard <bellard>2002-11-02 20:45:52 +0000
commit43f30315f95a09763bbca57df2ffda7049ea3ffc (patch)
treef3370586a0dadf8f735af1881c9f7ff1718d2235
parentc0180c4e5faaecf42335dab491ae5f635daaaa6d (diff)
downloadtinycc-43f30315f95a09763bbca57df2ffda7049ea3ffc.tar.gz
tinycc-43f30315f95a09763bbca57df2ffda7049ea3ffc.tar.bz2
added alignof and typeof - better sizeof support - fixed get_tok_str() for TOK_PPNUM
-rw-r--r--tcc.c390
1 files changed, 227 insertions, 163 deletions
diff --git a/tcc.c b/tcc.c
index 3009e9a..b690d23 100644
--- a/tcc.c
+++ b/tcc.c
@@ -270,6 +270,7 @@ int rsym, anon_sym,
prog, ind, loc;
/* expression generation modifiers */
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
globally (used during initializers parsing */
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
enum {
- TOK_INT = TOK_IDENT,
- 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,
-
+ TOK_LAST = TOK_IDENT - 1,
#define DEF(id, str) id,
#include "tcctok.h"
#undef DEF
};
-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 */
+static const char *tcc_keywords =
#define DEF(id, str) str "\0"
#include "tcctok.h"
#undef DEF
;
+#define TOK_UIDENT TOK_DEFINE
+
#ifdef WIN32
#define snprintf _snprintf
#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 *pstrcat(char *buf, int buf_size, const char *s);
-void sum(int l);
-void next(void);
-void next_nomacro(void);
+static void sum(int l);
+static void next(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);
-void expr_eq(void);
-void gexpr(void);
-void decl(int l);
+static void expr_eq(void);
+static void gexpr(void);
+static void decl(int l);
static void decl_initializer(int t, Section *sec, unsigned long c,
int first, int size_only);
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) {
case TOK_CINT:
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);
break;
case TOK_CLLONG:
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);
break;
case TOK_CCHAR:
@@ -1321,6 +1262,7 @@ char *get_tok_str(int v, CValue *cv)
len = cstr->size - 1;
for(i=0;i<len;i++)
add_char(&cstr_buf, ((unsigned char *)cstr->data)[i]);
+ cstr_ccat(&cstr_buf, '\0');
break;
case TOK_STR:
case TOK_LSTR:
@@ -2754,7 +2696,7 @@ static inline void next_nomacro1(void)
/* return next token without macro substitution. Can read input from
macro_ptr buffer */
-void next_nomacro()
+static void next_nomacro(void)
{
if (macro_ptr) {
redo:
@@ -2772,7 +2714,7 @@ void next_nomacro()
}
/* 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;
Sym *s;
@@ -2894,7 +2836,7 @@ static int *macro_twosharps(void)
p2 = get_tok_str(t, &cval);
cstr_cat(&cstr, p2);
cstr_ccat(&cstr, '\0');
-
+
if ((tok >= TOK_IDENT || tok == TOK_PPNUM) &&
(t >= TOK_IDENT || t == TOK_PPNUM)) {
if (tok == TOK_PPNUM) {
@@ -3130,7 +3072,7 @@ static void macro_subst(TokenString *tok_str,
}
/* return next token with macro substitution */
-void next(void)
+static void next(void)
{
Sym *nested_list, *s;
TokenString str;
@@ -3670,7 +3612,7 @@ void vpop(void)
v = vtop->r & VT_VALMASK;
#ifdef TCC_TARGET_I386
/* for x86, we need to pop the FP stack */
- if (v == REG_ST0) {
+ if (v == REG_ST0 && !nocode_wanted) {
o(0xd9dd); /* fstp %st(1) */
} else
#endif
@@ -4045,8 +3987,12 @@ void gen_opic(int op)
vtop->c.i += fc;
} else {
general_case:
- /* call low level op generator */
- gen_opi(op);
+ if (!nocode_wanted) {
+ /* call low level op generator */
+ gen_opi(op);
+ } else {
+ vtop--;
+ }
}
}
}
@@ -4107,7 +4053,11 @@ void gen_opif(int op)
vtop--;
} else {
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);
sbt = vtop->t & (VT_BTYPE | VT_UNSIGNED);
- if (sbt != dbt) {
+ if (sbt != dbt && !nocode_wanted) {
sf = is_float(sbt);
df = is_float(dbt);
c = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST;
@@ -4749,25 +4699,30 @@ 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 */
- size = type_size(vtop->t, &align);
- vpushi(size);
- gfunc_param(&gf);
- /* source */
- vtop->t = VT_INT;
- gaddrof();
- gfunc_param(&gf);
- /* destination */
- vswap();
- vtop->t = VT_INT;
- gaddrof();
- gfunc_param(&gf);
-
- save_regs(0);
- vpush_global_sym(func_old_type, TOK_memcpy);
- gfunc_call(&gf);
+ if (!nocode_wanted) {
+ vdup();
+ gfunc_start(&gf, FUNC_CDECL);
+ /* type size */
+ size = type_size(vtop->t, &align);
+ vpushi(size);
+ gfunc_param(&gf);
+ /* source */
+ vtop->t = VT_INT;
+ gaddrof();
+ gfunc_param(&gf);
+ /* destination */
+ vswap();
+ vtop->t = VT_INT;
+ gaddrof();
+ gfunc_param(&gf);
+
+ save_regs(0);
+ vpush_global_sym(func_old_type, TOK_memcpy);
+ gfunc_call(&gf);
+ } else {
+ vswap();
+ vpop();
+ }
/* leave source on stack */
} else if (ft & VT_BITFIELD) {
/* bitfield store handling */
@@ -4801,33 +4756,35 @@ void vstore(void)
vswap();
}
#endif
- rc = RC_INT;
- if (is_float(ft))
- rc = RC_FLOAT;
- r = gv(rc); /* generate value */
- /* if lvalue was saved on stack, must read it */
- if ((vtop[-1].r & VT_VALMASK) == VT_LLOCAL) {
- SValue sv;
- t = get_reg(RC_INT);
- sv.t = VT_INT;
- sv.r = VT_LOCAL | VT_LVAL;
- sv.c.ul = vtop[-1].c.ul;
- load(t, &sv);
- vtop[-1].r = t | VT_LVAL;
- }
- store(r, vtop - 1);
- /* two word case handling : store second register at word + 4 */
- if ((ft & VT_BTYPE) == VT_LLONG) {
- vswap();
- /* convert to int to increment easily */
- vtop->t = VT_INT;
- gaddrof();
- vpushi(4);
- gen_op('+');
- vtop->r |= VT_LVAL;
- vswap();
- /* XXX: it works because r2 is spilled last ! */
- store(vtop->r2, vtop - 1);
+ if (!nocode_wanted) {
+ rc = RC_INT;
+ if (is_float(ft))
+ rc = RC_FLOAT;
+ r = gv(rc); /* generate value */
+ /* if lvalue was saved on stack, must read it */
+ if ((vtop[-1].r & VT_VALMASK) == VT_LLOCAL) {
+ SValue sv;
+ t = get_reg(RC_INT);
+ sv.t = VT_INT;
+ sv.r = VT_LOCAL | VT_LVAL;
+ sv.c.ul = vtop[-1].c.ul;
+ load(t, &sv);
+ vtop[-1].r = t | VT_LVAL;
+ }
+ store(r, vtop - 1);
+ /* two word case handling : store second register at word + 4 */
+ if ((ft & VT_BTYPE) == VT_LLONG) {
+ vswap();
+ /* convert to int to increment easily */
+ vtop->t = VT_INT;
+ gaddrof();
+ vpushi(4);
+ gen_op('+');
+ vtop->r |= VT_LVAL;
+ vswap();
+ /* XXX: it works because r2 is spilled last ! */
+ store(vtop->r2, vtop - 1);
+ }
}
vswap();
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__:
parse_attribute(ad);
break;
+ /* GNUC typeof */
+ case TOK_TYPEOF:
+ next();
+ u = parse_expr_type();
+ goto basic_type1;
default:
s = sym_find(tok);
if (!s || !(s->t & VT_TYPEDEF))
@@ -5367,7 +5329,7 @@ static void indir(void)
{
if ((vtop->t & VT_BTYPE) != VT_PTR)
expect("pointer");
- if (vtop->r & VT_LVAL)
+ if ((vtop->r & VT_LVAL) && !nocode_wanted)
gv(RC_INT);
vtop->t = pointed_type(vtop->t);
/* an array is never an lvalue */
@@ -5394,10 +5356,31 @@ void gfunc_param_typed(GFuncContext *gf, Sym *func, Sym *arg)
} else {
gen_assign_cast(arg->t);
}
- gfunc_param(gf);
+ if (!nocode_wanted) {
+ gfunc_param(gf);
+ } else {
+ vpop();
+ }
+}
+
+/* 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;
}
-void unary(void)
+static void unary(void)
{
int n, t, ft, align, size, r;
Sym *s;
@@ -5515,25 +5498,17 @@ void unary(void)
vpushi(0);
gen_op('+');
} else
- if (t == TOK_SIZEOF) {
+ if (t == TOK_SIZEOF || t == TOK_ALIGNOF) {
if (tok == '(') {
- next();
- 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(')');
+ ft = parse_expr_type();
} else {
- unary();
- t = vtop->t;
- vpop();
+ ft = unary_type();
}
- vpushi(type_size(t, &t));
+ size = type_size(ft, &align);
+ if (t == TOK_SIZEOF)
+ vpushi(size);
+ else
+ vpushi(align);
} else
if (t == TOK_INC || t == TOK_DEC) {
unary();
@@ -5627,8 +5602,10 @@ void unary(void)
}
/* get return type */
s = sym_find((unsigned)vtop->t >> VT_STRUCT_SHIFT);
- save_regs(0); /* save used temporary registers */
- gfunc_start(&gf, s->r);
+ if (!nocode_wanted) {
+ save_regs(0); /* save used temporary registers */
+ gfunc_start(&gf, s->r);
+ }
next();
sa = s->next; /* first parameter */
#ifdef INVERT_FUNC_PARAMS
@@ -5693,7 +5670,10 @@ void unary(void)
problems */
vset(VT_INT, VT_LOCAL, loc);
ret.c = vtop->c;
- gfunc_param(&gf);
+ if (!nocode_wanted)
+ gfunc_param(&gf);
+ else
+ vtop--;
} else {
ret.t = s->t;
ret.r2 = VT_CONST;
@@ -5723,7 +5703,10 @@ void unary(void)
if (sa)
error("too few arguments to function");
skip(')');
- gfunc_call(&gf);
+ if (!nocode_wanted)
+ gfunc_call(&gf);
+ else
+ vtop--;
/* return value */
vsetc(ret.t, ret.r, &ret.c);
vtop->r2 = ret.r2;
@@ -5733,7 +5716,7 @@ void unary(void)
}
}
-void uneq(void)
+static void uneq(void)
{
int t;
@@ -5756,7 +5739,7 @@ void uneq(void)
}
}
-void sum(int l)
+static void sum(int l)
{
int t;
@@ -5784,7 +5767,7 @@ void sum(int l)
}
/* only used if non constant */
-void eand(void)
+static void eand(void)
{
int t;
@@ -5804,7 +5787,7 @@ void eand(void)
}
}
-void eor(void)
+static void eor(void)
{
int t;
@@ -5825,7 +5808,7 @@ void eor(void)
}
/* XXX: better constant handling */
-void expr_eq(void)
+static void expr_eq(void)
{
int tt, u, r1, r2, rc, t1, t2, t, bt1, bt2;
SValue sv;
@@ -5925,7 +5908,7 @@ void expr_eq(void)
}
}
-void gexpr(void)
+static void gexpr(void)
{
while (1) {
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. */
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 zero */
-int is_label(void)
+static int is_label(void)
{
int t;
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;
Sym *s;
@@ -6819,8 +6831,52 @@ void analyse_function(void)
}
#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 */
-void decl(int l)
+static void decl(int l)
{
int t, b, v, has_init, r;
Sym *sym;
@@ -6856,6 +6912,14 @@ void decl(int l)
printf("type = '%s'\n", buf);
}
#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 == '{') {
#ifdef CONFIG_REG_VARS
TokenString func_str;
@@ -7392,7 +7456,7 @@ int tcc_run(TCCState *s1, int argc, char **argv)
TCCState *tcc_new(void)
{
- char *p, *r;
+ const char *p, *r;
TCCState *s;
s = tcc_mallocz(sizeof(TCCState));