tcc -dt -run ... : simpler is better

* -dt now with lowercase t

* test snippets now separated by real preprocessor statements
  which is valid C also for other compilers

    #if defined test_xxx
       < test snippet x >
    #elif defined test_yyy
       < test snippet y >
    #elif ...
    #endif

* simpler implementation, behaves like -run if no 'test_...' macros
  are seen, works with -E too

* for demonstration I combined some of the small tests for errors
  and warnings (56..63,74) in "60_errors_and_warnings.c"

Also:
* libtcc.c:
  put tcc_preprocess() and tcc_assemble() under the setjmp clause
  to let them return to caller after errors.  This is for -dt -E.
* tccgen.c:
  - get rid of save/restore_parse_state(), macro_ptr is saved
    by begin_macro anyway, now line_num too.
  - use expr_eq for parsing _Generic's controlling_type
  - set nocode_wanted with const_wanted. too, This is to keep
    VT_JMP on vtop when parsing preprocessor expressions.
* tccpp.c: tcc -E: suppress trailing whitespace from lines with
  comments (that -E removes) such as
       NO_GOTPLT_ENTRY,\t    /* never generate ... */
master
grischka 2017-07-20 22:21:27 +02:00
parent ba2b25e4ea
commit 0cc24d0e84
31 changed files with 323 additions and 446 deletions

117
libtcc.c
View File

@ -508,8 +508,9 @@ static void error1(TCCState *s1, int is_warning, const char *fmt, va_list ap)
if (!s1->error_func) { if (!s1->error_func) {
/* default case: stderr */ /* default case: stderr */
if (s1->ppfp) /* print a newline during tcc -E */ if (s1->output_type == TCC_OUTPUT_PREPROCESS && s1->ppfp == stdout)
fprintf(s1->ppfp, "\n"), fflush(s1->ppfp); /* print a newline during tcc -E */
printf("\n"), fflush(stdout);
fflush(stdout); /* flush -v output */ fflush(stdout); /* flush -v output */
fprintf(stderr, "%s\n", buf); fprintf(stderr, "%s\n", buf);
fflush(stderr); /* print error/warning now (win32) */ fflush(stderr); /* print error/warning now (win32) */
@ -587,6 +588,7 @@ ST_FUNC void tcc_open_bf(TCCState *s1, const char *filename, int initlen)
bf->fd = -1; bf->fd = -1;
bf->prev = file; bf->prev = file;
file = bf; file = bf;
tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
} }
ST_FUNC void tcc_close(void) ST_FUNC void tcc_close(void)
@ -622,36 +624,36 @@ ST_FUNC int tcc_open(TCCState *s1, const char *filename)
return fd; return fd;
} }
/* compile the C file opened in 'file'. Return non zero if errors. */ /* compile the file opened in 'file'. Return non zero if errors. */
static int tcc_compile(TCCState *s1) static int tcc_compile(TCCState *s1)
{ {
Sym *define_start; Sym *define_start;
int filetype, is_asm;
define_start = define_stack; define_start = define_stack;
filetype = s1->filetype;
is_asm = filetype == AFF_TYPE_ASM || filetype == AFF_TYPE_ASMPP;
if (setjmp(s1->error_jmp_buf) == 0) { if (setjmp(s1->error_jmp_buf) == 0) {
s1->nb_errors = 0; s1->nb_errors = 0;
s1->error_set_jmp_enabled = 1; s1->error_set_jmp_enabled = 1;
preprocess_start(s1); preprocess_start(s1, is_asm);
tccgen_start(s1); if (s1->output_type == TCC_OUTPUT_PREPROCESS) {
#ifdef INC_DEBUG tcc_preprocess(s1);
printf("%s: **** new file\n", file->filename); } else if (is_asm) {
#ifdef CONFIG_TCC_ASM
tcc_assemble(s1, filetype == AFF_TYPE_ASMPP);
#else
tcc_error_noabort("asm not supported");
#endif #endif
ch = file->buf_ptr[0]; } else {
tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF; tccgen_compile(s1);
parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM | PARSE_FLAG_TOK_STR; }
next();
decl(VT_CONST);
if (tok != TOK_EOF)
expect("declaration");
/* free defines here already on behalf of of M.M.'s possibly existing
experimental preprocessor implementation. The normal call below
is still there to free after error-longjmp */
free_defines(define_start);
tccgen_end(s1);
} }
s1->error_set_jmp_enabled = 0; s1->error_set_jmp_enabled = 0;
preprocess_end(s1);
free_inline_functions(s1); free_inline_functions(s1);
/* reset define stack, but keep -D and built-ins */ /* reset define stack, but keep -D and built-ins */
free_defines(define_start); free_defines(define_start);
@ -689,10 +691,8 @@ LIBTCCAPI void tcc_define_symbol(TCCState *s1, const char *sym, const char *valu
memcpy(file->buffer + len1 + 1, value, len2); memcpy(file->buffer + len1 + 1, value, len2);
/* parse with define parser */ /* parse with define parser */
ch = file->buf_ptr[0];
next_nomacro(); next_nomacro();
parse_define(); parse_define();
tcc_close(); tcc_close();
} }
@ -713,6 +713,8 @@ static void tcc_cleanup(void)
{ {
if (NULL == tcc_state) if (NULL == tcc_state)
return; return;
while (file)
tcc_close();
tccpp_delete(tcc_state); tccpp_delete(tcc_state);
tcc_state = NULL; tcc_state = NULL;
/* free sym_pools */ /* free sym_pools */
@ -993,26 +995,7 @@ LIBTCCAPI int tcc_add_sysinclude_path(TCCState *s, const char *pathname)
ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
{ {
int ret, filetype; int ret;
filetype = flags & 0x0F;
if (filetype == 0) {
/* use a file extension to detect a filetype */
const char *ext = tcc_fileextension(filename);
if (ext[0]) {
ext++;
if (!strcmp(ext, "S"))
filetype = AFF_TYPE_ASMPP;
else if (!strcmp(ext, "s"))
filetype = AFF_TYPE_ASM;
else if (!PATHCMP(ext, "c") || !PATHCMP(ext, "i"))
filetype = AFF_TYPE_C;
else
filetype = AFF_TYPE_BIN;
} else {
filetype = AFF_TYPE_C;
}
}
/* open the file */ /* open the file */
ret = tcc_open(s1, filename); ret = tcc_open(s1, filename);
@ -1026,26 +1009,7 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
dynarray_add(&s1->target_deps, &s1->nb_target_deps, dynarray_add(&s1->target_deps, &s1->nb_target_deps,
tcc_strdup(filename)); tcc_strdup(filename));
parse_flags = 0; if (flags & AFF_TYPE_BIN) {
/* if .S file, define __ASSEMBLER__ like gcc does */
if (filetype == AFF_TYPE_ASM || filetype == AFF_TYPE_ASMPP) {
tcc_define_symbol(s1, "__ASSEMBLER__", NULL);
parse_flags = PARSE_FLAG_ASM_FILE;
}
if (flags & AFF_PREPROCESS) {
ret = tcc_preprocess(s1);
} else if (filetype == AFF_TYPE_C) {
ret = tcc_compile(s1);
#ifdef CONFIG_TCC_ASM
} else if (filetype == AFF_TYPE_ASMPP) {
/* non preprocessed assembler */
ret = tcc_assemble(s1, 1);
} else if (filetype == AFF_TYPE_ASM) {
/* preprocessed assembler */
ret = tcc_assemble(s1, 0);
#endif
} else {
ElfW(Ehdr) ehdr; ElfW(Ehdr) ehdr;
int fd, obj_type; int fd, obj_type;
@ -1098,6 +1062,8 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
tcc_error_noabort("unrecognized file type"); tcc_error_noabort("unrecognized file type");
break; break;
} }
} else {
ret = tcc_compile(s1);
} }
tcc_close(); tcc_close();
return ret; return ret;
@ -1105,10 +1071,27 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename) LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename)
{ {
if (s->output_type == TCC_OUTPUT_PREPROCESS) int filetype = s->filetype;
return tcc_add_file_internal(s, filename, AFF_PRINT_ERROR | AFF_PREPROCESS | s->filetype); int flags = AFF_PRINT_ERROR;
else if (filetype == 0) {
return tcc_add_file_internal(s, filename, AFF_PRINT_ERROR | s->filetype); /* use a file extension to detect a filetype */
const char *ext = tcc_fileextension(filename);
if (ext[0]) {
ext++;
if (!strcmp(ext, "S"))
filetype = AFF_TYPE_ASMPP;
else if (!strcmp(ext, "s"))
filetype = AFF_TYPE_ASM;
else if (!PATHCMP(ext, "c") || !PATHCMP(ext, "i"))
filetype = AFF_TYPE_C;
else
flags |= AFF_TYPE_BIN;
} else {
filetype = AFF_TYPE_C;
}
s->filetype = filetype;
}
return tcc_add_file_internal(s, filename, flags);
} }
LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname) LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname)
@ -1799,8 +1782,8 @@ reparse:
s->dflag = 3; s->dflag = 3;
else if (*optarg == 'M') else if (*optarg == 'M')
s->dflag = 7; s->dflag = 7;
else if (*optarg == 'T') else if (*optarg == 't')
s->do_test = argc; s->dflag = 16;
else if (isnum(*optarg)) else if (isnum(*optarg))
g_debug = atoi(optarg); g_debug = atoi(optarg);
else else

40
tcc.c
View File

@ -91,6 +91,7 @@ static const char help2[] =
" -static link to static libraries (not recommended)\n" " -static link to static libraries (not recommended)\n"
" -dumpversion print version\n" " -dumpversion print version\n"
" -print-search-dirs print search paths\n" " -print-search-dirs print search paths\n"
" -dt with -run/-E: auto-define 'test_...' macros\n"
"Ignored options:\n" "Ignored options:\n"
" --param -pedantic -pipe -s -std -traditional\n" " --param -pedantic -pipe -s -std -traditional\n"
"-W... warnings:\n" "-W... warnings:\n"
@ -244,18 +245,21 @@ static unsigned getclock_ms(void)
#endif #endif
} }
int main(int argc, char **argv) int main(int argc0, char **argv0)
{ {
TCCState *s; TCCState *s;
int ret, opt, n = 0; int ret, opt, n = 0, t = 0;
unsigned start_time = 0; unsigned start_time = 0;
const char *first_file; const char *first_file;
int argc; char **argv;
FILE *ppfp = stdout;
redo: redo:
argc = argc0, argv = argv0;
s = tcc_new(); s = tcc_new();
opt = tcc_parse_args(s, &argc, &argv, 1); opt = tcc_parse_args(s, &argc, &argv, 1);
if (n == 0) { if ((n | t) == 0) {
if (opt == OPT_HELP) if (opt == OPT_HELP)
return printf(help), 1; return printf(help), 1;
if (opt == OPT_HELP2) if (opt == OPT_HELP2)
@ -282,17 +286,11 @@ redo:
n = s->nb_files; n = s->nb_files;
if (n == 0) if (n == 0)
tcc_error("no input files\n"); tcc_error("no input files\n");
#ifdef TCC_IS_NATIVE
if (s->do_test)
tcc_tool_test(s, argc, argv); /* maybe never returns */
#endif
if (s->output_type == TCC_OUTPUT_PREPROCESS) { if (s->output_type == TCC_OUTPUT_PREPROCESS) {
if (!s->outfile) { if (s->outfile) {
s->ppfp = stdout; ppfp = fopen(s->outfile, "w");
} else { if (!ppfp)
s->ppfp = fopen(s->outfile, "w");
if (!s->ppfp)
tcc_error("could not write '%s'", s->outfile); tcc_error("could not write '%s'", s->outfile);
} }
} else if (s->output_type == TCC_OUTPUT_OBJ && !s->option_r) { } else if (s->output_type == TCC_OUTPUT_OBJ && !s->option_r) {
@ -313,6 +311,11 @@ redo:
if (s->output_type == 0) if (s->output_type == 0)
s->output_type = TCC_OUTPUT_EXE; s->output_type = TCC_OUTPUT_EXE;
tcc_set_output_type(s, s->output_type); tcc_set_output_type(s, s->output_type);
s->ppfp = ppfp;
if ((s->output_type == TCC_OUTPUT_MEMORY
|| s->output_type == TCC_OUTPUT_PREPROCESS) && (s->dflag & 16))
s->dflag |= t ? 32 : 0, s->run_test = ++t, n = s->nb_files;
/* compile or add each files or library */ /* compile or add each files or library */
for (first_file = NULL, ret = 0;;) { for (first_file = NULL, ret = 0;;) {
@ -338,8 +341,7 @@ redo:
} }
if (s->output_type == TCC_OUTPUT_PREPROCESS) { if (s->output_type == TCC_OUTPUT_PREPROCESS) {
if (s->outfile) ;
fclose(s->ppfp);
} else if (0 == ret) { } else if (0 == ret) {
if (s->output_type == TCC_OUTPUT_MEMORY) { if (s->output_type == TCC_OUTPUT_MEMORY) {
#ifdef TCC_IS_NATIVE #ifdef TCC_IS_NATIVE
@ -355,10 +357,18 @@ redo:
} }
} }
if (s->do_bench && ret == 0 && n == 0) if (t)
ret = 0;
if (s->run_test)
t = 0;
if (s->do_bench && (n | t | ret) == 0)
tcc_print_stats(s, getclock_ms() - start_time); tcc_print_stats(s, getclock_ms() - start_time);
tcc_delete(s); tcc_delete(s);
if (ret == 0 && n) if (ret == 0 && n)
goto redo; /* compile more files with -c */ goto redo; /* compile more files with -c */
if (t)
goto redo; /* run more tests with -dt -run */
if (ppfp && ppfp != stdout)
fclose(ppfp);
return ret; return ret;
} }

31
tcc.h
View File

@ -556,15 +556,6 @@ typedef struct BufferedFile {
#define CH_EOB '\\' /* end of buffer or '\0' char in file */ #define CH_EOB '\\' /* end of buffer or '\0' char in file */
#define CH_EOF (-1) /* end of file */ #define CH_EOF (-1) /* end of file */
/* parsing state (used to save parser state to reparse part of the
source several times) */
typedef struct ParseState {
const int *macro_ptr;
int line_num;
int tok;
CValue tokc;
} ParseState;
/* used to record tokens */ /* used to record tokens */
typedef struct TokenString { typedef struct TokenString {
int *str; int *str;
@ -572,6 +563,7 @@ typedef struct TokenString {
int lastlen; int lastlen;
int allocated_len; int allocated_len;
int last_line_num; int last_line_num;
int save_line_num;
/* used to chain token-strings with begin/end_macro() */ /* used to chain token-strings with begin/end_macro() */
struct TokenString *prev; struct TokenString *prev;
const int *prev_ptr; const int *prev_ptr;
@ -675,6 +667,7 @@ struct TCCState {
#ifdef TCC_TARGET_ARM #ifdef TCC_TARGET_ARM
enum float_abi float_abi; /* float ABI of the generated code*/ enum float_abi float_abi; /* float ABI of the generated code*/
#endif #endif
int run_test; /* nth test to run with -dt -run */
addr_t text_addr; /* address of text section */ addr_t text_addr; /* address of text section */
int has_text_addr; int has_text_addr;
@ -813,7 +806,6 @@ struct TCCState {
int option_pthread; /* -pthread option */ int option_pthread; /* -pthread option */
int argc; int argc;
char **argv; char **argv;
int do_test;
}; };
struct filespec { struct filespec {
@ -1145,14 +1137,13 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
/* flags: */ /* flags: */
#define AFF_PRINT_ERROR 0x10 /* print error if file not found */ #define AFF_PRINT_ERROR 0x10 /* print error if file not found */
#define AFF_REFERENCED_DLL 0x20 /* load a referenced dll from another dll */ #define AFF_REFERENCED_DLL 0x20 /* load a referenced dll from another dll */
#define AFF_PREPROCESS 0x40 /* preprocess file */ #define AFF_TYPE_BIN 0x40 /* file to add is binary */
/* combined with: */ /* s->filetype: */
#define AFF_TYPE_NONE 0 #define AFF_TYPE_NONE 0
#define AFF_TYPE_C 1 #define AFF_TYPE_C 1
#define AFF_TYPE_ASM 2 #define AFF_TYPE_ASM 2
#define AFF_TYPE_ASMPP 3 #define AFF_TYPE_ASMPP 3
#define AFF_TYPE_BIN 4 #define AFF_TYPE_LIB 4
#define AFF_TYPE_LIB 5
/* values from tcc_object_type(...) */ /* values from tcc_object_type(...) */
#define AFF_BINTYPE_REL 1 #define AFF_BINTYPE_REL 1
#define AFF_BINTYPE_DYN 2 #define AFF_BINTYPE_DYN 2
@ -1220,9 +1211,7 @@ ST_FUNC TokenSym *tok_alloc(const char *str, int len);
ST_FUNC const 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 begin_macro(TokenString *str, int alloc);
ST_FUNC void end_macro(void); ST_FUNC void end_macro(void);
ST_FUNC void set_idnum(int c, int val); ST_FUNC int set_idnum(int c, int val);
ST_FUNC void save_parse_state(ParseState *s);
ST_FUNC void restore_parse_state(ParseState *s);
ST_INLN void tok_str_new(TokenString *s); ST_INLN void tok_str_new(TokenString *s);
ST_FUNC TokenString *tok_str_alloc(void); ST_FUNC TokenString *tok_str_alloc(void);
ST_FUNC void tok_str_free(TokenString *s); ST_FUNC void tok_str_free(TokenString *s);
@ -1241,7 +1230,8 @@ ST_FUNC void preprocess(int is_bof);
ST_FUNC void next_nomacro(void); ST_FUNC void next_nomacro(void);
ST_FUNC void next(void); ST_FUNC void next(void);
ST_INLN void unget_tok(int last_tok); ST_INLN void unget_tok(int last_tok);
ST_FUNC void preprocess_start(TCCState *s1); ST_FUNC void preprocess_start(TCCState *s1, int is_asm);
ST_FUNC void preprocess_end(TCCState *s1);
ST_FUNC void tccpp_new(TCCState *s); ST_FUNC void tccpp_new(TCCState *s);
ST_FUNC void tccpp_delete(TCCState *s); ST_FUNC void tccpp_delete(TCCState *s);
ST_FUNC int tcc_preprocess(TCCState *s1); ST_FUNC int tcc_preprocess(TCCState *s1);
@ -1298,9 +1288,7 @@ ST_FUNC void tcc_debug_funcstart(TCCState *s1, Sym *sym);
ST_FUNC void tcc_debug_funcend(TCCState *s1, int size); ST_FUNC void tcc_debug_funcend(TCCState *s1, int size);
ST_FUNC void tcc_debug_line(TCCState *s1); ST_FUNC void tcc_debug_line(TCCState *s1);
ST_FUNC void tccgen_start(TCCState *s1); ST_FUNC int tccgen_compile(TCCState *s1);
ST_FUNC void tccgen_end(TCCState *s1);
ST_FUNC void free_inline_functions(TCCState *s); ST_FUNC void free_inline_functions(TCCState *s);
ST_FUNC void check_vstack(void); ST_FUNC void check_vstack(void);
@ -1342,7 +1330,6 @@ ST_FUNC void expr_prod(void);
ST_FUNC void expr_sum(void); ST_FUNC void expr_sum(void);
ST_FUNC void gexpr(void); ST_FUNC void gexpr(void);
ST_FUNC int expr_const(void); ST_FUNC int expr_const(void);
ST_FUNC void decl(int l);
#if defined CONFIG_TCC_BCHECK || defined TCC_TARGET_C67 #if defined CONFIG_TCC_BCHECK || defined TCC_TARGET_C67
ST_FUNC Sym *get_sym_ref(CType *type, Section *sec, unsigned long offset, unsigned long size); ST_FUNC Sym *get_sym_ref(CType *type, Section *sec, unsigned long offset, unsigned long size);
#endif #endif

View File

@ -628,20 +628,16 @@ static void asm_parse_directive(TCCState *s1, int global)
{ {
int repeat; int repeat;
TokenString *init_str; TokenString *init_str;
ParseState saved_parse_state = {0};
next(); next();
repeat = asm_int_expr(s1); repeat = asm_int_expr(s1);
init_str = tok_str_alloc(); init_str = tok_str_alloc();
next(); while (next(), tok != TOK_ASMDIR_endr) {
while ((tok != TOK_ASMDIR_endr) && (tok != CH_EOF)) { if (tok == CH_EOF)
tcc_error("we at end of file, .endr not found");
tok_str_add_tok(init_str); tok_str_add_tok(init_str);
next();
} }
if (tok == CH_EOF) tcc_error("we at end of file, .endr not found");
next();
tok_str_add(init_str, -1); tok_str_add(init_str, -1);
tok_str_add(init_str, 0); tok_str_add(init_str, 0);
save_parse_state(&saved_parse_state);
begin_macro(init_str, 1); begin_macro(init_str, 1);
while (repeat-- > 0) { while (repeat-- > 0) {
tcc_assemble_internal(s1, (parse_flags & PARSE_FLAG_PREPROCESS), tcc_assemble_internal(s1, (parse_flags & PARSE_FLAG_PREPROCESS),
@ -649,7 +645,7 @@ static void asm_parse_directive(TCCState *s1, int global)
macro_ptr = init_str->str; macro_ptr = init_str->str;
} }
end_macro(); end_macro();
restore_parse_state(&saved_parse_state); next();
break; break;
} }
case TOK_ASMDIR_org: case TOK_ASMDIR_org:
@ -917,13 +913,10 @@ static void asm_parse_directive(TCCState *s1, int global)
static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global) static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global)
{ {
int opcode; int opcode;
int saved_parse_flags = parse_flags;
/* XXX: undefine C labels */ /* XXX: undefine C labels */
ch = file->buf_ptr[0];
tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
parse_flags = PARSE_FLAG_ASM_FILE | PARSE_FLAG_TOK_STR; parse_flags = PARSE_FLAG_ASM_FILE | PARSE_FLAG_TOK_STR;
set_idnum('.', IS_ID);
if (do_preprocess) if (do_preprocess)
parse_flags |= PARSE_FLAG_PREPROCESS; parse_flags |= PARSE_FLAG_PREPROCESS;
for(;;) { for(;;) {
@ -990,30 +983,22 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global)
} }
asm_free_labels(s1); asm_free_labels(s1);
parse_flags = saved_parse_flags;
return 0; return 0;
} }
/* Assemble the current file */ /* Assemble the current file */
ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess) ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess)
{ {
Sym *define_start;
int ret; int ret;
define_start = define_stack;
preprocess_start(s1);
tcc_debug_start(s1); tcc_debug_start(s1);
/* default section is text */ /* default section is text */
cur_text_section = text_section; cur_text_section = text_section;
ind = cur_text_section->data_offset; ind = cur_text_section->data_offset;
nocode_wanted = 0; nocode_wanted = 0;
ret = tcc_assemble_internal(s1, do_preprocess, 1); ret = tcc_assemble_internal(s1, do_preprocess, 1);
cur_text_section->data_offset = ind; cur_text_section->data_offset = ind;
tcc_debug_end(s1); tcc_debug_end(s1);
free_defines(define_start);
return ret; return ret;
} }
@ -1025,21 +1010,16 @@ ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess)
end */ end */
static void tcc_assemble_inline(TCCState *s1, char *str, int len, int global) static void tcc_assemble_inline(TCCState *s1, char *str, int len, int global)
{ {
int saved_parse_flags; const int *saved_macro_ptr = macro_ptr;
const int *saved_macro_ptr; int dotid = set_idnum('.', IS_ID);
saved_parse_flags = parse_flags;
saved_macro_ptr = macro_ptr;
tcc_open_bf(s1, ":asm:", len); tcc_open_bf(s1, ":asm:", len);
memcpy(file->buffer, str, len); memcpy(file->buffer, str, len);
macro_ptr = NULL; macro_ptr = NULL;
tcc_assemble_internal(s1, 0, global); tcc_assemble_internal(s1, 0, global);
tcc_close(); tcc_close();
parse_flags = saved_parse_flags; set_idnum('.', dotid);
set_idnum('.', (parse_flags & PARSE_FLAG_ASM_FILE) ? IS_ID : 0);
macro_ptr = saved_macro_ptr; macro_ptr = saved_macro_ptr;
} }

View File

@ -84,6 +84,7 @@ static void init_putv(CType *type, Section *sec, unsigned long c);
static void decl_initializer(CType *type, Section *sec, unsigned long c, int first, int size_only); static void decl_initializer(CType *type, Section *sec, unsigned long c, int first, int size_only);
static void block(int *bsym, int *csym, int is_expr); static void block(int *bsym, int *csym, int is_expr);
static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope); static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope);
static void decl(int l);
static int decl0(int l, int is_for_loop_init, Sym *); static int decl0(int l, int is_for_loop_init, Sym *);
static void expr_eq(void); static void expr_eq(void);
static void vla_runtime_type_size(CType *type, int *a); static void vla_runtime_type_size(CType *type, int *a);
@ -91,9 +92,9 @@ static void vla_sp_restore(void);
static void vla_sp_restore_root(void); static void vla_sp_restore_root(void);
static int is_compatible_unqualified_types(CType *type1, CType *type2); static int is_compatible_unqualified_types(CType *type1, CType *type2);
static inline int64_t expr_const64(void); static inline int64_t expr_const64(void);
ST_FUNC void vpush64(int ty, unsigned long long v); static void vpush64(int ty, unsigned long long v);
ST_FUNC void vpush(CType *type); static void vpush(CType *type);
ST_FUNC int gvtst(int inv, int t); static int gvtst(int inv, int t);
static void gen_inline_functions(TCCState *s); static void gen_inline_functions(TCCState *s);
static void skip_or_save_block(TokenString **str); static void skip_or_save_block(TokenString **str);
static void gv_dup(void); static void gv_dup(void);
@ -225,7 +226,7 @@ ST_FUNC void tcc_debug_funcend(TCCState *s1, int size)
} }
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
ST_FUNC void tccgen_start(TCCState *s1) ST_FUNC int tccgen_compile(TCCState *s1)
{ {
cur_text_section = NULL; cur_text_section = NULL;
funcname = ""; funcname = "";
@ -253,14 +254,22 @@ ST_FUNC void tccgen_start(TCCState *s1)
#ifdef TCC_TARGET_ARM #ifdef TCC_TARGET_ARM
arm_init(s1); arm_init(s1);
#endif #endif
}
ST_FUNC void tccgen_end(TCCState *s1) #ifdef INC_DEBUG
{ printf("%s: **** new file\n", file->filename);
#endif
parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM | PARSE_FLAG_TOK_STR;
next();
decl(VT_CONST);
if (tok != TOK_EOF)
expect("declaration");
gen_inline_functions(s1); gen_inline_functions(s1);
check_vstack(); check_vstack();
/* end of translation unit info */ /* end of translation unit info */
tcc_debug_end(s1); tcc_debug_end(s1);
return 0;
} }
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
@ -4441,15 +4450,11 @@ static void gfunc_param_typed(Sym *func, Sym *arg)
} }
} }
/* parse an expression and return its type without any side effect. /* parse an expression and return its type without any side effect. */
If UNRY we parse an unary expression, otherwise a full one. */ static void expr_type(CType *type, void (*expr_fn)(void))
static void expr_type(CType *type, int unry)
{ {
nocode_wanted++; nocode_wanted++;
if (unry) expr_fn();
unary();
else
gexpr();
*type = vtop->type; *type = vtop->type;
vpop(); vpop();
nocode_wanted--; nocode_wanted--;
@ -4466,7 +4471,7 @@ static void parse_expr_type(CType *type)
if (parse_btype(type, &ad)) { if (parse_btype(type, &ad)) {
type_decl(type, &ad, &n, TYPE_ABSTRACT); type_decl(type, &ad, &n, TYPE_ABSTRACT);
} else { } else {
expr_type(type, 0); expr_type(type, gexpr);
} }
skip(')'); skip(')');
} }
@ -4694,7 +4699,7 @@ ST_FUNC void unary(void)
t = tok; t = tok;
next(); next();
in_sizeof++; in_sizeof++;
expr_type(&type, 1); // Perform a in_sizeof = 0; expr_type(&type, unary); /* Perform a in_sizeof = 0; */
s = vtop[1].sym; /* hack: accessing previous vtop */ s = vtop[1].sym; /* hack: accessing previous vtop */
size = type_size(&type, &align); size = type_size(&type, &align);
if (s && s->a.aligned) if (s && s->a.aligned)
@ -4896,70 +4901,60 @@ ST_FUNC void unary(void)
CType controlling_type; CType controlling_type;
int has_default = 0; int has_default = 0;
int has_match = 0; int has_match = 0;
CType cur_type;
AttributeDef ad_tmp;
int learn = 0; int learn = 0;
TokenString *str = NULL; TokenString *str = NULL;
ParseState saved_parse_state;
next(); next();
skip('('); skip('(');
expr_type(&controlling_type, 1); expr_type(&controlling_type, expr_eq);
if (controlling_type.t & VT_ARRAY) controlling_type.t &= ~(VT_CONSTANT|VT_VOLATILE|VT_ARRAY);
controlling_type.t = VT_PTR;
controlling_type.t &= ~VT_CONSTANT;
controlling_type.t &= ~VT_VOLATILE;
for (;;) { for (;;) {
learn = 0; learn = 0;
skip(','); skip(',');
if (tok == TOK_DEFAULT) { if (tok == TOK_DEFAULT) {
if (has_default) if (has_default)
tcc_error("too many 'default'"); tcc_error("too many 'default'");
if (!has_match) { has_default = 1;
has_default = 1; if (!has_match)
learn = 1; learn = 1;
}
next(); next();
} else { } else {
AttributeDef ad_tmp;
int itmp; int itmp;
CType cur_type;
parse_btype(&cur_type, &ad_tmp); parse_btype(&cur_type, &ad_tmp);
type_decl(&cur_type, &ad_tmp, &itmp, TYPE_ABSTRACT); type_decl(&cur_type, &ad_tmp, &itmp, TYPE_ABSTRACT);
if (compare_types(&controlling_type, &cur_type, 0)) { if (compare_types(&controlling_type, &cur_type, 0)) {
if (has_match) { if (has_match) {
// tcc_error("type match twice"); // tcc_error("type match twice");
} }
if (str)
tok_str_free(str);
has_match = 1; has_match = 1;
learn = 1; learn = 1;
} }
} }
skip(':'); skip(':');
if (learn) { if (learn) {
if (str)
tok_str_free(str);
skip_or_save_block(&str); skip_or_save_block(&str);
} else { } else {
skip_or_save_block(NULL); skip_or_save_block(NULL);
} }
if (tok == ',') if (tok == ')')
continue;
else if (tok == ')')
break; break;
} }
if (!has_match && !has_default) { if (!str) {
char buf[256]; char buf[60];
type_to_str(buf, sizeof buf, &controlling_type, NULL);
type_to_str(buf, 256, &controlling_type, NULL); tcc_error("type '%s' does not match any association", buf);
tcc_error("_Generic selector of type '%s' is not compatible with any assosiation",
buf);
} }
skip(')');
save_parse_state(&saved_parse_state);
begin_macro(str, 1); begin_macro(str, 1);
next(); next();
expr_eq(); expr_eq();
if (tok != TOK_EOF)
expect(",");
end_macro(); end_macro();
restore_parse_state(&saved_parse_state); next();
break; break;
} }
// special qnan , snan and infinity values // special qnan , snan and infinity values
@ -5599,7 +5594,9 @@ ST_FUNC void gexpr(void)
static void expr_const1(void) static void expr_const1(void)
{ {
const_wanted++; const_wanted++;
nocode_wanted++;
expr_cond(); expr_cond();
nocode_wanted--;
const_wanted--; const_wanted--;
} }
@ -6721,8 +6718,8 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
int has_init, int v, int scope) int has_init, int v, int scope)
{ {
int size, align, addr; int size, align, addr;
ParseState saved_parse_state = {0};
TokenString *init_str = NULL; TokenString *init_str = NULL;
Section *sec; Section *sec;
Sym *flexible_array; Sym *flexible_array;
Sym *sym = NULL; Sym *sym = NULL;
@ -6768,10 +6765,9 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
} else { } else {
skip_or_save_block(&init_str); skip_or_save_block(&init_str);
} }
unget_tok(0);
/* compute size */
save_parse_state(&saved_parse_state);
/* compute size */
begin_macro(init_str, 1); begin_macro(init_str, 1);
next(); next();
decl_initializer(type, NULL, 0, 1, 1); decl_initializer(type, NULL, 0, 1, 1);
@ -6959,7 +6955,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
/* restore parse state if needed */ /* restore parse state if needed */
if (init_str) { if (init_str) {
end_macro(); end_macro();
restore_parse_state(&saved_parse_state); next();
} }
nocode_wanted = saved_nocode_wanted; nocode_wanted = saved_nocode_wanted;
@ -7328,7 +7324,7 @@ found:
return 0; return 0;
} }
ST_FUNC void decl(int l) static void decl(int l)
{ {
decl0(l, 0, NULL); decl0(l, 0, NULL);
} }

136
tccpp.c
View File

@ -820,9 +820,11 @@ ST_FUNC uint8_t *parse_comment(uint8_t *p)
return p; return p;
} }
ST_FUNC void set_idnum(int c, int val) ST_FUNC int set_idnum(int c, int val)
{ {
int prev = isidnum_table[c - CH_EOF];
isidnum_table[c - CH_EOF] = val; isidnum_table[c - CH_EOF] = val;
return prev;
} }
#define cinp minp #define cinp minp
@ -999,30 +1001,6 @@ _default:
file->buf_ptr = p; file->buf_ptr = p;
} }
/* ParseState handling */
/* XXX: currently, no include file info is stored. Thus, we cannot display
accurate messages if the function or data definition spans multiple
files */
/* save current parse state in 's' */
ST_FUNC void save_parse_state(ParseState *s)
{
s->line_num = file->line_num;
s->macro_ptr = macro_ptr;
s->tok = tok;
s->tokc = tokc;
}
/* restore parse state from 's' */
ST_FUNC void restore_parse_state(ParseState *s)
{
file->line_num = s->line_num;
macro_ptr = s->macro_ptr;
tok = s->tok;
tokc = s->tokc;
}
#if 0 #if 0
/* return the number of additional 'ints' necessary to store the /* return the number of additional 'ints' necessary to store the
token */ token */
@ -1124,6 +1102,7 @@ ST_FUNC void begin_macro(TokenString *str, int alloc)
str->alloc = alloc; str->alloc = alloc;
str->prev = macro_stack; str->prev = macro_stack;
str->prev_ptr = macro_ptr; str->prev_ptr = macro_ptr;
str->save_line_num = file->line_num;
macro_ptr = str->str; macro_ptr = str->str;
macro_stack = str; macro_stack = str;
} }
@ -1133,6 +1112,7 @@ ST_FUNC void end_macro(void)
TokenString *str = macro_stack; TokenString *str = macro_stack;
macro_stack = str->prev; macro_stack = str->prev;
macro_ptr = str->prev_ptr; macro_ptr = str->prev_ptr;
file->line_num = str->save_line_num;
if (str->alloc == 2) { if (str->alloc == 2) {
str->alloc = 3; /* just mark as finished */ str->alloc = 3; /* just mark as finished */
} else { } else {
@ -1402,6 +1382,21 @@ ST_FUNC void label_pop(Sym **ptop, Sym *slast, int keep)
*ptop = slast; *ptop = slast;
} }
/* fake the nth "#if defined test_..." for tcc -dt -run */
static void maybe_run_test(TCCState *s, int *c)
{
const char *p;
if (s->include_stack_ptr != s->include_stack)
return;
p = get_tok_str(tok, NULL);
if (0 != memcmp(p, "test_", 5))
return;
if (0 != --s->run_test)
return;
fprintf(s->ppfp, "\n[%s]\n" + !(s->dflag & 32), p), fflush(s->ppfp);
*c = 1;
}
/* eval an expression for #if/#elif */ /* eval an expression for #if/#elif */
static int expr_preprocess(void) static int expr_preprocess(void)
{ {
@ -1420,6 +1415,8 @@ static int expr_preprocess(void)
if (tok < TOK_IDENT) if (tok < TOK_IDENT)
expect("identifier"); expect("identifier");
c = define_find(tok) != 0; c = define_find(tok) != 0;
if (tcc_state->run_test)
maybe_run_test(tcc_state, &c);
if (t == '(') { if (t == '(') {
next_nomacro(); next_nomacro();
if (tok != ')') if (tok != ')')
@ -1467,7 +1464,7 @@ ST_FUNC void parse_define(void)
/* '(' must be just after macro definition for MACRO_FUNC */ /* '(' must be just after macro definition for MACRO_FUNC */
next_nomacro_spc(); next_nomacro_spc();
if (tok == '(') { if (tok == '(') {
set_idnum('.', 0); int dotid = set_idnum('.', 0);
next_nomacro(); next_nomacro();
ps = &first; ps = &first;
if (tok != ')') for (;;) { if (tok != ')') for (;;) {
@ -1495,6 +1492,7 @@ ST_FUNC void parse_define(void)
} }
next_nomacro_spc(); next_nomacro_spc();
t = MACRO_FUNC; t = MACRO_FUNC;
set_idnum('.', dotid);
} }
tokstr_buf.len = 0; tokstr_buf.len = 0;
@ -1505,7 +1503,6 @@ ST_FUNC void parse_define(void)
ID character in asm mode). But '#' should be retained instead of ID character in asm mode). But '#' should be retained instead of
regarded as line comment leader, so still don't set ASM_FILE regarded as line comment leader, so still don't set ASM_FILE
in parse_flags. */ in parse_flags. */
set_idnum('.', (saved_parse_flags & PARSE_FLAG_ASM_FILE) ? IS_ID : 0);
while (tok != TOK_LINEFEED && tok != TOK_EOF) { while (tok != TOK_LINEFEED && tok != TOK_EOF) {
/* remove spaces around ## and after '#' */ /* remove spaces around ## and after '#' */
if (TOK_TWOSHARPS == tok) { if (TOK_TWOSHARPS == tok) {
@ -1613,7 +1610,7 @@ static void pragma_parse(TCCState *s1)
} else if (tok == TOK_once) { } else if (tok == TOK_once) {
search_cached_include(s1, file->filename, 1)->once = pp_once; search_cached_include(s1, file->filename, 1)->once = pp_once;
} else if (s1->ppfp) { } else if (s1->output_type == TCC_OUTPUT_PREPROCESS) {
/* tcc -E: keep pragmas below unchanged */ /* tcc -E: keep pragmas below unchanged */
unget_tok(' '); unget_tok(' ');
unget_tok(TOK_PRAGMA); unget_tok(TOK_PRAGMA);
@ -3043,6 +3040,7 @@ static int paste_tokens(int t1, CValue *v1, int t2, CValue *v2)
tcc_open_bf(tcc_state, ":paste:", cstr.size); tcc_open_bf(tcc_state, ":paste:", cstr.size);
memcpy(file->buffer, cstr.data, cstr.size); memcpy(file->buffer, cstr.data, cstr.size);
tok_flags = 0;
for (;;) { for (;;) {
next_nomacro1(); next_nomacro1();
if (0 == *file->buf_ptr) if (0 == *file->buf_ptr)
@ -3164,6 +3162,8 @@ static int next_argstream(Sym **nested_list, TokenString *ws_str)
break; break;
ch = ' '; ch = ' ';
} }
if (ch == '\n')
file->line_num++;
if (!(ch == '\f' || ch == '\v' || ch == '\r')) if (!(ch == '\f' || ch == '\v' || ch == '\r'))
tok_str_add(ws_str, ch); tok_str_add(ws_str, ch);
cinp(); cinp();
@ -3483,7 +3483,7 @@ ST_INLN void unget_tok(int last_tok)
tok = last_tok; tok = last_tok;
} }
ST_FUNC void preprocess_start(TCCState *s1) ST_FUNC void preprocess_start(TCCState *s1, int is_asm)
{ {
char *buf; char *buf;
@ -3496,7 +3496,7 @@ ST_FUNC void preprocess_start(TCCState *s1)
s1->pack_stack_ptr = s1->pack_stack; s1->pack_stack_ptr = s1->pack_stack;
set_idnum('$', s1->dollars_in_identifiers ? IS_ID : 0); set_idnum('$', s1->dollars_in_identifiers ? IS_ID : 0);
set_idnum('.', (parse_flags & PARSE_FLAG_ASM_FILE) ? IS_ID : 0); set_idnum('.', is_asm ? IS_ID : 0);
buf = tcc_malloc(3 + strlen(file->filename)); buf = tcc_malloc(3 + strlen(file->filename));
sprintf(buf, "\"%s\"", file->filename); sprintf(buf, "\"%s\"", file->filename);
@ -3517,6 +3517,20 @@ ST_FUNC void preprocess_start(TCCState *s1)
memcpy(file->buffer, cstr.data, cstr.size); memcpy(file->buffer, cstr.data, cstr.size);
cstr_free(&cstr); cstr_free(&cstr);
} }
if (is_asm)
tcc_define_symbol(s1, "__ASSEMBLER__", NULL);
parse_flags = is_asm ? PARSE_FLAG_ASM_FILE : 0;
tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
}
/* cleanup from error/setjmp */
ST_FUNC void preprocess_end(TCCState *s1)
{
while (macro_stack)
end_macro();
macro_ptr = NULL;
} }
ST_FUNC void tccpp_new(TCCState *s) ST_FUNC void tccpp_new(TCCState *s)
@ -3526,6 +3540,7 @@ ST_FUNC void tccpp_new(TCCState *s)
/* might be used in error() before preprocess_start() */ /* might be used in error() before preprocess_start() */
s->include_stack_ptr = s->include_stack; s->include_stack_ptr = s->include_stack;
s->ppfp = stdout;
/* init isid table */ /* init isid table */
for(i = CH_EOF; i<128; i++) for(i = CH_EOF; i<128; i++)
@ -3570,14 +3585,6 @@ ST_FUNC void tccpp_delete(TCCState *s)
/* free -D and compiler defines */ /* free -D and compiler defines */
free_defines(NULL); free_defines(NULL);
/* cleanup from error/setjmp */
while (macro_stack)
end_macro();
macro_ptr = NULL;
while (file)
tcc_close();
/* free tokens */ /* free tokens */
n = tok_ident - TOK_IDENT; n = tok_ident - TOK_IDENT;
for(i = 0; i < n; i++) for(i = 0; i < n; i++)
@ -3606,19 +3613,16 @@ ST_FUNC void tccpp_delete(TCCState *s)
static void tok_print(const char *msg, const int *str) static void tok_print(const char *msg, const int *str)
{ {
FILE *fp; FILE *fp;
int t; int t, s = 0;
CValue cval; CValue cval;
fp = tcc_state->ppfp; fp = tcc_state->ppfp;
if (!fp || !tcc_state->dflag) fprintf(fp, "%s", msg);
fp = stdout;
fprintf(fp, "%s ", msg);
while (str) { while (str) {
TOK_GET(&t, &str, &cval); TOK_GET(&t, &str, &cval);
if (!t) if (!t)
break; break;
fprintf(fp,"%s", get_tok_str(t, &cval)); fprintf(fp, " %s" + s, get_tok_str(t, &cval)), s = 1;
} }
fprintf(fp, "\n"); fprintf(fp, "\n");
} }
@ -3731,20 +3735,14 @@ ST_FUNC int tcc_preprocess(TCCState *s1)
BufferedFile **iptr; BufferedFile **iptr;
int token_seen, spcs, level; int token_seen, spcs, level;
const char *p; const char *p;
Sym *define_start; char white[400];
define_start = define_stack;
preprocess_start(s1);
ch = file->buf_ptr[0];
tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
parse_flags = PARSE_FLAG_PREPROCESS parse_flags = PARSE_FLAG_PREPROCESS
| (parse_flags & PARSE_FLAG_ASM_FILE) | (parse_flags & PARSE_FLAG_ASM_FILE)
| PARSE_FLAG_LINEFEED | PARSE_FLAG_LINEFEED
| PARSE_FLAG_SPACES | PARSE_FLAG_SPACES
| PARSE_FLAG_ACCEPT_STRAYS | PARSE_FLAG_ACCEPT_STRAYS
; ;
/* Credits to Fabrice Bellard's initial revision to demonstrate its /* Credits to Fabrice Bellard's initial revision to demonstrate its
capability to compile and run itself, provided all numbers are capability to compile and run itself, provided all numbers are
given as decimals. tcc -E -P10 will do. */ given as decimals. tcc -E -P10 will do. */
@ -3754,7 +3752,6 @@ ST_FUNC int tcc_preprocess(TCCState *s1)
#ifdef PP_BENCH #ifdef PP_BENCH
/* for PP benchmarks */ /* for PP benchmarks */
do next(); while (tok != TOK_EOF); do next(); while (tok != TOK_EOF);
free_defines(define_start);
return 0; return 0;
#endif #endif
@ -3765,48 +3762,43 @@ ST_FUNC int tcc_preprocess(TCCState *s1)
token_seen = TOK_LINEFEED, spcs = 0; token_seen = TOK_LINEFEED, spcs = 0;
pp_line(s1, file, 0); pp_line(s1, file, 0);
for (;;) { for (;;) {
iptr = s1->include_stack_ptr; iptr = s1->include_stack_ptr;
next(); next();
if (tok == TOK_EOF) if (tok == TOK_EOF)
break; break;
level = s1->include_stack_ptr - iptr; level = s1->include_stack_ptr - iptr;
if (level) { if (level) {
if (level > 0) if (level > 0)
pp_line(s1, *iptr, 0); pp_line(s1, *iptr, 0);
pp_line(s1, file, level); pp_line(s1, file, level);
} }
if (s1->dflag & 7) {
if (s1->dflag) {
pp_debug_defines(s1); pp_debug_defines(s1);
if (s1->dflag & 4) if (s1->dflag & 4)
continue; continue;
} }
if (token_seen == TOK_LINEFEED) { if (is_space(tok)) {
if (tok == ' ') { if (spcs < sizeof white - 1)
++spcs; white[spcs++] = tok;
continue; continue;
}
if (tok == TOK_LINEFEED) {
spcs = 0;
continue;
}
pp_line(s1, file, 0);
} else if (tok == TOK_LINEFEED) { } else if (tok == TOK_LINEFEED) {
spcs = 0;
if (token_seen == TOK_LINEFEED)
continue;
++file->line_ref; ++file->line_ref;
} else { } else if (token_seen == TOK_LINEFEED) {
spcs = pp_need_space(token_seen, tok); pp_line(s1, file, 0);
} else if (spcs == 0 && pp_need_space(token_seen, tok)) {
white[spcs++] = ' ';
} }
while (spcs) white[spcs] = 0, fputs(white, s1->ppfp), spcs = 0;
fputs(" ", s1->ppfp), --spcs;
fputs(p = get_tok_str(tok, &tokc), s1->ppfp); fputs(p = get_tok_str(tok, &tokc), s1->ppfp);
token_seen = pp_check_he0xE(tok, p);; token_seen = pp_check_he0xE(tok, p);
} }
/* reset define stack, but keep -D and built-ins */
free_defines(define_start);
return 0; return 0;
} }

View File

@ -108,6 +108,8 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
int (*prog_main)(int, char **); int (*prog_main)(int, char **);
s1->runtime_main = "main"; s1->runtime_main = "main";
if ((s1->dflag & 16) && !find_elf_sym(s1->symtab, s1->runtime_main))
return 0;
if (tcc_relocate(s1, TCC_RELOCATE_AUTO) < 0) if (tcc_relocate(s1, TCC_RELOCATE_AUTO) < 0)
return -1; return -1;
prog_main = tcc_get_symbol_err(s1, s1->runtime_main); prog_main = tcc_get_symbol_err(s1, s1->runtime_main);

View File

@ -543,111 +543,4 @@ ST_FUNC void gen_makedeps(TCCState *s, const char *target, const char *filename)
fclose(depout); fclose(depout);
} }
#ifdef TCC_IS_NATIVE
/* -------------------------------------------------------------- */
/* run test snippets from file */
static char *readfile(const char *fname)
{
char *buf;
int fsize;
FILE *fi;
fi = fopen(fname, "rb");
if (!fi)
return NULL;
fseek(fi, 0, SEEK_END);
fsize = ftell(fi);
fseek(fi, 0, SEEK_SET);
buf = tcc_malloc(fsize + 1);
fread(buf, fsize, 1, fi);
fclose(fi);
buf[fsize] = 0;
return buf;
}
static int run_prog(const char *prog, int ac, char **av)
{
TCCState *s;
int (*func)(int, char**);
int ret = -10000;
s = tcc_new();
tcc_parse_args(s, &ac, &av, 1);
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
if (tcc_compile_string(s, prog) == -1)
goto done;
if (tcc_relocate(s, TCC_RELOCATE_AUTO) < 0)
goto done;
func = tcc_get_symbol(s, "main");
if (!func)
goto done;
ret = func(ac, av);
done:
tcc_delete(s);
return ret;
}
static char *trimback(char *a, char *e)
{
while (e > a && (unsigned char)e[-1] <= ' ')
--e;
*e = 0;;
return a;
}
ST_FUNC int tcc_tool_test(TCCState *s, int argc, char **argv)
{
const char *fname;
char *buf, *p, *a, *b, *e, tmp[100];
int r = 0, c, n;
const char sep[] = "/*-* test";
n = s->do_test - argc;
if (!n)
return 0;
fname = argv[0], argv -= n, argc += n;
buf = readfile(fname);
if (NULL == buf)
return -1;
p = strstr(buf, sep);
if (!p) {
tcc_free(buf);
return -1;
}
while (*p) {
a = p, p = strchr(p, '\n');
if (NULL == p)
break;
*p++ = 0;
b = p, p = strstr(p, sep);
if (NULL == p)
p = strchr(b, 0);
c = *p, *p = 0;
trimback(a, b);
if (r)
printf("\n");
printf("%s\n", a);
fflush(stdout);
e = a += sizeof sep - 5;
while (*e && *e != ':')
++e;
if (!*e || e - a > 32)
e = a + 4;
n = snprintf(tmp, sizeof tmp, "#line 1 \"%.*s\"\n", (int)(e - a), a);
if (b - buf >= n)
b = memcpy(b - n, tmp, n);
n = run_prog(b, argc, argv);
if (n != -10000)
printf("returns %d\n", n);
*p = c, ++r;
}
tcc_free(buf);
exit(0);
}
#endif /* TCC_IS_NATIVE */
/* -------------------------------------------------------------- */ /* -------------------------------------------------------------- */

View File

@ -1 +0,0 @@
struct A {} int i;

View File

@ -1 +0,0 @@
56_btype_excess-1.c:1: error: too many basic types

View File

@ -1 +0,0 @@
char int i;

View File

@ -1 +0,0 @@
57_btype_excess-2.c:1: error: too many basic types

View File

@ -1,9 +0,0 @@
int f(void)
{
return 0;
}
int f(void)
{
return 1;
}

View File

@ -1 +0,0 @@
58_function_redefinition.c:7: error: redefinition of 'f'

View File

@ -1 +0,0 @@
int (*fct)[42](int x);

View File

@ -1 +0,0 @@
59_function_array.c:1: error: declaration of an array of functions

View File

@ -1,4 +0,0 @@
enum color {RED, GREEN, BLUE};
enum color {R, G, B};
enum color c;

View File

@ -1 +0,0 @@
60_enum_redefinition.c:2: error: struct/union/enum already defined

View File

@ -0,0 +1,51 @@
#if defined test_56_btype_excess_1
struct A {} int i;
#elif defined test_57_btype_excess_2
char int i;
#elif defined test_58_function_redefinition
int f(void) { return 0; }
int f(void) { return 1; }
#elif defined test_global_redefinition
int xxx = 1;
int xxx;
int xxx = 2;
#elif defined test_59_function_array
int (*fct)[42](int x);
#elif defined test_60_enum_redefinition
enum color { RED, GREEN, BLUE };
enum color { R, G, B };
enum color c;
#elif defined test_62_enumerator_redefinition
enum color { RED, GREEN, BLUE };
enum rgb { RED, G, B};
enum color c = RED;
#elif defined test_63_local_enumerator_redefinition
enum {
FOO,
BAR
};
int main(void)
{
enum {
FOO = 2,
BAR
};
return BAR - FOO;
}
#elif defined test_61_undefined_enum
enum rgb3 c = 42;
#elif defined test_74_non_const_init
int i = i++;
#endif

View File

@ -0,0 +1,28 @@
[test_56_btype_excess_1]
60_errors_and_warnings.c:2: error: too many basic types
[test_57_btype_excess_2]
60_errors_and_warnings.c:5: error: too many basic types
[test_58_function_redefinition]
60_errors_and_warnings.c:9: error: redefinition of 'f'
[test_global_redefinition]
60_errors_and_warnings.c:14: error: redefinition of 'xxx'
[test_59_function_array]
60_errors_and_warnings.c:17: error: declaration of an array of functions
[test_60_enum_redefinition]
60_errors_and_warnings.c:21: error: struct/union/enum already defined
[test_62_enumerator_redefinition]
60_errors_and_warnings.c:26: error: redefinition of enumerator 'RED'
[test_63_local_enumerator_redefinition]
[test_61_undefined_enum]
60_errors_and_warnings.c:46: error: unknown type size
[test_74_non_const_init]
60_errors_and_warnings.c:49: error: initializer element is not constant

View File

@ -1 +0,0 @@
enum rgb c = 42;

View File

@ -1 +0,0 @@
61_undefined_enum.c:1: error: unknown type size

View File

@ -1,4 +0,0 @@
enum color {RED, GREEN, BLUE};
enum rgb {RED, G, B};
enum color c = RED;

View File

@ -1 +0,0 @@
62_enumerator_redefinition.c:2: error: redefinition of enumerator 'RED'

View File

@ -1,14 +0,0 @@
enum {
FOO,
BAR
};
int main(void)
{
enum {
FOO = 2,
BAR
};
return BAR - FOO;
}

View File

@ -1 +0,0 @@
int i = i++;

View File

@ -1 +0,0 @@
74_nocode_wanted.c:1: error: initializer element is not constant

View File

@ -1,36 +1,35 @@
/*****************************************************************************/ /*****************************************************************************/
/* test 'nodata_wanted' data output suppression */ /* test 'nodata_wanted' data output suppression */
/*-* test 1: initializer not computable 1 */ #if defined test_static_data_error
void foo() { void foo() {
if (1) { if (1) {
static short w = (int)&foo; /* error */ static short w = (int)&foo; /* initializer not computable */
} }
} }
/*-* test 2: initializer not computable 2 */ #elif defined test_static_nodata_error
void foo() { void foo() {
if (0) { if (0) {
static short w = (int)&foo; /* error */ static short w = (int)&foo; /* initializer not computable */
} }
} }
/*-* test 3: initializer not computable 3 */ #elif defined test_global_data_error
void foo(); void foo();
static short w = (int)&foo; /* error */ static short w = (int)&foo; /* initializer not computable */
/*-* test 4: 2 cast warnings */ #elif defined test_local_data_noerror
void foo() { void foo() {
short w = &foo; /* no error */ short w = &foo; /* 2 cast warnings */
} }
/*-* test 5; nodata_wanted test */ #elif defined test_data_suppression
#include <stdio.h> #include <stdio.h>
#define DATA_LBL(s) \ #define ASMLABELS(s) \
__asm__(".global d"#s",t"#s"\n.data\nd"#s":\n.text\nt"#s":\n"); \ __asm__(".global d"#s",t"#s"\n.data\nd"#s":\n.text\nt"#s":\n")
extern char d##s[],t##s[];
#define PROG \ #define PROG \
static void *p = (void*)&main;\ static void *p = (void*)&main;\
@ -47,28 +46,29 @@ void foo() {
int main() int main()
{ {
extern char ds1[],ts1[];
extern char ds2[],ts2[];
extern char de1[],te1[];
extern char de2[],te2[];
printf("suppression off\n"); printf("suppression off\n");
DATA_LBL(s1);
if (1) { if (1) {
ASMLABELS(s1);
PROG PROG
ASMLABELS(e1);
} }
DATA_LBL(e1);
printf(" data length is %s\n", de1 - ds1 ? "not 0":"0"); printf(" data length is %s\n", de1 - ds1 ? "not 0":"0");
//printf(" text length is %s\n", te1 - ts1 ? "not 0":"0"); printf(" text length is %s\n", te1 - ts1 ? "not 0":"0");
printf("suppression on\n"); printf("suppression on\n");
DATA_LBL(s2);
if (0) { if (0) {
ASMLABELS(s2);
PROG PROG
ASMLABELS(e2);
} }
DATA_LBL(e2);
printf(" data length is %x\n", de2 - ds2); printf(" data length is %x\n", de2 - ds2);
//printf(" text length is %X\n", te2 - ts2); printf(" text length is %X\n", te2 - ts2);
return 0; return 0;
} }
/*-* test 6: some test */ #endif
int main()
{
return 34;
}

View File

@ -1,24 +1,22 @@
/*-* test 1: initializer not computable 1 */ [test_static_data_error]
test 1:3: error: initializer element is not computable at load time 96_nodata_wanted.c:7: error: initializer element is not computable at load time
/*-* test 2: initializer not computable 2 */ [test_static_nodata_error]
test 2:3: error: initializer element is not computable at load time 96_nodata_wanted.c:14: error: initializer element is not computable at load time
/*-* test 3: initializer not computable 3 */ [test_global_data_error]
test 3:2: error: initializer element is not computable at load time 96_nodata_wanted.c:20: error: initializer element is not computable at load time
/*-* test 4: 2 cast warnings */ [test_local_data_noerror]
test 4:2: warning: assignment makes integer from pointer without a cast 96_nodata_wanted.c:25: warning: assignment makes integer from pointer without a cast
test 4:2: warning: nonportable conversion from pointer to char/short 96_nodata_wanted.c:25: warning: nonportable conversion from pointer to char/short
/*-* test 5; nodata_wanted test */ [test_data_suppression]
suppression off suppression off
static data: 8 - 8.0 - 8.0 - main - static string static data: 8 - 8.0 - 8.0 - main - static string
static bitfields: 333 44 555555 6 7 static bitfields: 333 44 555555 6 7
data length is not 0 data length is not 0
text length is not 0
suppression on suppression on
data length is 0 data length is 0
returns 0 text length is 0
/*-* test 6: some test */
returns 34

View File

@ -20,7 +20,7 @@ endif
ifeq (,$(filter i386 x86_64,$(ARCH))) ifeq (,$(filter i386 x86_64,$(ARCH)))
SKIP += 85_asm-outside-function.test SKIP += 85_asm-outside-function.test
endif endif
ifeq (-$(findstring gcc,$(CC)-)-,--) ifeq (-$(findstring gcc,$(CC))-,--)
SKIP += $(patsubst %.expect,%.test,$(GEN-ALWAYS)) SKIP += $(patsubst %.expect,%.test,$(GEN-ALWAYS))
endif endif
ifeq (-$(CONFIG_WIN32)-$(CONFIG_i386)$(CONFIG_arm)-,--yes-) ifeq (-$(CONFIG_WIN32)-$(CONFIG_i386)$(CONFIG_arm)-,--yes-)
@ -40,8 +40,9 @@ NORUN =
FLAGS = FLAGS =
76_dollars_in_identifiers.test : FLAGS += -fdollars-in-identifiers 76_dollars_in_identifiers.test : FLAGS += -fdollars-in-identifiers
# run the source file cut into snippets # These tests run several snippets from the same file one by one
96_nodata_wanted.test : FLAGS = -dT 60_errors_and_warnings.test : FLAGS += -dt
96_nodata_wanted.test : FLAGS += -dt
# Always generate certain .expects (don't put these in the GIT), # Always generate certain .expects (don't put these in the GIT),
GEN-ALWAYS = GEN-ALWAYS =
@ -90,8 +91,8 @@ F2 = $1 UPDATE="$(patsubst %.test,%.expect,$1)"
@$(call GEN,$(SRC)/$*.c) $(FILTER) >$@ 2>&1 @$(call GEN,$(SRC)/$*.c) $(FILTER) >$@ 2>&1
@rm -f *.exe *.obj *.pdb @rm -f *.exe *.obj *.pdb
# using TCC for .expect if -dT in FLAGS # using TCC for .expect if -dt in FLAGS
GEN = $(if $(findstring -dT,$(FLAGS)),$(GEN-TCC),$(GEN-CC)) GEN = $(if $(filter -dt,$(FLAGS)),$(GEN-TCC),$(GEN-CC))
GEN-CC = $(CC) -w -std=gnu99 $(FLAGS) $1 -o a.exe && ./a.exe $(ARGS) GEN-CC = $(CC) -w -std=gnu99 $(FLAGS) $1 -o a.exe && ./a.exe $(ARGS)
GEN-TCC = $(TCC) $(FLAGS) -run $1 $(ARGS) GEN-TCC = $(TCC) $(FLAGS) -run $1 $(ARGS)
GEN-MSC = $(MS-CC) $1 && ./$(basename $@).exe GEN-MSC = $(MS-CC) $1 && ./$(basename $@).exe