diff --git a/tcc.h b/tcc.h index cbced87..67d09a0 100644 --- a/tcc.h +++ b/tcc.h @@ -561,6 +561,7 @@ typedef struct ParseState { typedef struct TokenString { int *str; int len; + int lastlen; int allocated_len; int last_line_num; /* used to chain token-strings with begin/end_macro() */ diff --git a/tccpp.c b/tccpp.c index dca900c..b81b4b5 100644 --- a/tccpp.c +++ b/tccpp.c @@ -48,6 +48,7 @@ static TokenString tokstr_buf; static unsigned char isidnum_table[256 - CH_EOF]; static int pp_debug_tok, pp_debug_symv; static int pp_once; +static int pp_expr; static void tok_print(const char *msg, const int *str); static struct TinyAlloc *toksym_alloc; @@ -127,7 +128,7 @@ ST_FUNC void expect(const char *msg) #define tal_free(al, p) tal_free_impl(al, p, __FILE__, __LINE__) #define tal_realloc(al, p, size) tal_realloc_impl(&al, p, size, __FILE__, __LINE__) #define TAL_DEBUG_PARAMS , const char *file, int line -#define TAL_DEBUG_FILE_LEN 15 +#define TAL_DEBUG_FILE_LEN 40 #endif #define TOKSYM_TAL_SIZE (768 * 1024) /* allocator for tiny TokenSym in table_ident */ @@ -1056,7 +1057,7 @@ static inline int tok_size(const int *p) ST_INLN void tok_str_new(TokenString *s) { s->str = NULL; - s->len = 0; + s->len = s->lastlen = 0; s->allocated_len = 0; s->last_line_num = -1; } @@ -1142,7 +1143,7 @@ static void tok_str_add2(TokenString *s, int t, CValue *cv) { int len, *str; - len = s->len; + len = s->lastlen = s->len; str = s->str; /* allocate space for worst case */ @@ -1271,19 +1272,6 @@ static inline void TOK_GET(int *t, const int **pp, CValue *cv) *pp = p; } -/* Calling this function is expensive, but it is not possible - to read a token string backwards. */ -static int tok_last(const int *str0, const int *str1) -{ - const int *str = str0; - int tok = 0; - CValue cval; - - while (str < str1) - TOK_GET(&tok, &str, &cval); - return tok; -} - static int macro_is_equal(const int *a, const int *b) { CValue cv; @@ -1418,6 +1406,7 @@ static int expr_preprocess(void) TokenString *str; str = tok_str_alloc(); + pp_expr = 1; while (tok != TOK_LINEFEED && tok != TOK_EOF) { next(); /* do macro subst */ if (tok == TOK_DEFINED) { @@ -1425,9 +1414,14 @@ static int expr_preprocess(void) t = tok; if (t == '(') next_nomacro(); + if (tok < TOK_IDENT) + expect("identifier"); c = define_find(tok) != 0; - if (t == '(') + if (t == '(') { next_nomacro(); + if (tok != ')') + expect("')'"); + } tok = TOK_CINT; tokc.i = c; } else if (tok >= TOK_IDENT) { @@ -1437,6 +1431,7 @@ static int expr_preprocess(void) } tok_str_add_tok(str); } + pp_expr = 0; tok_str_add(str, -1); /* simulate end of file */ tok_str_add(str, 0); /* now evaluate C constant expression */ @@ -1456,7 +1451,7 @@ ST_FUNC void parse_define(void) int saved_parse_flags = parse_flags; v = tok; - if (v < TOK_IDENT) + if (v < TOK_IDENT || v == TOK_DEFINED) tcc_error("invalid macro name '%s'", get_tok_str(tok, &tokc)); /* XXX: should check if same macro (ANSI) */ first = NULL; @@ -3403,23 +3398,26 @@ static void macro_subst( macro_str = macro_ptr; end_macro (); } - - spc = (tok_str->len && - is_space(tok_last(tok_str->str, - tok_str->str + tok_str->len))); - + if (tok_str->len) + spc = is_space(t = tok_str->str[tok_str->lastlen]); } else { - if (t == '\\' && !(parse_flags & PARSE_FLAG_ACCEPT_STRAYS)) tcc_error("stray '\\' in program"); - no_subst: if (!check_space(t, &spc)) tok_str_add2(tok_str, t, &cval); - nosubst = 0; + + if (nosubst) { + if (nosubst > 1 && (spc || (++nosubst == 3 && t == '('))) + continue; + nosubst = 0; + } if (t == TOK_NOSUBST) nosubst = 1; } + /* GCC supports 'defined' as result of a macto substitution */ + if (t == TOK_DEFINED && pp_expr) + nosubst = 2; } } diff --git a/tests/pp/21.c b/tests/pp/21.c new file mode 100644 index 0000000..1316226 --- /dev/null +++ b/tests/pp/21.c @@ -0,0 +1,36 @@ +/* accept 'defined' as result of substitution */ + +----- 1 ------ +#define AAA 2 +#define BBB +#define CCC (defined ( AAA ) && AAA > 1 && !defined BBB) +#if !CCC +OK +#else +NOT OK +#endif + +----- 2 ------ +#undef BBB +#if CCC +OK +#else +NOT OK +#endif + +----- 3 ------ +#define DEFINED defined +#define DDD (DEFINED ( AAA ) && AAA > 1 && !DEFINED BBB) +#if (DDD) +OK +#else +NOT OK +#endif + +----- 4 ------ +#undef AAA +#if !(DDD) +OK +#else +NOT OK +#endif diff --git a/tests/pp/21.expect b/tests/pp/21.expect new file mode 100644 index 0000000..5a1376b --- /dev/null +++ b/tests/pp/21.expect @@ -0,0 +1,8 @@ +----- 1 ------ +OK +----- 2 ------ +OK +----- 3 ------ +OK +----- 4 ------ +OK