mirror of
https://github.com/mirror/tinycc.git
synced 2025-01-25 06:00:11 +08:00
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 ... */
This commit is contained in:
parent
ba2b25e4ea
commit
0cc24d0e84
117
libtcc.c
117
libtcc.c
@ -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
40
tcc.c
@ -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
31
tcc.h
@ -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
|
||||
|
38
tccasm.c
38
tccasm.c
@ -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;
|
||||
}
|
||||
|
||||
|
92
tccgen.c
92
tccgen.c
@ -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
136
tccpp.c
@ -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;
|
||||
}
|
||||
|
||||
|
2
tccrun.c
2
tccrun.c
@ -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);
|
||||
|
107
tcctools.c
107
tcctools.c
@ -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 */
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
|
@ -1 +0,0 @@
|
||||
struct A {} int i;
|
@ -1 +0,0 @@
|
||||
56_btype_excess-1.c:1: error: too many basic types
|
@ -1 +0,0 @@
|
||||
char int i;
|
@ -1 +0,0 @@
|
||||
57_btype_excess-2.c:1: error: too many basic types
|
@ -1,9 +0,0 @@
|
||||
int f(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int f(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
@ -1 +0,0 @@
|
||||
58_function_redefinition.c:7: error: redefinition of 'f'
|
@ -1 +0,0 @@
|
||||
int (*fct)[42](int x);
|
@ -1 +0,0 @@
|
||||
59_function_array.c:1: error: declaration of an array of functions
|
@ -1,4 +0,0 @@
|
||||
enum color {RED, GREEN, BLUE};
|
||||
enum color {R, G, B};
|
||||
|
||||
enum color c;
|
@ -1 +0,0 @@
|
||||
60_enum_redefinition.c:2: error: struct/union/enum already defined
|
51
tests/tests2/60_errors_and_warnings.c
Normal file
51
tests/tests2/60_errors_and_warnings.c
Normal 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
|
28
tests/tests2/60_errors_and_warnings.expect
Normal file
28
tests/tests2/60_errors_and_warnings.expect
Normal 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
|
@ -1 +0,0 @@
|
||||
enum rgb c = 42;
|
@ -1 +0,0 @@
|
||||
61_undefined_enum.c:1: error: unknown type size
|
@ -1,4 +0,0 @@
|
||||
enum color {RED, GREEN, BLUE};
|
||||
enum rgb {RED, G, B};
|
||||
|
||||
enum color c = RED;
|
@ -1 +0,0 @@
|
||||
62_enumerator_redefinition.c:2: error: redefinition of enumerator 'RED'
|
@ -1,14 +0,0 @@
|
||||
enum {
|
||||
FOO,
|
||||
BAR
|
||||
};
|
||||
|
||||
int main(void)
|
||||
{
|
||||
enum {
|
||||
FOO = 2,
|
||||
BAR
|
||||
};
|
||||
|
||||
return BAR - FOO;
|
||||
}
|
@ -1 +0,0 @@
|
||||
int i = i++;
|
@ -1 +0,0 @@
|
||||
74_nocode_wanted.c:1: error: initializer element is not constant
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user