forked from Mirrors/tinycc
correct line numbers when reparsing - added explicit TokenString structure - better logic for search path
parent
dd35b8ccd1
commit
4e5a85292b
379
tcc.c
379
tcc.c
|
@ -57,6 +57,10 @@
|
||||||
#define CONFIG_TCC_BCHECK /* enable bound checking code */
|
#define CONFIG_TCC_BCHECK /* enable bound checking code */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef CONFIG_TCC_PREFIX
|
||||||
|
#define CONFIG_TCC_PREFIX "/usr/local"
|
||||||
|
#endif
|
||||||
|
|
||||||
/* amount of virtual memory associated to a section (currently, we do
|
/* amount of virtual memory associated to a section (currently, we do
|
||||||
not realloc them) */
|
not realloc them) */
|
||||||
#define SECTION_VSIZE (1024 * 1024)
|
#define SECTION_VSIZE (1024 * 1024)
|
||||||
|
@ -184,6 +188,22 @@ typedef struct BufferedFile {
|
||||||
#define CH_EOB 0 /* end of buffer or '\0' char in file */
|
#define CH_EOB 0 /* end of buffer or '\0' char in file */
|
||||||
#define CH_EOF (-1) /* end of 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 {
|
||||||
|
int *macro_ptr;
|
||||||
|
int line_num;
|
||||||
|
int tok;
|
||||||
|
CValue tokc;
|
||||||
|
} ParseState;
|
||||||
|
|
||||||
|
/* used to record tokens */
|
||||||
|
typedef struct TokenString {
|
||||||
|
int *str;
|
||||||
|
int len;
|
||||||
|
int last_line_num;
|
||||||
|
} TokenString;
|
||||||
|
|
||||||
/* parser */
|
/* parser */
|
||||||
struct BufferedFile *file;
|
struct BufferedFile *file;
|
||||||
int ch, ch1, tok, tok1;
|
int ch, ch1, tok, tok1;
|
||||||
|
@ -266,6 +286,9 @@ struct TCCState {
|
||||||
char/short stored in integer registers) */
|
char/short stored in integer registers) */
|
||||||
#define VT_MUSTBOUND 0x0800 /* bound checking must be done before
|
#define VT_MUSTBOUND 0x0800 /* bound checking must be done before
|
||||||
dereferencing value */
|
dereferencing value */
|
||||||
|
#define VT_LVAL_BYTE 0x1000 /* lvalue is a byte */
|
||||||
|
#define VT_LVAL_SHORT 0x2000 /* lvalue is a short */
|
||||||
|
#define VT_LVAL_UNSIGNED 0x4000 /* lvalue is unsigned */
|
||||||
|
|
||||||
/* types */
|
/* types */
|
||||||
#define VT_STRUCT_SHIFT 16 /* structure/enum name shift (16 bits left) */
|
#define VT_STRUCT_SHIFT 16 /* structure/enum name shift (16 bits left) */
|
||||||
|
@ -274,7 +297,7 @@ struct TCCState {
|
||||||
#define VT_BYTE 1 /* signed byte type */
|
#define VT_BYTE 1 /* signed byte type */
|
||||||
#define VT_SHORT 2 /* short type */
|
#define VT_SHORT 2 /* short type */
|
||||||
#define VT_VOID 3 /* void type */
|
#define VT_VOID 3 /* void type */
|
||||||
#define VT_PTR 4 /* pointer increment */
|
#define VT_PTR 4 /* pointer */
|
||||||
#define VT_ENUM 5 /* enum definition */
|
#define VT_ENUM 5 /* enum definition */
|
||||||
#define VT_FUNC 6 /* function type */
|
#define VT_FUNC 6 /* function type */
|
||||||
#define VT_STRUCT 7 /* struct/union definition */
|
#define VT_STRUCT 7 /* struct/union definition */
|
||||||
|
@ -328,6 +351,7 @@ struct TCCState {
|
||||||
#define TOK_LCHAR 0xb7
|
#define TOK_LCHAR 0xb7
|
||||||
#define TOK_LSTR 0xb8
|
#define TOK_LSTR 0xb8
|
||||||
#define TOK_CFLOAT 0xb9 /* float constant */
|
#define TOK_CFLOAT 0xb9 /* float constant */
|
||||||
|
#define TOK_LINENUM 0xba /* line number info */
|
||||||
#define TOK_CDOUBLE 0xc0 /* double constant */
|
#define TOK_CDOUBLE 0xc0 /* double constant */
|
||||||
#define TOK_CLDOUBLE 0xc1 /* long double constant */
|
#define TOK_CLDOUBLE 0xc1 /* long double constant */
|
||||||
#define TOK_UMULL 0xc2 /* unsigned 32x32 -> 64 mul */
|
#define TOK_UMULL 0xc2 /* unsigned 32x32 -> 64 mul */
|
||||||
|
@ -504,7 +528,7 @@ void vswap(void);
|
||||||
void vdup(void);
|
void vdup(void);
|
||||||
int get_reg(int rc);
|
int get_reg(int rc);
|
||||||
|
|
||||||
void macro_subst(int **tok_str, int *tok_len,
|
void macro_subst(TokenString *tok_str,
|
||||||
Sym **nested_list, int *macro_str);
|
Sym **nested_list, int *macro_str);
|
||||||
int save_reg_forced(int r);
|
int save_reg_forced(int r);
|
||||||
void gen_op(int op);
|
void gen_op(int op);
|
||||||
|
@ -1270,6 +1294,30 @@ void preprocess_skip(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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' */
|
||||||
|
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' */
|
||||||
|
void restore_parse_state(ParseState *s)
|
||||||
|
{
|
||||||
|
file->line_num = s->line_num;
|
||||||
|
macro_ptr = s->macro_ptr;
|
||||||
|
tok = s->tok;
|
||||||
|
tokc = s->tokc;
|
||||||
|
}
|
||||||
|
|
||||||
/* return the number of additionnal 'ints' necessary to store the
|
/* return the number of additionnal 'ints' necessary to store the
|
||||||
token */
|
token */
|
||||||
static inline int tok_ext_size(int t)
|
static inline int tok_ext_size(int t)
|
||||||
|
@ -1283,6 +1331,7 @@ static inline int tok_ext_size(int t)
|
||||||
case TOK_STR:
|
case TOK_STR:
|
||||||
case TOK_LSTR:
|
case TOK_LSTR:
|
||||||
case TOK_CFLOAT:
|
case TOK_CFLOAT:
|
||||||
|
case TOK_LINENUM:
|
||||||
return 1;
|
return 1;
|
||||||
case TOK_CDOUBLE:
|
case TOK_CDOUBLE:
|
||||||
case TOK_CLLONG:
|
case TOK_CLLONG:
|
||||||
|
@ -1295,33 +1344,56 @@ static inline int tok_ext_size(int t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tok_add(int **tok_str, int *tok_len, int t)
|
/* token string handling */
|
||||||
|
|
||||||
|
static inline void tok_str_new(TokenString *s)
|
||||||
|
{
|
||||||
|
s->str = NULL;
|
||||||
|
s->len = 0;
|
||||||
|
s->last_line_num = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tok_str_add(TokenString *s, int t)
|
||||||
{
|
{
|
||||||
int len, *str;
|
int len, *str;
|
||||||
len = *tok_len;
|
|
||||||
str = *tok_str;
|
len = s->len;
|
||||||
|
str = s->str;
|
||||||
if ((len & 63) == 0) {
|
if ((len & 63) == 0) {
|
||||||
str = realloc(str, (len + 64) * sizeof(int));
|
str = realloc(str, (len + 64) * sizeof(int));
|
||||||
if (!str)
|
if (!str)
|
||||||
return;
|
return;
|
||||||
*tok_str = str;
|
s->str = str;
|
||||||
}
|
}
|
||||||
str[len++] = t;
|
str[len++] = t;
|
||||||
*tok_len = len;
|
s->len = len;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tok_add2(int **tok_str, int *tok_len, int t, CValue *cv)
|
static void tok_str_add2(TokenString *s, int t, CValue *cv)
|
||||||
{
|
{
|
||||||
int n, i;
|
int n, i;
|
||||||
|
tok_str_add(s, t);
|
||||||
tok_add(tok_str, tok_len, t);
|
|
||||||
n = tok_ext_size(t);
|
n = tok_ext_size(t);
|
||||||
for(i=0;i<n;i++)
|
for(i=0;i<n;i++)
|
||||||
tok_add(tok_str, tok_len, cv->tab[i]);
|
tok_str_add(s, cv->tab[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add the current parse token in token string 's' */
|
||||||
|
static void tok_str_add_tok(TokenString *s)
|
||||||
|
{
|
||||||
|
CValue cval;
|
||||||
|
|
||||||
|
/* save line number info */
|
||||||
|
if (file->line_num != s->last_line_num) {
|
||||||
|
s->last_line_num = file->line_num;
|
||||||
|
cval.i = s->last_line_num;
|
||||||
|
tok_str_add2(s, TOK_LINENUM, &cval);
|
||||||
|
}
|
||||||
|
tok_str_add2(s, tok, &tokc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get a token from an integer array and increment pointer accordingly */
|
/* get a token from an integer array and increment pointer accordingly */
|
||||||
int tok_get(int **tok_str, CValue *cv)
|
static int tok_get(int **tok_str, CValue *cv)
|
||||||
{
|
{
|
||||||
int *p, t, n, i;
|
int *p, t, n, i;
|
||||||
|
|
||||||
|
@ -1337,10 +1409,10 @@ int tok_get(int **tok_str, CValue *cv)
|
||||||
/* eval an expression for #if/#elif */
|
/* eval an expression for #if/#elif */
|
||||||
int expr_preprocess(void)
|
int expr_preprocess(void)
|
||||||
{
|
{
|
||||||
int *str, len, c, t;
|
int c, t;
|
||||||
|
TokenString str;
|
||||||
|
|
||||||
str = NULL;
|
tok_str_new(&str);
|
||||||
len = 0;
|
|
||||||
while (1) {
|
while (1) {
|
||||||
skip_spaces();
|
skip_spaces();
|
||||||
if (ch == '\n')
|
if (ch == '\n')
|
||||||
|
@ -1361,16 +1433,16 @@ int expr_preprocess(void)
|
||||||
tok = TOK_CINT;
|
tok = TOK_CINT;
|
||||||
tokc.i = 0;
|
tokc.i = 0;
|
||||||
}
|
}
|
||||||
tok_add2(&str, &len, tok, &tokc);
|
tok_str_add_tok(&str);
|
||||||
}
|
}
|
||||||
tok_add(&str, &len, -1); /* simulate end of file */
|
tok_str_add(&str, -1); /* simulate end of file */
|
||||||
tok_add(&str, &len, 0);
|
tok_str_add(&str, 0);
|
||||||
/* now evaluate C constant expression */
|
/* now evaluate C constant expression */
|
||||||
macro_ptr = str;
|
macro_ptr = str.str;
|
||||||
next();
|
next();
|
||||||
c = expr_const();
|
c = expr_const();
|
||||||
macro_ptr = NULL;
|
macro_ptr = NULL;
|
||||||
free(str);
|
free(str.str);
|
||||||
return c != 0;
|
return c != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1394,7 +1466,8 @@ void tok_print(int *str)
|
||||||
void parse_define(void)
|
void parse_define(void)
|
||||||
{
|
{
|
||||||
Sym *s, *first, **ps;
|
Sym *s, *first, **ps;
|
||||||
int v, t, *str, len;
|
int v, t;
|
||||||
|
TokenString str;
|
||||||
|
|
||||||
v = tok;
|
v = tok;
|
||||||
/* XXX: should check if same macro (ANSI) */
|
/* XXX: should check if same macro (ANSI) */
|
||||||
|
@ -1418,21 +1491,20 @@ void parse_define(void)
|
||||||
}
|
}
|
||||||
t = MACRO_FUNC;
|
t = MACRO_FUNC;
|
||||||
}
|
}
|
||||||
str = NULL;
|
tok_str_new(&str);
|
||||||
len = 0;
|
|
||||||
while (1) {
|
while (1) {
|
||||||
skip_spaces();
|
skip_spaces();
|
||||||
if (ch == '\n' || ch == -1)
|
if (ch == '\n' || ch == -1)
|
||||||
break;
|
break;
|
||||||
next_nomacro();
|
next_nomacro();
|
||||||
tok_add2(&str, &len, tok, &tokc);
|
tok_str_add2(&str, tok, &tokc);
|
||||||
}
|
}
|
||||||
tok_add(&str, &len, 0);
|
tok_str_add(&str, 0);
|
||||||
#ifdef PP_DEBUG
|
#ifdef PP_DEBUG
|
||||||
printf("define %s %d: ", get_tok_str(v, NULL), t);
|
printf("define %s %d: ", get_tok_str(v, NULL), t);
|
||||||
tok_print(str);
|
tok_print(str);
|
||||||
#endif
|
#endif
|
||||||
s = sym_push1(&define_stack, v, t, (int)str);
|
s = sym_push1(&define_stack, v, t, (int)str.str);
|
||||||
s->next = first;
|
s->next = first;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1510,7 +1582,7 @@ void preprocess(void)
|
||||||
if (f)
|
if (f)
|
||||||
goto found;
|
goto found;
|
||||||
}
|
}
|
||||||
error("include file '%s' not found", buf1);
|
error("include file '%s' not found", buf);
|
||||||
f = NULL;
|
f = NULL;
|
||||||
found:
|
found:
|
||||||
/* push current file in stack */
|
/* push current file in stack */
|
||||||
|
@ -2065,9 +2137,15 @@ void next_nomacro1(void)
|
||||||
void next_nomacro()
|
void next_nomacro()
|
||||||
{
|
{
|
||||||
if (macro_ptr) {
|
if (macro_ptr) {
|
||||||
|
redo:
|
||||||
tok = *macro_ptr;
|
tok = *macro_ptr;
|
||||||
if (tok)
|
if (tok) {
|
||||||
tok = tok_get(¯o_ptr, &tokc);
|
tok = tok_get(¯o_ptr, &tokc);
|
||||||
|
if (tok == TOK_LINENUM) {
|
||||||
|
file->line_num = tokc.i;
|
||||||
|
goto redo;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
next_nomacro1();
|
next_nomacro1();
|
||||||
}
|
}
|
||||||
|
@ -2076,13 +2154,13 @@ void next_nomacro()
|
||||||
/* substitute args in macro_str and return allocated string */
|
/* substitute args in macro_str and return allocated string */
|
||||||
int *macro_arg_subst(Sym **nested_list, int *macro_str, Sym *args)
|
int *macro_arg_subst(Sym **nested_list, int *macro_str, Sym *args)
|
||||||
{
|
{
|
||||||
int *st, last_tok, t, notfirst, *str, len;
|
int *st, last_tok, t, notfirst;
|
||||||
Sym *s;
|
Sym *s;
|
||||||
TokenSym *ts;
|
TokenSym *ts;
|
||||||
CValue cval;
|
CValue cval;
|
||||||
|
TokenString str;
|
||||||
|
|
||||||
str = NULL;
|
tok_str_new(&str);
|
||||||
len = 0;
|
|
||||||
last_tok = 0;
|
last_tok = 0;
|
||||||
while(1) {
|
while(1) {
|
||||||
t = tok_get(¯o_str, &cval);
|
t = tok_get(¯o_str, &cval);
|
||||||
|
@ -2111,9 +2189,9 @@ int *macro_arg_subst(Sym **nested_list, int *macro_str, Sym *args)
|
||||||
/* add string */
|
/* add string */
|
||||||
ts = tok_alloc(token_buf, 0);
|
ts = tok_alloc(token_buf, 0);
|
||||||
cval.ts = ts;
|
cval.ts = ts;
|
||||||
tok_add2(&str, &len, TOK_STR, &cval);
|
tok_str_add2(&str, TOK_STR, &cval);
|
||||||
} else {
|
} else {
|
||||||
tok_add2(&str, &len, t, &cval);
|
tok_str_add2(&str, t, &cval);
|
||||||
}
|
}
|
||||||
} else if (t >= TOK_IDENT) {
|
} else if (t >= TOK_IDENT) {
|
||||||
s = sym_find2(args, t);
|
s = sym_find2(args, t);
|
||||||
|
@ -2122,33 +2200,33 @@ int *macro_arg_subst(Sym **nested_list, int *macro_str, Sym *args)
|
||||||
/* if '##' is present before or after , no arg substitution */
|
/* if '##' is present before or after , no arg substitution */
|
||||||
if (*macro_str == TOK_TWOSHARPS || last_tok == TOK_TWOSHARPS) {
|
if (*macro_str == TOK_TWOSHARPS || last_tok == TOK_TWOSHARPS) {
|
||||||
while (*st)
|
while (*st)
|
||||||
tok_add(&str, &len, *st++);
|
tok_str_add(&str, *st++);
|
||||||
} else {
|
} else {
|
||||||
macro_subst(&str, &len, nested_list, st);
|
macro_subst(&str, nested_list, st);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tok_add(&str, &len, t);
|
tok_str_add(&str, t);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tok_add2(&str, &len, t, &cval);
|
tok_str_add2(&str, t, &cval);
|
||||||
}
|
}
|
||||||
last_tok = t;
|
last_tok = t;
|
||||||
}
|
}
|
||||||
tok_add(&str, &len, 0);
|
tok_str_add(&str, 0);
|
||||||
return str;
|
return str.str;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* handle the '##' operator */
|
/* handle the '##' operator */
|
||||||
int *macro_twosharps(int *macro_str)
|
int *macro_twosharps(int *macro_str)
|
||||||
{
|
{
|
||||||
TokenSym *ts;
|
TokenSym *ts;
|
||||||
int *macro_str1, macro_str1_len, *macro_ptr1;
|
int *macro_ptr1;
|
||||||
int t;
|
int t;
|
||||||
char *p;
|
char *p;
|
||||||
CValue cval;
|
CValue cval;
|
||||||
|
TokenString macro_str1;
|
||||||
|
|
||||||
macro_str1 = NULL;
|
tok_str_new(¯o_str1);
|
||||||
macro_str1_len = 0;
|
|
||||||
tok = 0;
|
tok = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
next_nomacro();
|
next_nomacro();
|
||||||
|
@ -2177,25 +2255,24 @@ int *macro_twosharps(int *macro_str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tok_add2(¯o_str1, ¯o_str1_len, tok, &tokc);
|
tok_str_add2(¯o_str1, tok, &tokc);
|
||||||
}
|
}
|
||||||
tok_add(¯o_str1, ¯o_str1_len, 0);
|
tok_str_add(¯o_str1, 0);
|
||||||
return macro_str1;
|
return macro_str1.str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* do macro substitution of macro_str and add result to
|
/* do macro substitution of macro_str and add result to
|
||||||
(tok_str,tok_len). If macro_str is NULL, then input stream token is
|
(tok_str,tok_len). If macro_str is NULL, then input stream token is
|
||||||
substituted. 'nested_list' is the list of all macros we got inside
|
substituted. 'nested_list' is the list of all macros we got inside
|
||||||
to avoid recursing. */
|
to avoid recursing. */
|
||||||
void macro_subst(int **tok_str, int *tok_len,
|
void macro_subst(TokenString *tok_str,
|
||||||
Sym **nested_list, int *macro_str)
|
Sym **nested_list, int *macro_str)
|
||||||
{
|
{
|
||||||
Sym *s, *args, *sa, *sa1;
|
Sym *s, *args, *sa, *sa1;
|
||||||
int *str, parlevel, len, *mstr, t, *saved_macro_ptr;
|
int parlevel, *mstr, t, *saved_macro_ptr;
|
||||||
int mstr_allocated, *macro_str1;
|
int mstr_allocated, *macro_str1;
|
||||||
CValue cval;
|
CValue cval;
|
||||||
|
TokenString str;
|
||||||
|
|
||||||
saved_macro_ptr = macro_ptr;
|
saved_macro_ptr = macro_ptr;
|
||||||
macro_ptr = macro_str;
|
macro_ptr = macro_str;
|
||||||
|
@ -2213,16 +2290,16 @@ void macro_subst(int **tok_str, int *tok_len,
|
||||||
/* special macros */
|
/* special macros */
|
||||||
if (tok == TOK___LINE__) {
|
if (tok == TOK___LINE__) {
|
||||||
cval.i = file->line_num;
|
cval.i = file->line_num;
|
||||||
tok_add2(tok_str, tok_len, TOK_CINT, &cval);
|
tok_str_add2(tok_str, TOK_CINT, &cval);
|
||||||
} else if (tok == TOK___FILE__) {
|
} else if (tok == TOK___FILE__) {
|
||||||
cval.ts = tok_alloc(file->filename, 0);
|
cval.ts = tok_alloc(file->filename, 0);
|
||||||
tok_add2(tok_str, tok_len, TOK_STR, &cval);
|
tok_str_add2(tok_str, TOK_STR, &cval);
|
||||||
} else if (tok == TOK___DATE__) {
|
} else if (tok == TOK___DATE__) {
|
||||||
cval.ts = tok_alloc("Jan 1 1970", 0);
|
cval.ts = tok_alloc("Jan 1 1970", 0);
|
||||||
tok_add2(tok_str, tok_len, TOK_STR, &cval);
|
tok_str_add2(tok_str, TOK_STR, &cval);
|
||||||
} else if (tok == TOK___TIME__) {
|
} else if (tok == TOK___TIME__) {
|
||||||
cval.ts = tok_alloc("00:00:00", 0);
|
cval.ts = tok_alloc("00:00:00", 0);
|
||||||
tok_add2(tok_str, tok_len, TOK_STR, &cval);
|
tok_str_add2(tok_str, TOK_STR, &cval);
|
||||||
} else if ((s = sym_find1(&define_stack, tok)) != NULL) {
|
} 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 */
|
||||||
|
@ -2256,8 +2333,7 @@ void macro_subst(int **tok_str, int *tok_len,
|
||||||
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));
|
||||||
len = 0;
|
tok_str_new(&str);
|
||||||
str = NULL;
|
|
||||||
parlevel = 0;
|
parlevel = 0;
|
||||||
while ((parlevel > 0 ||
|
while ((parlevel > 0 ||
|
||||||
(tok != ')' &&
|
(tok != ')' &&
|
||||||
|
@ -2268,11 +2344,11 @@ void macro_subst(int **tok_str, int *tok_len,
|
||||||
parlevel++;
|
parlevel++;
|
||||||
else if (tok == ')')
|
else if (tok == ')')
|
||||||
parlevel--;
|
parlevel--;
|
||||||
tok_add2(&str, &len, tok, &tokc);
|
tok_str_add2(&str, tok, &tokc);
|
||||||
next_nomacro();
|
next_nomacro();
|
||||||
}
|
}
|
||||||
tok_add(&str, &len, 0);
|
tok_str_add(&str, 0);
|
||||||
sym_push2(&args, sa->v & ~SYM_FIELD, 0, (int)str);
|
sym_push2(&args, sa->v & ~SYM_FIELD, 0, (int)str.str);
|
||||||
if (tok == ')')
|
if (tok == ')')
|
||||||
break;
|
break;
|
||||||
if (tok != ',')
|
if (tok != ',')
|
||||||
|
@ -2297,7 +2373,7 @@ void macro_subst(int **tok_str, int *tok_len,
|
||||||
mstr_allocated = 1;
|
mstr_allocated = 1;
|
||||||
}
|
}
|
||||||
sym_push2(nested_list, s->v, 0, 0);
|
sym_push2(nested_list, s->v, 0, 0);
|
||||||
macro_subst(tok_str, tok_len, nested_list, mstr);
|
macro_subst(tok_str, nested_list, mstr);
|
||||||
/* pop nested defined symbol */
|
/* pop nested defined symbol */
|
||||||
sa1 = *nested_list;
|
sa1 = *nested_list;
|
||||||
*nested_list = sa1->prev;
|
*nested_list = sa1->prev;
|
||||||
|
@ -2309,7 +2385,7 @@ void macro_subst(int **tok_str, int *tok_len,
|
||||||
/* no need to add if reading input stream */
|
/* no need to add if reading input stream */
|
||||||
if (!macro_str)
|
if (!macro_str)
|
||||||
return;
|
return;
|
||||||
tok_add2(tok_str, tok_len, tok, &tokc);
|
tok_str_add2(tok_str, tok, &tokc);
|
||||||
}
|
}
|
||||||
/* only replace one macro while parsing input stream */
|
/* only replace one macro while parsing input stream */
|
||||||
if (!macro_str)
|
if (!macro_str)
|
||||||
|
@ -2323,8 +2399,8 @@ void macro_subst(int **tok_str, int *tok_len,
|
||||||
/* return next token with macro substitution */
|
/* return next token with macro substitution */
|
||||||
void next(void)
|
void next(void)
|
||||||
{
|
{
|
||||||
int len, *ptr;
|
|
||||||
Sym *nested_list;
|
Sym *nested_list;
|
||||||
|
TokenString str;
|
||||||
|
|
||||||
/* special 'ungettok' case for label parsing */
|
/* special 'ungettok' case for label parsing */
|
||||||
if (tok1) {
|
if (tok1) {
|
||||||
|
@ -2334,15 +2410,16 @@ void next(void)
|
||||||
} else {
|
} else {
|
||||||
redo:
|
redo:
|
||||||
if (!macro_ptr) {
|
if (!macro_ptr) {
|
||||||
/* if not reading from macro substituted string, then try to substitute */
|
/* if not reading from macro substituted string, then try
|
||||||
len = 0;
|
to substitute */
|
||||||
ptr = NULL;
|
/* XXX: optimize non macro case */
|
||||||
|
tok_str_new(&str);
|
||||||
nested_list = NULL;
|
nested_list = NULL;
|
||||||
macro_subst(&ptr, &len, &nested_list, NULL);
|
macro_subst(&str, &nested_list, NULL);
|
||||||
if (ptr) {
|
if (str.str) {
|
||||||
tok_add(&ptr, &len, 0);
|
tok_str_add(&str, 0);
|
||||||
macro_ptr = ptr;
|
macro_ptr = str.str;
|
||||||
macro_ptr_allocated = ptr;
|
macro_ptr_allocated = str.str;
|
||||||
goto redo;
|
goto redo;
|
||||||
}
|
}
|
||||||
if (tok == 0)
|
if (tok == 0)
|
||||||
|
@ -4673,15 +4750,16 @@ void unary(void)
|
||||||
sa = s->next; /* first parameter */
|
sa = s->next; /* first parameter */
|
||||||
#ifdef INVERT_FUNC_PARAMS
|
#ifdef INVERT_FUNC_PARAMS
|
||||||
{
|
{
|
||||||
int *str, len, parlevel, *saved_macro_ptr;
|
int parlevel;
|
||||||
Sym *args, *s1;
|
Sym *args, *s1;
|
||||||
|
ParseState saved_parse_state;
|
||||||
|
TokenString str;
|
||||||
|
|
||||||
/* read each argument and store it on a stack */
|
/* read each argument and store it on a stack */
|
||||||
/* XXX: merge it with macro args ? */
|
/* XXX: merge it with macro args ? */
|
||||||
args = NULL;
|
args = NULL;
|
||||||
while (tok != ')') {
|
while (tok != ')') {
|
||||||
len = 0;
|
tok_str_new(&str);
|
||||||
str = NULL;
|
|
||||||
parlevel = 0;
|
parlevel = 0;
|
||||||
while ((parlevel > 0 || (tok != ')' && tok != ',')) &&
|
while ((parlevel > 0 || (tok != ')' && tok != ',')) &&
|
||||||
tok != -1) {
|
tok != -1) {
|
||||||
|
@ -4689,12 +4767,12 @@ void unary(void)
|
||||||
parlevel++;
|
parlevel++;
|
||||||
else if (tok == ')')
|
else if (tok == ')')
|
||||||
parlevel--;
|
parlevel--;
|
||||||
tok_add2(&str, &len, tok, &tokc);
|
tok_str_add_tok(&str);
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
tok_add(&str, &len, -1); /* end of file added */
|
tok_str_add(&str, -1); /* end of file added */
|
||||||
tok_add(&str, &len, 0);
|
tok_str_add(&str, 0);
|
||||||
s1 = sym_push2(&args, 0, 0, (int)str);
|
s1 = sym_push2(&args, 0, 0, (int)str.str);
|
||||||
s1->next = sa; /* add reference to argument */
|
s1->next = sa; /* add reference to argument */
|
||||||
if (sa)
|
if (sa)
|
||||||
sa = sa->next;
|
sa = sa->next;
|
||||||
|
@ -4706,7 +4784,7 @@ void unary(void)
|
||||||
expect(")");
|
expect(")");
|
||||||
|
|
||||||
/* now generate code in reverse order by reading the stack */
|
/* now generate code in reverse order by reading the stack */
|
||||||
saved_macro_ptr = macro_ptr;
|
save_parse_state(&saved_parse_state);
|
||||||
while (args) {
|
while (args) {
|
||||||
macro_ptr = (int *)args->c;
|
macro_ptr = (int *)args->c;
|
||||||
next();
|
next();
|
||||||
|
@ -4719,9 +4797,7 @@ void unary(void)
|
||||||
free(args);
|
free(args);
|
||||||
args = s1;
|
args = s1;
|
||||||
}
|
}
|
||||||
macro_ptr = saved_macro_ptr;
|
restore_parse_state(&saved_parse_state);
|
||||||
/* restore token */
|
|
||||||
tok = ')';
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
/* compute first implicit argument if a structure is returned */
|
/* compute first implicit argument if a structure is returned */
|
||||||
|
@ -5520,8 +5596,10 @@ void decl_initializer(int t, int r, int c, int first, int size_only)
|
||||||
VT_LOCAL or VT_CONST). The allocated address in returned */
|
VT_LOCAL or VT_CONST). The allocated address in returned */
|
||||||
int decl_initializer_alloc(int t, AttributeDef *ad, int r, int has_init)
|
int decl_initializer_alloc(int t, AttributeDef *ad, int r, int has_init)
|
||||||
{
|
{
|
||||||
int size, align, addr, tok1, data_offset;
|
int size, align, addr, data_offset;
|
||||||
int *init_str, init_len, level, *saved_macro_ptr;
|
int level;
|
||||||
|
ParseState saved_parse_state;
|
||||||
|
TokenString init_str;
|
||||||
Section *sec;
|
Section *sec;
|
||||||
|
|
||||||
size = type_size(t, &align);
|
size = type_size(t, &align);
|
||||||
|
@ -5531,10 +5609,7 @@ int decl_initializer_alloc(int t, AttributeDef *ad, int r, int has_init)
|
||||||
(e.g. string pointers or ISOC99 compound
|
(e.g. string pointers or ISOC99 compound
|
||||||
literals). It also simplifies local
|
literals). It also simplifies local
|
||||||
initializers handling */
|
initializers handling */
|
||||||
init_len = 0;
|
tok_str_new(&init_str);
|
||||||
init_str = NULL;
|
|
||||||
saved_macro_ptr = NULL; /* avoid warning */
|
|
||||||
tok1 = 0;
|
|
||||||
if (size < 0) {
|
if (size < 0) {
|
||||||
if (!has_init)
|
if (!has_init)
|
||||||
error("unknown type size");
|
error("unknown type size");
|
||||||
|
@ -5543,7 +5618,7 @@ int decl_initializer_alloc(int t, AttributeDef *ad, int r, int has_init)
|
||||||
while (level > 0 || (tok != ',' && tok != ';')) {
|
while (level > 0 || (tok != ',' && tok != ';')) {
|
||||||
if (tok < 0)
|
if (tok < 0)
|
||||||
error("unexpected end of file in initializer");
|
error("unexpected end of file in initializer");
|
||||||
tok_add2(&init_str, &init_len, tok, &tokc);
|
tok_str_add_tok(&init_str);
|
||||||
if (tok == '{')
|
if (tok == '{')
|
||||||
level++;
|
level++;
|
||||||
else if (tok == '}') {
|
else if (tok == '}') {
|
||||||
|
@ -5553,17 +5628,17 @@ int decl_initializer_alloc(int t, AttributeDef *ad, int r, int has_init)
|
||||||
}
|
}
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
tok1 = tok;
|
tok_str_add(&init_str, -1);
|
||||||
tok_add(&init_str, &init_len, -1);
|
tok_str_add(&init_str, 0);
|
||||||
tok_add(&init_str, &init_len, 0);
|
|
||||||
|
|
||||||
/* compute size */
|
/* compute size */
|
||||||
saved_macro_ptr = macro_ptr;
|
save_parse_state(&saved_parse_state);
|
||||||
macro_ptr = init_str;
|
|
||||||
|
macro_ptr = init_str.str;
|
||||||
next();
|
next();
|
||||||
decl_initializer(t, r, 0, 1, 1);
|
decl_initializer(t, r, 0, 1, 1);
|
||||||
/* prepare second initializer parsing */
|
/* prepare second initializer parsing */
|
||||||
macro_ptr = init_str;
|
macro_ptr = init_str.str;
|
||||||
next();
|
next();
|
||||||
|
|
||||||
/* if still unknown size, error */
|
/* if still unknown size, error */
|
||||||
|
@ -5632,10 +5707,9 @@ int decl_initializer_alloc(int t, AttributeDef *ad, int r, int has_init)
|
||||||
if (has_init) {
|
if (has_init) {
|
||||||
decl_initializer(t, r, addr, 1, 0);
|
decl_initializer(t, r, addr, 1, 0);
|
||||||
/* restore parse state if needed */
|
/* restore parse state if needed */
|
||||||
if (init_str) {
|
if (init_str.str) {
|
||||||
free(init_str);
|
free(init_str.str);
|
||||||
macro_ptr = saved_macro_ptr;
|
restore_parse_state(&saved_parse_state);
|
||||||
tok = tok1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return addr;
|
return addr;
|
||||||
|
@ -5663,6 +5737,65 @@ void put_func_debug(int t)
|
||||||
last_line_num = 0;
|
last_line_num = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* not finished : try to put some local vars in registers */
|
||||||
|
//#define CONFIG_REG_VARS
|
||||||
|
|
||||||
|
#ifdef CONFIG_REG_VARS
|
||||||
|
void add_var_ref(int t)
|
||||||
|
{
|
||||||
|
printf("%s:%d: &%s\n",
|
||||||
|
file->filename, file->line_num,
|
||||||
|
get_tok_str(t, NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* first pass on a function with heuristic to extract variable usage
|
||||||
|
and pointer references to local variables for register allocation */
|
||||||
|
void analyse_function(void)
|
||||||
|
{
|
||||||
|
int level, t;
|
||||||
|
|
||||||
|
for(;;) {
|
||||||
|
if (tok == -1)
|
||||||
|
break;
|
||||||
|
/* any symbol coming after '&' is considered as being a
|
||||||
|
variable whose reference is taken. It is highly unaccurate
|
||||||
|
but it is difficult to do better without a complete parse */
|
||||||
|
if (tok == '&') {
|
||||||
|
next();
|
||||||
|
/* if '& number', then no need to examine next tokens */
|
||||||
|
if (tok == TOK_CINT ||
|
||||||
|
tok == TOK_CUINT ||
|
||||||
|
tok == TOK_CLLONG ||
|
||||||
|
tok == TOK_CULLONG) {
|
||||||
|
continue;
|
||||||
|
} else if (tok >= TOK_UIDENT) {
|
||||||
|
/* if '& ident [' or '& ident ->', then ident address
|
||||||
|
is not needed */
|
||||||
|
t = tok;
|
||||||
|
next();
|
||||||
|
if (tok != '[' && tok != TOK_ARROW)
|
||||||
|
add_var_ref(t);
|
||||||
|
} else {
|
||||||
|
level = 0;
|
||||||
|
while (tok != '}' && tok != ';' &&
|
||||||
|
!((tok == ',' || tok == ')') && level == 0)) {
|
||||||
|
if (tok >= TOK_UIDENT) {
|
||||||
|
add_var_ref(tok);
|
||||||
|
} else if (tok == '(') {
|
||||||
|
level++;
|
||||||
|
} else if (tok == ')') {
|
||||||
|
level--;
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* 'l' is VT_LOCAL or VT_CONST to define default storage type */
|
/* 'l' is VT_LOCAL or VT_CONST to define default storage type */
|
||||||
void decl(int l)
|
void decl(int l)
|
||||||
{
|
{
|
||||||
|
@ -5701,10 +5834,48 @@ void decl(int l)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (tok == '{') {
|
if (tok == '{') {
|
||||||
|
#ifdef CONFIG_REG_VARS
|
||||||
|
TokenString func_str;
|
||||||
|
ParseState saved_parse_state;
|
||||||
|
int block_level;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (l == VT_LOCAL)
|
if (l == VT_LOCAL)
|
||||||
error("cannot use local functions");
|
error("cannot use local functions");
|
||||||
if (!(t & VT_FUNC))
|
if (!(t & VT_FUNC))
|
||||||
expect("function definition");
|
expect("function definition");
|
||||||
|
|
||||||
|
#ifdef CONFIG_REG_VARS
|
||||||
|
/* parse all function code and record it */
|
||||||
|
|
||||||
|
tok_str_new(&func_str);
|
||||||
|
|
||||||
|
block_level = 0;
|
||||||
|
for(;;) {
|
||||||
|
int t;
|
||||||
|
if (tok == -1)
|
||||||
|
error("unexpected end of file");
|
||||||
|
tok_str_add_tok(&func_str);
|
||||||
|
t = tok;
|
||||||
|
next();
|
||||||
|
if (t == '{') {
|
||||||
|
block_level++;
|
||||||
|
} else if (t == '}') {
|
||||||
|
block_level--;
|
||||||
|
if (block_level == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tok_str_add(&func_str, -1);
|
||||||
|
tok_str_add(&func_str, 0);
|
||||||
|
|
||||||
|
save_parse_state(&saved_parse_state);
|
||||||
|
|
||||||
|
macro_ptr = func_str.str;
|
||||||
|
next();
|
||||||
|
analyse_function();
|
||||||
|
#endif
|
||||||
|
|
||||||
/* compute text section */
|
/* compute text section */
|
||||||
cur_text_section = ad.section;
|
cur_text_section = ad.section;
|
||||||
if (!cur_text_section)
|
if (!cur_text_section)
|
||||||
|
@ -5728,6 +5899,10 @@ void decl(int l)
|
||||||
gfunc_prolog(t);
|
gfunc_prolog(t);
|
||||||
loc = 0;
|
loc = 0;
|
||||||
rsym = 0;
|
rsym = 0;
|
||||||
|
#ifdef CONFIG_REG_VARS
|
||||||
|
macro_ptr = func_str.str;
|
||||||
|
next();
|
||||||
|
#endif
|
||||||
block(NULL, NULL, NULL, NULL, 0);
|
block(NULL, NULL, NULL, NULL, 0);
|
||||||
gsym(rsym);
|
gsym(rsym);
|
||||||
gfunc_epilog();
|
gfunc_epilog();
|
||||||
|
@ -5741,6 +5916,11 @@ void decl(int l)
|
||||||
funcname = ""; /* for safety */
|
funcname = ""; /* for safety */
|
||||||
func_vt = VT_VOID; /* for safety */
|
func_vt = VT_VOID; /* for safety */
|
||||||
ind = 0; /* for safety */
|
ind = 0; /* for safety */
|
||||||
|
|
||||||
|
#ifdef CONFIG_REG_VARS
|
||||||
|
free(func_str.str);
|
||||||
|
restore_parse_state(&saved_parse_state);
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
if (b & VT_TYPEDEF) {
|
if (b & VT_TYPEDEF) {
|
||||||
|
@ -6450,8 +6630,7 @@ TCCState *tcc_new(void)
|
||||||
/* default include paths */
|
/* default include paths */
|
||||||
nb_include_paths = 0;
|
nb_include_paths = 0;
|
||||||
tcc_add_include_path(s, "/usr/include");
|
tcc_add_include_path(s, "/usr/include");
|
||||||
tcc_add_include_path(s, "/usr/lib/tcc");
|
tcc_add_include_path(s, CONFIG_TCC_PREFIX "/lib/tcc/include");
|
||||||
tcc_add_include_path(s, "/usr/local/lib/tcc");
|
|
||||||
|
|
||||||
/* add all tokens */
|
/* add all tokens */
|
||||||
tok_ident = TOK_IDENT;
|
tok_ident = TOK_IDENT;
|
||||||
|
@ -6502,7 +6681,7 @@ int tcc_add_include_path(TCCState *s, const char *pathname)
|
||||||
|
|
||||||
void help(void)
|
void help(void)
|
||||||
{
|
{
|
||||||
printf("tcc version 0.9.7 - Tiny C Compiler - Copyright (C) 2001, 2002 Fabrice Bellard\n"
|
printf("tcc version 0.9.8 - Tiny C Compiler - Copyright (C) 2001, 2002 Fabrice Bellard\n"
|
||||||
"usage: tcc [-Idir] [-Dsym[=val]] [-Usym] [-llib] [-g] [-b]\n"
|
"usage: tcc [-Idir] [-Dsym[=val]] [-Usym] [-llib] [-g] [-b]\n"
|
||||||
" [-i infile] infile [infile_args...]\n"
|
" [-i infile] infile [infile_args...]\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
|
Loading…
Reference in New Issue