better type checks - syntax fixes (gnu_ext added) - variable external defs
This commit is contained in:
parent
8523baf61d
commit
d7e05e1b8f
1 changed files with 120 additions and 27 deletions
147
tcc.c
147
tcc.c
|
@ -111,7 +111,7 @@ typedef struct {
|
|||
anon_sym: anonymous symbol index
|
||||
*/
|
||||
FILE *file;
|
||||
int tok, tok1, tokc, rsym, anon_sym,
|
||||
int tok, tokc, tok1, tok1c, rsym, anon_sym,
|
||||
prog, ind, loc, glo, vt, vc, const_wanted, line_num;
|
||||
int global_expr; /* true if compound literals must be allocated
|
||||
globally (used during initializers parsing */
|
||||
|
@ -131,6 +131,9 @@ int ifdef_stack[IFDEF_STACK_SIZE], *ifdef_stack_ptr;
|
|||
char *include_paths[INCLUDE_PATHS_MAX];
|
||||
int nb_include_paths;
|
||||
|
||||
/* use GNU C extensions */
|
||||
int gnu_ext = 1;
|
||||
|
||||
/* The current value can be: */
|
||||
#define VT_VALMASK 0x000f
|
||||
#define VT_CONST 0x000a /* constant in vc
|
||||
|
@ -260,7 +263,8 @@ enum {
|
|||
TOK_SIZEOF,
|
||||
|
||||
/* preprocessor only */
|
||||
TOK_DEFINE,
|
||||
TOK_UIDENT, /* first "user" ident (not keyword) */
|
||||
TOK_DEFINE = TOK_UIDENT,
|
||||
TOK_INCLUDE,
|
||||
TOK_IFDEF,
|
||||
TOK_IFNDEF,
|
||||
|
@ -1410,6 +1414,7 @@ void next()
|
|||
/* special 'ungettok' case for label parsing */
|
||||
if (tok1) {
|
||||
tok = tok1;
|
||||
tokc = tok1c;
|
||||
tok1 = 0;
|
||||
} else {
|
||||
redo:
|
||||
|
@ -1517,6 +1522,7 @@ void greloc_patch(Sym *s, int val)
|
|||
p = p1;
|
||||
}
|
||||
s->c = val;
|
||||
s->t &= ~VT_FORWARD;
|
||||
}
|
||||
|
||||
/* output a symbol and patch all calls to it */
|
||||
|
@ -2802,29 +2808,68 @@ void unary(void)
|
|||
}
|
||||
}
|
||||
|
||||
/* check if types are compatible for assignation */
|
||||
int same_types(int t1, int t2)
|
||||
int is_compatible_types(int t1, int t2)
|
||||
{
|
||||
Sym *s1, *s2;
|
||||
|
||||
t1 &= VT_TYPE;
|
||||
t2 &= VT_TYPE;
|
||||
if (t1 & VT_PTR) {
|
||||
/* XXX: zero test ? */
|
||||
if (!(t2 & VT_PTR))
|
||||
return 0;
|
||||
t1 = pointed_type(t1);
|
||||
t2 = pointed_type(t2);
|
||||
/* if function, then convert implictely to function pointer */
|
||||
if (!(t2 & VT_FUNC)) {
|
||||
if (!(t2 & VT_PTR))
|
||||
return 0;
|
||||
t2 = pointed_type(t2);
|
||||
}
|
||||
/* void matches everything */
|
||||
t1 &= VT_TYPE;
|
||||
t2 &= VT_TYPE;
|
||||
if (t1 == VT_VOID || t2 == VT_VOID)
|
||||
return 1;
|
||||
return same_types(t1, t2);
|
||||
return is_compatible_types(t1, t2);
|
||||
} else if (t1 & VT_STRUCT) {
|
||||
return (t2 == t1);
|
||||
} else if (t1 & VT_FUNC) {
|
||||
if (!(t2 & VT_FUNC))
|
||||
return 0;
|
||||
s1 = sym_find(((unsigned)t1 >> VT_STRUCT_SHIFT));
|
||||
s2 = sym_find(((unsigned)t2 >> VT_STRUCT_SHIFT));
|
||||
if (!is_compatible_types(s1->t, s2->t))
|
||||
return 0;
|
||||
/* XXX: not complete */
|
||||
if (s1->c == FUNC_OLD || s2->c == FUNC_OLD)
|
||||
return 1;
|
||||
if (s1->c != s2->c)
|
||||
return 0;
|
||||
while (s1 != NULL) {
|
||||
if (s2 == NULL)
|
||||
return 0;
|
||||
if (!is_compatible_types(s1->t, s2->t))
|
||||
return 0;
|
||||
s1 = s1->next;
|
||||
s2 = s2->next;
|
||||
}
|
||||
if (s2)
|
||||
return 0;
|
||||
return 1;
|
||||
} else {
|
||||
/* XXX: not complete */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int check_assign_types(int t1, int t2)
|
||||
{
|
||||
t1 &= VT_TYPE;
|
||||
t2 &= VT_TYPE;
|
||||
if ((t1 & VT_PTR) && (t2 & VT_FUNC)) {
|
||||
return is_compatible_types(pointed_type(t1), t2);
|
||||
} else {
|
||||
return is_compatible_types(t1, t2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uneq()
|
||||
{
|
||||
|
@ -2841,8 +2886,8 @@ void uneq()
|
|||
next();
|
||||
if (t == '=') {
|
||||
expr_eq();
|
||||
if (!same_types(vt, vstack_ptr[-2]))
|
||||
error("incompatible types");
|
||||
if (!check_assign_types(vstack_ptr[-2], vt))
|
||||
warning("incompatible types");
|
||||
} else {
|
||||
vpush();
|
||||
expr_eq();
|
||||
|
@ -2979,6 +3024,31 @@ int expr_const()
|
|||
return vc;
|
||||
}
|
||||
|
||||
/* return the label token if current token is a label, otherwise
|
||||
return zero */
|
||||
int is_label(void)
|
||||
{
|
||||
int t, c;
|
||||
|
||||
/* fast test first */
|
||||
if (tok < TOK_UIDENT)
|
||||
return 0;
|
||||
t = tok;
|
||||
c = tokc;
|
||||
next();
|
||||
if (tok == ':') {
|
||||
next();
|
||||
return t;
|
||||
} else {
|
||||
/* XXX: may not work in all cases (macros ?) */
|
||||
tok1 = tok;
|
||||
tok1c = tokc;
|
||||
tok = t;
|
||||
tokc = c;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_reg)
|
||||
{
|
||||
int a, b, c, d;
|
||||
|
@ -3161,10 +3231,8 @@ void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_reg)
|
|||
next();
|
||||
skip(';');
|
||||
} else {
|
||||
b = tok;
|
||||
next();
|
||||
if (tok == ':') {
|
||||
next();
|
||||
b = is_label();
|
||||
if (b) {
|
||||
/* label case */
|
||||
s = sym_find1(&label_stack, b);
|
||||
if (s) {
|
||||
|
@ -3176,12 +3244,13 @@ void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_reg)
|
|||
} else {
|
||||
sym_push1(&label_stack, b, 0, ind);
|
||||
}
|
||||
block(bsym, csym, case_sym, def_sym, case_reg);
|
||||
/* we accept this, but it is a mistake */
|
||||
if (tok == '}')
|
||||
warning("deprecated use of label at end of compound statement");
|
||||
else
|
||||
block(bsym, csym, case_sym, def_sym, case_reg);
|
||||
} else {
|
||||
/* expression case: go backward of one token */
|
||||
/* XXX: currently incorrect if number/string/char */
|
||||
tok1 = tok;
|
||||
tok = b;
|
||||
/* expression case */
|
||||
if (tok != ';') {
|
||||
expr();
|
||||
}
|
||||
|
@ -3199,9 +3268,12 @@ void decl_designator(int t, int c,
|
|||
int size_only)
|
||||
{
|
||||
Sym *s, *f;
|
||||
int notfirst, index, align;
|
||||
int notfirst, index, align, l;
|
||||
|
||||
notfirst = 0;
|
||||
if (gnu_ext && (l = is_label()) != 0)
|
||||
goto struct_field;
|
||||
|
||||
while (tok == '[' || tok == '.') {
|
||||
if (tok == '[') {
|
||||
if (!(t & VT_ARRAY))
|
||||
|
@ -3217,20 +3289,22 @@ void decl_designator(int t, int c,
|
|||
t = pointed_type(t);
|
||||
c += index * type_size(t, &align);
|
||||
} else {
|
||||
next();
|
||||
l = tok;
|
||||
next();
|
||||
struct_field:
|
||||
if (!(t & VT_STRUCT))
|
||||
expect("struct/union type");
|
||||
next();
|
||||
s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT) | SYM_STRUCT);
|
||||
tok |= SYM_FIELD;
|
||||
l |= SYM_FIELD;
|
||||
f = s->next;
|
||||
while (f) {
|
||||
if (f->v == tok)
|
||||
if (f->v == l)
|
||||
break;
|
||||
f = f->next;
|
||||
}
|
||||
if (!f)
|
||||
expect("field");
|
||||
next();
|
||||
if (!notfirst)
|
||||
*cur_field = f;
|
||||
t = f->t | (t & VT_TYPEN);
|
||||
|
@ -3239,7 +3313,12 @@ void decl_designator(int t, int c,
|
|||
notfirst = 1;
|
||||
}
|
||||
if (notfirst) {
|
||||
skip('=');
|
||||
if (tok == '=') {
|
||||
next();
|
||||
} else {
|
||||
if (!gnu_ext)
|
||||
expect("=");
|
||||
}
|
||||
} else {
|
||||
if (t & VT_ARRAY) {
|
||||
index = *cur_index;
|
||||
|
@ -3643,7 +3722,21 @@ void decl(int l)
|
|||
if (has_init)
|
||||
next();
|
||||
addr = decl_initializer_alloc(u, has_init);
|
||||
sym_push(v, u, addr);
|
||||
if (l == VT_CONST) {
|
||||
/* global scope: see if already defined */
|
||||
sym = sym_find(v);
|
||||
if (!sym)
|
||||
goto do_def;
|
||||
if (!is_compatible_types(sym->t, u))
|
||||
error("incompatible types for redefinition of '%s'",
|
||||
get_tok_str(v, 0));
|
||||
if (!(sym->t & VT_FORWARD))
|
||||
error("redefinition of '%s'", get_tok_str(v, 0));
|
||||
greloc_patch(sym, addr);
|
||||
} else {
|
||||
do_def:
|
||||
sym_push(v, u, addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tok != ',') {
|
||||
|
|
Loading…
Reference in a new issue