tccpp: tcc_warning("extra tokens after directive")

with stuff like
    #endif int x;
Also fix
    /* */ #else
Also:
- search_cached_include(): search for file->true_filename
- tccasm.c: avoid crash with .file
This commit is contained in:
grischka 2024-03-22 01:02:30 +01:00
parent 6b78e561c8
commit 08a4c52de3
5 changed files with 105 additions and 67 deletions

6
tcc.h
View file

@ -502,7 +502,7 @@ typedef union CValue {
float f; float f;
uint64_t i; uint64_t i;
struct { struct {
const void *data; char *data;
int size; int size;
} str; } str;
int tab[LDOUBLE_SIZE/4]; int tab[LDOUBLE_SIZE/4];
@ -1390,6 +1390,7 @@ ST_FUNC void define_undef(Sym *s);
ST_INLN Sym *define_find(int v); ST_INLN Sym *define_find(int v);
ST_FUNC void free_defines(Sym *b); ST_FUNC void free_defines(Sym *b);
ST_FUNC void parse_define(void); ST_FUNC void parse_define(void);
ST_FUNC void skip_to_eol(int warn);
ST_FUNC void preprocess(int is_bof); ST_FUNC void preprocess(int is_bof);
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);
@ -1397,6 +1398,7 @@ ST_FUNC void preprocess_start(TCCState *s1, int filetype);
ST_FUNC void preprocess_end(TCCState *s1); 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 void tccpp_putfile(const char *filename);
ST_FUNC int tcc_preprocess(TCCState *s1); ST_FUNC int tcc_preprocess(TCCState *s1);
ST_FUNC void skip(int c); ST_FUNC void skip(int c);
ST_FUNC NORETURN void expect(const char *msg); ST_FUNC NORETURN void expect(const char *msg);
@ -1822,7 +1824,7 @@ ST_FUNC void tcc_debug_start(TCCState *s1);
ST_FUNC void tcc_debug_end(TCCState *s1); ST_FUNC void tcc_debug_end(TCCState *s1);
ST_FUNC void tcc_debug_bincl(TCCState *s1); ST_FUNC void tcc_debug_bincl(TCCState *s1);
ST_FUNC void tcc_debug_eincl(TCCState *s1); ST_FUNC void tcc_debug_eincl(TCCState *s1);
ST_FUNC void tcc_debug_putfile(TCCState *s1, const char *filename); ST_FUNC void tcc_debug_newfile(TCCState *s1);
ST_FUNC void tcc_debug_line(TCCState *s1); ST_FUNC void tcc_debug_line(TCCState *s1);
ST_FUNC void tcc_add_debug_info(TCCState *s1, int param, Sym *s, Sym *e); ST_FUNC void tcc_add_debug_info(TCCState *s1, int param, Sym *s, Sym *e);

View file

@ -728,7 +728,7 @@ static void asm_parse_directive(TCCState *s1, int global)
case TOK_ASMDIR_ascii: case TOK_ASMDIR_ascii:
case TOK_ASMDIR_asciz: case TOK_ASMDIR_asciz:
{ {
const uint8_t *p; const char *p;
int i, size, t; int i, size, t;
t = tok; t = tok;
@ -772,15 +772,21 @@ static void asm_parse_directive(TCCState *s1, int global)
break; break;
case TOK_ASMDIR_file: case TOK_ASMDIR_file:
{ {
char filename[512]; const char *p;
parse_flags &= ~PARSE_FLAG_TOK_STR;
filename[0] = '\0';
next(); next();
if (tok == TOK_STR) if (tok == TOK_PPNUM)
pstrcat(filename, sizeof(filename), tokc.str.data); next();
else if (tok == TOK_PPSTR && tokc.str.data[0] == '"') {
pstrcat(filename, sizeof(filename), get_tok_str(tok, NULL)); tokc.str.data[tokc.str.size - 2] = 0;
tcc_warning_c(warn_unsupported)("ignoring .file %s", filename); p = tokc.str.data + 1;
} else if (tok >= TOK_IDENT) {
p = get_tok_str(tok, &tokc);
} else {
skip_to_eol(0);
break;
}
tccpp_putfile(p);
next(); next();
} }
break; break;
@ -968,6 +974,7 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global)
next(); next();
if (tok == TOK_EOF) if (tok == TOK_EOF)
break; break;
tcc_debug_line(s1);
parse_flags |= PARSE_FLAG_LINEFEED; /* XXX: suppress that hack */ parse_flags |= PARSE_FLAG_LINEFEED; /* XXX: suppress that hack */
redo: redo:
if (tok == '#') { if (tok == '#') {
@ -1033,9 +1040,8 @@ ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess)
/* GCC inline asm support */ /* GCC inline asm support */
/* assemble the string 'str' in the current C compilation unit without /* assemble the string 'str' in the current C compilation unit without
C preprocessing. NOTE: str is modified by modifying the '\0' at the C preprocessing. */
end */ static void tcc_assemble_inline(TCCState *s1, const char *str, int len, int global)
static void tcc_assemble_inline(TCCState *s1, char *str, int len, int global)
{ {
const int *saved_macro_ptr = macro_ptr; const int *saved_macro_ptr = macro_ptr;
int dotid = set_idnum('.', IS_ID); int dotid = set_idnum('.', IS_ID);

View file

@ -1048,11 +1048,8 @@ static BufferedFile* put_new_file(TCCState *s1)
} }
/* put alternative filename */ /* put alternative filename */
ST_FUNC void tcc_debug_putfile(TCCState *s1, const char *filename) ST_FUNC void tcc_debug_newfile(TCCState *s1)
{ {
if (0 == strcmp(file->filename, filename))
return;
pstrcpy(file->filename, sizeof(file->filename), filename);
if (!s1->do_debug) if (!s1->do_debug)
return; return;
if (s1->dwarf) if (s1->dwarf)

View file

@ -8387,7 +8387,7 @@ static void gen_inline_functions(TCCState *s)
/* the function was used or forced (and then not internal): /* the function was used or forced (and then not internal):
generate its code and convert it to a normal function */ generate its code and convert it to a normal function */
fn->sym = NULL; fn->sym = NULL;
tcc_debug_putfile(s, fn->filename); tccpp_putfile(fn->filename);
begin_macro(fn->func_str, 1); begin_macro(fn->func_str, 1);
next(); next();
cur_text_section = text_section; cur_text_section = text_section;

129
tccpp.c
View file

@ -53,6 +53,8 @@ static int pp_debug_tok, pp_debug_symv;
static int pp_counter; static int pp_counter;
static void tok_print(const int *str, const char *msg, ...); static void tok_print(const int *str, const char *msg, ...);
static void next_nomacro(void); static void next_nomacro(void);
static void parse_number(const char *p);
static void parse_string(const char *p, int len);
static struct TinyAlloc *toksym_alloc; static struct TinyAlloc *toksym_alloc;
static struct TinyAlloc *tokstr_alloc; static struct TinyAlloc *tokstr_alloc;
@ -884,7 +886,6 @@ redo_start:
start_of_line = 1; start_of_line = 1;
in_warn_or_error = 0; in_warn_or_error = 0;
for(;;) { for(;;) {
redo_no_start:
c = *p; c = *p;
switch(c) { switch(c) {
case ' ': case ' ':
@ -893,7 +894,7 @@ redo_start:
case '\v': case '\v':
case '\r': case '\r':
p++; p++;
goto redo_no_start; continue;
case '\n': case '\n':
file->line_num++; file->line_num++;
p++; p++;
@ -904,7 +905,7 @@ redo_start:
expect("#endif"); expect("#endif");
if (c == '\\') if (c == '\\')
++p; ++p;
goto redo_no_start; continue;
/* skip strings */ /* skip strings */
case '\"': case '\"':
case '\'': case '\'':
@ -924,7 +925,7 @@ redo_start:
} else if (c == '/') { } else if (c == '/') {
p = parse_line_comment(p); p = parse_line_comment(p);
} }
break; continue;
case '#': case '#':
p++; p++;
if (start_of_line) { if (start_of_line) {
@ -1209,7 +1210,7 @@ static inline void tok_get(int *t, const int **pp, CValue *cv)
case TOK_PPNUM: case TOK_PPNUM:
case TOK_PPSTR: case TOK_PPSTR:
cv->str.size = *p++; cv->str.size = *p++;
cv->str.data = p; cv->str.data = (char*)p;
p += (cv->str.size + sizeof(int) - 1) / sizeof(int); p += (cv->str.size + sizeof(int) - 1) / sizeof(int);
break; break;
case TOK_CDOUBLE: case TOK_CDOUBLE:
@ -1331,6 +1332,16 @@ static void maybe_run_test(TCCState *s)
define_push(tok, MACRO_OBJ, NULL, NULL); define_push(tok, MACRO_OBJ, NULL, NULL);
} }
ST_FUNC void skip_to_eol(int warn)
{
if (tok == TOK_LINEFEED)
return;
if (warn)
tcc_warning("extra tokens after directive");
file->buf_ptr = parse_line_comment(file->buf_ptr - 1);
tok = TOK_LINEFEED;
}
static CachedInclude * static CachedInclude *
search_cached_include(TCCState *s1, const char *filename, int add); search_cached_include(TCCState *s1, const char *filename, int add);
@ -1370,6 +1381,9 @@ static int parse_include(TCCState *s1, int do_next, int test)
memmove(p, p + 1, i - 1), p[i - 1] = 0; memmove(p, p + 1, i - 1), p[i - 1] = 0;
} }
if (!test)
skip_to_eol(1);
i = do_next ? file->include_next_index : -1; i = do_next ? file->include_next_index : -1;
for (;;) { for (;;) {
++i; ++i;
@ -1658,7 +1672,7 @@ static CachedInclude *search_cached_include(TCCState *s1, const char *filename,
return e; return e;
} }
static void pragma_parse(TCCState *s1) static int pragma_parse(TCCState *s1)
{ {
next_nomacro(); next_nomacro();
if (tok == TOK_push_macro || tok == TOK_pop_macro) { if (tok == TOK_push_macro || tok == TOK_pop_macro) {
@ -1690,7 +1704,7 @@ static void pragma_parse(TCCState *s1)
pp_debug_tok = t, pp_debug_symv = v; pp_debug_tok = t, pp_debug_symv = v;
} else if (tok == TOK_once) { } else if (tok == TOK_once) {
search_cached_include(s1, file->filename, 1)->once = 1; search_cached_include(s1, file->true_filename, 1)->once = 1;
} else if (s1->output_type == TCC_OUTPUT_PREPROCESS) { } else if (s1->output_type == TCC_OUTPUT_PREPROCESS) {
/* tcc -E: keep pragmas below unchanged */ /* tcc -E: keep pragmas below unchanged */
@ -1698,6 +1712,7 @@ static void pragma_parse(TCCState *s1)
unget_tok(TOK_PRAGMA); unget_tok(TOK_PRAGMA);
unget_tok('#'); unget_tok('#');
unget_tok(TOK_LINEFEED); unget_tok(TOK_LINEFEED);
return 1;
} else if (tok == TOK_pack) { } else if (tok == TOK_pack) {
/* This may be: /* This may be:
@ -1749,7 +1764,7 @@ static void pragma_parse(TCCState *s1)
skip(','); skip(',');
if (tok != TOK_STR) if (tok != TOK_STR)
goto pragma_err; goto pragma_err;
p = tcc_strdup((char *)tokc.str.data); p = tcc_strdup(tokc.str.data);
next(); next();
if (tok != ')') if (tok != ')')
goto pragma_err; goto pragma_err;
@ -1761,13 +1776,37 @@ static void pragma_parse(TCCState *s1)
tcc_free(p); tcc_free(p);
} }
} else } else {
tcc_warning_c(warn_unsupported)("#pragma %s ignored", get_tok_str(tok, &tokc)); tcc_warning_c(warn_all)("#pragma %s ignored", get_tok_str(tok, &tokc));
return; return 0;
}
next();
return 1;
pragma_err: pragma_err:
tcc_error("malformed #pragma directive"); tcc_error("malformed #pragma directive");
return; }
/* put alternative filename */
ST_FUNC void tccpp_putfile(const char *filename)
{
char buf[1024];
buf[0] = 0;
if (!IS_ABSPATH(filename)) {
/* prepend directory from real file */
pstrcpy(buf, sizeof buf, file->true_filename);
*tcc_basename(buf) = 0;
}
pstrcat(buf, sizeof buf, filename);
#ifdef _WIN32
normalize_slashes(buf);
#endif
if (0 == strcmp(file->filename, buf))
return;
//printf("new file '%s'\n", buf);
if (file->true_filename == file->filename)
file->true_filename = tcc_strdup(file->filename);
pstrcpy(file->filename, sizeof file->filename, buf);
tcc_debug_newfile(tcc_state);
} }
/* is_bof is true if first non space token at beginning of file */ /* is_bof is true if first non space token at beginning of file */
@ -1803,6 +1842,7 @@ ST_FUNC void preprocess(int is_bof)
/* undefine symbol by putting an invalid name */ /* undefine symbol by putting an invalid name */
if (s) if (s)
define_undef(s); define_undef(s);
next_nomacro();
break; break;
case TOK_INCLUDE: case TOK_INCLUDE:
case TOK_INCLUDE_NEXT: case TOK_INCLUDE_NEXT:
@ -1832,12 +1872,14 @@ ST_FUNC void preprocess(int is_bof)
|| tok == TOK___HAS_INCLUDE || tok == TOK___HAS_INCLUDE
|| tok == TOK___HAS_INCLUDE_NEXT) || tok == TOK___HAS_INCLUDE_NEXT)
c ^= 1; c ^= 1;
next_nomacro();
do_if: do_if:
if (s1->ifdef_stack_ptr >= s1->ifdef_stack + IFDEF_STACK_SIZE) if (s1->ifdef_stack_ptr >= s1->ifdef_stack + IFDEF_STACK_SIZE)
tcc_error("memory full (ifdef)"); tcc_error("memory full (ifdef)");
*s1->ifdef_stack_ptr++ = c; *s1->ifdef_stack_ptr++ = c;
goto test_skip; goto test_skip;
case TOK_ELSE: case TOK_ELSE:
next_nomacro();
if (s1->ifdef_stack_ptr == s1->ifdef_stack) if (s1->ifdef_stack_ptr == s1->ifdef_stack)
tcc_error("#else without matching #if"); tcc_error("#else without matching #if");
if (s1->ifdef_stack_ptr[-1] & 2) if (s1->ifdef_stack_ptr[-1] & 2)
@ -1852,6 +1894,7 @@ ST_FUNC void preprocess(int is_bof)
tcc_error("#elif after #else"); tcc_error("#elif after #else");
/* last #if/#elif expression was true: we skip */ /* last #if/#elif expression was true: we skip */
if (c == 1) { if (c == 1) {
skip_to_eol(0);
c = 0; c = 0;
} else { } else {
c = expr_preprocess(s1); c = expr_preprocess(s1);
@ -1862,12 +1905,14 @@ ST_FUNC void preprocess(int is_bof)
file->ifndef_macro = 0; file->ifndef_macro = 0;
test_skip: test_skip:
if (!(c & 1)) { if (!(c & 1)) {
skip_to_eol(1);
preprocess_skip(); preprocess_skip();
is_bof = 0; is_bof = 0;
goto redo; goto redo;
} }
break; break;
case TOK_ENDIF: case TOK_ENDIF:
next_nomacro();
if (s1->ifdef_stack_ptr <= file->ifdef_stack_ptr) if (s1->ifdef_stack_ptr <= file->ifdef_stack_ptr)
tcc_error("#endif without matching #if"); tcc_error("#endif without matching #if");
s1->ifdef_stack_ptr--; s1->ifdef_stack_ptr--;
@ -1879,41 +1924,27 @@ ST_FUNC void preprocess(int is_bof)
/* need to set to zero to avoid false matches if another /* need to set to zero to avoid false matches if another
#ifndef at middle of file */ #ifndef at middle of file */
file->ifndef_macro = 0; file->ifndef_macro = 0;
while (tok != TOK_LINEFEED)
next_nomacro();
tok_flags |= TOK_FLAG_ENDIF; tok_flags |= TOK_FLAG_ENDIF;
goto the_end;
} }
break; break;
case TOK_PPNUM:
n = strtoul((char*)tokc.str.data, &q, 10);
goto _line_num;
case TOK_LINE: case TOK_LINE:
next(); next_nomacro();
if (tok != TOK_CINT) if (tok != TOK_PPNUM)
_line_err: _line_err:
tcc_error("wrong #line format"); tcc_error("wrong #line format");
case TOK_PPNUM:
parse_number(tokc.str.data);
n = tokc.i; n = tokc.i;
_line_num: next_nomacro();
next();
if (tok != TOK_LINEFEED) { if (tok != TOK_LINEFEED) {
if (tok == TOK_STR) { if (tok == TOK_PPSTR && tokc.str.data[0] == '"') {
if (file->true_filename == file->filename) tokc.str.data[tokc.str.size - 2] = 0;
file->true_filename = tcc_strdup(file->filename); tccpp_putfile(tokc.str.data + 1);
q = (char *)tokc.str.data;
buf[0] = 0;
if (!IS_ABSPATH(q)) {
/* prepend directory from real file */
pstrcpy(buf, sizeof buf, file->true_filename);
*tcc_basename(buf) = 0;
}
pstrcat(buf, sizeof buf, q);
tcc_debug_putfile(s1, buf);
} else if (parse_flags & PARSE_FLAG_ASM_FILE) } else if (parse_flags & PARSE_FLAG_ASM_FILE)
break; goto ignore;
else else
goto _line_err; goto _line_err;
--n; next_nomacro();
} }
if (file->fd > 0) if (file->fd > 0)
total_lines += file->line_num - n; total_lines += file->line_num - n;
@ -1922,6 +1953,7 @@ ST_FUNC void preprocess(int is_bof)
case TOK_ERROR: case TOK_ERROR:
case TOK_WARNING: case TOK_WARNING:
{
q = buf; q = buf;
c = skip_spaces(); c = skip_spaces();
while (c != '\n' && c != CH_EOF) { while (c != '\n' && c != CH_EOF) {
@ -1934,9 +1966,12 @@ ST_FUNC void preprocess(int is_bof)
tcc_error("#error %s", buf); tcc_error("#error %s", buf);
else else
tcc_warning("#warning %s", buf); tcc_warning("#warning %s", buf);
next_nomacro();
break; break;
}
case TOK_PRAGMA: case TOK_PRAGMA:
pragma_parse(s1); if (!pragma_parse(s1))
goto ignore;
break; break;
case TOK_LINEFEED: case TOK_LINEFEED:
goto the_end; goto the_end;
@ -1945,16 +1980,14 @@ ST_FUNC void preprocess(int is_bof)
if (saved_parse_flags & PARSE_FLAG_ASM_FILE) if (saved_parse_flags & PARSE_FLAG_ASM_FILE)
goto ignore; goto ignore;
if (tok == '!' && is_bof) if (tok == '!' && is_bof)
/* '!' is ignored at beginning to allow C scripts. */ /* '#!' is ignored at beginning to allow C scripts. */
goto ignore; goto ignore;
tcc_warning("Ignoring unknown preprocessing directive #%s", get_tok_str(tok, &tokc)); tcc_warning("Ignoring unknown preprocessing directive #%s", get_tok_str(tok, &tokc));
ignore: ignore:
file->buf_ptr = parse_line_comment(file->buf_ptr - 1); skip_to_eol(0);
break; goto the_end;
} }
/* ignore other preprocess commands or #! for C scripts */ skip_to_eol(1);
while (tok != TOK_LINEFEED)
next_nomacro();
the_end: the_end:
parse_flags = saved_parse_flags; parse_flags = saved_parse_flags;
} }
@ -2006,7 +2039,7 @@ static void parse_escape_string(CString *outstr, const uint8_t *buf, int is_long
c = c - 'A' + 10; c = c - 'A' + 10;
else if (isnum(c)) else if (isnum(c))
c = c - '0'; c = c - '0';
else if (i > 0) else if (i >= 0)
expect("more hex digits in universal-character-name"); expect("more hex digits in universal-character-name");
else else
goto add_hex_or_ucn; goto add_hex_or_ucn;
@ -2564,7 +2597,7 @@ static void next_nomacro(void)
#ifdef INC_DEBUG #ifdef INC_DEBUG
printf("#endif %s\n", get_tok_str(file->ifndef_macro_saved, NULL)); printf("#endif %s\n", get_tok_str(file->ifndef_macro_saved, NULL));
#endif #endif
search_cached_include(s1, file->filename, 1) search_cached_include(s1, file->true_filename, 1)
->ifndef_macro = file->ifndef_macro_saved; ->ifndef_macro = file->ifndef_macro_saved;
tok_flags &= ~TOK_FLAG_ENDIF; tok_flags &= ~TOK_FLAG_ENDIF;
} }
@ -3481,10 +3514,10 @@ convert:
/* convert preprocessor tokens into C tokens */ /* convert preprocessor tokens into C tokens */
if (t == TOK_PPNUM) { if (t == TOK_PPNUM) {
if (parse_flags & PARSE_FLAG_TOK_NUM) if (parse_flags & PARSE_FLAG_TOK_NUM)
parse_number((char *)tokc.str.data); parse_number(tokc.str.data);
} else if (t == TOK_PPSTR) { } else if (t == TOK_PPSTR) {
if (parse_flags & PARSE_FLAG_TOK_STR) if (parse_flags & PARSE_FLAG_TOK_STR)
parse_string((char *)tokc.str.data, tokc.str.size - 1); parse_string(tokc.str.data, tokc.str.size - 1);
} }
} }