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) {
/* default case: stderr */
if (s1->ppfp) /* print a newline during tcc -E */
fprintf(s1->ppfp, "\n"), fflush(s1->ppfp);
if (s1->output_type == TCC_OUTPUT_PREPROCESS && s1->ppfp == stdout)
/* print a newline during tcc -E */
printf("\n"), fflush(stdout);
fflush(stdout); /* flush -v output */
fprintf(stderr, "%s\n", buf);
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->prev = file;
file = bf;
tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
}
ST_FUNC void tcc_close(void)
@ -622,36 +624,36 @@ ST_FUNC int tcc_open(TCCState *s1, const char *filename)
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)
{
Sym *define_start;
int filetype, is_asm;
define_start = define_stack;
filetype = s1->filetype;
is_asm = filetype == AFF_TYPE_ASM || filetype == AFF_TYPE_ASMPP;
if (setjmp(s1->error_jmp_buf) == 0) {
s1->nb_errors = 0;
s1->error_set_jmp_enabled = 1;
preprocess_start(s1);
tccgen_start(s1);
#ifdef INC_DEBUG
printf("%s: **** new file\n", file->filename);
preprocess_start(s1, is_asm);
if (s1->output_type == TCC_OUTPUT_PREPROCESS) {
tcc_preprocess(s1);
} else if (is_asm) {
#ifdef CONFIG_TCC_ASM
tcc_assemble(s1, filetype == AFF_TYPE_ASMPP);
#else
tcc_error_noabort("asm not supported");
#endif
ch = file->buf_ptr[0];
tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
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);
} else {
tccgen_compile(s1);
}
}
s1->error_set_jmp_enabled = 0;
preprocess_end(s1);
free_inline_functions(s1);
/* reset define stack, but keep -D and built-ins */
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);
/* parse with define parser */
ch = file->buf_ptr[0];
next_nomacro();
parse_define();
tcc_close();
}
@ -713,6 +713,8 @@ static void tcc_cleanup(void)
{
if (NULL == tcc_state)
return;
while (file)
tcc_close();
tccpp_delete(tcc_state);
tcc_state = NULL;
/* 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)
{
int ret, filetype;
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;
}
}
int ret;
/* open the file */
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,
tcc_strdup(filename));
parse_flags = 0;
/* 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 {
if (flags & AFF_TYPE_BIN) {
ElfW(Ehdr) ehdr;
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");
break;
}
} else {
ret = tcc_compile(s1);
}
tcc_close();
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)
{
if (s->output_type == TCC_OUTPUT_PREPROCESS)
return tcc_add_file_internal(s, filename, AFF_PRINT_ERROR | AFF_PREPROCESS | s->filetype);
else
return tcc_add_file_internal(s, filename, AFF_PRINT_ERROR | s->filetype);
int filetype = s->filetype;
int flags = AFF_PRINT_ERROR;
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
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)
@ -1799,8 +1782,8 @@ reparse:
s->dflag = 3;
else if (*optarg == 'M')
s->dflag = 7;
else if (*optarg == 'T')
s->do_test = argc;
else if (*optarg == 't')
s->dflag = 16;
else if (isnum(*optarg))
g_debug = atoi(optarg);
else

40
tcc.c
View File

@ -91,6 +91,7 @@ static const char help2[] =
" -static link to static libraries (not recommended)\n"
" -dumpversion print version\n"
" -print-search-dirs print search paths\n"
" -dt with -run/-E: auto-define 'test_...' macros\n"
"Ignored options:\n"
" --param -pedantic -pipe -s -std -traditional\n"
"-W... warnings:\n"
@ -244,18 +245,21 @@ static unsigned getclock_ms(void)
#endif
}
int main(int argc, char **argv)
int main(int argc0, char **argv0)
{
TCCState *s;
int ret, opt, n = 0;
int ret, opt, n = 0, t = 0;
unsigned start_time = 0;
const char *first_file;
int argc; char **argv;
FILE *ppfp = stdout;
redo:
argc = argc0, argv = argv0;
s = tcc_new();
opt = tcc_parse_args(s, &argc, &argv, 1);
if (n == 0) {
if ((n | t) == 0) {
if (opt == OPT_HELP)
return printf(help), 1;
if (opt == OPT_HELP2)
@ -282,17 +286,11 @@ redo:
n = s->nb_files;
if (n == 0)
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->outfile) {
s->ppfp = stdout;
} else {
s->ppfp = fopen(s->outfile, "w");
if (!s->ppfp)
if (s->outfile) {
ppfp = fopen(s->outfile, "w");
if (!ppfp)
tcc_error("could not write '%s'", s->outfile);
}
} else if (s->output_type == TCC_OUTPUT_OBJ && !s->option_r) {
@ -313,6 +311,11 @@ redo:
if (s->output_type == 0)
s->output_type = TCC_OUTPUT_EXE;
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 */
for (first_file = NULL, ret = 0;;) {
@ -338,8 +341,7 @@ redo:
}
if (s->output_type == TCC_OUTPUT_PREPROCESS) {
if (s->outfile)
fclose(s->ppfp);
;
} else if (0 == ret) {
if (s->output_type == TCC_OUTPUT_MEMORY) {
#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_delete(s);
if (ret == 0 && n)
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;
}

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_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 */
typedef struct TokenString {
int *str;
@ -572,6 +563,7 @@ typedef struct TokenString {
int lastlen;
int allocated_len;
int last_line_num;
int save_line_num;
/* used to chain token-strings with begin/end_macro() */
struct TokenString *prev;
const int *prev_ptr;
@ -675,6 +667,7 @@ struct TCCState {
#ifdef TCC_TARGET_ARM
enum float_abi float_abi; /* float ABI of the generated code*/
#endif
int run_test; /* nth test to run with -dt -run */
addr_t text_addr; /* address of text section */
int has_text_addr;
@ -813,7 +806,6 @@ struct TCCState {
int option_pthread; /* -pthread option */
int argc;
char **argv;
int do_test;
};
struct filespec {
@ -1145,14 +1137,13 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
/* flags: */
#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_PREPROCESS 0x40 /* preprocess file */
/* combined with: */
#define AFF_TYPE_BIN 0x40 /* file to add is binary */
/* s->filetype: */
#define AFF_TYPE_NONE 0
#define AFF_TYPE_C 1
#define AFF_TYPE_ASM 2
#define AFF_TYPE_ASMPP 3
#define AFF_TYPE_BIN 4
#define AFF_TYPE_LIB 5
#define AFF_TYPE_LIB 4
/* values from tcc_object_type(...) */
#define AFF_BINTYPE_REL 1
#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 void begin_macro(TokenString *str, int alloc);
ST_FUNC void end_macro(void);
ST_FUNC void set_idnum(int c, int val);
ST_FUNC void save_parse_state(ParseState *s);
ST_FUNC void restore_parse_state(ParseState *s);
ST_FUNC int set_idnum(int c, int val);
ST_INLN void tok_str_new(TokenString *s);
ST_FUNC TokenString *tok_str_alloc(void);
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(void);
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_delete(TCCState *s);
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_line(TCCState *s1);
ST_FUNC void tccgen_start(TCCState *s1);
ST_FUNC void tccgen_end(TCCState *s1);
ST_FUNC int tccgen_compile(TCCState *s1);
ST_FUNC void free_inline_functions(TCCState *s);
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 gexpr(void);
ST_FUNC int expr_const(void);
ST_FUNC void decl(int l);
#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);
#endif

View File

@ -628,20 +628,16 @@ static void asm_parse_directive(TCCState *s1, int global)
{
int repeat;
TokenString *init_str;
ParseState saved_parse_state = {0};
next();
repeat = asm_int_expr(s1);
init_str = tok_str_alloc();
next();
while ((tok != TOK_ASMDIR_endr) && (tok != CH_EOF)) {
while (next(), tok != TOK_ASMDIR_endr) {
if (tok == CH_EOF)
tcc_error("we at end of file, .endr not found");
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, 0);
save_parse_state(&saved_parse_state);
begin_macro(init_str, 1);
while (repeat-- > 0) {
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;
}
end_macro();
restore_parse_state(&saved_parse_state);
next();
break;
}
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)
{
int opcode;
int saved_parse_flags = parse_flags;
/* 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;
set_idnum('.', IS_ID);
if (do_preprocess)
parse_flags |= PARSE_FLAG_PREPROCESS;
for(;;) {
@ -990,30 +983,22 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global)
}
asm_free_labels(s1);
parse_flags = saved_parse_flags;
return 0;
}
/* Assemble the current file */
ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess)
{
Sym *define_start;
int ret;
define_start = define_stack;
preprocess_start(s1);
tcc_debug_start(s1);
/* default section is text */
cur_text_section = text_section;
ind = cur_text_section->data_offset;
nocode_wanted = 0;
ret = tcc_assemble_internal(s1, do_preprocess, 1);
cur_text_section->data_offset = ind;
tcc_debug_end(s1);
free_defines(define_start);
return ret;
}
@ -1025,21 +1010,16 @@ ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess)
end */
static void tcc_assemble_inline(TCCState *s1, char *str, int len, int global)
{
int saved_parse_flags;
const int *saved_macro_ptr;
saved_parse_flags = parse_flags;
saved_macro_ptr = macro_ptr;
const int *saved_macro_ptr = macro_ptr;
int dotid = set_idnum('.', IS_ID);
tcc_open_bf(s1, ":asm:", len);
memcpy(file->buffer, str, len);
macro_ptr = NULL;
tcc_assemble_internal(s1, 0, global);
tcc_close();
parse_flags = saved_parse_flags;
set_idnum('.', (parse_flags & PARSE_FLAG_ASM_FILE) ? IS_ID : 0);
set_idnum('.', dotid);
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 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(int l);
static int decl0(int l, int is_for_loop_init, Sym *);
static void expr_eq(void);
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 int is_compatible_unqualified_types(CType *type1, CType *type2);
static inline int64_t expr_const64(void);
ST_FUNC void vpush64(int ty, unsigned long long v);
ST_FUNC void vpush(CType *type);
ST_FUNC int gvtst(int inv, int t);
static void vpush64(int ty, unsigned long long v);
static void vpush(CType *type);
static int gvtst(int inv, int t);
static void gen_inline_functions(TCCState *s);
static void skip_or_save_block(TokenString **str);
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;
funcname = "";
@ -253,14 +254,22 @@ ST_FUNC void tccgen_start(TCCState *s1)
#ifdef TCC_TARGET_ARM
arm_init(s1);
#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);
check_vstack();
/* end of translation unit info */
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.
If UNRY we parse an unary expression, otherwise a full one. */
static void expr_type(CType *type, int unry)
/* parse an expression and return its type without any side effect. */
static void expr_type(CType *type, void (*expr_fn)(void))
{
nocode_wanted++;
if (unry)
unary();
else
gexpr();
expr_fn();
*type = vtop->type;
vpop();
nocode_wanted--;
@ -4466,7 +4471,7 @@ static void parse_expr_type(CType *type)
if (parse_btype(type, &ad)) {
type_decl(type, &ad, &n, TYPE_ABSTRACT);
} else {
expr_type(type, 0);
expr_type(type, gexpr);
}
skip(')');
}
@ -4694,7 +4699,7 @@ ST_FUNC void unary(void)
t = tok;
next();
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 */
size = type_size(&type, &align);
if (s && s->a.aligned)
@ -4896,70 +4901,60 @@ ST_FUNC void unary(void)
CType controlling_type;
int has_default = 0;
int has_match = 0;
CType cur_type;
AttributeDef ad_tmp;
int learn = 0;
TokenString *str = NULL;
ParseState saved_parse_state;
next();
skip('(');
expr_type(&controlling_type, 1);
if (controlling_type.t & VT_ARRAY)
controlling_type.t = VT_PTR;
controlling_type.t &= ~VT_CONSTANT;
controlling_type.t &= ~VT_VOLATILE;
expr_type(&controlling_type, expr_eq);
controlling_type.t &= ~(VT_CONSTANT|VT_VOLATILE|VT_ARRAY);
for (;;) {
learn = 0;
skip(',');
if (tok == TOK_DEFAULT) {
if (has_default)
tcc_error("too many 'default'");
if (!has_match) {
has_default = 1;
has_default = 1;
if (!has_match)
learn = 1;
}
next();
} else {
AttributeDef ad_tmp;
int itmp;
CType cur_type;
parse_btype(&cur_type, &ad_tmp);
type_decl(&cur_type, &ad_tmp, &itmp, TYPE_ABSTRACT);
if (compare_types(&controlling_type, &cur_type, 0)) {
if (has_match) {
// tcc_error("type match twice");
}
if (str)
tok_str_free(str);
has_match = 1;
learn = 1;
}
}
skip(':');
if (learn) {
if (str)
tok_str_free(str);
skip_or_save_block(&str);
} else {
skip_or_save_block(NULL);
}
if (tok == ',')
continue;
else if (tok == ')')
if (tok == ')')
break;
}
if (!has_match && !has_default) {
char buf[256];
type_to_str(buf, 256, &controlling_type, NULL);
tcc_error("_Generic selector of type '%s' is not compatible with any assosiation",
buf);
if (!str) {
char buf[60];
type_to_str(buf, sizeof buf, &controlling_type, NULL);
tcc_error("type '%s' does not match any association", buf);
}
skip(')');
save_parse_state(&saved_parse_state);
begin_macro(str, 1);
next();
expr_eq();
if (tok != TOK_EOF)
expect(",");
end_macro();
restore_parse_state(&saved_parse_state);
next();
break;
}
// special qnan , snan and infinity values
@ -5599,7 +5594,9 @@ ST_FUNC void gexpr(void)
static void expr_const1(void)
{
const_wanted++;
nocode_wanted++;
expr_cond();
nocode_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 size, align, addr;
ParseState saved_parse_state = {0};
TokenString *init_str = NULL;
Section *sec;
Sym *flexible_array;
Sym *sym = NULL;
@ -6768,10 +6765,9 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
} else {
skip_or_save_block(&init_str);
}
/* compute size */
save_parse_state(&saved_parse_state);
unget_tok(0);
/* compute size */
begin_macro(init_str, 1);
next();
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 */
if (init_str) {
end_macro();
restore_parse_state(&saved_parse_state);
next();
}
nocode_wanted = saved_nocode_wanted;
@ -7328,7 +7324,7 @@ found:
return 0;
}
ST_FUNC void decl(int l)
static void decl(int l)
{
decl0(l, 0, NULL);
}

136
tccpp.c
View File

@ -820,9 +820,11 @@ ST_FUNC uint8_t *parse_comment(uint8_t *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;
return prev;
}
#define cinp minp
@ -999,30 +1001,6 @@ _default:
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
/* return the number of additional 'ints' necessary to store the
token */
@ -1124,6 +1102,7 @@ ST_FUNC void begin_macro(TokenString *str, int alloc)
str->alloc = alloc;
str->prev = macro_stack;
str->prev_ptr = macro_ptr;
str->save_line_num = file->line_num;
macro_ptr = str->str;
macro_stack = str;
}
@ -1133,6 +1112,7 @@ ST_FUNC void end_macro(void)
TokenString *str = macro_stack;
macro_stack = str->prev;
macro_ptr = str->prev_ptr;
file->line_num = str->save_line_num;
if (str->alloc == 2) {
str->alloc = 3; /* just mark as finished */
} else {
@ -1402,6 +1382,21 @@ ST_FUNC void label_pop(Sym **ptop, Sym *slast, int keep)
*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 */
static int expr_preprocess(void)
{
@ -1420,6 +1415,8 @@ static int expr_preprocess(void)
if (tok < TOK_IDENT)
expect("identifier");
c = define_find(tok) != 0;
if (tcc_state->run_test)
maybe_run_test(tcc_state, &c);
if (t == '(') {
next_nomacro();
if (tok != ')')
@ -1467,7 +1464,7 @@ ST_FUNC void parse_define(void)
/* '(' must be just after macro definition for MACRO_FUNC */
next_nomacro_spc();
if (tok == '(') {
set_idnum('.', 0);
int dotid = set_idnum('.', 0);
next_nomacro();
ps = &first;
if (tok != ')') for (;;) {
@ -1495,6 +1492,7 @@ ST_FUNC void parse_define(void)
}
next_nomacro_spc();
t = MACRO_FUNC;
set_idnum('.', dotid);
}
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
regarded as line comment leader, so still don't set ASM_FILE
in parse_flags. */
set_idnum('.', (saved_parse_flags & PARSE_FLAG_ASM_FILE) ? IS_ID : 0);
while (tok != TOK_LINEFEED && tok != TOK_EOF) {
/* remove spaces around ## and after '#' */
if (TOK_TWOSHARPS == tok) {
@ -1613,7 +1610,7 @@ static void pragma_parse(TCCState *s1)
} else if (tok == TOK_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 */
unget_tok(' ');
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);
memcpy(file->buffer, cstr.data, cstr.size);
tok_flags = 0;
for (;;) {
next_nomacro1();
if (0 == *file->buf_ptr)
@ -3164,6 +3162,8 @@ static int next_argstream(Sym **nested_list, TokenString *ws_str)
break;
ch = ' ';
}
if (ch == '\n')
file->line_num++;
if (!(ch == '\f' || ch == '\v' || ch == '\r'))
tok_str_add(ws_str, ch);
cinp();
@ -3483,7 +3483,7 @@ ST_INLN void unget_tok(int last_tok)
tok = last_tok;
}
ST_FUNC void preprocess_start(TCCState *s1)
ST_FUNC void preprocess_start(TCCState *s1, int is_asm)
{
char *buf;
@ -3496,7 +3496,7 @@ ST_FUNC void preprocess_start(TCCState *s1)
s1->pack_stack_ptr = s1->pack_stack;
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));
sprintf(buf, "\"%s\"", file->filename);
@ -3517,6 +3517,20 @@ ST_FUNC void preprocess_start(TCCState *s1)
memcpy(file->buffer, cstr.data, cstr.size);
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)
@ -3526,6 +3540,7 @@ ST_FUNC void tccpp_new(TCCState *s)
/* might be used in error() before preprocess_start() */
s->include_stack_ptr = s->include_stack;
s->ppfp = stdout;
/* init isid table */
for(i = CH_EOF; i<128; i++)
@ -3570,14 +3585,6 @@ ST_FUNC void tccpp_delete(TCCState *s)
/* free -D and compiler defines */
free_defines(NULL);
/* cleanup from error/setjmp */
while (macro_stack)
end_macro();
macro_ptr = NULL;
while (file)
tcc_close();
/* free tokens */
n = tok_ident - TOK_IDENT;
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)
{
FILE *fp;
int t;
int t, s = 0;
CValue cval;
fp = tcc_state->ppfp;
if (!fp || !tcc_state->dflag)
fp = stdout;
fprintf(fp, "%s ", msg);
fprintf(fp, "%s", msg);
while (str) {
TOK_GET(&t, &str, &cval);
if (!t)
break;
fprintf(fp,"%s", get_tok_str(t, &cval));
fprintf(fp, " %s" + s, get_tok_str(t, &cval)), s = 1;
}
fprintf(fp, "\n");
}
@ -3731,20 +3735,14 @@ ST_FUNC int tcc_preprocess(TCCState *s1)
BufferedFile **iptr;
int token_seen, spcs, level;
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_ASM_FILE)
| PARSE_FLAG_LINEFEED
| PARSE_FLAG_SPACES
| PARSE_FLAG_ACCEPT_STRAYS
;
/* Credits to Fabrice Bellard's initial revision to demonstrate its
capability to compile and run itself, provided all numbers are
given as decimals. tcc -E -P10 will do. */
@ -3754,7 +3752,6 @@ ST_FUNC int tcc_preprocess(TCCState *s1)
#ifdef PP_BENCH
/* for PP benchmarks */
do next(); while (tok != TOK_EOF);
free_defines(define_start);
return 0;
#endif
@ -3765,48 +3762,43 @@ ST_FUNC int tcc_preprocess(TCCState *s1)
token_seen = TOK_LINEFEED, spcs = 0;
pp_line(s1, file, 0);
for (;;) {
iptr = s1->include_stack_ptr;
next();
if (tok == TOK_EOF)
break;
level = s1->include_stack_ptr - iptr;
if (level) {
if (level > 0)
pp_line(s1, *iptr, 0);
pp_line(s1, file, level);
}
if (s1->dflag) {
if (s1->dflag & 7) {
pp_debug_defines(s1);
if (s1->dflag & 4)
continue;
}
if (token_seen == TOK_LINEFEED) {
if (tok == ' ') {
++spcs;
continue;
}
if (tok == TOK_LINEFEED) {
spcs = 0;
continue;
}
pp_line(s1, file, 0);
if (is_space(tok)) {
if (spcs < sizeof white - 1)
white[spcs++] = tok;
continue;
} else if (tok == TOK_LINEFEED) {
spcs = 0;
if (token_seen == TOK_LINEFEED)
continue;
++file->line_ref;
} else {
spcs = pp_need_space(token_seen, tok);
} else if (token_seen == TOK_LINEFEED) {
pp_line(s1, file, 0);
} else if (spcs == 0 && pp_need_space(token_seen, tok)) {
white[spcs++] = ' ';
}
while (spcs)
fputs(" ", s1->ppfp), --spcs;
white[spcs] = 0, fputs(white, s1->ppfp), spcs = 0;
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;
}

View File

@ -108,6 +108,8 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
int (*prog_main)(int, char **);
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)
return -1;
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);
}
#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 1: initializer not computable 1 */
#if defined test_static_data_error
void foo() {
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() {
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();
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() {
short w = &foo; /* no error */
short w = &foo; /* 2 cast warnings */
}
/*-* test 5; nodata_wanted test */
#elif defined test_data_suppression
#include <stdio.h>
#define DATA_LBL(s) \
__asm__(".global d"#s",t"#s"\n.data\nd"#s":\n.text\nt"#s":\n"); \
extern char d##s[],t##s[];
#define ASMLABELS(s) \
__asm__(".global d"#s",t"#s"\n.data\nd"#s":\n.text\nt"#s":\n")
#define PROG \
static void *p = (void*)&main;\
@ -47,28 +46,29 @@ void foo() {
int main()
{
extern char ds1[],ts1[];
extern char ds2[],ts2[];
extern char de1[],te1[];
extern char de2[],te2[];
printf("suppression off\n");
DATA_LBL(s1);
if (1) {
ASMLABELS(s1);
PROG
ASMLABELS(e1);
}
DATA_LBL(e1);
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");
DATA_LBL(s2);
if (0) {
ASMLABELS(s2);
PROG
ASMLABELS(e2);
}
DATA_LBL(e2);
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;
}
/*-* test 6: some test */
int main()
{
return 34;
}
#endif

View File

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

View File

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