diff --git a/i386-gen.c b/i386-gen.c index ef06fcb..40f1c2d 100644 --- a/i386-gen.c +++ b/i386-gen.c @@ -1,6 +1,22 @@ -/******************************************************/ -/* X86 code generator */ - +/* + * X86 code generator for TCC + * + * Copyright (c) 2001 Fabrice Bellard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ /* number of available registers */ #define NB_REGS 4 @@ -38,6 +54,13 @@ int reg_classes[NB_REGS] = { are directly pushed on stack. */ //#define FUNC_STRUCT_PARAM_AS_PTR +/* pointer size, in bytes */ +#define PTR_SIZE 4 + +/* long double size and alignment, in bytes */ +#define LDOUBLE_SIZE 12 +#define LDOUBLE_ALIGN 4 + /* function call context */ typedef struct GFuncContext { int args_size; @@ -161,6 +184,9 @@ void load(int r, int ft, int fc) } else if ((ft & VT_BTYPE) == VT_DOUBLE) { o(0xdd); /* fldl */ r = 0; + } else if ((ft & VT_BTYPE) == VT_LDOUBLE) { + o(0xdb); /* fldt */ + r = 5; } else if ((ft & VT_TYPE) == VT_BYTE) o(0xbe0f); /* movsbl */ else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) @@ -214,12 +240,16 @@ void store(r, ft, fc) fr = ft & VT_VALMASK; bt = ft & VT_BTYPE; /* XXX: incorrect if reg to reg */ + /* XXX: should not flush float stack */ if (bt == VT_FLOAT) { o(0xd9); /* fstps */ r = 3; } else if (bt == VT_DOUBLE) { o(0xdd); /* fstpl */ r = 3; + } else if (bt == VT_LDOUBLE) { + o(0xdb); /* fstpt */ + r = 7; } else { if (bt == VT_SHORT) o(0x66); @@ -269,17 +299,24 @@ void gfunc_param(GFuncContext *c) vc = fc; vstore(); c->args_size += size; - } else if ((vt & VT_BTYPE) == VT_DOUBLE || + } else if ((vt & VT_BTYPE) == VT_LDOUBLE || + (vt & VT_BTYPE) == VT_DOUBLE || (vt & VT_BTYPE) == VT_FLOAT) { gv(); /* only one float register */ if ((vt & VT_BTYPE) == VT_FLOAT) size = 4; - else + else if ((vt & VT_BTYPE) == VT_DOUBLE) size = 8; + else + size = 12; oad(0xec81, size); /* sub $xxx, %esp */ - o(0x245cd9 + size - 4); /* fstp[s|l] 0(%esp) */ + if (size == 12) + o(0x7cdb); + else + o(0x5cd9 + size - 4); /* fstp[s|l] 0(%esp) */ + g(0x24); g(0x00); - c->args_size += 8; + c->args_size += size; } else { /* simple type (currently always same size) */ /* XXX: implicit cast ? */ @@ -345,6 +382,7 @@ int gtst(int inv, int t) if ((vc != 0) != inv) t = gjmp(t); } else { + /* XXX: floats */ v = gv(); o(0x85); o(0xc0 + v * 9); @@ -499,7 +537,7 @@ void gen_opf(int op) o(0x05 + a); gen_addr32(fc, ft); } else if (r == VT_LOCAL) { - oad(0x85 + a, fc); + oad(0x85 + a, fc); } else { g(0x00 + a + r); } @@ -512,14 +550,14 @@ void gen_opf(int op) void gen_cvtf(int t) { if ((vt & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED)) { - /* unsigned int to float/double */ + /* unsigned int to float/double/long double */ o(0x6a); /* push $0 */ g(0x00); o(0x50 + (vt & VT_VALMASK)); /* push r */ o(0x242cdf); /* fildll (%esp) */ o(0x08c483); /* add $8, %esp */ } else { - /* int to float/double */ + /* int to float/double/long double */ o(0x50 + (vt & VT_VALMASK)); /* push r */ o(0x2404db); /* fildl (%esp) */ o(0x04c483); /* add $4, %esp */ diff --git a/tcc.c b/tcc.c index 59700f2..15da0a1 100644 --- a/tcc.c +++ b/tcc.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #ifndef CONFIG_TCC_STATIC #include #endif @@ -51,6 +53,17 @@ typedef struct TokenSym { char str[1]; } TokenSym; +/* constant value */ +typedef union CValue { + long double ld; + double d; + float f; + int i; + unsigned int ui; + struct TokenSym *ts; + int tab[1]; +} CValue; + /* symbol management */ typedef struct Sym { int v; /* symbol token */ @@ -101,7 +114,8 @@ typedef struct { /* parser */ FILE *file; -int ch, ch1, tok, tokc, tok1, tok1c; +int ch, ch1, tok, tok1; +CValue tokc, tok1c; /* loc : local variable index glo : global variable index @@ -135,6 +149,9 @@ int nb_include_paths; /* use GNU C extensions */ int gnu_ext = 1; +/* use Tiny C extensions */ +int tcc_ext = 1; + /* The current value can be: */ #define VT_VALMASK 0x000f #define VT_CONST 0x000a /* constant in vc @@ -167,7 +184,12 @@ int gnu_ext = 1; #define VT_STRUCT (7 << VT_BTYPE_SHIFT) /* struct/union definition */ #define VT_FLOAT (8 << VT_BTYPE_SHIFT) /* IEEE float */ #define VT_DOUBLE (9 << VT_BTYPE_SHIFT) /* IEEE double */ -#define VT_BOOL (10 << VT_BTYPE_SHIFT) /* ISOC99 boolean type */ +#define VT_LDOUBLE (10 << VT_BTYPE_SHIFT) /* IEEE long double */ +#define VT_BOOL (11 << VT_BTYPE_SHIFT) /* ISOC99 boolean type */ +#define VT_LLONG (12 << VT_BTYPE_SHIFT) /* 64 bit integer */ +#define VT_LONG (13 << VT_BTYPE_SHIFT) /* long integer (NEVER + USED as type, only + during parsing) */ #define VT_BTYPE (0xf << VT_BTYPE_SHIFT) /* mask for basic type */ #define VT_UNSIGNED (0x10 << VT_BTYPE_SHIFT) /* unsigned type */ #define VT_ARRAY (0x20 << VT_BTYPE_SHIFT) /* array type (also has VT_PTR) */ @@ -207,8 +229,11 @@ int gnu_ext = 1; #define TOK_TWOSHARPS 0xb6 /* ## preprocessing token */ #define TOK_LCHAR 0xb7 #define TOK_LSTR 0xb8 - -#define TOK_SHL 0x01 /* shift left */ +#define TOK_CFLOAT 0xb9 /* float constant */ +#define TOK_CDOUBLE 0xc0 /* double constant */ +#define TOK_CLDOUBLE 0xc1 /* long double constant */ + + #define TOK_SHL 0x01 /* shift left */ #define TOK_SAR 0x02 /* signed shift right */ /* assignement operators : normal operator or 0x80 */ @@ -291,11 +316,11 @@ enum { TOK_MAIN, }; -void sum(); +void sum(int l); void next(void); -void next_nomacro(); -int expr_const(); -void expr_eq(); +void next_nomacro(void); +int expr_const(void); +void expr_eq(void); void expr(void); void decl(int l); void decl_initializer(int t, int c, int first, int size_only); @@ -319,6 +344,10 @@ int pointed_type(int t); int pointed_size(int t); int ist(void); int type_decl(int *v, int t, int td); +void error(const char *fmt, ...); +void vset(int t, int v); + +#include "i386-gen.c" #ifdef CONFIG_TCC_STATIC @@ -367,18 +396,26 @@ void *dlsym(void *handle, char *symbol) #endif -inline int isid(int c) +static inline int isid(int c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'; } -inline int isnum(int c) +static inline int isnum(int c) { return c >= '0' & c <= '9'; } +static inline int toup(int c) +{ + if (ch >= 'a' && ch <= 'z') + return ch - 'a' + 'A'; + else + return ch; +} + void printline(void) { IncludeFile *f; @@ -492,7 +529,7 @@ void add_char(char **pp, int c) } /* XXX: buffer overflow */ -char *get_tok_str(int v, int c) +char *get_tok_str(int v, CValue *cv) { static char buf[STRING_MAX_SIZE + 1]; TokenSym *ts; @@ -500,17 +537,17 @@ char *get_tok_str(int v, int c) int i; if (v == TOK_NUM) { - sprintf(buf, "%d", c); + sprintf(buf, "%u", cv->ui); return buf; } else if (v == TOK_CCHAR || v == TOK_LCHAR) { p = buf; *p++ = '\''; - add_char(&p, c); + add_char(&p, cv->i); *p++ = '\''; *p = '\0'; return buf; } else if (v == TOK_STR || v == TOK_LSTR) { - ts = (TokenSym *)c; + ts = cv->ts; p = buf; *p++ = '\"'; for(i=0;ilen;i++) @@ -756,11 +793,26 @@ void preprocess_skip() } } -inline int is_long_tok(int t) +/* return the number of additionnal 'ints' necessary to store the + token */ +static inline int tok_ext_size(int t) { - return (t == TOK_NUM || - t == TOK_CCHAR || t == TOK_LCHAR || - t == TOK_STR || t == TOK_LSTR); + switch(t) { + /* 4 bytes */ + case TOK_NUM: + case TOK_CCHAR: + case TOK_LCHAR: + case TOK_STR: + case TOK_LSTR: + case TOK_CFLOAT: + return 1; + case TOK_CDOUBLE: + return 2; + case TOK_CLDOUBLE: + return LDOUBLE_SIZE / 4; + default: + return 0; + } } void tok_add(int **tok_str, int *tok_len, int t) @@ -778,15 +830,32 @@ void tok_add(int **tok_str, int *tok_len, int t) *tok_len = len; } -void tok_add2(int **tok_str, int *tok_len, int t, int c) +void tok_add2(int **tok_str, int *tok_len, int t, CValue *cv) { + int n, i; + tok_add(tok_str, tok_len, t); - if (is_long_tok(t)) - tok_add(tok_str, tok_len, c); + n = tok_ext_size(t); + for(i=0;itab[i]); +} + +/* get a token from an integer array and increment pointer accordingly */ +int tok_get(int **tok_str, CValue *cv) +{ + int *p, t, n, i; + + p = *tok_str; + t = *p++; + n = tok_ext_size(t); + for(i=0;itab[i] = *p++; + *tok_str = p; + return t; } /* eval an expression for #if/#elif */ -int expr_preprocess() +int expr_preprocess(void) { int *str, len, c, t; @@ -806,13 +875,13 @@ int expr_preprocess() if (t == '(') next_nomacro(); tok = TOK_NUM; - tokc = c; + tokc.i = c; } else if (tok >= TOK_IDENT) { /* if undefined macro */ tok = TOK_NUM; - tokc = 0; + tokc.i = 0; } - tok_add2(&str, &len, tok, tokc); + tok_add2(&str, &len, tok, &tokc); } tok_add(&str, &len, -1); /* simulate end of file */ tok_add(&str, &len, 0); @@ -828,16 +897,14 @@ int expr_preprocess() #ifdef DEBUG void tok_print(int *str) { - int t, c; + int t; + CValue cval; while (1) { - t = *str++; + t = tok_get(&str, &cval); if (!t) break; - c = 0; - if (is_long_tok(t)) - c = *str++; - printf(" %s", get_tok_str(t, c)); + printf(" %s", get_tok_str(t, &cval)); } printf("\n"); } @@ -848,11 +915,13 @@ void define_symbol(char *sym) { TokenSym *ts; int *str, len; + CValue cval; ts = tok_alloc(sym, 0); str = NULL; len = 0; - tok_add2(&str, &len, TOK_NUM, 1); + cval.i = 1; + tok_add2(&str, &len, TOK_NUM, &cval); tok_add(&str, &len, 0); sym_push1(&define_stack, ts->tok, MACRO_OBJ, (int)str); } @@ -899,7 +968,7 @@ void preprocess() if (ch == '\n' || ch == -1) break; next_nomacro(); - tok_add2(&str, &len, tok, tokc); + tok_add2(&str, &len, tok, &tokc); } tok_add(&str, &len, 0); #ifdef PP_DEBUG @@ -935,7 +1004,7 @@ void preprocess() if (tok != TOK_STR) error("#include syntax error"); /* XXX: buffer overflow */ - strcpy(buf, get_tok_str(tok, tokc)); + strcpy(buf, get_tok_str(tok, &tokc)); c = '\"'; } if (include_stack_ptr >= include_stack + INCLUDE_STACK_SIZE) @@ -1016,14 +1085,14 @@ void preprocess() next(); if (tok != TOK_NUM) error("#line"); - line_num = tokc; + line_num = tokc.i; skip_spaces(); if (ch != '\n') { next(); if (tok != TOK_STR) error("#line"); /* XXX: potential memory leak */ - filename = strdup(get_tok_str(tok, tokc)); + filename = strdup(get_tok_str(tok, &tokc)); } } else if (tok == TOK_ERROR) { error("#error"); @@ -1096,7 +1165,7 @@ int getq() c = '\v'; else if (ch == 'e' && gnu_ext) c = 27; - else if (ch == '\'' || ch == '\"' || ch == '\\') + else if (ch == '\'' || ch == '\"' || ch == '\\' || ch == '?') c = ch; else error("invalid escaped char"); @@ -1106,8 +1175,272 @@ int getq() return c; } +/* we use 64 bit numbers */ +#define BN_SIZE 2 + +/* bn = (bn << shift) | or_val */ +void bn_lshift(unsigned int *bn, int shift, int or_val) +{ + int i; + unsigned int v; + for(i=0;i> (32 - shift); + } +} + +void bn_zero(unsigned int *bn) +{ + int i; + for(i=0;i= '0' && ch <= '9') { + goto float_frac_parse; + } else if (ch == '.') { + cinp(); + if (ch != '.') + expect("'.'"); + cinp(); + tok = TOK_DOTS; + } else { + /* dots */ + tok = t; + } + return; + } else if (t == '0') { + if (ch == 'x' || ch == 'X') { + q--; + cinp(); + b = 16; + } else if (tcc_ext && (ch == 'b' || ch == 'B')) { + q--; + cinp(); + b = 2; + } + } + /* parse all digits. cannot check octal numbers at this stage + because of floating point constants */ + while (1) { + if (ch >= 'a' & ch <= 'f') + t = ch - 'a' + 10; + else if (ch >= 'A' & ch <= 'F') + t = ch - 'A' + 10; + else if (isnum(ch)) + t = ch - '0'; + else + break; + if (t >= b) + break; + if (q >= token_buf + STRING_MAX_SIZE) { + num_too_long: + error("number too long"); + } + *q++ = ch; + cinp(); + } + if (ch == '.' || + ((ch == 'e' || ch == 'E') && b == 10) || + ((ch == 'p' || ch == 'P') && (b == 16 || b == 2))) { + if (b != 10) { + /* NOTE: strtox should support that for hexa numbers, but + non ISOC99 libcs do not support it, so we prefer to do + it by hand */ + /* hexadecimal or binary floats */ + /* XXX: handle overflows */ + *q = '\0'; + if (b == 16) + shift = 4; + else + shift = 2; + bn_zero(bn); + q = token_buf; + while (1) { + t = *q++; + if (t == '\0') { + break; + } else if (t >= 'a') { + t = t - 'a' + 10; + } else if (t >= 'A') { + t = t - 'A' + 10; + } else { + t = t - '0'; + } + bn_lshift(bn, shift, t); + } + frac_bits = 0; + if (ch == '.') { + cinp(); + while (1) { + t = ch; + if (t >= 'a' && t <= 'f') { + t = t - 'a' + 10; + } else if (t >= 'A' && t <= 'F') { + t = t - 'A' + 10; + } else if (t >= '0' && t <= '9') { + t = t - '0'; + } else { + break; + } + if (t >= b) + error("invalid digit"); + bn_lshift(bn, shift, t); + frac_bits += shift; + cinp(); + } + } + if (ch != 'p' && ch != 'P') + error("exponent expected"); + cinp(); + s = 1; + exp_val = 0; + if (ch == '+') { + cinp(); + } else if (ch == '-') { + s = -1; + cinp(); + } + if (ch < '0' || ch > '9') + error("exponent digits expected"); + while (ch >= '0' && ch <= '9') { + exp_val = exp_val * 10 + ch - '0'; + cinp(); + } + exp_val = exp_val * s; + printf("num=%08x %08x %d %d\n", bn[1], bn[0], frac_bits, exp_val); + + /* now we can generate the number */ + /* XXX: should patch directly float number */ + d = (double)bn[1] * 4294967296.0 + (double)bn[0]; + d = ldexp(d, exp_val - frac_bits); + t = toup(ch); + if (t == 'F') { + cinp(); + tok = TOK_CFLOAT; + /* float : should handle overflow */ + cval.f = (float)d; + } else if (t == 'L') { + cinp(); + tok = TOK_CLDOUBLE; + /* XXX: not large enough */ + cval.ld = (long double)d; + } else { + tok = TOK_CDOUBLE; + cval.d = d; + } + } else { + /* decimal floats */ + if (ch == '.') { + if (q >= token_buf + STRING_MAX_SIZE) + goto num_too_long; + *q++ = ch; + cinp(); + float_frac_parse: + while (ch >= '0' && ch <= '9') { + if (q >= token_buf + STRING_MAX_SIZE) + goto num_too_long; + *q++ = ch; + cinp(); + } + } + if (ch == 'e' || ch == 'E') { + if (q >= token_buf + STRING_MAX_SIZE) + goto num_too_long; + *q++ = ch; + cinp(); + if (ch == '-' || ch == '+') { + if (q >= token_buf + STRING_MAX_SIZE) + goto num_too_long; + *q++ = ch; + cinp(); + } + if (ch < '0' || ch > '9') + error("exponent digits expected"); + while (ch >= '0' && ch <= '9') { + if (q >= token_buf + STRING_MAX_SIZE) + goto num_too_long; + *q++ = ch; + cinp(); + } + } + *q = '\0'; + t = toup(ch); + errno = 0; + if (t == 'F') { + cinp(); + tok = TOK_CFLOAT; + /* XXX: this is an ISOC99 function */ + cval.f = strtof(token_buf, NULL); + } else if (t == 'L') { + cinp(); + tok = TOK_CLDOUBLE; + /* XXX: this is an ISOC99 function */ + cval.ld = strtold(token_buf, NULL); + } else { + tok = TOK_CDOUBLE; + cval.d = strtod(token_buf, NULL); + } + } + } else { + /* integer number */ + *q = '\0'; + q = token_buf; + if (b == 10 && *q == '0') { + b = 8; + q++; + } + n = 0; + while(1) { + t = *q++; + /* no need for checks except for base 10 / 8 errors */ + if (t == '\0') { + break; + } else if (t >= 'a') { + t = t - 'a' + 10; + } else if (t >= 'A') { + t = t - 'A' + 10; + } else { + t = t - '0'; + if (t >= b) + error("invalid digit"); + } + n1 = n; + n = n * b + t; + /* detect overflow */ + if (n < n1) + error("integer constant overflow"); + } + tokc.ui = n; + tok = TOK_NUM; + /* XXX: add unsigned constant support (ANSI) */ + while (ch == 'L' || ch == 'l' || ch == 'U' || ch == 'u') + cinp(); + } +} + + /* return next token without macro substitution */ -void next_nomacro1() +void next_nomacro1(void) { int b; char *q; @@ -1152,30 +1485,13 @@ void next_nomacro1() *q = '\0'; ts = tok_alloc(token_buf, q - token_buf); tok = ts->tok; - } else if (isnum(ch)) { - /* number */ - b = 10; - if (ch == '0') { - cinp(); - b = 8; - if (ch == 'x' || ch == 'X') { - cinp(); - b = 16; - } else if (ch == 'b' || ch == 'B') { - cinp(); - b = 2; - } - } - tokc = getn(b); - /* XXX: add unsigned constant support (ANSI) */ - while (ch == 'L' || ch == 'l' || ch == 'U' || ch == 'u') - cinp(); - tok = TOK_NUM; + } else if (isnum(ch) || ch == '.') { + parse_number(); } else if (ch == '\'') { tok = TOK_CCHAR; char_const: minp(); - tokc = getq(); + tokc.i = getq(); if (ch != '\'') expect("\'"); minp(); @@ -1193,7 +1509,7 @@ void next_nomacro1() *q++ = b; } *q = '\0'; - tokc = (int)tok_alloc(token_buf, q - token_buf); + tokc.ts = tok_alloc(token_buf, q - token_buf); minp(); } else { q = "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<<\1>>\2+=\253-=\255*=\252/=\257%=\245&=\246^=\336|=\374->\247..\250##\266"; @@ -1201,7 +1517,7 @@ void next_nomacro1() tok = ch; cinp(); while (*q) { - if (*q == tok & q[1] == ch) { + if (*q == tok && q[1] == ch) { cinp(); tok = q[2] & 0xff; /* three chars tests */ @@ -1233,11 +1549,8 @@ void next_nomacro() { if (macro_ptr) { tok = *macro_ptr; - if (tok) { - macro_ptr++; - if (is_long_tok(tok)) - tokc = *macro_ptr++; - } + if (tok) + tok = tok_get(¯o_ptr, &tokc); } else { next_nomacro1(); } @@ -1246,20 +1559,21 @@ void next_nomacro() /* substitute args in macro_str and return allocated string */ int *macro_arg_subst(Sym **nested_list, int *macro_str, Sym *args) { - int *st, last_tok, t, c, notfirst, *str, len; + int *st, last_tok, t, notfirst, *str, len; Sym *s; TokenSym *ts; + CValue cval; str = NULL; len = 0; last_tok = 0; while(1) { - t = *macro_str++; + t = tok_get(¯o_str, &cval); if (!t) break; if (t == '#') { /* stringize */ - t = *macro_str++; + t = tok_get(¯o_str, &cval); if (!t) break; s = sym_find2(args, t); @@ -1271,11 +1585,8 @@ int *macro_arg_subst(Sym **nested_list, int *macro_str, Sym *args) while (*st) { if (notfirst) strcat(token_buf, " "); - t = *st++; - c = 0; - if (is_long_tok(t)) - c = *st++; - strcat(token_buf, get_tok_str(t, c)); + t = tok_get(&st, &cval); + strcat(token_buf, get_tok_str(t, &cval)); notfirst = 1; } #ifdef PP_DEBUG @@ -1283,13 +1594,12 @@ int *macro_arg_subst(Sym **nested_list, int *macro_str, Sym *args) #endif /* add string */ ts = tok_alloc(token_buf, 0); - tok_add2(&str, &len, TOK_STR, (int)ts); + cval.ts = ts; + tok_add2(&str, &len, TOK_STR, &cval); } else { - tok_add(&str, &len, t); + tok_add2(&str, &len, t, &cval); } - } else if (is_long_tok(t)) { - tok_add2(&str, &len, t, *macro_str++); - } else { + } else if (t >= TOK_IDENT) { s = sym_find2(args, t); if (s) { st = (int *)s->c; @@ -1303,6 +1613,8 @@ int *macro_arg_subst(Sym **nested_list, int *macro_str, Sym *args) } else { tok_add(&str, &len, t); } + } else { + tok_add2(&str, &len, t, &cval); } last_tok = t; } @@ -1315,8 +1627,9 @@ int *macro_twosharps(int *macro_str) { TokenSym *ts; int *macro_str1, macro_str1_len, *macro_ptr1; - int t, c; + int t; char *p; + CValue cval; macro_str1 = NULL; macro_str1_len = 0; @@ -1330,28 +1643,25 @@ int *macro_twosharps(int *macro_str) macro_ptr1 = macro_ptr; t = *macro_ptr; if (t) { - macro_ptr++; - c = 0; - if (is_long_tok(t)) - c = *macro_ptr++; + t = tok_get(¯o_ptr, &cval); /* XXX: we handle only most common cases: ident + ident or ident + number */ if (tok >= TOK_IDENT && (t >= TOK_IDENT || t == TOK_NUM)) { /* XXX: buffer overflow */ - p = get_tok_str(tok, tokc); + p = get_tok_str(tok, &tokc); strcpy(token_buf, p); - p = get_tok_str(t, c); + p = get_tok_str(t, &cval); strcat(token_buf, p); ts = tok_alloc(token_buf, 0); - tok_add2(¯o_str1, ¯o_str1_len, ts->tok, 0); + tok_add(¯o_str1, ¯o_str1_len, ts->tok); } else { /* cannot merge tokens: skip '##' */ macro_ptr = macro_ptr1; } } } else { - tok_add2(¯o_str1, ¯o_str1_len, tok, tokc); + tok_add2(¯o_str1, ¯o_str1_len, tok, &tokc); } } tok_add(¯o_str1, ¯o_str1_len, 0); @@ -1370,6 +1680,7 @@ void macro_subst(int **tok_str, int *tok_len, Sym *s, *args, *sa, *sa1; int *str, parlevel, len, *mstr, t, *saved_macro_ptr; int mstr_allocated, *macro_str1; + CValue cval; saved_macro_ptr = macro_ptr; macro_ptr = macro_str; @@ -1386,16 +1697,17 @@ void macro_subst(int **tok_str, int *tok_len, break; /* special macros */ if (tok == TOK___LINE__) { - tok_add2(tok_str, tok_len, TOK_NUM, line_num); + cval.i = line_num; + tok_add2(tok_str, tok_len, TOK_NUM, &cval); } else if (tok == TOK___FILE__) { - tok_add2(tok_str, tok_len, TOK_STR, - (int)tok_alloc(filename, 0)); + cval.ts = tok_alloc(filename, 0); + tok_add2(tok_str, tok_len, TOK_STR, &cval); } else if (tok == TOK___DATE__) { - tok_add2(tok_str, tok_len, TOK_STR, - (int)tok_alloc("Jan 1 1970", 0)); + cval.ts = tok_alloc("Jan 1 1970", 0); + tok_add2(tok_str, tok_len, TOK_STR, &cval); } else if (tok == TOK___TIME__) { - tok_add2(tok_str, tok_len, TOK_STR, - (int)tok_alloc("00:00:00", 0)); + cval.ts = tok_alloc("00:00:00", 0); + tok_add2(tok_str, tok_len, TOK_STR, &cval); } else if ((s = sym_find1(&define_stack, tok)) != NULL) { /* if symbol is a macro, prepare substitution */ /* if nested substitution, do nothing */ @@ -1434,7 +1746,7 @@ void macro_subst(int **tok_str, int *tok_len, parlevel++; else if (tok == ')') parlevel--; - tok_add2(&str, &len, tok, tokc); + tok_add2(&str, &len, tok, &tokc); next_nomacro(); } tok_add(&str, &len, 0); @@ -1471,7 +1783,7 @@ void macro_subst(int **tok_str, int *tok_len, /* no need to add if reading input stream */ if (!macro_str) return; - tok_add2(tok_str, tok_len, tok, tokc); + tok_add2(tok_str, tok_len, tok, &tokc); } /* only replace one macro while parsing input stream */ if (!macro_str) @@ -1538,8 +1850,6 @@ void vset(int t, int v) vc = v; } -#include "i386-gen.c" - int save_reg_forced(int r) { int i, l, *p, t; @@ -1805,6 +2115,14 @@ int pointed_size(int t) return type_size(pointed_type(t), &t); } +/* true if float/double/long double type */ +static inline int is_float(int t) +{ + int bt; + bt = t & VT_BTYPE; + return bt == VT_LDOUBLE || bt == VT_DOUBLE || bt == VT_FLOAT; +} + /* generic gen_op: handles types problems */ void gen_op(int op) { @@ -1816,13 +2134,14 @@ void gen_op(int op) bt1 = t1 & VT_BTYPE; bt2 = t2 & VT_BTYPE; - if (bt1 == VT_FLOAT || bt1 == VT_DOUBLE || - bt2 == VT_FLOAT || bt2 == VT_DOUBLE) { + if (is_float(bt1) || is_float(bt2)) { /* compute bigger type and do implicit casts */ - if (bt1 != VT_DOUBLE && bt2 != VT_DOUBLE) { - t = VT_FLOAT; - } else { + if (bt1 == VT_LDOUBLE || bt2 == VT_LDOUBLE) { + t = VT_LDOUBLE; + } else if (bt1 == VT_DOUBLE || bt2 == VT_DOUBLE) { t = VT_DOUBLE; + } else { + t = VT_FLOAT; } if (op != '+' && op != '-' && op != '*' && op != '/' && op < TOK_EQ || op > TOK_GT) @@ -1902,44 +2221,42 @@ void gen_op(int op) /* cast (vt, vc) to 't' type */ void gen_cast(int t) { - int r, bits, bt; + int r, bits, bt, vbt; r = vt & VT_VALMASK; if (!(t & VT_LVAL)) { /* if not lvalue, then we convert now */ bt = t & VT_BTYPE; - if (bt == VT_FLOAT || bt == VT_DOUBLE) { - if ((vt & VT_BTYPE) != bt) { + vbt = vt & VT_BTYPE; + if (bt != vbt) { + if (is_float(bt)) { /* need to generate value and do explicit cast */ gv(); gen_cvtf(bt); + } else if (bt == VT_BOOL) { + vpush(); + vset(VT_CONST, 0); + gen_op(TOK_NE); + } else if (bt == VT_BYTE || bt == VT_SHORT) { + if (bt == VT_BYTE) + bits = 8; + else + bits = 16; + vpush(); + if (t & VT_UNSIGNED) { + vset(VT_CONST, (1 << bits) - 1); + gen_op('&'); + } else { + bits = 32 - bits; + vset(VT_CONST, bits); + gen_op(TOK_SHL); + vpush(); + vset(VT_CONST, bits); + gen_op(TOK_SAR); + } } - goto the_end; - } else if (bt == VT_BOOL) { - vpush(); - vset(VT_CONST, 0); - gen_op(TOK_NE); - goto the_end; - } else if (bt == VT_BYTE) - bits = 8; - else if (bt == VT_SHORT) - bits = 16; - else - goto the_end; - vpush(); - if (t & VT_UNSIGNED) { - vset(VT_CONST, (1 << bits) - 1); - gen_op('&'); - } else { - bits = 32 - bits; - vset(VT_CONST, bits); - gen_op(TOK_SHL); - vpush(); - vset(VT_CONST, bits); - gen_op(TOK_SAR); } } - the_end: vt = (vt & ~VT_TYPE) | t; } @@ -1960,10 +2277,13 @@ int type_size(int t, int *a) s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT)); return type_size(s->t, a) * s->c; } else { - *a = 4; - return 4; + *a = PTR_SIZE; + return PTR_SIZE; } - } else if (bt == VT_DOUBLE) { + } else if (bt == VT_LDOUBLE) { + *a = LDOUBLE_ALIGN; + return LDOUBLE_SIZE; + } else if (bt == VT_DOUBLE || vt == VT_LLONG) { *a = 8; return 8; } else if (bt == VT_INT || bt == VT_ENUM || bt == VT_FLOAT) { @@ -2055,8 +2375,8 @@ void vstore(void) /* store result */ vstore(); } else { + /* generate cast if needed implicit cast for bool */ if ((vstack_ptr[-2] & VT_BTYPE) == VT_BOOL) { - /* implicit cast for bool */ gen_cast(VT_BOOL); } r = gv(); /* generate value */ @@ -2287,9 +2607,16 @@ int ist(void) next(); break; case TOK_LONG: - /* XXX: add long type */ - u = VT_INT; - goto basic_type; + next(); + if ((t & VT_BTYPE) == VT_DOUBLE) { + t = (t & ~VT_BTYPE) | VT_LDOUBLE; + } else if ((t & VT_BTYPE) == VT_LONG) { + t = (t & ~VT_BTYPE) | VT_LLONG; + } else { + u = VT_LONG; + goto basic_type1; + } + break; case TOK_BOOL: u = VT_BOOL; goto basic_type; @@ -2297,8 +2624,14 @@ int ist(void) u = VT_FLOAT; goto basic_type; case TOK_DOUBLE: - u = VT_DOUBLE; - goto basic_type; + next(); + if ((t & VT_BTYPE) == VT_LONG) { + t = (t & ~VT_BTYPE) | VT_LDOUBLE; + } else { + u = VT_DOUBLE; + goto basic_type1; + } + break; case TOK_ENUM: u = struct_decl(VT_ENUM); goto basic_type1; @@ -2346,6 +2679,9 @@ int ist(void) t |= 2; } the_end: + /* long is never used as type */ + if ((t & VT_BTYPE) == VT_LONG) + t = (t & ~VT_BTYPE) | VT_INT; return t; } @@ -2506,7 +2842,7 @@ void unary(void) GFuncContext gf; if (tok == TOK_NUM || tok == TOK_CCHAR || tok == TOK_LCHAR) { - vset(VT_CONST, tokc); + vset(VT_CONST, tokc.i); next(); } else if (tok == TOK___FUNC__) { /* special function name identifier */ @@ -2716,7 +3052,7 @@ void unary(void) parlevel++; else if (tok == ')') parlevel--; - tok_add2(&str, &len, tok, tokc); + tok_add2(&str, &len, tok, &tokc); next(); } tok_add(&str, &len, -1); /* end of file added */ @@ -2794,7 +3130,7 @@ int is_compatible_types(int t1, int t2) bt2 = t2 & VT_BTYPE; if (bt1 == VT_PTR) { t1 = pointed_type(t1); - /* if function, then convert implictely to function pointer */ + /* if function, then convert implicitely to function pointer */ if (bt2 != VT_FUNC) { if (bt2 != VT_PTR) return 0; @@ -2876,7 +3212,7 @@ void uneq(void) } } -void sum(l) +void sum(int l) { int t; @@ -2946,7 +3282,7 @@ void eor(void) } /* XXX: better constant handling */ -void expr_eq() +void expr_eq(void) { int t, u, c, r1, r2; @@ -2981,7 +3317,7 @@ void expr_eq() } } -void expr() +void expr(void) { while (1) { expr_eq(); @@ -2991,7 +3327,7 @@ void expr() } } -int expr_const() +int expr_const(void) { int a; a = const_wanted; @@ -3007,11 +3343,13 @@ int expr_const() return zero */ int is_label(void) { - int t, c; + int t; + CValue c; /* fast test first */ if (tok < TOK_UIDENT) return 0; + /* no need to save tokc since we expect an identifier */ t = tok; c = tokc; next(); @@ -3402,7 +3740,7 @@ void decl_initializer(int t, int c, int first, int size_only) (t1 & VT_BTYPE) == VT_BYTE)) { /* XXX: move multiple string parsing in parser ? */ while (tok == TOK_STR || tok == TOK_LSTR) { - ts = (TokenSym *)tokc; + ts = tokc.ts; /* compute maximum number of chars wanted */ nb = ts->len; if (n >= 0 && nb > (n - array_length)) @@ -3538,7 +3876,7 @@ int decl_initializer_alloc(int t, int has_init) while (level > 0 || (tok != ',' && tok != ';')) { if (tok < 0) error("unexpect end of file in initializer"); - tok_add2(&init_str, &init_len, tok, tokc); + tok_add2(&init_str, &init_len, tok, &tokc); if (tok == '{') level++; else if (tok == '}') {