aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgrischka <grischka>2015-05-09 14:29:39 +0200
committergrischka <grischka>2015-05-09 14:29:39 +0200
commit30df3189b177c65d65094bed3a066a2722fe2dc0 (patch)
tree5cc01304899af2f09b051cdb5cf980ceb8f6b9c1
parent70a6c4601e471054edbe2fd984e37e2ca320db14 (diff)
downloadtinycc-30df3189b177c65d65094bed3a066a2722fe2dc0.tar.gz
tinycc-30df3189b177c65d65094bed3a066a2722fe2dc0.tar.bz2
tccpp: fix issues, add tests
* fix some macro expansion issues * add some pp tests in tests/pp * improved tcc -E output for better diff'ability * remove -dD feature (quirky code, exotic feature, didn't work well) Based partially on ideas / researches from PipCet Some issues remain with VA_ARGS macros (if used in a rather tricky way). Also, to keep it simple, the pp doesn't automtically add any extra spaces to separate tokens which otherwise would form wrong tokens if re-read from tcc -E output (such as '+' '=') GCC does that, other compilers don't. * cleanups - #line 01 "file" / # 01 "file" processing - #pragma comment(lib,"foo") - tcc -E: forward some pragmas to output (pack, comment(lib)) - fix macro parameter list parsing mess from a3fc54345949535524d01319e1ca6378b7c2c201 a715d7143d9d17da17e67fec6af1c01409a71a31 (some coffee might help, next time ;) - introduce TOK_PPSTR - to have character constants as written in the file (similar to TOK_PPNUM) - allow '\' appear in macros - new functions begin/end_macro to: - fix switching macro levels during expansion - allow unget_tok to unget more than one tok - slight speedup by using bitflags in isidnum_table Also: - x86_64.c : fix decl after statements - i386-gen,c : fix a vstack leak with VLA on windows - configure/Makefile : build on windows (MSYS) was broken - tcc_warning: fflush stderr to keep output order (win32)
-rwxr-xr-xconfigure6
-rw-r--r--i386-gen.c1
-rw-r--r--libtcc.c83
-rw-r--r--tcc.c27
-rw-r--r--tcc.h45
-rw-r--r--tccasm.c2
-rw-r--r--tccelf.c2
-rw-r--r--tccgen.c56
-rw-r--r--tccpe.c9
-rw-r--r--tccpp.c1391
-rw-r--r--tests/Makefile25
-rw-r--r--tests/abitest.c39
-rw-r--r--tests/libtcc_test.c16
-rw-r--r--tests/pp/01.c6
-rw-r--r--tests/pp/01.expect1
-rw-r--r--tests/pp/02.c28
-rw-r--r--tests/pp/02.expect5
-rw-r--r--tests/pp/03.c15
-rw-r--r--tests/pp/03.expect5
-rw-r--r--tests/pp/04.c4
-rw-r--r--tests/pp/04.expect1
-rw-r--r--tests/pp/05.c7
-rw-r--r--tests/pp/05.expect3
-rw-r--r--tests/pp/06.c5
-rw-r--r--tests/pp/06.expect1
-rw-r--r--tests/pp/07.c4
-rw-r--r--tests/pp/07.expect2
-rw-r--r--tests/pp/08.c4
-rw-r--r--tests/pp/08.expect1
-rw-r--r--tests/pp/09.c4
-rw-r--r--tests/pp/09.expect1
-rw-r--r--tests/pp/10.c10
-rw-r--r--tests/pp/10.expect5
-rw-r--r--tests/pp/11.c31
-rw-r--r--tests/pp/11.expect15
-rw-r--r--tests/pp/Makefile35
-rw-r--r--tests/tcctest.c2
-rw-r--r--tests/tests2/65_macro_concat_start.c2
-rw-r--r--tests/tests2/65_macro_concat_start.expect1
-rw-r--r--tests/tests2/66_macro_concat_end.c2
-rw-r--r--tests/tests2/66_macro_concat_end.expect1
-rw-r--r--tests/tests2/68_macro_param_list_err_1.c9
-rw-r--r--tests/tests2/68_macro_param_list_err_1.expect1
-rw-r--r--tests/tests2/69_macro_param_list_err_2.c9
-rw-r--r--tests/tests2/69_macro_param_list_err_2.expect1
-rw-r--r--tests/tests2/72_long_long_constant.c2
-rw-r--r--tests/tests2/72_long_long_constant.expect1
-rw-r--r--tests/tests2/Makefile107
-rw-r--r--x86_64-gen.c9
49 files changed, 1057 insertions, 985 deletions
diff --git a/configure b/configure
index 9bef59f..01bcdb1 100755
--- a/configure
+++ b/configure
@@ -449,12 +449,6 @@ LIBSUF=$LIBSUF
EXESUF=$EXESUF
HOST_OS=$host_os
EOF
-if test "$mingw32" = "yes"; then
-cat >>config.mak <<EOF
-XCC=$cc
-XAR=$ar
-EOF
-fi
print_inc() {
if test -n "$2"; then
diff --git a/i386-gen.c b/i386-gen.c
index a1ce4c5..8284cf0 100644
--- a/i386-gen.c
+++ b/i386-gen.c
@@ -1116,7 +1116,6 @@ ST_FUNC void gen_vla_alloc(CType *type, int align) {
vpush_global_sym(&func_old_type, TOK_alloca);
vswap(); /* Move alloca ref past allocation size */
gfunc_call(1);
- vset(type, REG_IRET, 0);
#else
int r;
r = gv(RC_INT); /* allocation size */
diff --git a/libtcc.c b/libtcc.c
index ef727c9..248dc7c 100644
--- a/libtcc.c
+++ b/libtcc.c
@@ -608,7 +608,10 @@ static void error1(TCCState *s1, int is_warning, const char *fmt, va_list ap)
if (!s1->error_func) {
/* default case: stderr */
+ if (s1->ppfp) /* print a newline during tcc -E */
+ fprintf(s1->ppfp, "\n"), fflush(s1->ppfp);
fprintf(stderr, "%s\n", buf);
+ fflush(stderr); /* print error/warning now (win32) */
} else {
s1->error_func(s1->error_opaque, buf);
}
@@ -672,7 +675,7 @@ ST_FUNC void tcc_open_bf(TCCState *s1, const char *filename, int initlen)
BufferedFile *bf;
int buflen = initlen ? initlen : IO_BUF_SIZE;
- bf = tcc_malloc(sizeof(BufferedFile) + buflen);
+ bf = tcc_mallocz(sizeof(BufferedFile) + buflen);
bf->buf_ptr = bf->buffer;
bf->buf_end = bf->buffer + initlen;
bf->buf_end[0] = CH_EOB; /* put eob symbol */
@@ -681,7 +684,6 @@ ST_FUNC void tcc_open_bf(TCCState *s1, const char *filename, int initlen)
normalize_slashes(bf->filename);
#endif
bf->line_num = 1;
- bf->ifndef_macro = 0;
bf->ifdef_stack_ptr = s1->ifdef_stack_ptr;
bf->fd = -1;
bf->prev = file;
@@ -703,7 +705,7 @@ ST_FUNC int tcc_open(TCCState *s1, const char *filename)
{
int fd;
if (strcmp(filename, "-") == 0)
- fd = 0, filename = "stdin";
+ fd = 0, filename = "<stdin>";
else
fd = open(filename, O_RDONLY | O_BINARY);
if ((s1->verbose == 2 && fd >= 0) || s1->verbose == 3)
@@ -721,7 +723,6 @@ ST_FUNC int tcc_open(TCCState *s1, const char *filename)
static int tcc_compile(TCCState *s1)
{
Sym *define_start;
- SValue *pvtop;
char buf[512];
volatile int section_sym;
@@ -797,14 +798,12 @@ static int tcc_compile(TCCState *s1)
ch = file->buf_ptr[0];
tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
- parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM;
- pvtop = vtop;
+ parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM | PARSE_FLAG_TOK_STR;
next();
decl(VT_CONST);
if (tok != TOK_EOF)
expect("declaration");
- if (pvtop != vtop)
- tcc_warning("internal compiler error: vstack leak? (%d)", vtop - pvtop);
+ check_vstack();
/* end of translation unit info */
if (s1->do_debug) {
@@ -829,31 +828,13 @@ static int tcc_compile(TCCState *s1)
LIBTCCAPI int tcc_compile_string(TCCState *s, const char *str)
{
- int i;
int len, ret;
- len = strlen(str);
+ len = strlen(str);
tcc_open_bf(s, "<string>", len);
memcpy(file->buffer, str, len);
-
- len = s->nb_files;
ret = tcc_compile(s);
tcc_close();
-
- /* habdle #pragma comment(lib,) */
- for(i = len; i < s->nb_files; i++) {
- /* int filetype = *(unsigned char *)s->files[i]; */
- const char *filename = s->files[i] + 1;
- if (filename[0] == '-' && filename[1] == 'l') {
- if (tcc_add_library(s, filename + 2) < 0) {
- tcc_warning("cannot find library 'lib%s'", filename+2);
- ret++;
- }
- }
- tcc_free(s->files[i]);
- }
- s->nb_files = len;
-
return ret;
}
@@ -896,20 +877,11 @@ LIBTCCAPI void tcc_undefine_symbol(TCCState *s1, const char *sym)
/* cleanup all static data used during compilation */
static void tcc_cleanup(void)
{
- int i, n;
if (NULL == tcc_state)
return;
tcc_state = NULL;
- /* free -D defines */
- free_defines(NULL);
-
- /* free tokens */
- n = tok_ident - TOK_IDENT;
- for(i = 0; i < n; i++)
- tcc_free(table_ident[i]);
- tcc_free(table_ident);
- table_ident = NULL;
+ preprocess_delete();
/* free sym_pools */
dynarray_reset(&sym_pools, &nb_sym_pools);
@@ -917,8 +889,6 @@ static void tcc_cleanup(void)
cstr_free(&tokcstr);
/* reset symbol stack */
sym_free_first = NULL;
- /* cleanup from error/setjmp */
- macro_ptr = NULL;
}
LIBTCCAPI TCCState *tcc_new(void)
@@ -1128,6 +1098,7 @@ LIBTCCAPI void tcc_delete(TCCState *s1)
tcc_free(s1->deps_outfile);
dynarray_reset(&s1->files, &s1->nb_files);
dynarray_reset(&s1->target_deps, &s1->nb_target_deps);
+ dynarray_reset(&s1->pragma_libs, &s1->nb_pragma_libs);
#ifdef TCC_IS_NATIVE
# ifdef HAVE_SELINUX
@@ -1138,8 +1109,7 @@ LIBTCCAPI void tcc_delete(TCCState *s1)
# endif
#endif
- if(s1->sym_attrs) tcc_free(s1->sym_attrs);
-
+ tcc_free(s1->sym_attrs);
tcc_free(s1);
}
@@ -1338,6 +1308,22 @@ LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname)
return -1;
}
+PUB_FUNC int tcc_add_library_err(TCCState *s, const char *libname)
+{
+ int ret = tcc_add_library(s, libname);
+ if (ret < 0)
+ tcc_error_noabort("cannot find library 'lib%s'", libname);
+ return ret;
+}
+
+/* habdle #pragma comment(lib,) */
+ST_FUNC void tcc_add_pragma_libs(TCCState *s1)
+{
+ int i;
+ for (i = 0; i < s1->nb_pragma_libs; i++)
+ tcc_add_library_err(s1, s1->pragma_libs[i]);
+}
+
LIBTCCAPI int tcc_add_symbol(TCCState *s, const char *name, const void *val)
{
#ifdef TCC_TARGET_PE
@@ -1355,8 +1341,6 @@ LIBTCCAPI int tcc_add_symbol(TCCState *s, const char *name, const void *val)
LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type)
{
s->output_type = output_type;
- if (output_type == TCC_OUTPUT_PREPROCESS)
- print_defines();
if (!s->nostdinc) {
/* default include paths */
@@ -1694,7 +1678,6 @@ enum {
TCC_OPTION_g,
TCC_OPTION_c,
TCC_OPTION_dumpversion,
- TCC_OPTION_d,
TCC_OPTION_float_abi,
TCC_OPTION_static,
TCC_OPTION_std,
@@ -1751,7 +1734,6 @@ static const TCCOption tcc_options[] = {
{ "g", TCC_OPTION_g, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "c", TCC_OPTION_c, 0 },
{ "dumpversion", TCC_OPTION_dumpversion, 0},
- { "d", TCC_OPTION_d, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
#ifdef TCC_TARGET_ARM
{ "mfloat-abi", TCC_OPTION_float_abi, TCC_OPTION_HAS_ARG },
#endif
@@ -1878,8 +1860,7 @@ PUB_FUNC int tcc_parse_args(TCCState *s, int argc, char **argv)
case TCC_OPTION_HELP:
return 0;
case TCC_OPTION_I:
- if (tcc_add_include_path(s, optarg) < 0)
- tcc_error("too many include paths");
+ tcc_add_include_path(s, optarg);
break;
case TCC_OPTION_D:
parse_option_D(s, optarg);
@@ -1924,14 +1905,6 @@ PUB_FUNC int tcc_parse_args(TCCState *s, int argc, char **argv)
tcc_warning("-c: some compiler action already specified (%d)", s->output_type);
s->output_type = TCC_OUTPUT_OBJ;
break;
- case TCC_OPTION_d:
- if (*optarg != 'D') {
- if (s->warn_unsupported)
- goto unsupported_option;
- tcc_error("invalid option -- '%s'", r);
- }
- s->dflag = 1;
- break;
#ifdef TCC_TARGET_ARM
case TCC_OPTION_float_abi:
/* tcc doesn't support soft float yet */
diff --git a/tcc.c b/tcc.c
index a0b1c70..29508eb 100644
--- a/tcc.c
+++ b/tcc.c
@@ -55,31 +55,28 @@ static void display_info(TCCState *s, int what)
# endif
#endif
#ifdef TCC_TARGET_PE
- ", mingw"
+ " Windows"
#else
- #ifdef __linux
- ", Linux"
- #else
- ", Unknown"
- #endif
+ " Linux"
#endif
")\n", TCC_VERSION);
break;
case 1:
printf("install: %s\n", s->tcc_lib_path);
/* print_paths("programs", NULL, 0); */
- print_paths("crt", s->crt_paths, s->nb_crt_paths);
- print_paths("libraries", s->library_paths, s->nb_library_paths);
print_paths("include", s->sysinclude_paths, s->nb_sysinclude_paths);
+ print_paths("libraries", s->library_paths, s->nb_library_paths);
+#ifndef TCC_TARGET_PE
+ print_paths("crt", s->crt_paths, s->nb_crt_paths);
printf("elfinterp:\n %s\n", DEFAULT_ELFINTERP(s));
+#endif
break;
}
}
-static void help(TCCState *s)
+static void help(void)
{
- display_info(s, 0);
- printf("Tiny C Compiler - Copyright (C) 2001-2006 Fabrice Bellard\n"
+ printf("Tiny C Compiler "TCC_VERSION" - Copyright (C) 2001-2006 Fabrice Bellard\n"
"Usage: tcc [options...] [-o outfile] [-c] infile(s)...\n"
" tcc [options...] -run infile [arguments...]\n"
"General options:\n"
@@ -94,13 +91,11 @@ static void help(TCCState *s)
" -dumpversion\n"
" -bench show compilation statistics\n"
"Preprocessor options:\n"
- " -E preprocess only\n"
" -Idir add include path 'dir'\n"
" -Dsym[=val] define 'sym' with value 'val'\n"
" -Usym undefine 'sym'\n"
- " -P do not output a #line directive\n"
- " -P1 use a #line directive in output instead of the gcc style\n"
- " -dD put a define directive in the output (inside a comment)\n"
+ " -E preprocess only\n"
+ " -P[1] no/alternative output of #line directives with -E\n"
"Linker options:\n"
" -Ldir add library path 'dir'\n"
" -llib link with dynamic or static library 'lib'\n"
@@ -260,7 +255,7 @@ int main(int argc, char **argv)
tcc_set_environment(s);
if (optind == 0) {
- help(s);
+ help();
return 1;
}
diff --git a/tcc.h b/tcc.h
index 331d6e4..314045b 100644
--- a/tcc.h
+++ b/tcc.h
@@ -498,11 +498,12 @@ typedef struct BufferedFile {
int fd;
struct BufferedFile *prev;
int line_num; /* current line number - here to simplify code */
- int line_ref; /* moved from tcc_preprocess(), needed for a right ouput in other places */
+ int line_ref; /* tcc -E: last printed line */
int ifndef_macro; /* #ifndef macro / #endif search */
int ifndef_macro_saved; /* saved ifndef_macro */
int *ifdef_stack_ptr; /* ifdef_stack value at the start of the file */
char filename[1024]; /* filename */
+ unsigned char unget[4];
unsigned char buffer[1]; /* extra size for CH_EOB char */
} BufferedFile;
@@ -524,11 +525,15 @@ typedef struct TokenString {
int len;
int allocated_len;
int last_line_num;
+ /* used to chain token-strings with begin/end_macro() */
+ struct TokenString *prev;
+ const int *prev_ptr;
+ char alloc;
} TokenString;
/* inline functions */
typedef struct InlineFunc {
- int *token_str;
+ TokenString func_str;
Sym *sym;
char filename[1];
} InlineFunc;
@@ -663,8 +668,7 @@ struct TCCState {
LINE_MACRO_OUTPUT_FORMAT_GCC,
LINE_MACRO_OUTPUT_FORMAT_NONE,
LINE_MACRO_OUTPUT_FORMAT_STD,
- } Pflag;
- int dflag; /* for keeping a -dD value */
+ } Pflag; /* -P switch */
/* for -MD/-MF: collected dependencies for this compilation */
char **target_deps;
@@ -685,6 +689,8 @@ struct TCCState {
/* #pragma pack stack */
int pack_stack[PACK_STACK_SIZE];
int *pack_stack_ptr;
+ char **pragma_libs;
+ int nb_pragma_libs;
/* inline functions are stored as token lists and compiled last
only if referenced */
@@ -860,21 +866,21 @@ struct TCCState {
#define TOK_CDOUBLE 0xbc /* double constant */
#define TOK_CLDOUBLE 0xbd /* long double constant */
#define TOK_PPNUM 0xbe /* preprocessor number */
-#define TOK_LINENUM 0xbf /* line number info */
+#define TOK_PPSTR 0xbf /* preprocessor string */
+#define TOK_LINENUM 0xc0 /* line number info */
/* <-- */
-#define TOK_TWOSHARPS 0xc0 /* ## preprocessing token */
-#define TOK_PLCHLDR 0xc1 /* placeholder token as defined in C99 */
#define TOK_UMULL 0xc2 /* unsigned 32x32 -> 64 mul */
#define TOK_ADDC1 0xc3 /* add with carry generation */
#define TOK_ADDC2 0xc4 /* add with carry use */
#define TOK_SUBC1 0xc5 /* add with carry generation */
#define TOK_SUBC2 0xc6 /* add with carry use */
-#define TOK_ARROW 0xcb
-#define TOK_DOTS 0xcc /* three dots */
-#define TOK_SHR 0xcd /* unsigned shift right */
-#define TOK_NOSUBST 0xcf /* means following token has already been pp'd */
-#define TOK_GNUCOMMA 0xd0 /* ,## preprocessing token */
+#define TOK_ARROW 0xc7
+#define TOK_DOTS 0xc8 /* three dots */
+#define TOK_SHR 0xc9 /* unsigned shift right */
+#define TOK_TWOSHARPS 0xca /* ## preprocessing token */
+#define TOK_PLCHLDR 0xcb /* placeholder token as defined in C99 */
+#define TOK_NOSUBST 0xcc /* means following token has already been pp'd */
#define TOK_SHL 0x01 /* shift left */
#define TOK_SAR 0x02 /* signed shift right */
@@ -1113,10 +1119,11 @@ ST_FUNC void tcc_close(void);
ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags, int filetype);
ST_FUNC int tcc_add_crt(TCCState *s, const char *filename);
ST_FUNC int tcc_add_dll(TCCState *s, const char *filename, int flags);
+ST_FUNC void tcc_add_pragma_libs(TCCState *s1);
+PUB_FUNC int tcc_add_library_err(TCCState *s, const char *f);
PUB_FUNC void tcc_print_stats(TCCState *s, int64_t total_time);
PUB_FUNC int tcc_parse_args(TCCState *s, int argc, char **argv);
-
PUB_FUNC void tcc_set_environment(TCCState *s);
/* ------------ tccpp.c ------------ */
@@ -1148,9 +1155,12 @@ ST_DATA TokenSym **table_ident;
#define PARSE_FLAG_ASM_FILE 0x0008 /* we processing an asm file: '#' can be used for line comment, etc. */
#define PARSE_FLAG_SPACES 0x0010 /* next() returns space tokens (for -E) */
#define PARSE_FLAG_ACCEPT_STRAYS 0x0020 /* next() returns '\\' token */
+#define PARSE_FLAG_TOK_STR 0x0040 /* return parsed strings instead of TOK_PPSTR */
ST_FUNC TokenSym *tok_alloc(const char *str, int len);
-ST_FUNC char *get_tok_str(int v, CValue *cv);
+ST_FUNC const char *get_tok_str(int v, CValue *cv);
+ST_FUNC void begin_macro(TokenString *str, int alloc);
+ST_FUNC void end_macro(void);
ST_FUNC void save_parse_state(ParseState *s);
ST_FUNC void restore_parse_state(ParseState *s);
ST_INLN void tok_str_new(TokenString *s);
@@ -1161,7 +1171,6 @@ ST_INLN void define_push(int v, int macro_type, int *str, Sym *first_arg);
ST_FUNC void define_undef(Sym *s);
ST_INLN Sym *define_find(int v);
ST_FUNC void free_defines(Sym *b);
-ST_FUNC void print_defines(void);
ST_FUNC Sym *label_find(int v);
ST_FUNC Sym *label_push(Sym **ptop, int v, int flags);
ST_FUNC void label_pop(Sym **ptop, Sym *slast);
@@ -1172,6 +1181,7 @@ ST_FUNC void next(void);
ST_INLN void unget_tok(int last_tok);
ST_FUNC void preprocess_init(TCCState *s1);
ST_FUNC void preprocess_new(void);
+ST_FUNC void preprocess_delete(void);
ST_FUNC int tcc_preprocess(TCCState *s1);
ST_FUNC void skip(int c);
ST_FUNC NORETURN void expect(const char *msg);
@@ -1204,7 +1214,7 @@ ST_DATA Sym *local_label_stack;
ST_DATA Sym *global_label_stack;
ST_DATA Sym *define_stack;
ST_DATA CType char_pointer_type, func_old_type, int_type, size_type;
-ST_DATA SValue __vstack[1+/*to make bcheck happy*/ VSTACK_SIZE], *vtop;
+ST_DATA SValue __vstack[1+/*to make bcheck happy*/ VSTACK_SIZE], *vtop, *pvtop;
#define vstack (__vstack + 1)
ST_DATA int rsym, anon_sym, ind, loc;
@@ -1215,8 +1225,9 @@ ST_DATA CType func_vt; /* current function return type (used by return instructi
ST_DATA int func_var; /* true if current function is variadic */
ST_DATA int func_vc;
ST_DATA int last_line_num, last_ind, func_ind; /* debug last line number and pc */
-ST_DATA char *funcname;
+ST_DATA const char *funcname;
+ST_FUNC void check_vstack(void);
ST_INLN int is_float(int t);
ST_FUNC int ieee_finite(double d);
ST_FUNC void test_lvalue(void);
diff --git a/tccasm.c b/tccasm.c
index b46ce3d..3cbae19 100644
--- a/tccasm.c
+++ b/tccasm.c
@@ -747,7 +747,7 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess)
ch = file->buf_ptr[0];
tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
- parse_flags = PARSE_FLAG_ASM_FILE;
+ parse_flags = PARSE_FLAG_ASM_FILE | PARSE_FLAG_TOK_STR;
if (do_preprocess)
parse_flags |= PARSE_FLAG_PREPROCESS;
next();
diff --git a/tccelf.c b/tccelf.c
index 581ebef..1f87946 100644
--- a/tccelf.c
+++ b/tccelf.c
@@ -1605,6 +1605,8 @@ ST_FUNC void tcc_add_bcheck(TCCState *s1)
/* add tcc runtime libraries */
ST_FUNC void tcc_add_runtime(TCCState *s1)
{
+ tcc_add_pragma_libs(s1);
+
/* add libc */
if (!s1->nostdlib) {
tcc_add_library(s1, "c");
diff --git a/tccgen.c b/tccgen.c
index 5c89b2d..fcec8f1 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -59,7 +59,7 @@ ST_DATA int vlas_in_scope; /* number of VLAs that are currently in scope */
ST_DATA int vla_sp_root_loc; /* vla_sp_loc for SP before any VLAs were pushed */
ST_DATA int vla_sp_loc; /* Pointer to variable holding location to store stack pointer on the stack when modifying stack pointer */
-ST_DATA SValue __vstack[1+VSTACK_SIZE], *vtop;
+ST_DATA SValue __vstack[1+VSTACK_SIZE], *vtop, *pvtop;
ST_DATA int const_wanted; /* true if constant wanted */
ST_DATA int nocode_wanted; /* true if no code generation wanted for an expression */
@@ -68,7 +68,7 @@ ST_DATA CType func_vt; /* current function return type (used by return instructi
ST_DATA int func_var; /* true if current function is variadic (used by return instruction) */
ST_DATA int func_vc;
ST_DATA int last_line_num, last_ind, func_ind; /* debug last line number and pc */
-ST_DATA char *funcname;
+ST_DATA const char *funcname;
ST_DATA CType char_pointer_type, func_old_type, int_type, size_type;
@@ -118,6 +118,12 @@ ST_FUNC void test_lvalue(void)
expect("lvalue");
}
+ST_FUNC void check_vstack(void)
+{
+ if (pvtop != vtop)
+ tcc_error("internal compiler error: vstack leak (%d)", vtop - pvtop);
+}
+
/* ------------------------------------------------------------------------- */
/* symbol allocator */
static Sym *__sym_malloc(void)
@@ -4005,9 +4011,9 @@ ST_FUNC void unary(void)
break;
}
case TOK___va_arg: {
+ CType type;
if (nocode_wanted)
tcc_error("statement in global scope");
- CType type;
next();
skip('(');
expr_eq();
@@ -5777,7 +5783,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
/* compute size */
save_parse_state(&saved_parse_state);
- macro_ptr = init_str.str;
+ begin_macro(&init_str, 0);
next();
decl_initializer(type, NULL, 0, 1, 1);
/* prepare second initializer parsing */
@@ -5937,7 +5943,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
decl_initializer(type, sec, addr, 1, 0);
/* restore parse state if needed */
if (init_str.str) {
- tok_str_free(init_str.str);
+ end_macro();
restore_parse_state(&saved_parse_state);
}
/* patch flexible array member size back to -1, */
@@ -6018,6 +6024,7 @@ static void func_decl_list(Sym *func_sym)
static void gen_function(Sym *sym)
{
int saved_nocode_wanted = nocode_wanted;
+
nocode_wanted = 0;
ind = cur_text_section->data_offset;
/* NOTE: we patch the symbol size later */
@@ -6034,11 +6041,9 @@ static void gen_function(Sym *sym)
sym_push2(&local_stack, SYM_FIELD, 0, 0);
gfunc_prolog(&sym->type);
#ifdef CONFIG_TCC_BCHECK
- if (tcc_state->do_bounds_check
- && !strcmp(get_tok_str(sym->v, NULL), "main")) {
+ if (tcc_state->do_bounds_check && !strcmp(funcname, "main")) {
int i;
-
- sym = local_stack;
+ Sym *sym;
for (i = 0, sym = local_stack; i < 2; i++, sym = sym->prev) {
if (sym->v & SYM_FIELD || sym->prev->v & SYM_FIELD)
break;
@@ -6075,14 +6080,16 @@ static void gen_function(Sym *sym)
func_var = 0; /* for safety */
ind = 0; /* for safety */
nocode_wanted = saved_nocode_wanted;
+ check_vstack();
}
ST_FUNC void gen_inline_functions(void)
{
Sym *sym;
- int *str, inline_generated, i;
+ int inline_generated, i, ln;
struct InlineFunc *fn;
+ ln = file->line_num;
/* iterate while inline function are referenced */
for(;;) {
inline_generated = 0;
@@ -6092,18 +6099,17 @@ ST_FUNC void gen_inline_functions(void)
if (sym && sym->c) {
/* the function was used: generate its code and
convert it to a normal function */
- str = fn->token_str;
fn->sym = NULL;
if (file)
pstrcpy(file->filename, sizeof file->filename, fn->filename);
sym->r = VT_SYM | VT_CONST;
sym->type.t &= ~VT_INLINE;
- macro_ptr = str;
+ begin_macro(&fn->func_str, 0);
next();
cur_text_section = text_section;
gen_function(sym);
- macro_ptr = NULL; /* fail safe */
+ end_macro();
inline_generated = 1;
}
@@ -6111,10 +6117,12 @@ ST_FUNC void gen_inline_functions(void)
if (!inline_generated)
break;
}
+ file->line_num = ln;
+ /* free tokens of unused inline functions */
for (i = 0; i < tcc_state->nb_inline_fns; ++i) {
fn = tcc_state->inline_fns[i];
- str = fn->token_str;
- tok_str_free(str);
+ if (fn->sym)
+ tok_str_free(fn->func_str.str);
}
dynarray_reset(&tcc_state->inline_fns, &tcc_state->nb_inline_fns);
}
@@ -6267,19 +6275,22 @@ static int decl0(int l, int is_for_loop_init)
the compilation unit only if they are used */
if ((type.t & (VT_INLINE | VT_STATIC)) ==
(VT_INLINE | VT_STATIC)) {
- TokenString func_str;
int block_level;
struct InlineFunc *fn;
const char *filename;
- tok_str_new(&func_str);
+ filename = file ? file->filename : "";
+ fn = tcc_malloc(sizeof *fn + strlen(filename));
+ strcpy(fn->filename, filename);
+ fn->sym = sym;
+ tok_str_new(&fn->func_str);
block_level = 0;
for(;;) {
int t;
if (tok == TOK_EOF)
tcc_error("unexpected end of file");
- tok_str_add_tok(&func_str);
+ tok_str_add_tok(&fn->func_str);
t = tok;
next();
if (t == '{') {
@@ -6290,13 +6301,8 @@ static int decl0(int l, int is_for_loop_init)
break;
}
}
- tok_str_add(&func_str, -1);
- tok_str_add(&func_str, 0);
- filename = file ? file->filename : "";
- fn = tcc_malloc(sizeof *fn + strlen(filename));
- strcpy(fn->filename, filename);
- fn->sym = sym;
- fn->token_str = func_str.str;
+ tok_str_add(&fn->func_str, -1);
+ tok_str_add(&fn->func_str, 0);
dynarray_add((void ***)&tcc_state->inline_fns, &tcc_state->nb_inline_fns, fn);
} else {
diff --git a/tccpe.c b/tccpe.c
index e392f40..0fd8c36 100644
--- a/tccpe.c
+++ b/tccpe.c
@@ -1767,17 +1767,18 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
SHN_UNDEF, start_symbol);
+ tcc_add_pragma_libs(s1);
+
if (0 == s1->nostdlib) {
static const char *libs[] = {
- "libtcc1.a", "msvcrt", "kernel32", "", "user32", "gdi32", NULL
+ "tcc1", "msvcrt", "kernel32", "", "user32", "gdi32", NULL
};
const char **pp, *p;
for (pp = libs; 0 != (p = *pp); ++pp) {
if (0 == *p) {
if (PE_DLL != pe_type && PE_GUI != pe_type)
break;
- } else if (pp == libs ? tcc_add_dll(s1, p, 0) : tcc_add_library(s1, p)) {
- tcc_error_noabort("cannot find library: %s", p);
+ } else if (tcc_add_library_err(s1, p) < 0) {
break;
}
}
@@ -1805,8 +1806,8 @@ ST_FUNC int pe_output_file(TCCState * s1, const char *filename)
pe.filename = filename;
pe.s1 = s1;
- tcc_add_bcheck(s1);
pe_add_runtime(s1, &pe);
+ tcc_add_bcheck(s1);
relocate_common_syms(); /* assign bss adresses */
tcc_add_linker_symbols(s1);
diff --git a/tccpp.c b/tccpp.c
index 95c3f23..1c03feb 100644
--- a/tccpp.c
+++ b/tccpp.c
@@ -40,14 +40,15 @@ ST_DATA TokenSym **table_ident;
/* ------------------------------------------------------------------------- */
-static int *macro_ptr_allocated;
-static const int *unget_saved_macro_ptr;
-static int unget_saved_buffer[TOK_MAX_SIZE + 1];
-static int unget_buffer_enabled;
static TokenSym *hash_ident[TOK_HASH_SIZE];
static char token_buf[STRING_MAX_SIZE + 1];
-/* true if isid(c) || isnum(c) */
-static unsigned char isidnum_table[256-CH_EOF];
+static unsigned char isidnum_table[256 - CH_EOF];
+/* isidnum_table flags: */
+#define IS_SPC 1
+#define IS_ID 2
+#define IS_NUM 4
+
+static TokenString *macro_stack;
static const char tcc_keywords[] =
#define DEF(id, str) str "\0"
@@ -85,18 +86,7 @@ static const unsigned char tok_two_chars[] =
0
};
-struct macro_level {
- struct macro_level *prev;
- const int *p;
-};
-
static void next_nomacro_spc(void);
-static void macro_subst(
- TokenString *tok_str,
- Sym **nested_list,
- const int *macro_str,
- struct macro_level **can_read_stream
- );
ST_FUNC void skip(int c)
{
@@ -110,6 +100,29 @@ ST_FUNC void expect(const char *msg)
tcc_error("%s expected", msg);
}
+ST_FUNC void begin_macro(TokenString *str, int alloc)
+{
+ str->alloc = alloc;
+ str->prev = macro_stack;
+ str->prev_ptr = macro_ptr;
+ macro_ptr = str->str;
+ macro_stack = str;
+}
+
+ST_FUNC void end_macro(void)
+{
+ TokenString *str = macro_stack;
+ macro_stack = str->prev;
+ macro_ptr = str->prev_ptr;
+ if (str->alloc == 2) {
+ str->alloc = 3; /* just mark as finished */
+ } else {
+ tok_str_free(str->str);
+ if (str->alloc == 1)
+ tcc_free(str);
+ }
+}
+
/* ------------------------------------------------------------------------- */
/* CString handling */
static void cstr_realloc(CString *cstr, int new_size)
@@ -262,7 +275,7 @@ ST_FUNC TokenSym *tok_alloc(const char *str, int len)
/* XXX: buffer overflow */
/* XXX: float tokens */
-ST_FUNC char *get_tok_str(int v, CValue *cv)
+ST_FUNC const char *get_tok_str(int v, CValue *cv)
{
static char buf[STRING_MAX_SIZE + 1];
static CString cstr_buf;
@@ -276,10 +289,6 @@ ST_FUNC char *get_tok_str(int v, CValue *cv)
cstr_buf.size_allocated = sizeof(buf);
p = buf;
-/* just an explanation, should never happen:
- if (v <= TOK_LINENUM && v >= TOK_CINT && cv == NULL)
- tcc_error("internal error: get_tok_str"); */
-
switch(v) {
case TOK_CINT:
case TOK_CUINT:
@@ -304,12 +313,8 @@ ST_FUNC char *get_tok_str(int v, CValue *cv)
cstr_ccat(&cstr_buf, '\0');
break;
case TOK_PPNUM:
- cstr = cv->cstr;
- 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_PPSTR:
+ return (char*)cv->cstr->data;
case TOK_LSTR:
cstr_ccat(&cstr_buf, 'L');
case TOK_STR:
@@ -361,6 +366,10 @@ ST_FUNC char *get_tok_str(int v, CValue *cv)
}
q += 3;
}
+ if (v >= 127) {
+ sprintf(buf, "<%02x>", v);
+ return buf;
+ }
addv:
*p++ = v;
*p = '\0';
@@ -378,10 +387,13 @@ ST_FUNC char *get_tok_str(int v, CValue *cv)
return cstr_buf.data;
}
-/* fill input buffer and peek next char */
-static int tcc_peekc_slow(BufferedFile *bf)
+/* return the current character, handling end of block if necessary
+ (but not stray) */
+ST_FUNC int handle_eob(void)
{
+ BufferedFile *bf = file;
int len;
+
/* only tries to read if really end of buffer */
if (bf->buf_ptr >= bf->buf_end) {
if (bf->fd != -1) {
@@ -409,13 +421,6 @@ static int tcc_peekc_slow(BufferedFile *bf)
}
}
-/* return the current character, handling end of block if necessary
- (but not stray) */
-ST_FUNC int handle_eob(void)
-{
- return tcc_peekc_slow(file);
-}
-
/* read next char from current input file and handle end of input buffer */
ST_INLN void inp(void)
{
@@ -459,20 +464,21 @@ static int handle_stray1(uint8_t *p)
{
int c;
+ file->buf_ptr = p;
if (p >= file->buf_end) {
- file->buf_ptr = p;
c = handle_eob();
+ if (c != '\\')
+ return c;
p = file->buf_ptr;
- if (c == '\\')
- goto parse_stray;
- } else {
- parse_stray:
- file->buf_ptr = p;
- ch = *p;
- handle_stray();
- p = file->buf_ptr;
- c = *p;
}
+ ch = *p;
+ if (handle_stray_noerror()) {
+ if (!(parse_flags & PARSE_FLAG_ACCEPT_STRAYS))
+ tcc_error("stray '\\' in program");
+ *--file->buf_ptr = '\\';
+ }
+ p = file->buf_ptr;
+ c = *p;
return c;
}
@@ -625,13 +631,13 @@ ST_FUNC uint8_t *parse_comment(uint8_t *p)
static inline void skip_spaces(void)
{
- while (is_space(ch))
+ while (isidnum_table[ch - CH_EOF] & IS_SPC)
cinp();
}
static inline int check_space(int t, int *spc)
{
- if (is_space(t)) {
+ if (t < 256 && (isidnum_table[t - CH_EOF] & IS_SPC)) {
if (*spc)
return 1;
*spc = 1;
@@ -779,10 +785,7 @@ redo_start:
in_warn_or_error = 1;
else if (tok == TOK_LINEFEED)
goto redo_start;
- else if (parse_flags & PARSE_FLAG_ASM_FILE)
- p = parse_line_comment(p);
- }
- else if (parse_flags & PARSE_FLAG_ASM_FILE)
+ } else if (parse_flags & PARSE_FLAG_ASM_FILE)
p = parse_line_comment(p);
break;
_default:
@@ -822,9 +825,9 @@ ST_FUNC void restore_parse_state(ParseState *s)
/* return the number of additional 'ints' necessary to store the
token */
-static inline int tok_ext_size(int t)
+static inline int tok_size(const int *p)
{
- switch(t) {
+ switch(*p) {
/* 4 bytes */
case TOK_CINT:
case TOK_CUINT:
@@ -832,20 +835,20 @@ static inline int tok_ext_size(int t)
case TOK_LCHAR:
case TOK_CFLOAT:
case TOK_LINENUM:
- return 1;
+ return 1 + 1;
case TOK_STR:
case TOK_LSTR:
case TOK_PPNUM:
- tcc_error("unsupported token");
- return 1;
+ case TOK_PPSTR:
+ return 1 + ((sizeof(CString) + ((CString *)(p+1))->size + 3) >> 2);
case TOK_CDOUBLE:
case TOK_CLLONG:
case TOK_CULLONG:
- return 2;
+ return 1 + 2;
case TOK_CLDOUBLE:
- return LDOUBLE_SIZE / 4;
+ return 1 + LDOUBLE_SIZE / 4;
default:
- return 0;
+ return 1 + 0;
}
}
@@ -912,6 +915,7 @@ static void tok_str_add2(TokenString *s, int t, CValue *cv)
str[len++] = cv->tab[0];
break;
case TOK_PPNUM:
+ case TOK_PPSTR:
case TOK_STR:
case TOK_LSTR:
{
@@ -995,6 +999,7 @@ static inline void TOK_GET(int *t, const int **pp, CValue *cv)
case TOK_STR:
case TOK_LSTR:
case TOK_PPNUM:
+ case TOK_PPSTR:
cv->cstr = (CString *)p;
cv->cstr->data = (char *)p + sizeof(CString);
p += (sizeof(CString) + cv->cstr->size + 3) >> 2;
@@ -1040,54 +1045,6 @@ static int macro_is_equal(const int *a, const int *b)
return !(*a || *b);
}
-static void define_print(Sym *s, int is_undef)
-{
- int c, t;
- CValue cval;
- const int *str;
- Sym *arg;
-
- if (tcc_state->dflag == 0 || !s || !tcc_state->ppfp)
- return;
-
- if (file) {
- c = file->line_num - file->line_ref - 1;
- if (c > 0) {
- while (c--)
- fputs("\n", tcc_state->ppfp);
- file->line_ref = file->line_num;
- }
- }
-
- if (is_undef) {
- fprintf(tcc_state->ppfp, "// #undef %s", get_tok_str(s->v, NULL));
- return;
- }
-
- fprintf(tcc_state->ppfp, "// #define %s", get_tok_str(s->v, NULL));
- arg = s->next;
- if (arg) {
- char *sep = "(";
- while (arg) {
- fprintf(tcc_state->ppfp, "%s%s", sep, get_tok_str(arg->v & ~SYM_FIELD, NULL));
- sep = ",";
- arg = arg->next;
- }
- fprintf(tcc_state->ppfp, ")");
- }
-
- str = s->d;
- if (str)
- fprintf(tcc_state->ppfp, " ");
-
- while (str) {
- TOK_GET(&t, &str, &cval);
- if (!t)
- break;
- fprintf(tcc_state->ppfp, "%s", get_tok_str(t, &cval));
- }
-}
-
/* defines handling */
ST_INLN void define_push(int v, int macro_type, int *str, Sym *first_arg)
{
@@ -1101,7 +1058,6 @@ ST_INLN void define_push(int v, int macro_type, int *str, Sym *first_arg)
s->d = str;
s->next = first_arg;
table_ident[v - TOK_IDENT]->sym_define = s;
- define_print(s, 0);
}
/* undefined a define symbol. Its name is just set to zero */
@@ -1109,10 +1065,8 @@ ST_FUNC void define_undef(Sym *s)
{
int v;
v = s->v;
- if (v >= TOK_IDENT && v < tok_ident) {
- define_print(s, 1);
+ if (v >= TOK_IDENT && v < tok_ident)
table_ident[v - TOK_IDENT]->sym_define = NULL;
- }
}
ST_INLN Sym *define_find(int v)
@@ -1144,22 +1098,6 @@ ST_FUNC void free_defines(Sym *b)
define_stack = b;
}
-ST_FUNC void print_defines(void)
-{
- Sym *top, *s;
- int v;
-
- top = define_stack;
- while (top) {
- v = top->v;
- if (v >= TOK_IDENT && v < tok_ident) {
- s = table_ident[v - TOK_IDENT]->sym_define;
- define_print(s, 0);
- }
- top = top->prev;
- }
-}
-
/* label lookup */
ST_FUNC Sym *label_find(int v)
{
@@ -1241,20 +1179,59 @@ static int expr_preprocess(void)
tok_str_add(&str, -1); /* simulate end of file */
tok_str_add(&str, 0);
/* now evaluate C constant expression */
- macro_ptr = str.str;
+ begin_macro(&str, 0);
next();
c = expr_const();
- macro_ptr = NULL;
- tok_str_free(str.str);
+ end_macro();
return c != 0;
}
+//#define PP_DEBUG
+
+#if defined(PARSE_DEBUG) || defined(PP_DEBUG)
+static void tok_print(const char *msg, const int *str)
+{
+ int t;
+ CValue cval;
+
+ printf("%s ", msg);
+ while (1) {
+ TOK_GET(&t, &str, &cval);
+ if (!t)
+ break;
+ printf("%s", get_tok_str(t, &cval));
+ }
+ printf("\n");
+}
+
+static void define_print(int v)
+{
+ Sym *s, *a;
+
+ s = define_find(v);
+ printf("#define %s", get_tok_str(v, NULL));
+ if (s->type.t == MACRO_FUNC) {
+ a = s->next;
+ printf("(");
+ if (a)
+ for (;;) {
+ printf("%s", get_tok_str(a->v & ~SYM_FIELD, NULL));
+ if (!(a = a->next))
+ break;
+ printf(",");
+ }
+ printf(")");
+ }
+ tok_print("", s->d);
+}
+#endif
+
/* parse after #define */
ST_FUNC void parse_define(void)
{
Sym *s, *first, **ps;
- int v, t, varg, is_vaargs, spc, ptok, macro_list_start;
- int saved_parse_flags;
+ int v, t, varg, is_vaargs, spc;
+ int saved_parse_flags = parse_flags;
TokenString str;
v = tok;
@@ -1264,11 +1241,12 @@ ST_FUNC void parse_define(void)
first = NULL;
t = MACRO_OBJ;
/* '(' must be just after macro definition for MACRO_FUNC */
+ parse_flags |= PARSE_FLAG_SPACES;
next_nomacro_spc();
if (tok == '(') {
next_nomacro();
ps = &first;
- while (tok != ')') {
+ if (tok != ')') for (;;) {
varg = tok;
next_nomacro();
is_vaargs = 0;
@@ -1280,12 +1258,15 @@ ST_FUNC void parse_define(void)
next_nomacro();
}
if (varg < TOK_IDENT)
- tcc_error( "\'%s\' may not appear in parameter list", get_tok_str(varg, NULL));
+ bad_list:
+ tcc_error("bad macro parameter list");
s = sym_push2(&define_stack, varg | SYM_FIELD, is_vaargs, 0);
*ps = s;
ps = &s->next;
- if (tok != ',')
- continue;
+ if (tok == ')')
+ break;
+ if (tok != ',' || is_vaargs)
+ goto bad_list;
next_nomacro();
}
next_nomacro_spc();
@@ -1293,37 +1274,36 @@ ST_FUNC void parse_define(void)
}
tok_str_new(&str);
spc = 2;
- /* EOF testing necessary for '-D' handling */
- ptok = 0;
- macro_list_start = 1;
- saved_parse_flags = parse_flags;
parse_flags |= PARSE_FLAG_ACCEPT_STRAYS | PARSE_FLAG_SPACES | PARSE_FLAG_LINEFEED;
while (tok != TOK_LINEFEED && tok != TOK_EOF) {
- if (macro_list_start && spc == 2 && tok == TOK_TWOSHARPS)
- tcc_error("'##' invalid at start of macro");
- ptok = tok;
/* remove spaces around ## and after '#' */
if (TOK_TWOSHARPS == tok) {
+ if (2 == spc)
+ goto bad_twosharp;
if (1 == spc)
--str.len;
- spc = 2;
+ spc = 3;
} else if ('#' == tok) {
- spc = 2;
+ spc = 4;
} else if (check_space(tok, &spc)) {
goto skip;
}
tok_str_add2(&str, tok, &tokc);
- macro_list_start = 0;
skip:
next_nomacro_spc();
}
+
parse_flags = saved_parse_flags;
- if (ptok == TOK_TWOSHARPS)
- tcc_error("'##' invalid at end of macro");
if (spc == 1)
--str.len; /* remove trailing space */
tok_str_add(&str, 0);
+ if (3 == spc)
+bad_twosharp:
+ tcc_error("'##' cannot appear at either end of macro");
define_push(v, t, str.str, first);
+#ifdef PP_DEBUG
+ define_print(v);
+#endif
}
static inline int hash_cached_include(const char *filename)
@@ -1381,14 +1361,49 @@ static inline void add_cached_include(TCCState *s1, const char *filename, int if
static void pragma_parse(TCCState *s1)
{
next_nomacro();
- if (tok == TOK_pack) {
- /*
- This may be:
- #pragma pack(1) // set
- #pragma pack() // reset to default
- #pragma pack(push,1) // push & set
- #pragma pack(pop) // restore previous
- */
+ if (tok == TOK_push_macro || tok == TOK_pop_macro) {
+ int t = tok, v;
+ Sym *s;
+
+ if (next(), tok != '(')
+ goto pragma_err;
+ if (next(), tok != TOK_STR)
+ goto pragma_err;
+ v = tok_alloc(tokc.cstr->data, tokc.cstr->size - 1)->tok;
+ if (next(), tok != ')')
+ goto pragma_err;
+ if (t == TOK_push_macro) {
+ while (NULL == (s = define_find(v)))
+ define_push(v, 0, NULL, NULL);
+ s->type.ref = s; /* set push boundary */
+ } else {
+ for (s = define_stack; s; s = s->prev)
+ if (s->v == v && s->type.ref == s) {
+ s->type.ref = NULL;
+ break;
+ }
+ }
+ if (s)
+ table_ident[v - TOK_IDENT]->sym_define = s->d ? s : NULL;
+ else
+ tcc_warning("unbalanced #pragma pop_macro");
+
+ } else if (tok == TOK_once) {
+ add_cached_include(s1, file->filename, TOK_once);
+
+ } else if (s1->ppfp) {
+ /* tcc -E: keep pragmas below unchanged */
+ unget_tok(' ');
+ unget_tok(TOK_PRAGMA);
+ unget_tok('#');
+ unget_tok(TOK_LINEFEED);
+
+ } else if (tok == TOK_pack) {
+ /* This may be:
+ #pragma pack(1) // set
+ #pragma pack() // reset to default
+ #pragma pack(push,1) // push & set
+ #pragma pack(pop) // restore previous */
next();
skip('(');
if (tok == TOK_ASM_pop) {
@@ -1419,81 +1434,32 @@ static void pragma_parse(TCCState *s1)
}
if (tok != ')')
goto pragma_err;
- } else if (tok == TOK_comment) {
- if (s1->ms_extensions) {
- next();
- skip('(');
- if (tok == TOK_lib) {
- next();
- skip(',');
- if (tok != TOK_STR) {
- tcc_error("invalid library specification");
- } else {
- int len = strlen((char *)tokc.cstr->data);
- char *file = tcc_malloc(len + 4); /* filetype, "-l", and \0 at the end */
- file[0] = TCC_FILETYPE_BINARY;
- file[1] = '-';
- file[2] = 'l';
- strcpy(&file[3],(char *)tokc.cstr->data);
- dynarray_add((void ***)&s1->files, &s1->nb_files, file);
- }
- next();
- tok = TOK_LINEFEED;
- } else {
- tcc_warning("unknown specifier '%s' in #pragma comment", get_tok_str(tok, &tokc));
- }
- } else {
- tcc_warning("#pragma comment(lib) is ignored");
- }
- } else if (tok == TOK_push_macro || tok == TOK_pop_macro) {
- int t = tok, v;
- Sym *s;
- if (next_nomacro(), tok != '(')
- goto pragma_err;
- if (next_nomacro(), tok != TOK_STR)
+ } else if (tok == TOK_comment) {
+ char *file;
+ next();
+ skip('(');
+ if (tok != TOK_lib)
+ goto pragma_warn;
+ next();
+ skip(',');
+ if (tok != TOK_STR)
goto pragma_err;
- v = tok_alloc(tokc.cstr->data, tokc.cstr->size - 1)->tok;
- if (next_nomacro(), tok != ')')
+ file = tcc_strdup((char *)tokc.cstr->data);
+ dynarray_add((void ***)&s1->pragma_libs, &s1->nb_pragma_libs, file);
+ next();
+ if (tok != ')')
goto pragma_err;
- if (t == TOK_push_macro) {
- while (NULL == (s = define_find(v)))
- define_push(v, 0, NULL, NULL);
- s->type.ref = s; /* set push boundary */
- } else {
- for (s = define_stack; s; s = s->prev)
- if (s->v == v && s->type.ref == s) {
- s->type.ref = NULL;
- break;
- }
- }
- if (s)
- table_ident[v - TOK_IDENT]->sym_define = s->d ? s : NULL;
- else
- tcc_warning("unbalanced #pragma pop_macro");
-
- /* print info when tcc is called with "-E -dD" switches */
- if (s1->dflag && s1->ppfp) {
- if (file) {
- int c = file->line_num - file->line_ref - 1;
- if (c > 0) {
- while (c--)
- fputs("\n", tcc_state->ppfp);
- file->line_ref = file->line_num;
- }
- }
- fprintf(s1->ppfp, "// #pragma %s_macro(\"%s\")",
- (t == TOK_push_macro) ? "push" : "pop",
- get_tok_str(v, NULL));
- }
- } else if (tok == TOK_once) {
- add_cached_include(s1, file->filename, TOK_once);
} else {
- tcc_warning("unknown #pragma %s", get_tok_str(tok, &tokc));
+pragma_warn:
+ if (s1->warn_unsupported)
+ tcc_warning("#pragma %s is ignored", get_tok_str(tok, &tokc));
}
return;
+
pragma_err:
tcc_error("malformed #pragma directive");
+ return;
}
/* is_bof is true if first non space token at beginning of file */
@@ -1505,9 +1471,13 @@ ST_FUNC void preprocess(int is_bof)
Sym *s;
saved_parse_flags = parse_flags;
- parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM |
- PARSE_FLAG_LINEFEED;
- parse_flags |= (saved_parse_flags & PARSE_FLAG_ASM_FILE);
+ parse_flags = PARSE_FLAG_PREPROCESS
+ | PARSE_FLAG_TOK_NUM
+ | PARSE_FLAG_TOK_STR
+ | PARSE_FLAG_LINEFEED
+ | (parse_flags & PARSE_FLAG_ASM_FILE)
+ ;
+
next_nomacro();
redo:
switch(tok) {
@@ -1735,29 +1705,29 @@ include_done:
goto the_end;
}
break;
+ case TOK_PPNUM:
+ n = strtoul((char*)tokc.cstr->data, &q, 10);
+ goto _line_num;
case TOK_LINE:
next();
if (tok != TOK_CINT)
- tcc_error("A #line format is wrong");
- case TOK_PPNUM:
- if (tok != TOK_CINT) {
- char *p = tokc.cstr->data;
- tokc.i = strtoul(p, (char **)&p, 10);
- }
- i = file->line_num;
- file->line_num = tokc.i - 1;
+_line_err:
+ tcc_error("wrong #line format");
+ n = tokc.i;
+_line_num:
next();
if (tok != TOK_LINEFEED) {
- if (tok != TOK_STR) {
- if ((parse_flags & PARSE_FLAG_ASM_FILE) == 0) {
- file->line_num = i;
- tcc_error("#line format is wrong");
- }
- break;
- }
- pstrcpy(file->filename, sizeof(file->filename),
- (char *)tokc.cstr->data);
+ if (tok == TOK_STR)
+ pstrcpy(file->filename, sizeof(file->filename), (char *)tokc.cstr->data);
+ else if (parse_flags & PARSE_FLAG_ASM_FILE)
+ break;
+ else
+ goto _line_err;
+ --n;
}
+ if (file->fd > 0)
+ total_lines += file->line_num - n;
+ file->line_num = n;
if (s1->do_debug)
put_stabs(file->filename, N_BINCL, 0, 0, 0);
break;
@@ -1785,20 +1755,19 @@ include_done:
case TOK_PRAGMA:
pragma_parse(s1);
break;
+ case TOK_LINEFEED:
+ goto the_end;
default:
- if (tok == TOK_LINEFEED || tok == '!' || tok == TOK_PPNUM) {
- /* '!' is ignored to allow C scripts. numbers are ignored
- to emulate cpp behaviour */
- } else {
- if (!(parse_flags & PARSE_FLAG_ASM_FILE))
- tcc_warning("Ignoring unknown preprocessing directive #%s", get_tok_str(tok, &tokc));
- else {
- /* this is a gas line comment in an 'S' file. */
- file->buf_ptr = parse_line_comment(file->buf_ptr);
- goto the_end;
- }
- }
- break;
+ /* ignore gas line comment in an 'S' file. */
+ if (saved_parse_flags & PARSE_FLAG_ASM_FILE)
+ goto ignore;
+ if (tok == '!' && is_bof)
+ /* '!' is ignored at beginning to allow C scripts. */
+ goto ignore;
+ tcc_warning("Ignoring unknown preprocessing directive #%s", get_tok_str(tok, &tokc));
+ ignore:
+ file->buf_ptr = parse_line_comment(file->buf_ptr);
+ goto the_end;
}
/* ignore other preprocess commands or #! for C scripts */
while (tok != TOK_LINEFEED)
@@ -1914,6 +1883,52 @@ static void parse_escape_string(CString *outstr, const uint8_t *buf, int is_long
cstr_wccat(outstr, '\0');
}
+void parse_string(const char *s, int len)
+{
+ uint8_t buf[1000], *p = buf;
+ int is_long, sep;
+
+ if ((is_long = *s == 'L'))
+ ++s, --len;
+ sep = *s++;
+ len -= 2;
+ if (len >= sizeof buf)
+ p = tcc_malloc(len + 1);
+ memcpy(p, s, len);
+ p[len] = 0;
+
+ cstr_reset(&tokcstr);
+ parse_escape_string(&tokcstr, p, is_long);
+ if (p != buf)
+ tcc_free(p);
+
+ if (sep == '\'') {
+ int char_size;
+ /* XXX: make it portable */
+ if (!is_long)
+ char_size = 1;
+ else
+ char_size = sizeof(nwchar_t);
+ if (tokcstr.size <= char_size)
+ tcc_error("empty character constant");
+ if (tokcstr.size > 2 * char_size)
+ tcc_warning("multi-character character constant");
+ if (!is_long) {
+ tokc.i = *(int8_t *)tokcstr.data;
+ tok = TOK_CCHAR;
+ } else {
+ tokc.i = *(nwchar_t *)tokcstr.data;
+ tok = TOK_LCHAR;
+ }
+ } else {
+ tokc.cstr = &tokcstr;
+ if (!is_long)
+ tok = TOK_STR;
+ else
+ tok = TOK_LSTR;
+ }
+}
+
/* we use 64 bit numbers */
#define BN_SIZE 2
@@ -2256,7 +2271,11 @@ static inline void next_nomacro1(void)
case '\t':
tok = c;
p++;
- goto keep_tok_flags;
+ if (parse_flags & PARSE_FLAG_SPACES)
+ goto keep_tok_flags;
+ while (isidnum_table[*p - CH_EOF] & IS_SPC)
+ ++p;
+ goto redo_no_start;
case '\f':
case '\v':
case '\r':
@@ -2264,28 +2283,12 @@ static inline void next_nomacro1(void)
goto redo_no_start;
case '\\':
/* first look if it is in fact an end of buffer */
- if (p >= file->buf_end) {
- file->buf_ptr = p;
- handle_eob();
- p = file->buf_ptr;
- if (p >= file->buf_end)
- goto parse_eof;
- else
- goto redo_no_start;
- } else {
- file->buf_ptr = p;
- ch = *p;
- if (parse_flags & PARSE_FLAG_ACCEPT_STRAYS) {
- if (handle_stray_noerror() != 0) {
- goto parse_simple;
- }
- } else {
- handle_stray();
- }
- p = file->buf_ptr;
+ c = handle_stray1(p);
+ p = file->buf_ptr;
+ if (c == '\\')
+ goto parse_simple;
+ if (c != CH_EOF)
goto redo_no_start;
- }
- parse_eof:
{
TCCState *s1 = tcc_state;
if ((parse_flags & PARSE_FLAG_LINEFEED)
@@ -2340,11 +2343,6 @@ maybe_newline:
case '#':
/* XXX: simplify */
PEEKC(c, p);
- if (is_space(c) && (parse_flags & PARSE_FLAG_ASM_FILE)) {
- p = parse_line_comment(p);
- goto redo_no_start;
- }
- else
if ((tok_flags & TOK_FLAG_BOL) &&
(parse_flags & PARSE_FLAG_PREPROCESS)) {
file->buf_ptr = p;
@@ -2368,8 +2366,9 @@ maybe_newline:
/* dollar is allowed to start identifiers when not parsing asm */
case '$':
- if (!tcc_state->dollars_in_identifiers
- || (parse_flags & PARSE_FLAG_ASM_FILE)) goto parse_simple;
+ if (!(isidnum_table[c - CH_EOF] & IS_ID)
+ || (parse_flags & PARSE_FLAG_ASM_FILE))
+ goto parse_simple;
case 'a': case 'b': case 'c': case 'd':
case 'e': case 'f': case 'g': case 'h':
@@ -2390,15 +2389,8 @@ maybe_newline:
p1 = p;
h = TOK_HASH_INIT;
h = TOK_HASH_FUNC(h, c);
- p++;
- for(;;) {
- c = *p;
- if (!isidnum_table[c-CH_EOF]
- && (tcc_state->dollars_in_identifiers ? (c != '$') : 1))
- break;
+ while (c = *++p, isidnum_table[c - CH_EOF] & (IS_ID|IS_NUM))
h = TOK_HASH_FUNC(h, c);
- p++;
- }
if (c != '\\') {
TokenSym **pts;
int len;
@@ -2429,8 +2421,7 @@ maybe_newline:
p--;
PEEKC(c, p);
parse_ident_slow:
- while (isidnum_table[c-CH_EOF]
- || (tcc_state->dollars_in_identifiers ? (c == '$') : 0)) {
+ while (isidnum_table[c - CH_EOF] & (IS_ID|IS_NUM)) {
cstr_ccat(&tokcstr, c);
PEEKC(c, p);
}
@@ -2455,10 +2446,10 @@ maybe_newline:
}
}
break;
+
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
case '8': case '9':
-
cstr_reset(&tokcstr);
/* after the first digit, accept digits, alpha, '.' or sign if
prefixed by 'eEpP' */
@@ -2467,9 +2458,11 @@ maybe_newline:
t = c;
cstr_ccat(&tokcstr, c);
PEEKC(c, p);
- if (!(isnum(c) || isid(c) || c == '.' ||
- ((c == '+' || c == '-') &&
- (t == 'e' || t == 'E' || t == 'p' || t == 'P'))))
+ if (!((isidnum_table[c - CH_EOF] & (IS_ID|IS_NUM))
+ || c == '.'
+ || ((c == '+' || c == '-')
+ && (t == 'e' || t == 'E' || t == 'p' || t == 'P')
+ )))
break;
}
/* We add a trailing '\0' to ease parsing */
@@ -2477,6 +2470,7 @@ maybe_newline:
tokc.cstr = &tokcstr;
tok = TOK_PPNUM;
break;
+
case '.':
/* special dot handling because it can also start a number */
PEEKC(c, p);
@@ -2486,12 +2480,8 @@ maybe_newline:
goto parse_num;
} else if (c == '.') {
PEEKC(c, p);
- if (c != '.') {
- if ((parse_flags & PARSE_FLAG_ASM_FILE) == 0)
- expect("'.'");
- tok = '.';
- break;
- }
+ if (c != '.')
+ expect("'.'");
PEEKC(c, p);
tok = TOK_DOTS;
} else {
@@ -2502,48 +2492,15 @@ maybe_newline:
case '\"':
is_long = 0;
str_const:
- {
- CString str;
- int sep;
-
- sep = c;
-
- /* parse the string */
- cstr_new(&str);
- p = parse_pp_string(p, sep, &str);
- cstr_ccat(&str, '\0');
-
- /* eval the escape (should be done as TOK_PPNUM) */
- cstr_reset(&tokcstr);
- parse_escape_string(&tokcstr, str.data, is_long);
- cstr_free(&str);
-
- if (sep == '\'') {
- int char_size;
- /* XXX: make it portable */
- if (!is_long)
- char_size = 1;
- else
- char_size = sizeof(nwchar_t);
- if (tokcstr.size <= char_size)
- tcc_error("empty character constant");
- if (tokcstr.size > 2 * char_size)
- tcc_warning("multi-character character constant");
- if (!is_long) {
- tokc.i = *(int8_t *)tokcstr.data;
- tok = TOK_CCHAR;
- } else {
- tokc.i = *(nwchar_t *)tokcstr.data;
- tok = TOK_LCHAR;
- }
- } else {
- tokc.cstr = &tokcstr;
- if (!is_long)
- tok = TOK_STR;
- else
- tok = TOK_LSTR;
- }
- }
+ cstr_reset(&tokcstr);
+ if (is_long)
+ cstr_ccat(&tokcstr, 'L');
+ cstr_ccat(&tokcstr, c);
+ p = parse_pp_string(p, c, &tokcstr);
+ cstr_ccat(&tokcstr, c);
+ cstr_ccat(&tokcstr, '\0');
+ tokc.cstr = &tokcstr;
+ tok = TOK_PPSTR;
break;
case '<':
@@ -2563,7 +2520,6 @@ maybe_newline:
tok = TOK_LT;
}
break;
-
case '>':
PEEKC(c, p);
if (c == '=') {
@@ -2681,12 +2637,7 @@ maybe_newline:
p++;
break;
default:
- if ((parse_flags & PARSE_FLAG_ASM_FILE) == 0)
- tcc_error("unrecognized character \\x%02x", c);
- else {
- tok = ' ';
- p++;
- }
+ tcc_error("unrecognized character \\x%02x", c);
break;
}
tok_flags = 0;
@@ -2720,23 +2671,30 @@ ST_FUNC void next_nomacro(void)
{
do {
next_nomacro_spc();
- } while (is_space(tok));
+ } while (tok < 256 && (isidnum_table[tok - CH_EOF] & IS_SPC));
}
+
+static void macro_subst(
+ TokenString *tok_str,
+ Sym **nested_list,
+ const int *macro_str,
+ int can_read_stream
+ );
+
/* substitute arguments in replacement lists in macro_str by the values in
args (field d) and return allocated string */
static int *macro_arg_subst(Sym **nested_list, const int *macro_str, Sym *args)
{
- int last_tok, t, spc;
+ int t, t0, t1, spc;
const int *st;
Sym *s;
CValue cval;
TokenString str;
CString cstr;
- CString cstr2;
tok_str_new(&str);
- last_tok = 0;
+ t0 = t1 = 0;
while(1) {
TOK_GET(&t, &macro_str, &cval);
if (!t)
@@ -2745,73 +2703,86 @@ static int *macro_arg_subst(Sym **nested_list, const int *macro_str, Sym *args)
/* stringize */
TOK_GET(&t, &macro_str, &cval);
if (!t)
- break;
+ goto bad_stringy;
s = sym_find2(args, t);
if (s) {
cstr_new(&cstr);
+ cstr_ccat(&cstr, '\"');
st = s->d;
spc = 0;
while (*st) {
TOK_GET(&t, &st, &cval);
- if (t != TOK_PLCHLDR && !check_space(t, &spc))
- cstr_cat(&cstr, get_tok_str(t, &cval));
+ if (t != TOK_PLCHLDR
+ && t != TOK_NOSUBST
+ && 0 == check_space(t, &spc)) {
+ const char *s = get_tok_str(t, &cval);
+ while (*s) {
+ if (t == TOK_PPSTR && *s != '\'')
+ add_char(&cstr, *s);
+ else
+ cstr_ccat(&cstr, *s);
+ ++s;
+ }
+ }
}
cstr.size -= spc;
+ cstr_ccat(&cstr, '\"');
cstr_ccat(&cstr, '\0');
#ifdef PP_DEBUG
- printf("stringize: %s\n", (char *)cstr.data);
+ printf("\nstringize: <%s>\n", (char *)cstr.data);
#endif
/* add string */
- cstr_new(&cstr2);
- /* emulate GCC behaviour and parse escapes in the token string */
- parse_escape_string(&cstr2, cstr.data, 0);
- cstr_free(&cstr);
- cval.cstr = &cstr2;
- tok_str_add2(&str, TOK_STR, &cval);
+ cval.cstr = &cstr;
+ tok_str_add2(&str, TOK_PPSTR, &cval);
cstr_free(cval.cstr);
} else {
- tok_str_add2(&str, t, &cval);
+ bad_stringy:
+ expect("macro parameter after '#'");
}
} else if (t >= TOK_IDENT) {
s = sym_find2(args, t);
if (s) {
+ int l0 = str.len;
st = s->d;
/* if '##' is present before or after, no arg substitution */
- if (*macro_str == TOK_TWOSHARPS || last_tok == TOK_TWOSHARPS) {
- /* special case for var arg macros : ## eats the
- ',' if empty VA_ARGS variable. */
- /* XXX: test of the ',' is not 100%
- reliable. should fix it to avoid security
- problems */
- if (gnu_ext && s->type.t &&
- last_tok == TOK_TWOSHARPS &&
- str.len >= 2 && str.str[str.len - 2] == ',') {
- str.len -= 2;
- tok_str_add(&str, TOK_GNUCOMMA);
+ if (*macro_str == TOK_TWOSHARPS || t1 == TOK_TWOSHARPS) {
+ /* special case for var arg macros : ## eats the ','
+ if empty VA_ARGS variable. */
+ if (t1 == TOK_TWOSHARPS && t0 == ',' && gnu_ext && s->type.t) {
+ if (*st == 0) {
+ /* suppress ',' '##' */
+ str.len -= 2;
+ } else {
+ /* suppress '##' and add variable */
+ str.len--;
+ goto add_var;
+ }
+ } else {
+ for(;;) {
+ int t1;
+ TOK_GET(&t1, &st, &cval);
+ if (!t1)
+ break;
+ tok_str_add2(&str, t1, &cval);
+ }
}
- for(;;) {
- int t1;
- TOK_GET(&t1, &st, &cval);
- if (!t1)
- break;
- tok_str_add2(&str, t1, &cval);
- }
} else {
+ add_var:
/* NOTE: the stream cannot be read when macro
substituing an argument */
- macro_subst(&str, nested_list, st, NULL);
+ macro_subst(&str, nested_list, st, 0);
}
+ if (str.len == l0) /* exanded to empty string */
+ tok_str_add(&str, TOK_PLCHLDR);
} else {
tok_str_add(&str, t);
}
} else {
tok_str_add2(&str, t, &cval);
}
- last_tok = t;
+ t0 = t1, t1 = t;
}
- if (str.len == 0)
- tok_str_add(&str, TOK_PLCHLDR);
tok_str_add(&str, 0);
return str.str;
}
@@ -2822,16 +2793,75 @@ static char const ab_month_name[12][4] =
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
+/* peek or read [ws_str == NULL] next token from function macro call,
+ walking up macro levels up to the file if necessary */
+static int next_argstream(Sym **nested_list, int can_read_stream, TokenString *ws_str)
+{
+ int t;
+ const int *p;
+ Sym *sa;
+
+ for (;;) {
+ if (macro_ptr) {
+ p = macro_ptr, t = *p;
+ if (ws_str) {
+ while (is_space(t) || TOK_LINEFEED == t)
+ tok_str_add(ws_str, t), t = *++p;
+ }
+ if (t == 0 && can_read_stream) {
+ end_macro();
+ /* also, end of scope for nested defined symbol */
+ sa = *nested_list;
+ while (sa && sa->v == -1)
+ sa = sa->prev;
+ if (sa)
+ sa->v = -1;
+ continue;
+ }
+ } else {
+ ch = handle_eob();
+ if (ws_str) {
+ while (is_space(ch) || ch == '\n' || ch == '/') {
+ if (ch == '/') {
+ int c;
+ uint8_t *p = file->buf_ptr;
+ PEEKC(c, p);
+ if (c == '*') {
+ p = parse_comment(p);
+ file->buf_ptr = p - 1;
+ } else if (c == '/') {
+ p = parse_line_comment(p);
+ file->buf_ptr = p - 1;
+ } else
+ break;
+ ch = ' ';
+ }
+ tok_str_add(ws_str, ch);
+ cinp();
+ }
+ }
+ t = ch;
+ }
+
+ if (ws_str)
+ return t;
+ next_nomacro_spc();
+ return tok;
+ }
+}
+
/* do macro substitution of current token with macro 's' and add
result to (tok_str,tok_len). 'nested_list' is the list of all
macros we got inside to avoid recursing. Return non zero if no
substitution needs to be done */
-static int macro_subst_tok(TokenString *tok_str,
- Sym **nested_list, Sym *s, struct macro_level **can_read_stream)
+static int macro_subst_tok(
+ TokenString *tok_str,
+ Sym **nested_list,
+ Sym *s,
+ int can_read_stream)
{
Sym *args, *sa, *sa1;
- int mstr_allocated, parlevel, *mstr, t, t1, spc;
- const int *p;
+ int parlevel, *mstr, t, t1, spc;
TokenString str;
char *cstrval;
CValue cval;
@@ -2872,89 +2902,48 @@ static int macro_subst_tok(TokenString *tok_str,
tok_str_add2(tok_str, t1, &cval);
cstr_free(&cstr);
} else {
- int mtok = tok;
int saved_parse_flags = parse_flags;
- parse_flags |= PARSE_FLAG_ACCEPT_STRAYS | PARSE_FLAG_SPACES | PARSE_FLAG_LINEFEED;
mstr = s->d;
- mstr_allocated = 0;
if (s->type.t == MACRO_FUNC) {
- TokenString ws_str; /* whitespace between macro name and
- * argument list */
+ /* whitespace between macro name and argument list */
+ TokenString ws_str;
tok_str_new(&ws_str);
+
spc = 0;
- /* NOTE: we do not use next_nomacro to avoid eating the
- next token. XXX: find better solution */
- redo:
- if (macro_ptr) {
- p = macro_ptr;
- while (is_space(t = *p) || TOK_LINEFEED == t) {
- if (saved_parse_flags & PARSE_FLAG_SPACES)
- tok_str_add(&ws_str, t);
- ++p;
- }
- if (t == 0 && can_read_stream) {
- /* end of macro stream: we must look at the token
- after in the file */
- struct macro_level *ml = *can_read_stream;
- macro_ptr = NULL;
- if (ml)
- {
- macro_ptr = ml->p;
- ml->p = NULL;
- *can_read_stream = ml -> prev;
- }
- /* also, end of scope for nested defined symbol */
- (*nested_list)->v = -1;
- goto redo;
- }
- } else {
- ch = tcc_peekc_slow(file);
- while (is_space(ch) || ch == '\n' || ch == '/')
- {
- if (ch == '/')
- {
- int c;
- uint8_t *p = file->buf_ptr;
- PEEKC(c, p);
- if (c == '*') {
- p = parse_comment(p);
- file->buf_ptr = p - 1;
- } else if (c == '/') {
- p = parse_line_comment(p);
- file->buf_ptr = p - 1;
- } else
- break;
- ch = ' ';
- }
- if (saved_parse_flags & PARSE_FLAG_SPACES)
- tok_str_add(&ws_str, ch);
- cinp();
- }
- t = ch;
- }
+ parse_flags |= PARSE_FLAG_SPACES | PARSE_FLAG_LINEFEED
+ | PARSE_FLAG_ACCEPT_STRAYS;
+
+ /* get next token from argument stream */
+ t = next_argstream(nested_list, can_read_stream, &ws_str);
if (t != '(') {
/* not a macro substitution after all, restore the
* macro token plus all whitespace we've read.
* whitespace is intentionally not merged to preserve
* newlines. */
- int i;
- tok_str_add(tok_str, mtok);
- for(i=0; i<ws_str.len; i++)
- tok_str_add(tok_str, ws_str.str[i]);
- tok_str_free(ws_str.str);
parse_flags = saved_parse_flags;
- return -1;
+ tok_str_add(tok_str, tok);
+ if (parse_flags & PARSE_FLAG_SPACES) {
+ int i;
+ for (i = 0; i < ws_str.len; i++)
+ tok_str_add(tok_str, ws_str.str[i]);
+ }
+ tok_str_free(ws_str.str);
+ return 0;
} else {
tok_str_free(ws_str.str);
}
+ next_nomacro(); /* eat '(' */
+
/* argument macro */
- next_nomacro();
- next_nomacro();
args = NULL;
sa = s->next;
/* NOTE: empty args are allowed, except if no args */
for(;;) {
+ do {
+ next_argstream(nested_list, can_read_stream, NULL);
+ } while (is_space(tok) || TOK_LINEFEED == tok);
+ empty_arg:
/* handle '()' case */
if (!args && !sa && tok == ')')
break;
@@ -2977,13 +2966,11 @@ static int macro_subst_tok(TokenString *tok_str,
tok = ' ';
if (!check_space(tok, &spc))
tok_str_add2(&str, tok, &tokc);
- next_nomacro_spc();
+ next_argstream(nested_list, can_read_stream, NULL);
}
if (parlevel)
expect(")");
str.len -= spc;
- if (str.len == 0)
- tok_str_add(&str, TOK_PLCHLDR);
tok_str_add(&str, 0);
sa1 = sym_push2(&args, sa->v & ~SYM_FIELD, sa->type.t, 0);
sa1->d = str.str;
@@ -2992,19 +2979,19 @@ static int macro_subst_tok(TokenString *tok_str,
/* special case for gcc var args: add an empty
var arg argument if it is omitted */
if (sa && sa->type.t && gnu_ext)
- continue;
- else
- break;
+ goto empty_arg;
+ break;
}
if (tok != ',')
expect(",");
- next_nomacro();
}
if (sa) {
tcc_error("macro '%s' used with too few args",
get_tok_str(s->v, 0));
}
+ parse_flags = saved_parse_flags;
+
/* now subst each arg */
mstr = macro_arg_subst(nested_list, mstr, args);
/* free memory */
@@ -3015,258 +3002,232 @@ static int macro_subst_tok(TokenString *tok_str,
sym_free(sa);
sa = sa1;
}
- mstr_allocated = 1;
}
+
sym_push2(nested_list, s->v, 0, 0);
parse_flags = saved_parse_flags;
macro_subst(tok_str, nested_list, mstr, can_read_stream);
+
/* pop nested defined symbol */
sa1 = *nested_list;
*nested_list = sa1->prev;
sym_free(sa1);
- if (mstr_allocated)
+ if (mstr != s->d)
tok_str_free(mstr);
}
return 0;
}
+int paste_tokens(int t1, CValue *v1, int t2, CValue *v2)
+{
+ CString cstr;
+ int n;
+
+ cstr_new(&cstr);
+ if (t1 != TOK_PLCHLDR)
+ cstr_cat(&cstr, get_tok_str(t1, v1));
+ n = cstr.size;
+ if (t2 != TOK_PLCHLDR)
+ cstr_cat(&cstr, get_tok_str(t2, v2));
+ cstr_ccat(&cstr, '\0');
+
+ tcc_open_bf(tcc_state, ":paste:", cstr.size);
+ memcpy(file->buffer, cstr.data, cstr.size);
+ for (;;) {
+ next_nomacro1();
+ if (0 == *file->buf_ptr)
+ break;
+ if (is_space(tok))
+ continue;
+ tcc_warning("pasting <%.*s> and <%s> does not give a valid preprocessing token",
+ n, cstr.data, (char*)cstr.data + n);
+ break;
+ }
+ tcc_close();
+
+ //printf("paste <%s>\n", (char*)cstr.data);
+ cstr_free(&cstr);
+ return 0;
+}
+
/* handle the '##' operator. Return NULL if no '##' seen. Otherwise
return the resulting string (which must be freed). */
-static inline int *macro_twosharps(const int *macro_str)
+static inline int *macro_twosharps(const int *ptr0)
{
- const int *ptr;
int t;
+ CValue cval;
TokenString macro_str1;
- CString cstr;
- int n, start_of_nosubsts;
+ int start_of_nosubsts = -1;
+ const int *ptr;
/* we search the first '##' */
- for(ptr = macro_str;;) {
- CValue cval;
+ for (ptr = ptr0;;) {
TOK_GET(&t, &ptr, &cval);
if (t == TOK_TWOSHARPS)
break;
- /* nothing more to do if end of string */
if (t == 0)
return NULL;
}
- /* we saw '##', so we need more processing to handle it */
- start_of_nosubsts = -1;
tok_str_new(&macro_str1);
- for(ptr = macro_str;;) {
- TOK_GET(&tok, &ptr, &tokc);
- if (tok == 0)
+
+ //tok_print(" $$$", ptr0);
+ for (ptr = ptr0;;) {
+ TOK_GET(&t, &ptr, &cval);
+ if (t == 0)
break;
- if (tok == TOK_TWOSHARPS)
+ if (t == TOK_TWOSHARPS)
continue;
- if (tok == TOK_NOSUBST && start_of_nosubsts < 0)
- start_of_nosubsts = macro_str1.len;
while (*ptr == TOK_TWOSHARPS) {
+ int t1; CValue cv1;
/* given 'a##b', remove nosubsts preceding 'a' */
if (start_of_nosubsts >= 0)
macro_str1.len = start_of_nosubsts;
- /* given 'a##b', skip '##' */
- t = *++ptr;
/* given 'a##b', remove nosubsts preceding 'b' */
- while (t == TOK_NOSUBST)
- t = *++ptr;
- if (t && t != TOK_TWOSHARPS) {
- CValue cval;
- TOK_GET(&t, &ptr, &cval);
- /* We concatenate the two tokens */
- cstr_new(&cstr);
- if (tok != TOK_PLCHLDR)
- cstr_cat(&cstr, get_tok_str(tok, &tokc));
- n = cstr.size;
- if (t != TOK_PLCHLDR || tok == TOK_PLCHLDR)
- cstr_cat(&cstr, get_tok_str(t, &cval));
- cstr_ccat(&cstr, '\0');
-
- tcc_open_bf(tcc_state, ":paste:", cstr.size);
- memcpy(file->buffer, cstr.data, cstr.size);
- for (;;) {
- next_nomacro1();
- if (0 == *file->buf_ptr)
- break;
- tok_str_add2(&macro_str1, tok, &tokc);
- tcc_warning("pasting \"%.*s\" and \"%s\" does not give a valid preprocessing token",
- n, cstr.data, (char*)cstr.data + n);
+ while ((t1 = *++ptr) == TOK_NOSUBST)
+ ;
+ if (t1 && t1 != TOK_TWOSHARPS) {
+ TOK_GET(&t1, &ptr, &cv1);
+ if (t != TOK_PLCHLDR || t1 != TOK_PLCHLDR) {
+ paste_tokens(t, &cval, t1, &cv1);
+ t = tok, cval = tokc;
}
- tcc_close();
- cstr_free(&cstr);
}
}
- if (tok != TOK_NOSUBST) {
- tok_str_add2(&macro_str1, tok, &tokc);
- tok = ' ';
+ if (t == TOK_NOSUBST) {
+ if (start_of_nosubsts < 0)
+ start_of_nosubsts = macro_str1.len;
+ } else {
start_of_nosubsts = -1;
}
- tok_str_add2(&macro_str1, tok, &tokc);
+ tok_str_add2(&macro_str1, t, &cval);
}
tok_str_add(&macro_str1, 0);
+ //tok_print(" ###", macro_str1.str);
return macro_str1.str;
}
-
/* do macro substitution of macro_str and add result to
(tok_str,tok_len). 'nested_list' is the list of all macros we got
inside to avoid recursing. */
-static void macro_subst(TokenString *tok_str, Sym **nested_list,
- const int *macro_str, struct macro_level ** can_read_stream)
+static void macro_subst(
+ TokenString *tok_str,
+ Sym **nested_list,
+ const int *macro_str,
+ int can_read_stream
+ )
{
Sym *s;
- int *macro_str1;
const int *ptr;
- int t, spc;
+ int t, spc, nosubst;
CValue cval;
- struct macro_level ml;
- int force_blank;
- int gnucomma_index = -1;
+ int *macro_str1 = NULL;
/* first scan for '##' operator handling */
ptr = macro_str;
- macro_str1 = macro_twosharps(ptr);
+ spc = nosubst = 0;
- if (macro_str1)
- ptr = macro_str1;
- spc = 0;
- force_blank = 0;
+ /* first scan for '##' operator handling */
+ if (can_read_stream) {
+ macro_str1 = macro_twosharps(ptr);
+ if (macro_str1)
+ ptr = macro_str1;
+ }
while (1) {
- /* NOTE: ptr == NULL can only happen if tokens are read from
- file stream due to a macro function call */
- if (ptr == NULL)
- break;
TOK_GET(&t, &ptr, &cval);
if (t == 0)
break;
- if (t == '\\' && !(parse_flags & PARSE_FLAG_ACCEPT_STRAYS)) {
- tcc_error("stray '\\' in program");
- }
- if (t == TOK_NOSUBST) {
- /* following token has already been subst'd. just copy it on */
- tok_str_add2(tok_str, TOK_NOSUBST, NULL);
- TOK_GET(&t, &ptr, &cval);
- goto no_subst;
- }
- if (t == TOK_GNUCOMMA) {
- if (gnucomma_index != -1)
- tcc_error("two GNU commas in the same macro");
- gnucomma_index = tok_str->len;
- tok_str_add(tok_str, ',');
- TOK_GET(&t, &ptr, &cval);
- }
- s = define_find(t);
- if (s != NULL) {
- int old_len = tok_str->len;
+
+ if (t >= TOK_IDENT && 0 == nosubst) {
+ s = define_find(t);
+ if (s == NULL)
+ goto no_subst;
+
/* if nested substitution, do nothing */
if (sym_find2(*nested_list, t)) {
/* and mark it as TOK_NOSUBST, so it doesn't get subst'd again */
tok_str_add2(tok_str, TOK_NOSUBST, NULL);
goto no_subst;
}
- ml.p = macro_ptr;
- if (can_read_stream)
- ml.prev = *can_read_stream, *can_read_stream = &ml;
- macro_ptr = (int *)ptr;
- tok = t;
- macro_subst_tok(tok_str, nested_list, s, can_read_stream);
+
+ {
+ TokenString str;
+ str.str = (int*)ptr;
+ begin_macro(&str, 2);
+
+ tok = t;
+ macro_subst_tok(tok_str, nested_list, s, can_read_stream);
+
+ if (str.alloc == 3) {
+ /* already finished by reading function macro arguments */
+ break;
+ }
+
+ ptr = macro_ptr;
+ end_macro ();
+ }
+
spc = tok_str->len && is_space(tok_str->str[tok_str->len-1]);
- ptr = (int *)macro_ptr;
- macro_ptr = ml.p;
- if (can_read_stream && *can_read_stream == &ml)
- *can_read_stream = ml.prev;
- if (parse_flags & PARSE_FLAG_SPACES)
- force_blank = 1;
- if (old_len == tok_str->len)
- tok_str_add(tok_str, TOK_PLCHLDR);
+
} else {
- no_subst:
- if (force_blank) {
- tok_str_add(tok_str, ' ');
- spc = 1;
- force_blank = 0;
- }
- if (!check_space(t, &spc))
+
+ 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 (t == TOK_NOSUBST)
+ nosubst = 1;
}
- if (gnucomma_index != -1) {
- if (tok_str->len >= gnucomma_index+2) {
- if (tok_str->str[gnucomma_index+1] == TOK_PLCHLDR)
- tok_str->len -= 2;
- gnucomma_index = -1;
- }
- }
- if (tok_str->len && tok_str->str[tok_str->len-1] == TOK_PLCHLDR)
- tok_str->len--;
}
if (macro_str1)
tok_str_free(macro_str1);
+
}
/* return next token with macro substitution */
ST_FUNC void next(void)
{
- Sym *nested_list, *s;
- TokenString str;
- struct macro_level *ml;
-
redo:
if (parse_flags & PARSE_FLAG_SPACES)
next_nomacro_spc();
else
next_nomacro();
- if (!macro_ptr) {
- /* if not reading from macro substituted string, then try
- to substitute macros */
- if (tok >= TOK_IDENT &&
- (parse_flags & PARSE_FLAG_PREPROCESS)) {
- s = define_find(tok);
- if (s) {
- /* we have a macro: we try to substitute */
- tok_str_new(&str);
- nested_list = NULL;
- ml = NULL;
- if (macro_subst_tok(&str, &nested_list, s, &ml) == 0) {
- /* substitution done, NOTE: maybe empty */
- tok_str_add(&str, 0);
- macro_ptr = str.str;
- macro_ptr_allocated = str.str;
- goto redo;
- } else {
- tok_str_add(&str, 0);
- if (str.len > 1) {
- macro_ptr = str.str + 1;
- macro_ptr_allocated = str.str;
- }
- tok = str.str[0];
- }
- }
- }
- } else {
- if (tok == 0) {
- /* end of macro or end of unget buffer */
- if (unget_buffer_enabled) {
- macro_ptr = unget_saved_macro_ptr;
- unget_buffer_enabled = 0;
- } else {
- /* end of macro string: free it */
- tok_str_free(macro_ptr_allocated);
- macro_ptr_allocated = NULL;
- macro_ptr = NULL;
- }
+
+ if (macro_ptr) {
+ if (tok == TOK_NOSUBST || tok == TOK_PLCHLDR) {
+ /* discard preprocessor markers */
goto redo;
- } else if (tok == TOK_NOSUBST) {
- /* discard preprocessor's nosubst markers */
+ } else if (tok == 0) {
+ /* end of macro or unget token string */
+ end_macro();
+ goto redo;
+ }
+ } else if (tok >= TOK_IDENT && (parse_flags & PARSE_FLAG_PREPROCESS)) {
+ Sym *s;
+ /* if reading from file, try to substitute macros */
+ s = define_find(tok);
+ if (s) {
+ static TokenString str; /* using static string for speed */
+ Sym *nested_list = NULL;
+ tok_str_new(&str);
+ nested_list = NULL;
+ macro_subst_tok(&str, &nested_list, s, 1);
+ tok_str_add(&str, 0);
+ begin_macro(&str, 0);
goto redo;
}
}
-
/* convert preprocessor tokens into C tokens */
- if (tok == TOK_PPNUM &&
- (parse_flags & PARSE_FLAG_TOK_NUM)) {
- parse_number((char *)tokc.cstr->data);
+ if (tok == TOK_PPNUM) {
+ if (parse_flags & PARSE_FLAG_TOK_NUM)
+ parse_number((char *)tokc.cstr->data);
+ } else if (tok == TOK_PPSTR) {
+ if (parse_flags & PARSE_FLAG_TOK_STR)
+ parse_string((char *)tokc.cstr->data, tokc.cstr->size - 1);
}
}
@@ -3274,29 +3235,14 @@ ST_FUNC void next(void)
identifier case handled for labels. */
ST_INLN void unget_tok(int last_tok)
{
- int i, n;
- int *q;
- if (unget_buffer_enabled)
- {
- /* assert(macro_ptr == unget_saved_buffer + 1);
- assert(*macro_ptr == 0); */
- }
- else
- {
- unget_saved_macro_ptr = macro_ptr;
- unget_buffer_enabled = 1;
- }
- q = unget_saved_buffer;
- macro_ptr = q;
- *q++ = tok;
- n = tok_ext_size(tok) - 1;
- for(i=0;i<n;i++)
- *q++ = tokc.tab[i];
- *q = 0; /* end of token string */
+ TokenString *str = tcc_malloc(sizeof *str);
+ tok_str_new(str);
+ tok_str_add2(str, tok, &tokc);
+ tok_str_add(str, 0);
+ begin_macro(str, 1);
tok = last_tok;
}
-
/* better than nothing, but needs extension to handle '-E' option
correctly too */
ST_FUNC void preprocess_init(TCCState *s1)
@@ -3307,9 +3253,12 @@ ST_FUNC void preprocess_init(TCCState *s1)
s1->ifdef_stack_ptr = s1->ifdef_stack;
file->ifdef_stack_ptr = s1->ifdef_stack_ptr;
- vtop = vstack - 1;
+ pvtop = vtop = vstack - 1;
s1->pack_stack[0] = 0;
s1->pack_stack_ptr = s1->pack_stack;
+
+ isidnum_table['$' - CH_EOF] =
+ tcc_state->dollars_in_identifiers ? IS_ID : 0;
}
ST_FUNC void preprocess_new(void)
@@ -3318,15 +3267,13 @@ ST_FUNC void preprocess_new(void)
const char *p, *r;
/* init isid table */
+ for(i = CH_EOF; i<256; i++)
+ isidnum_table[i - CH_EOF]
+ = is_space(i) ? IS_SPC
+ : isid(i) ? IS_ID
+ : isnum(i) ? IS_NUM
+ : 0;
- for(i=CH_EOF;i<256;i++)
- isidnum_table[i-CH_EOF] = isid(i) || isnum(i);
-
- /* add all tokens */
- if (table_ident) {
- tcc_free (table_ident);
- table_ident = NULL;
- }
memset(hash_ident, 0, TOK_HASH_SIZE * sizeof(TokenSym *));
tok_ident = TOK_IDENT;
@@ -3343,80 +3290,102 @@ ST_FUNC void preprocess_new(void)
}
}
-static void line_macro_output(BufferedFile *f, const char *s, TCCState *s1)
+ST_FUNC void preprocess_delete(void)
{
- switch (s1->Pflag) {
- case LINE_MACRO_OUTPUT_FORMAT_STD:
- /* "tcc -E -P1" case */
- fprintf(s1->ppfp, "# line %d \"%s\"\n", f->line_num, f->filename);
- break;
+ int i, n;
- case LINE_MACRO_OUTPUT_FORMAT_NONE:
- /* "tcc -E -P" case: don't output a line directive */
- break;
+ /* free -D and compiler defines */
+ free_defines(NULL);
- case LINE_MACRO_OUTPUT_FORMAT_GCC:
- default:
- /* "tcc -E" case: a gcc standard by default */
- fprintf(s1->ppfp, "# %d \"%s\"%s\n", f->line_num, f->filename, s);
- break;
+ /* cleanup from error/setjmp */
+ while (macro_stack)
+ end_macro();
+ macro_ptr = NULL;
+
+ /* free tokens */
+ n = tok_ident - TOK_IDENT;
+ for(i = 0; i < n; i++)
+ tcc_free(table_ident[i]);
+ tcc_free(table_ident);
+ table_ident = NULL;
+}
+
+static void pp_line(TCCState *s1, BufferedFile *f, int level)
+{
+ int d;
+ if (s1->Pflag == LINE_MACRO_OUTPUT_FORMAT_NONE)
+ return;
+ if (level == 0 && f->line_ref && (d = f->line_num - f->line_ref) < 8) {
+ while (d > 0)
+ fputs("\n", s1->ppfp), --d;
+ } else if (s1->Pflag == LINE_MACRO_OUTPUT_FORMAT_STD) {
+ fprintf(s1->ppfp, "#line %d \"%s\"\n", f->line_num, f->filename);
+ } else {
+ fprintf(s1->ppfp, "# %d \"%s\"%s\n", f->line_num, f->filename,
+ level > 0 ? " 1" : level < 0 ? " 2" : "");
}
+ f->line_ref = f->line_num;
}
/* Preprocess the current file */
ST_FUNC int tcc_preprocess(TCCState *s1)
{
- BufferedFile *file_ref, **iptr, **iptr_new;
- int token_seen, d;
- const char *s;
+ Sym *define_start;
+ BufferedFile **iptr;
+ int token_seen, spcs, level;
preprocess_init(s1);
+ define_start = define_stack;
ch = file->buf_ptr[0];
tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
- parse_flags &= PARSE_FLAG_ASM_FILE;
- parse_flags |= PARSE_FLAG_PREPROCESS | PARSE_FLAG_LINEFEED | PARSE_FLAG_SPACES | PARSE_FLAG_ACCEPT_STRAYS;
- token_seen = 0;
- file->line_ref = 0;
- file_ref = NULL;
- iptr = s1->include_stack_ptr;
+ parse_flags = PARSE_FLAG_PREPROCESS
+ | (parse_flags & PARSE_FLAG_ASM_FILE)
+ | PARSE_FLAG_LINEFEED
+ | PARSE_FLAG_SPACES
+ | PARSE_FLAG_ACCEPT_STRAYS
+ ;
+
+#ifdef PP_BENCH
+ do next(); while (tok != TOK_EOF); return 0;
+#endif
+
+ token_seen = spcs = 0;
+ pp_line(s1, file, 0);
for (;;) {
+ iptr = s1->include_stack_ptr;
next();
- if (tok == TOK_EOF) {
+ if (tok == TOK_EOF)
break;
- } else if (file != file_ref) {
- if (file_ref)
- line_macro_output(file_ref, "", s1);
- goto print_line;
- } else if (tok == TOK_LINEFEED) {
- if (!token_seen)
+ level = s1->include_stack_ptr - iptr;
+ if (level) {
+ if (level > 0)
+ pp_line(s1, *iptr, 0);
+ pp_line(s1, file, level);
+ }
+
+ if (0 == token_seen) {
+ if (tok == ' ') {
+ ++spcs;
continue;
- file->line_ref++;
- token_seen = 0;
- } else if (!token_seen) {
- d = file->line_num - file->line_ref;
- if (file != file_ref || d >= 8) {
-print_line:
- s = "";
- if (tcc_state->Pflag == LINE_MACRO_OUTPUT_FORMAT_GCC) {
- iptr_new = s1->include_stack_ptr;
- s = iptr_new > iptr ? " 1"
- : iptr_new < iptr ? " 2"
- : iptr_new > s1->include_stack ? " 3"
- : ""
- ;
- }
- line_macro_output(file, s, s1);
- } else {
- while (d > 0)
- fputs("\n", s1->ppfp), --d;
}
- file->line_ref = (file_ref = file)->line_num;
- token_seen = tok != TOK_LINEFEED;
- if (!token_seen)
+ if (tok == TOK_LINEFEED) {
+ spcs = 0;
continue;
+ }
+ pp_line(s1, file, 0);
+ while (spcs)
+ fputs(" ", s1->ppfp), --spcs;
+ token_seen = 1;
+
+ } else if (tok == TOK_LINEFEED) {
+ ++file->line_ref;
+ token_seen = 0;
}
+
fputs(get_tok_str(tok, &tokc), s1->ppfp);
}
+
+ free_defines(define_start);
return 0;
}
diff --git a/tests/Makefile b/tests/Makefile
index 98ccb1e..270eaa7 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -19,7 +19,7 @@ TESTS = \
test3 \
abitest \
vla_test-run \
- moretests
+ tests2-dir pp-dir
BTESTS = test1b test3b btest
@@ -36,7 +36,7 @@ ifneq ($(ARCH),i386)
TESTS := $(filter-out $(BTESTS),$(TESTS))
endif
ifdef CONFIG_WIN32
- TESTS := w32-prep $(filter-out $(BTESTS),$(TESTS))
+ TESTS := $(filter-out $(BTESTS),$(TESTS))
endif
ifeq ($(TARGETOS),Darwin)
TESTS := $(filter-out hello-exe test3 $(BTESTS),$(TESTS))
@@ -60,9 +60,9 @@ ifeq ($(TARGETOS),Darwin)
endif
# run local version of tcc with local libraries and includes
-TCCFLAGS = -B$(TOP) -I$(TOP) -I$(top_srcdir) -I$(top_srcdir)/include
+TCCFLAGS = -B$(TOP) -I$(TOP) -I$(top_srcdir) -I$(top_srcdir)/include -L$(TOP)
ifdef CONFIG_WIN32
- TCCFLAGS = -B$(top_srcdir)/win32 -I$(top_srcdir) -I$(top_srcdir)/include -I$(TOP) -L$(TOP)
+ TCCFLAGS = -B$(top_srcdir)/win32 -I$(top_srcdir) -I$(top_srcdir)/include -L$(TOP)
endif
XTCCFLAGS = -B$(TOP) -B$(top_srcdir)/win32 -I$(TOP) -I$(top_srcdir) -I$(top_srcdir)/include
@@ -97,17 +97,14 @@ hello-run: ../examples/ex1.c
libtest: libtcc_test$(EXESUF) $(LIBTCC1)
@echo ------------ $@ ------------
- ./libtcc_test$(EXESUF) lib_path=..
+ ./libtcc_test$(EXESUF) $(TCCFLAGS)
libtcc_test$(EXESUF): libtcc_test.c $(top_builddir)/$(LIBTCC)
$(CC) -o $@ $^ $(CPPFLAGS) $(CFLAGS) $(NATIVE_DEFINES) $(LIBS) $(LINK_LIBTCC) $(LDFLAGS) -I$(top_srcdir)
-moretests:
+%-dir:
@echo ------------ $@ ------------
- $(MAKE) -C tests2
-
-w32-prep:
- cp ../libtcc1.a ../lib
+ $(MAKE) -k -C $*
# test.ref - generate using cc
test.ref: tcctest.c
@@ -223,9 +220,8 @@ endif
abitest: $(ABITESTS)
@echo ------------ $@ ------------
- ./abitest-cc$(EXESUF) lib_path=.. include="$(top_srcdir)/include"
- if [ "$(CONFIG_arm_eabi)" != "yes" ]; then \
- ./abitest-tcc$(EXESUF) lib_path=.. include="$(top_srcdir)/include"; fi
+ ./abitest-cc$(EXESUF) $(TCCFLAGS)
+ if [ "$(CONFIG_arm_eabi)" != "yes" ]; then ./abitest-tcc$(EXESUF) $(TCCFLAGS); fi
vla_test$(EXESUF): vla_test.c
$(TCC) -o $@ $^ $(CPPFLAGS) $(CFLAGS)
@@ -253,5 +249,4 @@ clean:
$(MAKE) -C tests2 $@
rm -vf *~ *.o *.a *.bin *.i *.ref *.out *.out? *.out?b *.cc \
*-cc *-tcc *.exe \
- hello libtcc_test vla_test tcctest[1234] ex? tcc_g tcclib.h \
- ../lib/libtcc1.a
+ hello libtcc_test vla_test tcctest[1234] ex? tcc_g
diff --git a/tests/abitest.c b/tests/abitest.c
index 9cdeb87..896e97b 100644
--- a/tests/abitest.c
+++ b/tests/abitest.c
@@ -13,8 +13,24 @@
#define LONG_DOUBLE_LITERAL(x) x ## L
#endif
-static const char *tccdir = NULL;
-static const char *include_dir = NULL;
+static int g_argc;
+static char **g_argv;
+
+static void set_options(TCCState *s, int argc, char **argv)
+{
+ int i;
+ for (i = 1; i < argc; ++i) {
+ char *a = argv[i];
+ if (a[0] == '-') {
+ if (a[1] == 'B')
+ tcc_set_lib_path(s, a+2);
+ else if (a[1] == 'I')
+ tcc_add_include_path(s, a+2);
+ else if (a[1] == 'L')
+ tcc_add_library_path(s, a+2);
+ }
+ }
+}
typedef int (*callback_type) (void*);
@@ -29,12 +45,9 @@ static int run_callback(const char *src, callback_type callback) {
s = tcc_new();
if (!s)
return -1;
- if (tccdir)
- tcc_set_lib_path(s, tccdir);
- if (include_dir) {
- if (tcc_add_include_path(s, include_dir) == -1)
- return -1;
- }
+
+ set_options(s, g_argc, g_argv);
+
if (tcc_set_output_type(s, TCC_OUTPUT_MEMORY) == -1)
return -1;
if (tcc_compile_string(s, src) == -1)
@@ -611,13 +624,11 @@ int main(int argc, char **argv) {
/* if tcclib.h and libtcc1.a are not installed, where can we find them */
for (i = 1; i < argc; ++i) {
- if (!memcmp(argv[i], "lib_path=",9))
- tccdir = argv[i] + 9;
- else if (!memcmp(argv[i], "run_test=", 9))
+ if (!memcmp(argv[i], "run_test=", 9))
testname = argv[i] + 9;
- else if (!memcmp(argv[i], "include=", 8))
- include_dir = argv[i] + 8;
- }
+ }
+
+ g_argv = argv, g_argc = argc;
RUN_TEST(ret_int_test);
RUN_TEST(ret_longlong_test);
diff --git a/tests/libtcc_test.c b/tests/libtcc_test.c
index 414cc9b..109e488 100644
--- a/tests/libtcc_test.c
+++ b/tests/libtcc_test.c
@@ -16,7 +16,7 @@ int add(int a, int b)
}
char my_program[] =
-"#include <stdio.h> // printf()\n"
+"#include <tcclib.h>\n" /* include the "Simple libc header for TCC" */
"extern int add(int a, int b);\n"
"int fib(int n)\n"
"{\n"
@@ -37,6 +37,7 @@ char my_program[] =
int main(int argc, char **argv)
{
TCCState *s;
+ int i;
int (*func)(int);
s = tcc_new();
@@ -46,8 +47,17 @@ int main(int argc, char **argv)
}
/* if tcclib.h and libtcc1.a are not installed, where can we find them */
- if (argc == 2 && !memcmp(argv[1], "lib_path=",9))
- tcc_set_lib_path(s, argv[1]+9);
+ for (i = 1; i < argc; ++i) {
+ char *a = argv[i];
+ if (a[0] == '-') {
+ if (a[1] == 'B')
+ tcc_set_lib_path(s, a+2);
+ else if (a[1] == 'I')
+ tcc_add_include_path(s, a+2);
+ else if (a[1] == 'L')
+ tcc_add_library_path(s, a+2);
+ }
+ }
/* MUST BE CALLED before any compilation */
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
diff --git a/tests/pp/01.c b/tests/pp/01.c
new file mode 100644
index 0000000..2fc3d79
--- /dev/null
+++ b/tests/pp/01.c
@@ -0,0 +1,6 @@
+#define hash_hash # ## #
+#define mkstr(a) # a
+#define in_between(a) mkstr(a)
+#define join(c, d) in_between(c hash_hash d)
+char p[] = join(x, y);
+// char p[] = "x ## y";
diff --git a/tests/pp/01.expect b/tests/pp/01.expect
new file mode 100644
index 0000000..cf5b153
--- /dev/null
+++ b/tests/pp/01.expect
@@ -0,0 +1 @@
+char p[] = "x ## y";
diff --git a/tests/pp/02.c b/tests/pp/02.c
new file mode 100644
index 0000000..feb1254
--- /dev/null
+++ b/tests/pp/02.c
@@ -0,0 +1,28 @@
+#define x 3
+#define f(a) f(x * (a))
+#undef x
+#define x 2
+#define g f
+#define z z[0]
+#define h g(~
+#define m(a) a(w)
+#define w 0,1
+#define t(a) a
+#define p() int
+#define q(x) x
+#define r(x,y) x ## y
+#define str(x) # x
+f(y+1) + f(f(z)) % t(t(g)(0) + t)(1);
+g(x+(3,4)-w) | h 5) & m
+(f)^m(m);
+char c[2][6] = { str(hello), str() };
+/*
+ * f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1);
+ * f(2 * (2+(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1))^m(0,1);
+ * char c[2][6] = { "hello", "" };
+ */
+#define L21 f(y+1) + f(f(z)) % t(t(g)(0) + t)(1);
+#define L22 g(x+(3,4)-w) | h 5) & m\
+(f)^m(m);
+L21
+L22
diff --git a/tests/pp/02.expect b/tests/pp/02.expect
new file mode 100644
index 0000000..16f42ae
--- /dev/null
+++ b/tests/pp/02.expect
@@ -0,0 +1,5 @@
+f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1);
+f(2 * (2+(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1))^m(0,1);
+char c[2][6] = { "hello", "" };
+f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1);
+f(2 * (2+(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1))^m(0,1);
diff --git a/tests/pp/03.c b/tests/pp/03.c
new file mode 100644
index 0000000..a659245
--- /dev/null
+++ b/tests/pp/03.c
@@ -0,0 +1,15 @@
+#define str(s) # s
+#define xstr(s) str(s)
+#define debug(s, t) printf("x" # s "= %d, x" # t "= %s", \
+ x ## s, x ## t)
+#define INCFILE(n) vers ## n
+#define glue(a, b) a ## b
+#define xglue(a, b) glue(a, b)
+#define HIGHLOW "hello"
+#define LOW LOW ", world"
+debug(1, 2);
+fputs(str(strncmp("abc\0d", "abc", '\4') // this goes away
+ == 0) str(: @\n), s);
+\#include xstr(INCFILE(2).h)
+glue(HIGH, LOW);
+xglue(HIGH, LOW)
diff --git a/tests/pp/03.expect b/tests/pp/03.expect
new file mode 100644
index 0000000..44aad0a
--- /dev/null
+++ b/tests/pp/03.expect
@@ -0,0 +1,5 @@
+printf("x" "1" "= %d, x" "2" "= %s", x1, x2);
+fputs("strncmp(\"abc\\0d\", \"abc\", '\\4') == 0" ": @\n", s);
+\#include "vers2.h"
+"hello";
+"hello" ", world"
diff --git a/tests/pp/04.c b/tests/pp/04.c
new file mode 100644
index 0000000..0068f37
--- /dev/null
+++ b/tests/pp/04.c
@@ -0,0 +1,4 @@
+#define foobar 1
+#define C(x,y) x##y
+#define D(x) (C(x,bar))
+D(foo)
diff --git a/tests/pp/04.expect b/tests/pp/04.expect
new file mode 100644
index 0000000..7c67b01
--- /dev/null
+++ b/tests/pp/04.expect
@@ -0,0 +1 @@
+(1)
diff --git a/tests/pp/05.c b/tests/pp/05.c
new file mode 100644
index 0000000..7274941
--- /dev/null
+++ b/tests/pp/05.c
@@ -0,0 +1,7 @@
+#define t(x,y,z) x ## y ## z
+#define xxx(s) int s[] = { t(1,2,3), t(,4,5), t(6,,7), t(8,9,), \
+ t(10,,), t(,11,), t(,,12), t(,,) };
+
+int j[] = { t(1,2,3), t(,4,5), t(6,,7), t(8,9,),
+ t(10,,), t(,11,), t(,,12), t(,,) };
+xxx(j)
diff --git a/tests/pp/05.expect b/tests/pp/05.expect
new file mode 100644
index 0000000..9f9be37
--- /dev/null
+++ b/tests/pp/05.expect
@@ -0,0 +1,3 @@
+int j[] = { 123, 45, 67, 89,
+ 10, 11, 12, };
+int j[] = { 123, 45, 67, 89, 10, 11, 12, };
diff --git a/tests/pp/06.c b/tests/pp/06.c
new file mode 100644
index 0000000..28cfdde
--- /dev/null
+++ b/tests/pp/06.c
@@ -0,0 +1,5 @@
+#define X(a,b, \
+ c,d) \
+ foo
+
+X(1,2,3,4)
diff --git a/tests/pp/06.expect b/tests/pp/06.expect
new file mode 100644
index 0000000..257cc56
--- /dev/null
+++ b/tests/pp/06.expect
@@ -0,0 +1 @@
+foo
diff --git a/tests/pp/07.c b/tests/pp/07.c
new file mode 100644
index 0000000..b22b22b
--- /dev/null
+++ b/tests/pp/07.c
@@ -0,0 +1,4 @@
+#define a() YES
+#define b() a
+b()
+b()()
diff --git a/tests/pp/07.expect b/tests/pp/07.expect
new file mode 100644
index 0000000..ad0e20a
--- /dev/null
+++ b/tests/pp/07.expect
@@ -0,0 +1,2 @@
+a
+YES
diff --git a/tests/pp/08.c b/tests/pp/08.c
new file mode 100644
index 0000000..93018e1
--- /dev/null
+++ b/tests/pp/08.c
@@ -0,0 +1,4 @@
+// test macro expansion in arguments
+#define s_pos s_s.s_pos
+#define foo(x) (x)
+foo(hej.s_pos)
diff --git a/tests/pp/08.expect b/tests/pp/08.expect
new file mode 100644
index 0000000..2b2e3ee
--- /dev/null
+++ b/tests/pp/08.expect
@@ -0,0 +1 @@
+(hej.s_s.s_pos)
diff --git a/tests/pp/09.c b/tests/pp/09.c
new file mode 100644
index 0000000..315b297
--- /dev/null
+++ b/tests/pp/09.c
@@ -0,0 +1,4 @@
+#define C(a,b,c) a##b##c
+#define N(x,y) C(x,_,y)
+#define A_O aaaaoooo
+N(A,O)
diff --git a/tests/pp/09.expect b/tests/pp/09.expect
new file mode 100644
index 0000000..adce0f9
--- /dev/null
+++ b/tests/pp/09.expect
@@ -0,0 +1 @@
+aaaaoooo
diff --git a/tests/pp/10.c b/tests/pp/10.c
new file mode 100644
index 0000000..f180eff
--- /dev/null
+++ b/tests/pp/10.c
@@ -0,0 +1,10 @@
+#define f(x) x
+#define g(x) f(x) f(x
+#define i(x) g(x)) g(x
+#define h(x) i(x))) i(x
+#define k(x) i(x))) i(x))))
+f(x)
+g(x))
+i(x)))
+h(x))))
+k(x))))
diff --git a/tests/pp/10.expect b/tests/pp/10.expect
new file mode 100644
index 0000000..bd18e18
--- /dev/null
+++ b/tests/pp/10.expect
@@ -0,0 +1,5 @@
+x
+x x
+x x x x
+x x x x x x x x
+x x x x x x x x))))
diff --git a/tests/pp/11.c b/tests/pp/11.c
new file mode 100644
index 0000000..c0edf62
--- /dev/null
+++ b/tests/pp/11.c
@@ -0,0 +1,31 @@
+#define D1(s, ...) s
+#define D2(s, ...) s D1(__VA_ARGS__)
+#define D3(s, ...) s D2(__VA_ARGS__)
+#define D4(s, ...) s D3(__VA_ARGS__)
+
+D1(a)
+D2(a, b)
+D3(a, b, c)
+D4(a, b, c, d)
+
+x D4(a, b, c, d) y
+x D4(a, b, c) y
+x D4(a, b) y
+x D4(a) y
+x D4() y
+
+#define GNU_COMMA(X,Y...) X,## Y
+
+x GNU_COMMA(A,B,C) y
+x GNU_COMMA(A,B) y
+x GNU_COMMA(A) y
+x GNU_COMMA() y
+
+#define __sun_attr___noreturn__ __attribute__((__noreturn__))
+#define ___sun_attr_inner(__a) __sun_attr_##__a
+#define __sun_attr__(__a) ___sun_attr_inner __a
+#define __NORETURN __sun_attr__((__noreturn__))
+__NORETURN
+#define X(...)
+#define Y(...) 1 __VA_ARGS__ 2
+Y(X X() ())
diff --git a/tests/pp/11.expect b/tests/pp/11.expect
new file mode 100644
index 0000000..6b9806c
--- /dev/null
+++ b/tests/pp/11.expect
@@ -0,0 +1,15 @@
+a
+a b
+a b c
+a b c d
+x a b c d y
+x a b c y
+x a b y
+x a y
+x y
+x A,B,C y
+x A,B y
+x A y
+x y
+__attribute__((__noreturn__))
+1 2
diff --git a/tests/pp/Makefile b/tests/pp/Makefile
new file mode 100644
index 0000000..c656f9a
--- /dev/null
+++ b/tests/pp/Makefile
@@ -0,0 +1,35 @@
+#
+# credits: 01..13.c from the pcc cpp-tests suite
+#
+
+TCC = ../../tcc
+TESTS = $(patsubst %.c,%.test,$(wildcard *.c))
+
+all test : $(TESTS)
+
+%.test: %.c %.expect
+ @echo PPTest $* ...
+ @$(TCC) -E -P $< >$*.output 2>&1 ; \
+ diff -Nu -b -B -I "^#" $(EXTRA_DIFF_OPTS) $*.expect $*.output \
+ && rm -f $*.output
+
+# automatically generate .expect files with gcc:
+%.expect :
+ gcc -E -P $*.c >$*.expect 2>&1
+
+# tell make not to delete
+.PRECIOUS: %.expect
+
+clean:
+ rm -vf *.output
+
+# 02.test : EXTRA_DIFF_OPTS = -w
+# 03.test : EXTRA_DIFF_OPTS = -w
+# 04.test : EXTRA_DIFF_OPTS = -w
+# 10.test : EXTRA_DIFF_OPTS = -w
+
+# diff options:
+# -b ighore space changes
+# -w ighore all whitespace
+# -B ignore blank lines
+# -I <RE> ignore lines matching RE
diff --git a/tests/tcctest.c b/tests/tcctest.c
index 49fa587..a822500 100644
--- a/tests/tcctest.c
+++ b/tests/tcctest.c
@@ -316,6 +316,7 @@ void macro_test(void)
printf("__LINE__=%d __FILE__=%s\n",
__LINE__, __FILE__);
+#if 0
#line 200
printf("__LINE__=%d __FILE__=%s\n",
__LINE__, __FILE__);
@@ -323,6 +324,7 @@ void macro_test(void)
printf("__LINE__=%d __FILE__=%s\n",
__LINE__, __FILE__);
#line 227 "tcctest.c"
+#endif
/* not strictly preprocessor, but we test it there */
#ifdef C99_MACROS
diff --git a/tests/tests2/65_macro_concat_start.c b/tests/tests2/65_macro_concat_start.c
deleted file mode 100644
index d63d67a..0000000
--- a/tests/tests2/65_macro_concat_start.c
+++ /dev/null
@@ -1,2 +0,0 @@
-#define paste(A,B) ##A B
-paste(x,y)
diff --git a/tests/tests2/65_macro_concat_start.expect b/tests/tests2/65_macro_concat_start.expect
deleted file mode 100644
index 88ed6c5..0000000
--- a/tests/tests2/65_macro_concat_start.expect
+++ /dev/null
@@ -1 +0,0 @@
-65_macro_concat_start.c:1: error: '##' invalid at start of macro
diff --git a/tests/tests2/66_macro_concat_end.c b/tests/tests2/66_macro_concat_end.c
deleted file mode 100644
index 55dcaef..0000000
--- a/tests/tests2/66_macro_concat_end.c
+++ /dev/null
@@ -1,2 +0,0 @@
-#define paste(A,B) A B##
-paste(x,y)
diff --git a/tests/tests2/66_macro_concat_end.expect b/tests/tests2/66_macro_concat_end.expect
deleted file mode 100644
index 224e5c9..0000000
--- a/tests/tests2/66_macro_concat_end.expect
+++ /dev/null
@@ -1 +0,0 @@
-66_macro_concat_end.c:2: error: '##' invalid at end of macro
diff --git a/tests/tests2/68_macro_param_list_err_1.c b/tests/tests2/68_macro_param_list_err_1.c
deleted file mode 100644
index fd08dc7..0000000
--- a/tests/tests2/68_macro_param_list_err_1.c
+++ /dev/null
@@ -1,9 +0,0 @@
-#include <stdio.h>
-#define hexCh(c (c >= 10 ? 'a' + c - 10 : '0' + c)
-
-int main(void)
-{
- int c = 0xa;
- printf("hex: %c\n", hexCh(c));
- return 0;
-}
diff --git a/tests/tests2/68_macro_param_list_err_1.expect b/tests/tests2/68_macro_param_list_err_1.expect
deleted file mode 100644
index 3246640..0000000
--- a/tests/tests2/68_macro_param_list_err_1.expect
+++ /dev/null
@@ -1 +0,0 @@
-68_macro_param_list_err_1.c:2: error: '(' may not appear in parameter list
diff --git a/tests/tests2/69_macro_param_list_err_2.c b/tests/tests2/69_macro_param_list_err_2.c
deleted file mode 100644
index 06f0b41..0000000
--- a/tests/tests2/69_macro_param_list_err_2.c
+++ /dev/null
@@ -1,9 +0,0 @@
-#include <stdio.h>
-#define hexCh(c/3) (c >= 10 ? 'a' + c - 10 : '0' + c)
-
-int main(void)
-{
- int c = 0xa;
- printf("hex: %c\n", hexCh(c));
- return 0;
-}
diff --git a/tests/tests2/69_macro_param_list_err_2.expect b/tests/tests2/69_macro_param_list_err_2.expect
deleted file mode 100644
index 6d6b9d1..0000000
--- a/tests/tests2/69_macro_param_list_err_2.expect
+++ /dev/null
@@ -1 +0,0 @@
-69_macro_param_list_err_2.c:2: error: '/' may not appear in parameter list
diff --git a/tests/tests2/72_long_long_constant.c b/tests/tests2/72_long_long_constant.c
index a698fd6..6608213 100644
--- a/tests/tests2/72_long_long_constant.c
+++ b/tests/tests2/72_long_long_constant.c
@@ -13,5 +13,7 @@ int main()
printf("Error: 2147483647 < 0\n");
return 2;
}
+ else
+ printf("long long constant test ok.\n");
return 0;
}
diff --git a/tests/tests2/72_long_long_constant.expect b/tests/tests2/72_long_long_constant.expect
new file mode 100644
index 0000000..dda9e66
--- /dev/null
+++ b/tests/tests2/72_long_long_constant.expect
@@ -0,0 +1 @@
+long long constant test ok.
diff --git a/tests/tests2/Makefile b/tests/tests2/Makefile
index a441674..254fa5c 100644
--- a/tests/tests2/Makefile
+++ b/tests/tests2/Makefile
@@ -19,89 +19,9 @@ endif
TCC = $(TOP)/tcc $(TCCFLAGS)
-TESTS = \
- 00_assignment.test \
- 01_comment.test \
- 02_printf.test \
- 03_struct.test \
- 04_for.test \
- 05_array.test \
- 06_case.test \
- 07_function.test \
- 08_while.test \
- 09_do_while.test \
- 10_pointer.test \
- 11_precedence.test \
- 12_hashdefine.test \
- 13_integer_literals.test \
- 14_if.test \
- 15_recursion.test \
- 16_nesting.test \
- 17_enum.test \
- 18_include.test \
- 19_pointer_arithmetic.test \
- 20_pointer_comparison.test \
- 21_char_array.test \
- 22_floating_point.test \
- 23_type_coercion.test \
- 24_math_library.test \
- 25_quicksort.test \
- 26_character_constants.test \
- 27_sizeof.test \
- 28_strings.test \
- 29_array_address.test \
- 30_hanoi.test \
- 31_args.test \
- 32_led.test \
- 33_ternary_op.test \
- 34_array_assignment.test \
- 35_sizeof.test \
- 36_array_initialisers.test \
- 37_sprintf.test \
- 38_multiple_array_index.test \
- 39_typedef.test \
- 40_stdio.test \
- 41_hashif.test \
- 42_function_pointer.test \
- 43_void_param.test \
- 44_scoped_declarations.test \
- 45_empty_for.test \
- 46_grep.test \
- 47_switch_return.test \
- 48_nested_break.test \
- 49_bracket_evaluation.test \
- 50_logical_second_arg.test \
- 51_static.test \
- 52_unnamed_enum.test \
- 54_goto.test \
- 55_lshift_type.test \
- 56_btype_excess-1.test \
- 57_btype_excess-2.test \
- 58_function_redefinition.test \
- 59_function_array.test \
- 60_enum_redefinition.test \
- 61_undefined_enum.test \
- 62_enumerator_redefinition.test \
- 63_local_enumerator_redefinition.test \
- 64_macro_nesting.test \
- 65_macro_concat_start.test \
- 66_macro_concat_end.test \
- 67_macro_concat.test \
- 68_macro_param_list_err_1.test \
- 69_macro_param_list_err_2.test \
- 70_floating_point_literals.test \
- 71_macro_empty_arg.test \
- 72_long_long_constant.test \
- 73_arm64.test \
- 74_nocode_wanted.test \
- 75_array_in_struct_init.test \
- 76_dollars_in_identifiers.test \
- 77_push_pop_macro.test \
- 78_vla_label.test \
- 79_vla_continue.test
+TESTS = $(patsubst %.c,%.test,$(wildcard *.c))
# 34_array_assignment.test -- array assignment is not in C standard
-
SKIP = 34_array_assignment.test
# some tests do not pass on all platforms, remove them for now
@@ -128,16 +48,29 @@ ARGS =
FLAGS =
76_dollars_in_identifiers.test : FLAGS = -fdollars-in-identifiers
+# Filter some always-warning
+FILTER =
+ifeq (-$(findstring arm,$(ARCH))-,-arm-)
+FILTER = 2>&1 | grep -v 'warning: soft float ABI currently not supported'
+endif
+
all test: $(filter-out $(SKIP),$(TESTS))
-%.test: %.c
+%.test: %.c %.expect
@echo Test: $*...
-
- @$(TCC) -run $(FLAGS) $< $(ARGS) 2>&1 | grep -v 'warning: soft float ABI currently not supported: default to softfp' >$*.output || true
+# test -run
+ @$(TCC) $(FLAGS) -run $< $(ARGS) $(FILTER) >$*.output 2>&1 || true
@diff -Nbu $*.expect $*.output && rm -f $*.output
+# test exe (disabled for speed)
+# @($(TCC) $(FLAGS) $< -o $*.exe && ./$*.exe $(ARGS)) $(FiLTER) >$*.output2 2>&1 ; \
+# diff -Nbu $*.expect $*.output2 && rm -f $*.output2 $*.exe
+
+# automatically generate .expect files with gcc:
+%.expect :
+ (gcc $*.c -o a.exe && ./a.exe $(ARGS)) >$*.expect 2>&1; rm -f a.exe
- @($(TCC) $(FLAGS) $< -o $*.exe && ./$*.exe $(ARGS)) 2>&1 | grep -v 'warning: soft float ABI currently not supported: default to softfp' >$*.output2 || true
- @diff -Nbu $*.expect $*.output2 && rm -f $*.output2 $*.exe
+# tell make not to delete
+.PRECIOUS: %.expect
clean:
- rm -vf fred.txt *.output* *.exe
+ rm -vf fred.txt *.output a.exe
diff --git a/x86_64-gen.c b/x86_64-gen.c
index 8495737..2d69b75 100644
--- a/x86_64-gen.c
+++ b/x86_64-gen.c
@@ -1254,12 +1254,12 @@ void gfunc_call(int nb_args)
in on the stack and swap it back to its original position
if it is a register. */
SValue tmp = vtop[0];
+ int arg_stored = 1;
+
vtop[0] = vtop[-i];
vtop[-i] = tmp;
-
mode = classify_x86_64_arg(&vtop->type, NULL, &size, &align, &reg_count);
- int arg_stored = 1;
switch (vtop->type.t & VT_BTYPE) {
case VT_STRUCT:
if (mode == x86_64_mode_sse) {
@@ -1413,9 +1413,10 @@ void gfunc_call(int nb_args)
} else if (mode == x86_64_mode_integer) {
/* simple type */
/* XXX: implicit cast ? */
+ int d;
gen_reg -= reg_count;
r = gv(RC_INT);
- int d = arg_prepare_reg(gen_reg);
+ d = arg_prepare_reg(gen_reg);
orex(1,d,r,0x89); /* mov */
o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d));
if (reg_count == 2) {
@@ -2225,7 +2226,6 @@ ST_FUNC void gen_vla_sp_restore(int addr) {
/* Subtract from the stack pointer, and push the resulting value onto the stack */
ST_FUNC void gen_vla_alloc(CType *type, int align) {
- int r;
#ifdef TCC_TARGET_PE
/* alloca does more than just adjust %rsp on Windows */
vpush_global_sym(&func_old_type, TOK_alloca);
@@ -2233,6 +2233,7 @@ ST_FUNC void gen_vla_alloc(CType *type, int align) {
gfunc_call(1);
vset(type, REG_IRET, 0);
#else
+ int r;
r = gv(RC_INT); /* allocation size */
/* sub r,%rsp */
o(0x2b48);