suppressed secondary hash tables - began parsing optimization

tcc-xref
bellard 2002-11-20 00:29:04 +00:00
parent 9620fd18e4
commit 5286d3d84c
1 changed files with 393 additions and 139 deletions

514
tcc.c
View File

@ -79,12 +79,14 @@
#define TOK_HASH_SIZE 2048 /* must be a power of two */ #define TOK_HASH_SIZE 2048 /* must be a power of two */
#define TOK_ALLOC_INCR 512 /* must be a power of two */ #define TOK_ALLOC_INCR 512 /* must be a power of two */
#define SYM_HASH_SIZE 1031
/* token symbol management */ /* token symbol management */
typedef struct TokenSym { typedef struct TokenSym {
struct TokenSym *hash_next; struct TokenSym *hash_next;
struct Sym *sym_define; /* direct pointer to define */ struct Sym *sym_define; /* direct pointer to define */
struct Sym *sym_label; /* direct pointer to label */
struct Sym *sym_struct; /* direct pointer to structure */
struct Sym *sym_identifier; /* direct pointer to identifier */
int tok; /* token number */ int tok; /* token number */
int len; int len;
char str[1]; char str[1];
@ -136,14 +138,9 @@ typedef struct Sym {
CType type; /* associated type */ CType type; /* associated type */
struct Sym *next; /* next related symbol */ struct Sym *next; /* next related symbol */
struct Sym *prev; /* prev symbol in stack */ struct Sym *prev; /* prev symbol in stack */
struct Sym *hash_next; /* next symbol in hash table */ struct Sym *prev_tok; /* previous symbol for this token */
} Sym; } Sym;
typedef struct SymStack {
struct Sym *top;
struct Sym *hash[SYM_HASH_SIZE];
} SymStack;
/* section definition */ /* section definition */
/* XXX: use directly ELF structure for parameters ? */ /* XXX: use directly ELF structure for parameters ? */
/* special flag to indicate that the section should not be linked to /* special flag to indicate that the section should not be linked to
@ -293,8 +290,9 @@ TokenSym **table_ident;
TokenSym *hash_ident[TOK_HASH_SIZE]; TokenSym *hash_ident[TOK_HASH_SIZE];
char token_buf[STRING_MAX_SIZE + 1]; char token_buf[STRING_MAX_SIZE + 1];
char *funcname; char *funcname;
SymStack global_stack, local_stack, label_stack; Sym *global_stack, *local_stack;
Sym *define_stack; Sym *define_stack;
Sym *label_stack;
SValue vstack[VSTACK_SIZE], *vtop; SValue vstack[VSTACK_SIZE], *vtop;
int *macro_ptr, *macro_ptr_allocated; int *macro_ptr, *macro_ptr_allocated;
@ -577,8 +575,8 @@ void gen_op(int op);
void force_charshort_cast(int t); void force_charshort_cast(int t);
static void gen_cast(CType *type); static void gen_cast(CType *type);
void vstore(void); void vstore(void);
Sym *sym_find(int v); static Sym *sym_find(int v);
Sym *sym_push(int v, CType *type, int r, int c); static Sym *sym_push(int v, CType *type, int r, int c);
/* type handling */ /* type handling */
int type_size(CType *type, int *a); int type_size(CType *type, int *a);
@ -1147,6 +1145,9 @@ TokenSym *tok_alloc(const char *str, int len)
table_ident[i] = ts; table_ident[i] = ts;
ts->tok = tok_ident++; ts->tok = tok_ident++;
ts->sym_define = NULL; ts->sym_define = NULL;
ts->sym_label = NULL;
ts->sym_struct = NULL;
ts->sym_identifier = NULL;
ts->len = len; ts->len = len;
ts->hash_next = NULL; ts->hash_next = NULL;
memcpy(ts->str, str, len + 1); memcpy(ts->str, str, len + 1);
@ -1342,7 +1343,7 @@ char *get_tok_str(int v, CValue *cv)
} }
/* push, without hashing */ /* push, without hashing */
Sym *sym_push2(Sym **ps, int v, int t, int c) static Sym *sym_push2(Sym **ps, int v, int t, int c)
{ {
Sym *s; Sym *s;
s = tcc_malloc(sizeof(Sym)); s = tcc_malloc(sizeof(Sym));
@ -1358,7 +1359,7 @@ Sym *sym_push2(Sym **ps, int v, int t, int c)
/* find a symbol and return its associated structure. 's' is the top /* find a symbol and return its associated structure. 's' is the top
of the symbol stack */ of the symbol stack */
Sym *sym_find2(Sym *s, int v) static Sym *sym_find2(Sym *s, int v)
{ {
while (s) { while (s) {
if (s->v == v) if (s->v == v)
@ -1368,75 +1369,95 @@ Sym *sym_find2(Sym *s, int v)
return NULL; return NULL;
} }
#define HASH_SYM(v) ((unsigned)(v) % SYM_HASH_SIZE) /* structure lookup */
static Sym *struct_find(int v)
/* find a symbol and return its associated structure. 'st' is the
symbol stack */
Sym *sym_find1(SymStack *st, int v)
{ {
Sym *s; v -= TOK_IDENT;
if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT))
s = st->hash[HASH_SYM(v)];
while (s) {
if (s->v == v)
return s;
s = s->hash_next;
}
return NULL; return NULL;
return table_ident[v]->sym_struct;
} }
Sym *sym_push1(SymStack *st, int v, int t, int c) /* find an identifier */
static inline Sym *sym_find(int v)
{
v -= TOK_IDENT;
if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT))
return NULL;
return table_ident[v]->sym_identifier;
}
/* push a given symbol on the symbol stack */
static Sym *sym_push(int v, CType *type, int r, int c)
{ {
Sym *s, **ps; Sym *s, **ps;
s = sym_push2(&st->top, v, t, c); TokenSym *ts;
/* add in hash table */
if (v) { if (local_stack)
ps = &st->hash[HASH_SYM(v)]; ps = &local_stack;
s->hash_next = *ps; else
ps = &global_stack;
s = sym_push2(ps, v, type->t, c);
s->type.ref = type->ref;
s->r = r;
/* don't record fields or anonymous symbols */
/* XXX: simplify */
if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
/* record symbol in token array */
ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT];
if (v & SYM_STRUCT)
ps = &ts->sym_struct;
else
ps = &ts->sym_identifier;
s->prev_tok = *ps;
*ps = s; *ps = s;
} }
return s; return s;
} }
/* find a symbol in the right symbol space */ /* push a global identifier */
Sym *sym_find(int v) static Sym *global_identifier_push(int v, int t, int c)
{ {
Sym *s; Sym *s, **ps;
s = sym_find1(&local_stack, v); s = sym_push2(&global_stack, v, t, c);
if (!s) /* don't record anonymous symbol */
s = sym_find1(&global_stack, v); if (v < SYM_FIRST_ANOM) {
return s; ps = &table_ident[v - TOK_IDENT]->sym_identifier;
/* modify the top most local identifier, so that
sym_identifier will point to 's' when popped */
while (*ps != NULL)
ps = &(*ps)->prev_tok;
s->prev_tok = NULL;
*ps = s;
} }
/* push a given symbol on the symbol stack */
Sym *sym_push(int v, CType *type, int r, int c)
{
Sym *s;
if (local_stack.top)
s = sym_push1(&local_stack, v, type->t, c);
else
s = sym_push1(&global_stack, v, type->t, c);
s->type.ref = type->ref;
s->r = r;
return s; return s;
} }
/* pop symbols until top reaches 'b' */ /* pop symbols until top reaches 'b' */
void sym_pop(SymStack *st, Sym *b) static void sym_pop(Sym **ptop, Sym *b)
{ {
Sym *s, *ss; Sym *s, *ss, **ps;
TokenSym *ts;
int v;
s = st->top; s = *ptop;
while(s != b) { while(s != b) {
ss = s->prev; ss = s->prev;
/* free hash table entry, except if symbol was freed (only v = s->v;
used for #undef symbols) */ /* remove symbol in token array */
if (s->v) /* XXX: simplify */
st->hash[HASH_SYM(s->v)] = s->hash_next; if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT];
if (v & SYM_STRUCT)
ps = &ts->sym_struct;
else
ps = &ts->sym_identifier;
*ps = s->prev_tok;
}
tcc_free(s); tcc_free(s);
s = ss; s = ss;
} }
st->top = b; *ptop = b;
} }
/* I/O layer */ /* I/O layer */
@ -1845,6 +1866,24 @@ static void free_defines(Sym *b)
define_stack = b; define_stack = b;
} }
/* label lookup */
static Sym *label_find(int v)
{
v -= TOK_IDENT;
if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT))
return NULL;
return table_ident[v]->sym_label;
}
static Sym *label_push(int v, int flags)
{
Sym *s;
s = sym_push2(&label_stack, v, 0, 0);
s->r = flags;
table_ident[v - TOK_IDENT]->sym_label = s;
return s;
}
/* eval an expression for #if/#elif */ /* eval an expression for #if/#elif */
int expr_preprocess(void) int expr_preprocess(void)
{ {
@ -1996,7 +2035,7 @@ enum IncludeState {
void preprocess(void) void preprocess(void)
{ {
TCCState *s1 = tcc_state; TCCState *s1 = tcc_state;
int size, i, c, n; int size, i, c, n, line_num;
enum IncludeState state; enum IncludeState state;
char buf[1024], *q, *p; char buf[1024], *q, *p;
char buf1[1024]; char buf1[1024];
@ -2012,16 +2051,19 @@ void preprocess(void)
cinp(); cinp();
next_nomacro(); next_nomacro();
redo: redo:
if (tok == TOK_DEFINE) { switch(tok) {
case TOK_DEFINE:
next_nomacro(); next_nomacro();
parse_define(); parse_define();
} else if (tok == TOK_UNDEF) { break;
case TOK_UNDEF:
next_nomacro(); next_nomacro();
s = define_find(tok); s = define_find(tok);
/* undefine symbol by putting an invalid name */ /* undefine symbol by putting an invalid name */
if (s) if (s)
define_undef(s); define_undef(s);
} else if (tok == TOK_INCLUDE) { break;
case TOK_INCLUDE:
skip_spaces(); skip_spaces();
if (ch == '<') { if (ch == '<') {
c = '>'; c = '>';
@ -2139,13 +2181,14 @@ void preprocess(void)
state = INCLUDE_STATE_SEEK_IFNDEF; state = INCLUDE_STATE_SEEK_IFNDEF;
goto redo1; goto redo1;
} }
} else if (tok == TOK_IFNDEF) { break;
case TOK_IFNDEF:
c = 1; c = 1;
goto do_ifdef; goto do_ifdef;
} else if (tok == TOK_IF) { case TOK_IF:
c = expr_preprocess(); c = expr_preprocess();
goto do_if; goto do_if;
} else if (tok == TOK_IFDEF) { case TOK_IFDEF:
c = 0; c = 0;
do_ifdef: do_ifdef:
next_nomacro(); next_nomacro();
@ -2163,14 +2206,14 @@ void preprocess(void)
error("memory full"); error("memory full");
*s1->ifdef_stack_ptr++ = c; *s1->ifdef_stack_ptr++ = c;
goto test_skip; goto test_skip;
} else if (tok == TOK_ELSE) { case TOK_ELSE:
if (s1->ifdef_stack_ptr == s1->ifdef_stack) if (s1->ifdef_stack_ptr == s1->ifdef_stack)
error("#else without matching #if"); error("#else without matching #if");
if (s1->ifdef_stack_ptr[-1] & 2) if (s1->ifdef_stack_ptr[-1] & 2)
error("#else after #else"); error("#else after #else");
c = (s1->ifdef_stack_ptr[-1] ^= 3); c = (s1->ifdef_stack_ptr[-1] ^= 3);
goto test_skip; goto test_skip;
} else if (tok == TOK_ELIF) { case TOK_ELIF:
if (s1->ifdef_stack_ptr == s1->ifdef_stack) if (s1->ifdef_stack_ptr == s1->ifdef_stack)
error("#elif without matching #if"); error("#elif without matching #if");
c = s1->ifdef_stack_ptr[-1]; c = s1->ifdef_stack_ptr[-1];
@ -2188,7 +2231,8 @@ void preprocess(void)
state = INCLUDE_STATE_NONE; state = INCLUDE_STATE_NONE;
goto redo; goto redo;
} }
} else if (tok == TOK_ENDIF) { break;
case TOK_ENDIF:
if (s1->ifdef_stack_ptr <= file->ifdef_stack_ptr) if (s1->ifdef_stack_ptr <= file->ifdef_stack_ptr)
error("#endif without matching #if"); error("#endif without matching #if");
if (file->ifndef_macro && if (file->ifndef_macro &&
@ -2209,8 +2253,8 @@ void preprocess(void)
} }
} }
s1->ifdef_stack_ptr--; s1->ifdef_stack_ptr--;
} else if (tok == TOK_LINE) { break;
int line_num; case TOK_LINE:
next(); next();
if (tok != TOK_CINT) if (tok != TOK_CINT)
error("#line"); error("#line");
@ -2224,8 +2268,31 @@ void preprocess(void)
} }
/* NOTE: we do it there to avoid problems with linefeed */ /* NOTE: we do it there to avoid problems with linefeed */
file->line_num = line_num; file->line_num = line_num;
} else if (tok == TOK_ERROR) { break;
error("#error"); case TOK_ERROR:
case TOK_WARNING:
c = tok;
skip_spaces();
q = buf;
while (ch != '\n' && ch != CH_EOF) {
if ((q - buf) < sizeof(buf) - 1)
*q++ = ch;
minp();
}
*q = '\0';
if (c == TOK_ERROR)
error("#error %s", buf);
else
warning("#warning %s", buf);
break;
default:
if (tok == TOK_LINEFEED || tok == '!' || tok == TOK_CINT) {
/* '!' is ignored to allow C scripts. numbers are ignored
to emulate cpp behaviour */
} else {
error("invalid preprocessing directive #%s", get_tok_str(tok, &tokc));
}
break;
} }
/* ignore other preprocess commands or #! for C scripts */ /* ignore other preprocess commands or #! for C scripts */
while (tok != TOK_LINEFEED && tok != TOK_EOF) while (tok != TOK_LINEFEED && tok != TOK_EOF)
@ -2604,7 +2671,7 @@ 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; int b, t;
char *q; char *q;
TokenSym *ts; TokenSym *ts;
@ -2628,20 +2695,44 @@ static inline void next_nomacro1(void)
break; break;
cinp(); cinp();
} }
if (isid(ch)) { switch(ch) {
case '#':
tok = ch;
cinp();
#if 0
if (start_of_line) {
preprocess();
goto redo_no_start;
} else
#endif
{
if (ch == '#') {
cinp();
tok = TOK_TWOSHARPS;
}
}
break;
case 'a': case 'b': case 'c': case 'd':
case 'e': case 'f': case 'g': case 'h':
case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'p':
case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z':
case 'A': case 'B': case 'C': case 'D':
case 'E': case 'F': case 'G': case 'H':
case 'I': case 'J': case 'K':
case 'M': case 'N': case 'O': case 'P':
case 'Q': case 'R': case 'S': case 'T':
case 'U': case 'V': case 'W': case 'X':
case 'Y': case 'Z':
case '_':
q = token_buf; q = token_buf;
*q++ = ch; *q++ = ch;
cinp(); cinp();
if (q[-1] == 'L') { parse_ident:
if (ch == '\'') {
tok = TOK_LCHAR;
goto char_const;
}
if (ch == '\"') {
tok = TOK_LSTR;
goto str_const;
}
}
while (isid(ch) || isnum(ch)) { while (isid(ch) || isnum(ch)) {
if (q >= token_buf + STRING_MAX_SIZE) if (q >= token_buf + STRING_MAX_SIZE)
error("ident too long"); error("ident too long");
@ -2651,8 +2742,25 @@ static inline void next_nomacro1(void)
*q = '\0'; *q = '\0';
ts = tok_alloc(token_buf, q - token_buf); ts = tok_alloc(token_buf, q - token_buf);
tok = ts->tok; tok = ts->tok;
} else if (isnum(ch)) { break;
int t; case 'L':
cinp();
if (ch == '\'') {
tok = TOK_LCHAR;
goto char_const;
}
if (ch == '\"') {
tok = TOK_LSTR;
goto str_const;
}
q = token_buf;
*q++ = 'L';
goto parse_ident;
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
case '8': case '9':
cstr_reset(&tokcstr); cstr_reset(&tokcstr);
/* after the first digit, accept digits, alpha, '.' or sign if /* after the first digit, accept digits, alpha, '.' or sign if
prefixed by 'eEpP' */ prefixed by 'eEpP' */
@ -2670,7 +2778,8 @@ static inline void next_nomacro1(void)
cstr_ccat(&tokcstr, '\0'); cstr_ccat(&tokcstr, '\0');
tokc.cstr = &tokcstr; tokc.cstr = &tokcstr;
tok = TOK_PPNUM; tok = TOK_PPNUM;
} else if (ch == '.') { break;
case '.':
/* special dot handling because it can also start a number */ /* special dot handling because it can also start a number */
cinp(); cinp();
if (isnum(ch)) { if (isnum(ch)) {
@ -2687,7 +2796,8 @@ static inline void next_nomacro1(void)
} else { } else {
tok = '.'; tok = '.';
} }
} else if (ch == '\'') { break;
case '\'':
tok = TOK_CCHAR; tok = TOK_CCHAR;
char_const: char_const:
minp(); minp();
@ -2699,7 +2809,8 @@ static inline void next_nomacro1(void)
if (ch != '\'') if (ch != '\'')
expect("\'"); expect("\'");
minp(); minp();
} else if (ch == '\"') { break;
case '\"':
tok = TOK_STR; tok = TOK_STR;
str_const: str_const:
minp(); minp();
@ -2719,35 +2830,177 @@ static inline void next_nomacro1(void)
cstr_wccat(&tokcstr, '\0'); cstr_wccat(&tokcstr, '\0');
tokc.cstr = &tokcstr; tokc.cstr = &tokcstr;
minp(); minp();
break;
case '<':
cinp();
if (ch == '=') {
cinp();
tok = TOK_LE;
} else if (ch == '<') {
cinp();
if (ch == '=') {
cinp();
tok = TOK_A_SHL;
} else { } else {
q = tok_two_chars; tok = TOK_SHL;
/* two chars */ }
} else {
tok = TOK_LT;
}
break;
case '>':
cinp();
if (ch == '=') {
cinp();
tok = TOK_GE;
} else if (ch == '>') {
cinp();
if (ch == '=') {
cinp();
tok = TOK_A_SAR;
} else {
tok = TOK_SAR;
}
} else {
tok = TOK_GT;
}
break;
case '!':
tok = ch; tok = ch;
cinp(); cinp();
while (*q) {
if (*q == tok && q[1] == ch) {
cinp();
tok = q[2] & 0xff;
/* three chars tests */
if (tok == TOK_SHL || tok == TOK_SAR) {
if (ch == '=') { if (ch == '=') {
tok = tok | 0x80;
cinp(); cinp();
tok = TOK_NE;
} }
} else if (tok == TOK_DOTS) { break;
if (ch != '.')
error("parse error"); case '=':
tok = ch;
cinp(); cinp();
if (ch == '=') {
cinp();
tok = TOK_EQ;
} }
return; break;
case '&':
tok = ch;
cinp();
if (ch == '&') {
cinp();
tok = TOK_LAND;
} else if (ch == '=') {
cinp();
tok = TOK_A_AND;
} }
q = q + 3; break;
case '|':
tok = ch;
cinp();
if (ch == '|') {
cinp();
tok = TOK_LOR;
} else if (ch == '=') {
cinp();
tok = TOK_A_OR;
} }
/* single char substitutions */ break;
if (tok == '<')
tok = TOK_LT; case '+':
else if (tok == '>') tok = ch;
tok = TOK_GT; cinp();
if (ch == '+') {
cinp();
tok = TOK_INC;
} else if (ch == '=') {
cinp();
tok = TOK_A_ADD;
}
break;
case '-':
tok = ch;
cinp();
if (ch == '-') {
cinp();
tok = TOK_DEC;
} else if (ch == '=') {
cinp();
tok = TOK_A_SUB;
} else if (ch == '>') {
cinp();
tok = TOK_ARROW;
}
break;
case '*':
tok = ch;
cinp();
if (ch == '=') {
cinp();
tok = TOK_A_MUL;
}
break;
case '%':
tok = ch;
cinp();
if (ch == '=') {
cinp();
tok = TOK_A_MOD;
}
break;
case '^':
tok = ch;
cinp();
if (ch == '=') {
cinp();
tok = TOK_A_XOR;
}
break;
/* comments or operator */
case '/':
tok = ch;
cinp();
if (ch == '=') {
cinp();
tok = TOK_A_DIV;
}
#if 0
else if (ch == '/' || ch == '*') {
parse_comments();
goto redo_no_start;
}
#endif
break;
/* simple tokens */
case '(':
case ')':
case '[':
case ']':
case '{':
case '}':
case ',':
case ';':
case ':':
case '?':
case '~':
tok = ch;
cinp();
break;
case CH_EOF:
tok = TOK_EOF;
break;
default:
error("unrecognized character \\x%02x", ch);
break;
} }
} }
@ -3224,7 +3477,7 @@ static Sym *get_sym_ref(CType *type, Section *sec,
Sym *sym; Sym *sym;
v = anon_sym++; v = anon_sym++;
sym = sym_push1(&global_stack, v, type->t | VT_STATIC, 0); sym = global_identifier_push(v, type->t | VT_STATIC, 0);
sym->type.ref = type->ref; sym->type.ref = type->ref;
sym->r = VT_CONST | VT_SYM; sym->r = VT_CONST | VT_SYM;
put_extern_sym(sym, sec, offset, size); put_extern_sym(sym, sec, offset, size);
@ -3249,8 +3502,7 @@ static Sym *external_global_sym(int v, CType *type, int r)
s = sym_find(v); s = sym_find(v);
if (!s) { if (!s) {
/* push forward reference */ /* push forward reference */
s = sym_push1(&global_stack, s = global_identifier_push(v, type->t | VT_EXTERN, 0);
v, type->t | VT_EXTERN, 0);
s->type.ref = type->ref; s->type.ref = type->ref;
s->r = r | VT_CONST | VT_SYM; s->r = r | VT_CONST | VT_SYM;
} }
@ -4562,7 +4814,7 @@ static inline CType *pointed_type(CType *type)
static void mk_pointer(CType *type) static void mk_pointer(CType *type)
{ {
Sym *s; Sym *s;
s = sym_push(0, type, 0, -1); s = sym_push(SYM_FIELD, type, 0, -1);
type->t = VT_PTR | (type->t & ~VT_TYPE); type->t = VT_PTR | (type->t & ~VT_TYPE);
type->ref = s; type->ref = s;
} }
@ -4972,7 +5224,7 @@ static void struct_decl(CType *type, int u)
next(); next();
/* struct already defined ? return it */ /* struct already defined ? return it */
/* XXX: check consistency */ /* XXX: check consistency */
s = sym_find(v | SYM_STRUCT); s = struct_find(v);
if (s) { if (s) {
if (s->type.t != a) if (s->type.t != a)
error("invalid type"); error("invalid type");
@ -5302,7 +5554,7 @@ static void post_type(CType *type, AttributeDef *ad)
type->t &= ~(VT_TYPEDEF | VT_STATIC | VT_EXTERN); type->t &= ~(VT_TYPEDEF | VT_STATIC | VT_EXTERN);
post_type(type, ad); post_type(type, ad);
/* we push a anonymous symbol which will contain the function prototype */ /* we push a anonymous symbol which will contain the function prototype */
s = sym_push(0, type, ad->func_call, l); s = sym_push(SYM_FIELD, type, ad->func_call, l);
s->next = first; s->next = first;
type->t = t1 | VT_FUNC; type->t = t1 | VT_FUNC;
type->ref = s; type->ref = s;
@ -5323,7 +5575,7 @@ static void post_type(CType *type, AttributeDef *ad)
/* we push a anonymous symbol which will contain the array /* we push a anonymous symbol which will contain the array
element type */ element type */
s = sym_push(0, type, 0, n); s = sym_push(SYM_FIELD, type, 0, n);
type->t = t1 | VT_ARRAY | VT_PTR; type->t = t1 | VT_ARRAY | VT_PTR;
type->ref = s; type->ref = s;
} }
@ -5610,10 +5862,9 @@ static void unary(void)
/* allow to take the address of a label */ /* allow to take the address of a label */
if (tok < TOK_UIDENT) if (tok < TOK_UIDENT)
expect("label identifier"); expect("label identifier");
s = sym_find1(&label_stack, tok); s = label_find(tok);
if (!s) { if (!s) {
s = sym_push1(&label_stack, tok, 0, 0); s = label_push(tok, LABEL_FORWARD);
s->r = LABEL_FORWARD;
} }
if (!s->type.t) { if (!s->type.t) {
s->type.t = VT_VOID; s->type.t = VT_VOID;
@ -6148,7 +6399,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_re
} else if (tok == '{') { } else if (tok == '{') {
next(); next();
/* declarations */ /* declarations */
s = local_stack.top; s = local_stack;
while (tok != '}') { while (tok != '}') {
decl(VT_LOCAL); decl(VT_LOCAL);
if (tok != '}') if (tok != '}')
@ -6317,11 +6568,10 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_re
expect("pointer"); expect("pointer");
ggoto(); ggoto();
} else if (tok >= TOK_UIDENT) { } else if (tok >= TOK_UIDENT) {
s = sym_find1(&label_stack, tok); s = label_find(tok);
/* put forward definition if needed */ /* put forward definition if needed */
if (!s) { if (!s) {
s = sym_push1(&label_stack, tok, 0, 0); s = label_push(tok, LABEL_FORWARD);
s->r = LABEL_FORWARD;
} }
/* label already defined */ /* label already defined */
if (s->r & LABEL_FORWARD) if (s->r & LABEL_FORWARD)
@ -6337,13 +6587,13 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_re
b = is_label(); b = is_label();
if (b) { if (b) {
/* label case */ /* label case */
s = sym_find1(&label_stack, b); s = label_find(b);
if (s) { if (s) {
if (!(s->r & LABEL_FORWARD)) if (!(s->r & LABEL_FORWARD))
error("multiple defined label"); error("multiple defined label");
gsym((long)s->next); gsym((long)s->next);
} else { } else {
s = sym_push1(&label_stack, b, 0, 0); s = label_push(b, 0);
} }
s->next = (void *)ind; s->next = (void *)ind;
s->r = 0; s->r = 0;
@ -7110,7 +7360,7 @@ static void decl(int l)
sym->type = type; sym->type = type;
} else { } else {
/* put function symbol */ /* put function symbol */
sym = sym_push1(&global_stack, v, type.t, 0); sym = global_identifier_push(v, type.t, 0);
sym->type.ref = type.ref; sym->type.ref = type.ref;
} }
/* NOTE: we patch the symbol size later */ /* NOTE: we patch the symbol size later */
@ -7121,7 +7371,7 @@ static void decl(int l)
if (do_debug) if (do_debug)
put_func_debug(sym); put_func_debug(sym);
/* push a dummy symbol to enable local sym storage */ /* push a dummy symbol to enable local sym storage */
sym_push1(&local_stack, 0, 0, 0); sym_push2(&local_stack, SYM_FIELD, 0, 0);
gfunc_prolog(&type); gfunc_prolog(&type);
loc = 0; loc = 0;
rsym = 0; rsym = 0;
@ -7136,8 +7386,9 @@ static void decl(int l)
/* look if any labels are undefined. Define symbols if /* look if any labels are undefined. Define symbols if
'&&label' was used. */ '&&label' was used. */
{ {
Sym *s; Sym *s, *s1;
for(s = label_stack.top; s != NULL; s = s->prev) { for(s = label_stack; s != NULL; s = s1) {
s1 = s->prev;
if (s->r & LABEL_FORWARD) { if (s->r & LABEL_FORWARD) {
error("label '%s' used but not defined", error("label '%s' used but not defined",
get_tok_str(s->v, NULL)); get_tok_str(s->v, NULL));
@ -7147,9 +7398,12 @@ static void decl(int l)
1 is put. */ 1 is put. */
put_extern_sym(s, cur_text_section, (long)s->next, 1); put_extern_sym(s, cur_text_section, (long)s->next, 1);
} }
/* remove label */
table_ident[s->v - TOK_IDENT]->sym_label = NULL;
tcc_free(s);
} }
label_stack = NULL;
} }
sym_pop(&label_stack, NULL); /* reset label stack */
sym_pop(&local_stack, NULL); /* reset local stack */ sym_pop(&local_stack, NULL); /* reset local stack */
/* end of function */ /* end of function */
/* patch symbol size */ /* patch symbol size */
@ -7253,7 +7507,7 @@ static int tcc_compile(TCCState *s1)
mk_pointer(&char_pointer_type); mk_pointer(&char_pointer_type);
func_old_type.t = VT_FUNC; func_old_type.t = VT_FUNC;
func_old_type.ref = sym_push(0, &int_type, FUNC_CDECL, FUNC_OLD); func_old_type.ref = sym_push(SYM_FIELD, &int_type, FUNC_CDECL, FUNC_OLD);
#if 0 #if 0
/* define 'void *alloca(unsigned int)' builtin function */ /* define 'void *alloca(unsigned int)' builtin function */
@ -7262,7 +7516,7 @@ static int tcc_compile(TCCState *s1)
p = anon_sym++; p = anon_sym++;
sym = sym_push(p, mk_pointer(VT_VOID), FUNC_CDECL, FUNC_NEW); sym = sym_push(p, mk_pointer(VT_VOID), FUNC_CDECL, FUNC_NEW);
s1 = sym_push(0, VT_UNSIGNED | VT_INT, 0, 0); s1 = sym_push(SYM_FIELD, VT_UNSIGNED | VT_INT, 0, 0);
s1->next = NULL; s1->next = NULL;
sym->next = s1; sym->next = s1;
sym_push(TOK_alloca, VT_FUNC | (p << VT_STRUCT_SHIFT), VT_CONST, 0); sym_push(TOK_alloca, VT_FUNC | (p << VT_STRUCT_SHIFT), VT_CONST, 0);