added linux define - added __FUNCTION - fixed spaces parsing - defined special macros
This commit is contained in:
parent
5e85ad260d
commit
41391fbb20
1 changed files with 157 additions and 126 deletions
283
tcc.c
283
tcc.c
|
@ -501,15 +501,7 @@ enum {
|
||||||
TOK_UNDEF,
|
TOK_UNDEF,
|
||||||
TOK_ERROR,
|
TOK_ERROR,
|
||||||
TOK_LINE,
|
TOK_LINE,
|
||||||
TOK___LINE__,
|
|
||||||
TOK___FILE__,
|
|
||||||
TOK___DATE__,
|
|
||||||
TOK___TIME__,
|
|
||||||
TOK___VA_ARGS__,
|
|
||||||
|
|
||||||
/* special identifiers */
|
|
||||||
TOK___FUNC__,
|
|
||||||
TOK_MAIN,
|
|
||||||
#define DEF(id, str) id,
|
#define DEF(id, str) id,
|
||||||
#include "tcctok.h"
|
#include "tcctok.h"
|
||||||
#undef DEF
|
#undef DEF
|
||||||
|
@ -524,8 +516,6 @@ char *tcc_keywords =
|
||||||
/* the following are not keywords. They are included to ease parsing */
|
/* the following are not keywords. They are included to ease parsing */
|
||||||
"define\0include\0ifdef\0ifndef\0elif\0endif\0"
|
"define\0include\0ifdef\0ifndef\0elif\0endif\0"
|
||||||
"defined\0undef\0error\0line\0"
|
"defined\0undef\0error\0line\0"
|
||||||
"__LINE__\0__FILE__\0__DATE__\0__TIME__\0__VA_ARGS__\0"
|
|
||||||
"__func__\0main\0"
|
|
||||||
/* builtin functions */
|
/* builtin functions */
|
||||||
#define DEF(id, str) str "\0"
|
#define DEF(id, str) str "\0"
|
||||||
#include "tcctok.h"
|
#include "tcctok.h"
|
||||||
|
@ -1470,22 +1460,38 @@ static inline void inp(void)
|
||||||
// printf("ch1=%c 0x%x\n", ch1, ch1);
|
// printf("ch1=%c 0x%x\n", ch1, ch1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* input with '\\n' handling */
|
/* handle '\\n' and '\\r\n' */
|
||||||
|
static void handle_stray(void)
|
||||||
|
{
|
||||||
|
do {
|
||||||
|
if (ch1 == '\n') {
|
||||||
|
inp();
|
||||||
|
} else if (ch1 == '\r') {
|
||||||
|
inp();
|
||||||
|
if (ch1 != '\n')
|
||||||
|
error("invalid character after '\\'");
|
||||||
|
inp();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ch = ch1;
|
||||||
|
inp();
|
||||||
|
} while (ch == '\\');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* input with '\\n' handling. Also supports '\\r\n' for horrible MSDOS
|
||||||
|
case */
|
||||||
static inline void minp(void)
|
static inline void minp(void)
|
||||||
{
|
{
|
||||||
redo:
|
|
||||||
ch = ch1;
|
ch = ch1;
|
||||||
inp();
|
inp();
|
||||||
if (ch == '\\' && ch1 == '\n') {
|
if (ch == '\\')
|
||||||
inp();
|
handle_stray();
|
||||||
goto redo;
|
|
||||||
}
|
|
||||||
//printf("ch=%c 0x%x\n", ch, ch);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* same as minp, but also skip comments */
|
/* same as minp, but also skip comments */
|
||||||
void cinp(void)
|
static void cinp(void)
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
|
@ -1494,14 +1500,13 @@ void cinp(void)
|
||||||
if (ch1 == '/') {
|
if (ch1 == '/') {
|
||||||
/* single line C++ comments */
|
/* single line C++ comments */
|
||||||
inp();
|
inp();
|
||||||
while (ch1 != '\n' && ch1 != -1)
|
while (ch1 != '\n' && ch1 != CH_EOF)
|
||||||
inp();
|
inp();
|
||||||
inp();
|
|
||||||
ch = ' '; /* return space */
|
ch = ' '; /* return space */
|
||||||
} else if (ch1 == '*') {
|
} else if (ch1 == '*') {
|
||||||
/* C comments */
|
/* C comments */
|
||||||
inp();
|
inp();
|
||||||
while (ch1 != -1) {
|
while (ch1 != CH_EOF) {
|
||||||
c = ch1;
|
c = ch1;
|
||||||
inp();
|
inp();
|
||||||
if (c == '*' && ch1 == '/') {
|
if (c == '*' && ch1 == '/') {
|
||||||
|
@ -1518,9 +1523,15 @@ void cinp(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void skip_spaces(void)
|
/* space exlcuding newline */
|
||||||
|
static inline int is_space(int ch)
|
||||||
{
|
{
|
||||||
while (ch == ' ' || ch == '\t')
|
return ch == ' ' || ch == '\t' || ch == '\v' || ch == '\f' || ch == '\r';
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void skip_spaces(void)
|
||||||
|
{
|
||||||
|
while (is_space(ch))
|
||||||
cinp();
|
cinp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1532,7 +1543,7 @@ void preprocess_skip(void)
|
||||||
a = 0;
|
a = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
while (ch != '\n') {
|
while (ch != '\n') {
|
||||||
if (ch == -1)
|
if (ch == CH_EOF)
|
||||||
expect("#endif");
|
expect("#endif");
|
||||||
cinp();
|
cinp();
|
||||||
}
|
}
|
||||||
|
@ -1798,7 +1809,7 @@ void parse_define(void)
|
||||||
tok_str_new(&str);
|
tok_str_new(&str);
|
||||||
while (1) {
|
while (1) {
|
||||||
skip_spaces();
|
skip_spaces();
|
||||||
if (ch == '\n' || ch == -1)
|
if (ch == '\n' || ch == CH_EOF)
|
||||||
break;
|
break;
|
||||||
next_nomacro();
|
next_nomacro();
|
||||||
tok_str_add2(&str, tok, &tokc);
|
tok_str_add2(&str, tok, &tokc);
|
||||||
|
@ -2067,6 +2078,9 @@ static int getq(void)
|
||||||
error("invalid escaped char");
|
error("invalid escaped char");
|
||||||
minp();
|
minp();
|
||||||
}
|
}
|
||||||
|
} else if (c == '\r' && ch == '\n') {
|
||||||
|
minp();
|
||||||
|
c = '\n';
|
||||||
}
|
}
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
@ -2384,15 +2398,14 @@ void next_nomacro1(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
cinp();
|
cinp();
|
||||||
while (ch == ' ' || ch == '\t')
|
skip_spaces();
|
||||||
cinp();
|
|
||||||
if (ch == '#') {
|
if (ch == '#') {
|
||||||
/* preprocessor command if # at start of line after
|
/* preprocessor command if # at start of line after
|
||||||
spaces */
|
spaces */
|
||||||
preprocess();
|
preprocess();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ch != ' ' && ch != '\t' && ch != '\f')
|
if (!is_space(ch))
|
||||||
break;
|
break;
|
||||||
cinp();
|
cinp();
|
||||||
}
|
}
|
||||||
|
@ -2660,113 +2673,119 @@ void macro_subst(TokenString *tok_str,
|
||||||
next_nomacro();
|
next_nomacro();
|
||||||
if (tok == 0)
|
if (tok == 0)
|
||||||
break;
|
break;
|
||||||
/* special macros */
|
if ((s = sym_find1(&define_stack, tok)) != NULL) {
|
||||||
if (tok == TOK___LINE__) {
|
|
||||||
cval.i = file->line_num;
|
|
||||||
tok_str_add2(tok_str, TOK_CINT, &cval);
|
|
||||||
} else if (tok == TOK___FILE__) {
|
|
||||||
cstrval = file->filename;
|
|
||||||
goto add_cstr;
|
|
||||||
tok_str_add2(tok_str, TOK_STR, &cval);
|
|
||||||
} else if (tok == TOK___DATE__) {
|
|
||||||
cstrval = "Jan 1 1970";
|
|
||||||
goto add_cstr;
|
|
||||||
} else if (tok == TOK___TIME__) {
|
|
||||||
cstrval = "00:00:00";
|
|
||||||
add_cstr:
|
|
||||||
cstr_new(&cstr);
|
|
||||||
cstr_cat(&cstr, cstrval);
|
|
||||||
cstr_ccat(&cstr, '\0');
|
|
||||||
cval.cstr = &cstr;
|
|
||||||
tok_str_add2(tok_str, TOK_STR, &cval);
|
|
||||||
cstr_free(&cstr);
|
|
||||||
} else if ((s = sym_find1(&define_stack, tok)) != NULL) {
|
|
||||||
/* if symbol is a macro, prepare substitution */
|
/* if symbol is a macro, prepare substitution */
|
||||||
/* if nested substitution, do nothing */
|
/* if nested substitution, do nothing */
|
||||||
if (sym_find2(*nested_list, tok))
|
if (sym_find2(*nested_list, tok))
|
||||||
goto no_subst;
|
goto no_subst;
|
||||||
mstr = (int *)s->c;
|
|
||||||
mstr_allocated = 0;
|
/* special macros */
|
||||||
if (s->t == MACRO_FUNC) {
|
if (tok == TOK___LINE__) {
|
||||||
/* NOTE: we do not use next_nomacro to avoid eating the
|
cval.i = file->line_num;
|
||||||
next token. XXX: find better solution */
|
tok_str_add2(tok_str, TOK_CINT, &cval);
|
||||||
if (macro_ptr) {
|
} else if (tok == TOK___FILE__) {
|
||||||
t = *macro_ptr;
|
cstrval = file->filename;
|
||||||
} else {
|
goto add_cstr;
|
||||||
while (ch == ' ' || ch == '\t' || ch == '\n')
|
tok_str_add2(tok_str, TOK_STR, &cval);
|
||||||
cinp();
|
} else if (tok == TOK___DATE__) {
|
||||||
t = ch;
|
cstrval = "Jan 1 2002";
|
||||||
}
|
goto add_cstr;
|
||||||
if (t != '(') /* no macro subst */
|
} else if (tok == TOK___TIME__) {
|
||||||
goto no_subst;
|
cstrval = "00:00:00";
|
||||||
|
goto add_cstr;
|
||||||
|
} else if (tok == TOK___FUNCTION__) {
|
||||||
|
cstrval = funcname;
|
||||||
|
add_cstr:
|
||||||
|
cstr_new(&cstr);
|
||||||
|
cstr_cat(&cstr, cstrval);
|
||||||
|
cstr_ccat(&cstr, '\0');
|
||||||
|
cval.cstr = &cstr;
|
||||||
|
tok_str_add2(tok_str, TOK_STR, &cval);
|
||||||
|
cstr_free(&cstr);
|
||||||
|
} else {
|
||||||
|
mstr = (int *)s->c;
|
||||||
|
mstr_allocated = 0;
|
||||||
|
if (s->t == MACRO_FUNC) {
|
||||||
|
/* NOTE: we do not use next_nomacro to avoid eating the
|
||||||
|
next token. XXX: find better solution */
|
||||||
|
if (macro_ptr) {
|
||||||
|
t = *macro_ptr;
|
||||||
|
} else {
|
||||||
|
while (is_space(ch) || ch == '\n')
|
||||||
|
cinp();
|
||||||
|
t = ch;
|
||||||
|
}
|
||||||
|
if (t != '(') /* no macro subst */
|
||||||
|
goto no_subst;
|
||||||
|
|
||||||
/* argument macro */
|
/* argument macro */
|
||||||
next_nomacro();
|
next_nomacro();
|
||||||
next_nomacro();
|
next_nomacro();
|
||||||
args = NULL;
|
args = NULL;
|
||||||
sa = s->next;
|
sa = s->next;
|
||||||
/* NOTE: empty args are allowed, except if no args */
|
/* NOTE: empty args are allowed, except if no args */
|
||||||
for(;;) {
|
for(;;) {
|
||||||
/* handle '()' case */
|
/* handle '()' case */
|
||||||
if (!args && tok == ')')
|
if (!args && tok == ')')
|
||||||
break;
|
break;
|
||||||
if (!sa)
|
if (!sa)
|
||||||
error("macro '%s' used with too many args",
|
error("macro '%s' used with too many args",
|
||||||
get_tok_str(s->v, 0));
|
get_tok_str(s->v, 0));
|
||||||
tok_str_new(&str);
|
tok_str_new(&str);
|
||||||
parlevel = 0;
|
parlevel = 0;
|
||||||
/* NOTE: non zero sa->t indicates VA_ARGS */
|
/* NOTE: non zero sa->t indicates VA_ARGS */
|
||||||
while ((parlevel > 0 ||
|
while ((parlevel > 0 ||
|
||||||
(tok != ')' &&
|
(tok != ')' &&
|
||||||
(tok != ',' || sa->t))) &&
|
(tok != ',' || sa->t))) &&
|
||||||
tok != -1) {
|
tok != -1) {
|
||||||
if (tok == '(')
|
if (tok == '(')
|
||||||
parlevel++;
|
parlevel++;
|
||||||
else if (tok == ')')
|
else if (tok == ')')
|
||||||
parlevel--;
|
parlevel--;
|
||||||
tok_str_add2(&str, tok, &tokc);
|
tok_str_add2(&str, tok, &tokc);
|
||||||
|
next_nomacro();
|
||||||
|
}
|
||||||
|
tok_str_add(&str, 0);
|
||||||
|
sym_push2(&args, sa->v & ~SYM_FIELD, sa->t, (int)str.str);
|
||||||
|
sa = sa->next;
|
||||||
|
if (tok == ')') {
|
||||||
|
/* special case for gcc var args: add an empty
|
||||||
|
var arg argument if it is omitted */
|
||||||
|
if (sa && sa->t && gnu_ext)
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (tok != ',')
|
||||||
|
expect(",");
|
||||||
next_nomacro();
|
next_nomacro();
|
||||||
}
|
}
|
||||||
tok_str_add(&str, 0);
|
if (sa) {
|
||||||
sym_push2(&args, sa->v & ~SYM_FIELD, sa->t, (int)str.str);
|
error("macro '%s' used with too few args",
|
||||||
sa = sa->next;
|
get_tok_str(s->v, 0));
|
||||||
if (tok == ')') {
|
|
||||||
/* special case for gcc var args: add an empty
|
|
||||||
var arg argument if it is omitted */
|
|
||||||
if (sa && sa->t && gnu_ext)
|
|
||||||
continue;
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
if (tok != ',')
|
|
||||||
expect(",");
|
|
||||||
next_nomacro();
|
|
||||||
}
|
|
||||||
if (sa) {
|
|
||||||
error("macro '%s' used with too few args",
|
|
||||||
get_tok_str(s->v, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* now subst each arg */
|
/* now subst each arg */
|
||||||
mstr = macro_arg_subst(nested_list, mstr, args);
|
mstr = macro_arg_subst(nested_list, mstr, args);
|
||||||
/* free memory */
|
/* free memory */
|
||||||
sa = args;
|
sa = args;
|
||||||
while (sa) {
|
while (sa) {
|
||||||
sa1 = sa->prev;
|
sa1 = sa->prev;
|
||||||
tok_str_free((int *)sa->c);
|
tok_str_free((int *)sa->c);
|
||||||
tcc_free(sa);
|
tcc_free(sa);
|
||||||
sa = sa1;
|
sa = sa1;
|
||||||
|
}
|
||||||
|
mstr_allocated = 1;
|
||||||
}
|
}
|
||||||
mstr_allocated = 1;
|
sym_push2(nested_list, s->v, 0, 0);
|
||||||
|
macro_subst(tok_str, nested_list, mstr);
|
||||||
|
/* pop nested defined symbol */
|
||||||
|
sa1 = *nested_list;
|
||||||
|
*nested_list = sa1->prev;
|
||||||
|
tcc_free(sa1);
|
||||||
|
if (mstr_allocated)
|
||||||
|
tok_str_free(mstr);
|
||||||
}
|
}
|
||||||
sym_push2(nested_list, s->v, 0, 0);
|
|
||||||
macro_subst(tok_str, nested_list, mstr);
|
|
||||||
/* pop nested defined symbol */
|
|
||||||
sa1 = *nested_list;
|
|
||||||
*nested_list = sa1->prev;
|
|
||||||
tcc_free(sa1);
|
|
||||||
if (mstr_allocated)
|
|
||||||
tok_str_free(mstr);
|
|
||||||
} else {
|
} else {
|
||||||
no_subst:
|
no_subst:
|
||||||
/* no need to add if reading input stream */
|
/* no need to add if reading input stream */
|
||||||
|
@ -2880,7 +2899,7 @@ void vpush_ref(int t, Section *sec, unsigned long offset, unsigned long size)
|
||||||
vsetc(t, VT_CONST | VT_SYM, &cval);
|
vsetc(t, VT_CONST | VT_SYM, &cval);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* push a reference to symbol v */
|
/* push a reference to global symbol v */
|
||||||
void vpush_sym(int t, int v)
|
void vpush_sym(int t, int v)
|
||||||
{
|
{
|
||||||
Sym *sym;
|
Sym *sym;
|
||||||
|
@ -6524,7 +6543,7 @@ void decl(int l)
|
||||||
/* compile the C file opened in 'file'. Return non zero if errors. */
|
/* compile the C file opened in 'file'. Return non zero if errors. */
|
||||||
static int tcc_compile(TCCState *s)
|
static int tcc_compile(TCCState *s)
|
||||||
{
|
{
|
||||||
Sym *define_start;
|
Sym *define_start, *sym;
|
||||||
char buf[512];
|
char buf[512];
|
||||||
int p, section_sym;
|
int p, section_sym;
|
||||||
|
|
||||||
|
@ -6560,7 +6579,8 @@ static int tcc_compile(TCCState *s)
|
||||||
char_pointer_type = mk_pointer(VT_BYTE);
|
char_pointer_type = mk_pointer(VT_BYTE);
|
||||||
/* define an old type function 'int func()' */
|
/* define an old type function 'int func()' */
|
||||||
p = anon_sym++;
|
p = anon_sym++;
|
||||||
sym_push1(&global_stack, p, 0, FUNC_OLD);
|
sym = sym_push1(&global_stack, p, 0, FUNC_OLD);
|
||||||
|
sym->r = FUNC_CDECL;
|
||||||
func_old_type = VT_FUNC | (p << VT_STRUCT_SHIFT);
|
func_old_type = VT_FUNC | (p << VT_STRUCT_SHIFT);
|
||||||
|
|
||||||
define_start = define_stack.top;
|
define_start = define_stack.top;
|
||||||
|
@ -6894,10 +6914,21 @@ TCCState *tcc_new(void)
|
||||||
p = r;
|
p = r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* we add dummy defines for some special macros to speed up tests
|
||||||
|
and to have working defined() */
|
||||||
|
sym_push1(&define_stack, TOK___LINE__, MACRO_OBJ, 0);
|
||||||
|
sym_push1(&define_stack, TOK___FILE__, MACRO_OBJ, 0);
|
||||||
|
sym_push1(&define_stack, TOK___DATE__, MACRO_OBJ, 0);
|
||||||
|
sym_push1(&define_stack, TOK___TIME__, MACRO_OBJ, 0);
|
||||||
|
sym_push1(&define_stack, TOK___FUNCTION__, MACRO_OBJ, 0);
|
||||||
|
|
||||||
/* standard defines */
|
/* standard defines */
|
||||||
tcc_define_symbol(s, "__STDC__", NULL);
|
tcc_define_symbol(s, "__STDC__", NULL);
|
||||||
#if defined(TCC_TARGET_I386)
|
#if defined(TCC_TARGET_I386)
|
||||||
tcc_define_symbol(s, "__i386__", NULL);
|
tcc_define_symbol(s, "__i386__", NULL);
|
||||||
|
#endif
|
||||||
|
#if defined(linux)
|
||||||
|
tcc_define_symbol(s, "linux", NULL);
|
||||||
#endif
|
#endif
|
||||||
/* tiny C specific defines */
|
/* tiny C specific defines */
|
||||||
tcc_define_symbol(s, "__TINYC__", NULL);
|
tcc_define_symbol(s, "__TINYC__", NULL);
|
||||||
|
|
Loading…
Reference in a new issue