suppressed ch1 and preparser

tcc-xref
bellard 2002-11-22 18:12:41 +00:00
parent e926c359bb
commit 2956bd85cd
2 changed files with 320 additions and 180 deletions

375
tcc.c
View File

@ -43,7 +43,8 @@
#include "libtcc.h" #include "libtcc.h"
//#define DEBUG /* parser debug */
//#define PARSE_DEBUG
/* preprocessor debug */ /* preprocessor debug */
//#define PP_DEBUG //#define PP_DEBUG
/* include file debug */ /* include file debug */
@ -249,7 +250,7 @@ typedef struct CachedInclude {
/* parser */ /* parser */
struct BufferedFile *file; struct BufferedFile *file;
int ch, ch1, tok, tok1; int ch, tok, tok1;
CValue tokc, tok1c; CValue tokc, tok1c;
CString tokcstr; /* current parsed string, if any */ CString tokcstr; /* current parsed string, if any */
/* if true, line feed is returned as a token. line feed is also /* if true, line feed is returned as a token. line feed is also
@ -1481,7 +1482,7 @@ BufferedFile *tcc_open(TCCState *s1, const char *filename)
bf->buf_end = bf->buffer; bf->buf_end = bf->buffer;
bf->buffer[0] = CH_EOB; /* put eob symbol */ bf->buffer[0] = CH_EOB; /* put eob symbol */
pstrcpy(bf->filename, sizeof(bf->filename), filename); pstrcpy(bf->filename, sizeof(bf->filename), filename);
bf->line_num = 1; bf->line_num = 0;
bf->ifndef_macro = 0; bf->ifndef_macro = 0;
bf->ifdef_stack_ptr = s1->ifdef_stack_ptr; bf->ifdef_stack_ptr = s1->ifdef_stack_ptr;
// printf("opening '%s'\n", filename); // printf("opening '%s'\n", filename);
@ -1495,9 +1496,6 @@ void tcc_close(BufferedFile *bf)
tcc_free(bf); tcc_free(bf);
} }
/* read one char. MUST call tcc_fillbuf if CH_EOB is read */
#define TCC_GETC(bf) (*(bf)->buf_ptr++)
/* fill input buffer and return next char */ /* fill input buffer and return next char */
int tcc_getc_slow(BufferedFile *bf) int tcc_getc_slow(BufferedFile *bf)
{ {
@ -1534,12 +1532,12 @@ void handle_eob(void)
return; return;
for(;;) { for(;;) {
ch1 = tcc_getc_slow(file); ch = tcc_getc_slow(file);
if (ch1 != CH_EOF) if (ch != CH_EOF)
return; return;
eof_seen = 1; eof_seen = 1;
if (return_linefeed) { if (return_linefeed) {
ch1 = '\n'; ch = '\n';
return; return;
} }
if (s1->include_stack_ptr == s1->include_stack) if (s1->include_stack_ptr == s1->include_stack)
@ -1555,81 +1553,101 @@ void handle_eob(void)
} }
} }
/* read next char from current input file */ /* read next char from current input file and handle end of input buffer */
static inline void inp(void) static inline void inp(void)
{ {
ch1 = TCC_GETC(file); ch = *(file->buf_ptr++);
/* end of buffer/file handling */ /* end of buffer/file handling */
if (ch1 == CH_EOB) if (ch == CH_EOB)
handle_eob(); handle_eob();
if (ch1 == '\n')
file->line_num++;
// printf("ch1=%c 0x%x\n", ch1, ch1);
} }
/* handle '\\n' and '\\r\n' */ /* handle '\[\r]\n' */
static void handle_stray(void) static void handle_stray(void)
{ {
do { while (ch == '\\') {
if (ch1 == '\n') { inp();
if (ch == '\n') {
file->line_num++;
inp(); inp();
} else if (ch1 == '\r') { } else if (ch == '\r') {
inp(); inp();
if (ch1 != '\n') if (ch != '\n')
error("invalid character after '\\'"); goto fail;
file->line_num++;
inp(); inp();
} else { } else {
break; fail:
error("stray '\\' in program");
} }
ch = ch1; }
inp();
} while (ch == '\\');
} }
/* input with '\\n' handling. Also supports '\\r\n' for horrible MSDOS /* input with '\[\r]\n' handling. Note that this function cannot
case */ handle other characters after '\', so you cannot call it inside
static inline void minp(void) strings or comments */
static void minp(void)
{ {
ch = ch1;
inp(); inp();
if (ch == '\\') if (ch == '\\')
handle_stray(); handle_stray();
} }
/* same as minp, but also skip comments */ static void parse_line_comment(void)
static void cinp(void)
{ {
int c; /* single line C++ comments */
/* XXX: accept '\\\n' ? */
if (ch1 == '/') { inp();
while (ch != '\n' && ch != TOK_EOF)
inp(); inp();
if (ch1 == '/') { }
/* single line C++ comments */
static void parse_comment(void)
{
/* C comments */
minp();
for(;;) {
/* fast skip loop */
while (ch != '\n' && ch != '*' && ch != TOK_EOF)
inp(); inp();
while (ch1 != '\n' && ch1 != CH_EOF) /* now we can handle all the cases */
inp(); if (ch == '\n') {
ch = ' '; /* return space */ file->line_num++;
} else if (ch1 == '*') {
/* C comments */
inp(); inp();
while (ch1 != CH_EOF) { } else if (ch == '*') {
c = ch1; for(;;) {
inp(); inp();
if (c == '*' && ch1 == '/') { if (ch == '/') {
inp(); goto end_of_comment;
ch = ' '; /* return space */ } else if (ch == '\\') {
break; inp();
} if (ch == '\n') {
file->line_num++;
inp();
} else if (ch == '\r') {
inp();
if (ch != '\n')
break;
file->line_num++;
inp();
} else {
break;
}
} else if (ch != '*') {
break;
}
} }
} else { } else {
ch = '/'; error("unexpected end of file in comment");
} }
} else {
minp();
} }
end_of_comment:
inp();
} }
#define cinp minp
/* space exlcuding newline */ /* space exlcuding newline */
static inline int is_space(int ch) static inline int is_space(int ch)
{ {
@ -1646,28 +1664,85 @@ static inline void skip_spaces(void)
#if/#endif */ #if/#endif */
void preprocess_skip(void) void preprocess_skip(void)
{ {
int a; int a, start_of_line, sep;
start_of_line = 1;
a = 0; a = 0;
while (1) { while (1) {
while (ch != '\n') { switch(ch) {
if (ch == CH_EOF) case ' ':
expect("#endif"); case '\t':
cinp(); case '\f':
} case '\v':
cinp(); case '\r':
skip_spaces(); inp();
if (ch == '#') { break;
cinp(); case '\n':
next_nomacro(); start_of_line = 1;
if (a == 0 && file->line_num++;
(tok == TOK_ELSE || tok == TOK_ELIF || tok == TOK_ENDIF)) inp();
break; break;
if (tok == TOK_IF || tok == TOK_IFDEF || tok == TOK_IFNDEF) case '\\':
a++; handle_stray();
else if (tok == TOK_ENDIF) break;
a--; /* skip strings */
case '\"':
case '\'':
start_of_line = 0;
sep = ch;
inp();
while (ch != sep) {
/* XXX: better error message */
if (ch == TOK_EOF) {
error("unterminated string");
} else if (ch == '\n') {
file->line_num++;
} else if (ch == '\\') {
/* ignore next char */
inp();
if (ch == '\n')
file->line_num++;
}
inp();
}
minp();
break;
/* skip comments */
case '/':
minp();
if (ch == '*') {
parse_comment();
} else if (ch == '/') {
parse_line_comment();
} else {
start_of_line = 0;
}
break;
case '#':
minp();
if (start_of_line) {
next_nomacro();
if (a == 0 &&
(tok == TOK_ELSE || tok == TOK_ELIF || tok == TOK_ENDIF))
goto the_end;
if (tok == TOK_IF || tok == TOK_IFDEF || tok == TOK_IFNDEF)
a++;
else if (tok == TOK_ENDIF)
a--;
}
start_of_line = 0;
break;
case CH_EOF:
expect("#endif");
break;
default:
inp();
start_of_line = 0;
break;
} }
} }
the_end: ;
} }
/* ParseState handling */ /* ParseState handling */
@ -1927,7 +2002,7 @@ int expr_preprocess(void)
return c != 0; return c != 0;
} }
#if defined(DEBUG) || defined(PP_DEBUG) #if defined(PARSE_DEBUG) || defined(PP_DEBUG)
void tok_print(int *str) void tok_print(int *str)
{ {
int t; int t;
@ -2054,7 +2129,6 @@ void preprocess(void)
state = INCLUDE_STATE_NONE; state = INCLUDE_STATE_NONE;
eof_seen = 0; eof_seen = 0;
redo1: redo1:
cinp();
next_nomacro(); next_nomacro();
redo: redo:
switch(tok) { switch(tok) {
@ -2085,10 +2159,12 @@ void preprocess(void)
minp(); minp();
} }
*q = '\0'; *q = '\0';
#if 0
/* eat all spaces and comments after include */ /* eat all spaces and comments after include */
/* XXX: slightly incorrect */ /* XXX: slightly incorrect */
while (ch1 != '\n' && ch1 != CH_EOF) while (ch1 != '\n' && ch1 != CH_EOF)
inp(); inp();
#endif
} else { } else {
/* computed #include : either we have only strings or /* computed #include : either we have only strings or
we have anything enclosed in '<>' */ we have anything enclosed in '<>' */
@ -2185,6 +2261,7 @@ void preprocess(void)
if (ch != '#') if (ch != '#')
goto the_end; goto the_end;
state = INCLUDE_STATE_SEEK_IFNDEF; state = INCLUDE_STATE_SEEK_IFNDEF;
cinp();
goto redo1; goto redo1;
} }
break; break;
@ -2324,7 +2401,7 @@ static int getn(int b)
if (t < 0 || t >= b) if (t < 0 || t >= b)
break; break;
n = n * b + t; n = n * b + t;
cinp(); inp();
} }
return n; return n;
} }
@ -2334,50 +2411,76 @@ static int getq(void)
{ {
int c; int c;
redo:
c = ch; c = ch;
minp(); inp();
if (c == '\\') { if (c == '\\') {
if (isoct(ch)) { switch(ch) {
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
/* at most three octal digits */ /* at most three octal digits */
c = ch - '0'; c = ch - '0';
minp(); inp();
if (isoct(ch)) { if (isoct(ch)) {
c = c * 8 + ch - '0'; c = c * 8 + ch - '0';
minp(); inp();
if (isoct(ch)) { if (isoct(ch)) {
c = c * 8 + ch - '0'; c = c * 8 + ch - '0';
minp(); inp();
} }
} }
return c; return c;
} else if (ch == 'x') { case 'x':
minp(); inp();
return getn(16); return getn(16);
} else { case 'a':
if (ch == 'a') c = '\a';
c = '\a'; break;
else if (ch == 'b') case 'b':
c = '\b'; c = '\b';
else if (ch == 'f') break;
c = '\f'; case 'f':
else if (ch == 'n') c = '\f';
c = '\n'; break;
else if (ch == 'r') case 'n':
c = '\r'; c = '\n';
else if (ch == 't') break;
c = '\t'; case 'r':
else if (ch == 'v') c = '\r';
c = '\v'; break;
else if (ch == 'e' && gnu_ext) case 't':
c = 27; c = '\t';
else if (ch == '\'' || ch == '\"' || ch == '\\' || ch == '?') break;
c = ch; case 'v':
else c = '\v';
error("invalid escaped char"); break;
minp(); case 'e':
if (!gnu_ext)
goto invalid_escape;
c = 27;
break;
case '\'':
case '\"':
case '\\':
case '?':
c = ch;
break;
case '\n':
inp();
goto redo;
case '\r':
inp();
if (ch != '\n')
goto invalid_escape;
inp();
goto redo;
default:
invalid_escape:
error("invalid escaped char");
} }
inp();
} else if (c == '\r' && ch == '\n') { } else if (c == '\r' && ch == '\n') {
minp(); inp();
c = '\n'; c = '\n';
} }
return c; return c;
@ -2677,10 +2780,11 @@ void parse_number(const char *p)
/* return next token without macro substitution */ /* return next token without macro substitution */
static inline void next_nomacro1(void) static inline void next_nomacro1(void)
{ {
int b, t; int b, t, start_of_line;
char *q; char *q;
TokenSym *ts; TokenSym *ts;
start_of_line = 0;
redo_no_start: redo_no_start:
switch(ch) { switch(ch) {
case ' ': case ' ':
@ -2688,38 +2792,36 @@ static inline void next_nomacro1(void)
case '\f': case '\f':
case '\v': case '\v':
case '\r': case '\r':
cinp(); inp();
goto redo_no_start; goto redo_no_start;
case '\\':
handle_stray();
goto redo_no_start;
case '\n': case '\n':
file->line_num++;
if (return_linefeed) { if (return_linefeed) {
/* XXX: should eat token ? */ /* XXX: should eat token ? */
tok = TOK_LINEFEED; tok = TOK_LINEFEED;
} else { } else {
cinp(); start_of_line = 1;
skip_spaces(); inp();
if (ch == '#') {
/* preprocessor command if # at start of line after
spaces */
preprocess();
}
goto redo_no_start; goto redo_no_start;
} }
break; break;
case '#': case '#':
tok = ch; minp();
cinp();
#if 0
if (start_of_line) { if (start_of_line) {
preprocess(); preprocess();
goto redo_no_start; goto redo_no_start;
} else } else {
#endif
{
if (ch == '#') { if (ch == '#') {
cinp(); inp();
tok = TOK_TWOSHARPS; tok = TOK_TWOSHARPS;
} else {
tok = '#';
} }
} }
break; break;
@ -2754,7 +2856,7 @@ static inline void next_nomacro1(void)
tok = ts->tok; tok = ts->tok;
break; break;
case 'L': case 'L':
cinp(); minp();
if (ch == '\'') { if (ch == '\'') {
tok = TOK_LCHAR; tok = TOK_LCHAR;
goto char_const; goto char_const;
@ -2810,7 +2912,7 @@ static inline void next_nomacro1(void)
case '\'': case '\'':
tok = TOK_CCHAR; tok = TOK_CCHAR;
char_const: char_const:
minp(); inp();
b = getq(); b = getq();
/* this cast is needed if >= 128 */ /* this cast is needed if >= 128 */
if (tok == TOK_CCHAR) if (tok == TOK_CCHAR)
@ -2818,12 +2920,12 @@ static inline void next_nomacro1(void)
tokc.i = b; tokc.i = b;
if (ch != '\'') if (ch != '\'')
error("unterminated character constant"); error("unterminated character constant");
minp(); inp();
break; break;
case '\"': case '\"':
tok = TOK_STR; tok = TOK_STR;
str_const: str_const:
minp(); inp();
cstr_reset(&tokcstr); cstr_reset(&tokcstr);
while (ch != '\"') { while (ch != '\"') {
b = getq(); b = getq();
@ -2839,7 +2941,7 @@ static inline void next_nomacro1(void)
else else
cstr_wccat(&tokcstr, '\0'); cstr_wccat(&tokcstr, '\0');
tokc.cstr = &tokcstr; tokc.cstr = &tokcstr;
minp(); inp();
break; break;
case '<': case '<':
@ -2976,18 +3078,19 @@ static inline void next_nomacro1(void)
/* comments or operator */ /* comments or operator */
case '/': case '/':
tok = ch; minp();
cinp(); if (ch == '*') {
if (ch == '=') { parse_comment();
goto redo_no_start;
} else if (ch == '/') {
parse_line_comment();
goto redo_no_start;
} else if (ch == '=') {
cinp(); cinp();
tok = TOK_A_DIV; tok = TOK_A_DIV;
} } else {
#if 0 tok = '/';
else if (ch == '/' || ch == '*') {
parse_comments();
goto redo_no_start;
} }
#endif
break; break;
/* simple tokens */ /* simple tokens */
@ -3012,6 +3115,9 @@ static inline void next_nomacro1(void)
error("unrecognized character \\x%02x", ch); error("unrecognized character \\x%02x", ch);
break; break;
} }
#if defined(PARSE_DEBUG)
printf("token = %s\n", get_tok_str(tok, &tokc));
#endif
} }
/* return next token without macro substitution. Can read input from /* return next token without macro substitution. Can read input from
@ -3437,9 +3543,6 @@ static void next(void)
parse_number((char *)tokc.cstr->data); parse_number((char *)tokc.cstr->data);
} }
} }
#if defined(DEBUG)
printf("token = %s\n", get_tok_str(tok, &tokc));
#endif
} }
void swap(int *p, int *q) void swap(int *p, int *q)
@ -7539,7 +7642,6 @@ static int tcc_compile(TCCState *s1)
s1->nb_errors = 0; s1->nb_errors = 0;
s1->error_set_jmp_enabled = 1; s1->error_set_jmp_enabled = 1;
inp();
ch = '\n'; /* needed to parse correctly first preprocessor command */ ch = '\n'; /* needed to parse correctly first preprocessor command */
next(); next();
decl(VT_CONST); decl(VT_CONST);
@ -7617,7 +7719,6 @@ void tcc_define_symbol(TCCState *s1, const char *sym, const char *value)
s1->include_stack_ptr = s1->include_stack; s1->include_stack_ptr = s1->include_stack;
/* parse with define parser */ /* parse with define parser */
inp();
ch = '\n'; /* needed to parse correctly first preprocessor command */ ch = '\n'; /* needed to parse correctly first preprocessor command */
next_nomacro(); next_nomacro();
parse_define(); parse_define();

125
tccelf.c
View File

@ -378,7 +378,7 @@ static void relocate_common_syms(void)
static void *resolve_sym(const char *sym) static void *resolve_sym(const char *sym)
{ {
return dlsym(NULL, sym); return dlsym(RTLD_DEFAULT, sym);
} }
/* relocate symbol table, resolve undefined symbols if do_resolve is /* relocate symbol table, resolve undefined symbols if do_resolve is
@ -1813,71 +1813,110 @@ static int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level)
return ret; return ret;
} }
/* return -2 if error and CH_EOF if eof */ #define LD_TOK_NAME 256
static void ld_skipspaces(void) #define LD_TOK_EOF (-1)
{
while (ch == ' ' || ch == '\t' || ch == '\n')
cinp();
}
static int ld_get_cmd(char *cmd, int cmd_size) /* return next ld script token */
static int ld_next(TCCState *s1, char *name, int name_size)
{ {
int c;
char *q; char *q;
ld_skipspaces(); redo:
if (ch == CH_EOF) switch(ch) {
return -1; case ' ':
q = cmd; case '\t':
for(;;) { case '\f':
if (!((ch >= 'a' && ch <= 'z') || case '\v':
(ch >= 'A' && ch <= 'Z') || case '\r':
(ch >= '0' && ch <= '9') || case '\n':
strchr("/.-_+=$:\\,~?*", ch))) inp();
break; goto redo;
if ((q - cmd) >= (cmd_size - 1)) case '/':
return -2; minp();
*q++ = ch; if (ch == '*') {
cinp(); parse_comment();
goto redo;
} else {
q = name;
*q++ = '/';
goto parse_name;
}
break;
case 'a' ... 'z':
case 'A' ... 'Z':
case '_':
case '\\':
case '.':
case '$':
case '~':
q = name;
parse_name:
for(;;) {
if (!((ch >= 'a' && ch <= 'z') ||
(ch >= 'A' && ch <= 'Z') ||
(ch >= '0' && ch <= '9') ||
strchr("/.-_+=$:\\,~", ch)))
break;
if ((q - name) < name_size - 1) {
*q++ = ch;
}
minp();
}
*q = '\0';
c = LD_TOK_NAME;
break;
case CH_EOF:
c = LD_TOK_EOF;
break;
default:
c = ch;
inp();
break;
} }
*q = '\0'; #if 0
return 0; printf("tok=%c %d\n", c, c);
if (c == LD_TOK_NAME)
printf(" name=%s\n", name);
#endif
return c;
} }
/* interpret a subset of GNU ldscripts to handle the dummy libc.so /* interpret a subset of GNU ldscripts to handle the dummy libc.so
files */ files */
static int tcc_load_ldscript(TCCState *s1) static int tcc_load_ldscript(TCCState *s1)
{ {
char cmd[64]; char cmd[64];
char filename[1024]; char filename[1024];
int ret; int t;
inp(); inp();
cinp();
for(;;) { for(;;) {
ret = ld_get_cmd(cmd, sizeof(cmd)); t = ld_next(s1, cmd, sizeof(cmd));
if (ret == CH_EOF) if (t == LD_TOK_EOF)
return 0; return 0;
else if (ret < 0) else if (t != LD_TOK_NAME)
return -1; return -1;
// printf("cmd='%s'\n", cmd);
if (!strcmp(cmd, "INPUT") || if (!strcmp(cmd, "INPUT") ||
!strcmp(cmd, "GROUP")) { !strcmp(cmd, "GROUP")) {
ld_skipspaces(); t = ld_next(s1, cmd, sizeof(cmd));
if (ch != '(') if (t != '(')
expect("("); expect("(");
cinp(); t = ld_next(s1, filename, sizeof(filename));
for(;;) { for(;;) {
ld_get_cmd(filename, sizeof(filename)); if (t == LD_TOK_EOF) {
tcc_add_file(s1, filename);
ld_skipspaces();
if (ch == ',') {
cinp();
} else if (ch == ')') {
cinp();
break;
} else if (ch == CH_EOF) {
error_noabort("unexpected end of file"); error_noabort("unexpected end of file");
return -1; return -1;
} else if (t == ')') {
break;
} else if (t != LD_TOK_NAME) {
error_noabort("filename expected");
return -1;
}
tcc_add_file(s1, filename);
t = ld_next(s1, filename, sizeof(filename));
if (t == ',') {
t = ld_next(s1, filename, sizeof(filename));
} }
} }
} else { } else {