added enum, typedefs, goto, switch
This commit is contained in:
parent
4e92bac070
commit
b15f269fbe
1 changed files with 172 additions and 35 deletions
207
tcc.c
207
tcc.c
|
@ -15,7 +15,7 @@
|
|||
prog: output code
|
||||
astk: arg position stack
|
||||
*/
|
||||
int tok, *vac, *vat, rsym,
|
||||
int tok, tok1, *vac, *vat, rsym,
|
||||
prog, ind, loc, glo, file, vt,
|
||||
vc, *macro_stack, *macro_stack_ptr, line_num;
|
||||
char *idtable, *idptr, *filename;
|
||||
|
@ -62,7 +62,10 @@ char *idtable, *idptr, *filename;
|
|||
#define VT_STATIC 0x10000 /* static variable */
|
||||
|
||||
/* Special infos */
|
||||
#define VT_LABEL 0x40000 /* goto label symbol */
|
||||
#define VT_DEFINE 0x80000 /* special value for #defined symbols */
|
||||
#define VT_ENUM 0x100000 /* enum definition */
|
||||
#define VT_TYPEDEF 0x200000 /* typedef definition */
|
||||
|
||||
/* token values */
|
||||
#define TOK_INT 256
|
||||
|
@ -97,8 +100,8 @@ char *idtable, *idptr, *filename;
|
|||
#define TOK_DOUBLE 281
|
||||
#define TOK_STRUCT 282
|
||||
#define TOK_UNION 283
|
||||
#define TOK_TYPEDEF 284
|
||||
|
||||
#define TOK_TYPEDEF 284
|
||||
#define TOK_DEFAULT 285
|
||||
#define TOK_ENUM 286
|
||||
|
||||
|
@ -214,6 +217,13 @@ void next()
|
|||
int c, v;
|
||||
char *q, *p;
|
||||
|
||||
/* special 'ungettok' case for label parsing */
|
||||
if (tok1) {
|
||||
tok = tok1;
|
||||
tok1 = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
while(1) {
|
||||
c = inp();
|
||||
#ifndef TINY
|
||||
|
@ -543,32 +553,72 @@ void gen_op(op, l)
|
|||
}
|
||||
}
|
||||
|
||||
int expr_const()
|
||||
{
|
||||
expr_eq();
|
||||
if ((vt & (VT_CONST | VT_LVAL)) != VT_CONST)
|
||||
error("constant expected");
|
||||
return vc;
|
||||
}
|
||||
|
||||
/* return 0 if no type declaration. otherwise, return the basic type
|
||||
and skip it.
|
||||
XXX: A '2' is ored to ensure non zero return if int type.
|
||||
*/
|
||||
int ist()
|
||||
{
|
||||
int t;
|
||||
int t, n, v;
|
||||
|
||||
t = 0;
|
||||
while(1) {
|
||||
if (tok == TOK_CHAR | tok == TOK_VOID) {
|
||||
t |= VT_BYTE;
|
||||
} else if (tok == TOK_INT |
|
||||
(tok >= TOK_CONST & tok <= TOK_SIGNED)) {
|
||||
/* ignored types */
|
||||
} else if (tok >= TOK_FLOAT & tok <= TOK_TYPEDEF) {
|
||||
error("unsupported type");
|
||||
} else if (tok == TOK_EXTERN) {
|
||||
t |= VT_EXTERN;
|
||||
} else if (tok == TOK_STATIC) {
|
||||
t |= VT_STATIC;
|
||||
} else if (tok == TOK_UNSIGNED) {
|
||||
t |= VT_UNSIGNED;
|
||||
if (tok == TOK_ENUM) {
|
||||
next();
|
||||
if (tok != '{')
|
||||
next();
|
||||
if (tok == '{') {
|
||||
next();
|
||||
n = 0;
|
||||
while (tok != '}' & tok != -1) {
|
||||
v = tok;
|
||||
next();
|
||||
if (tok == '=') {
|
||||
next();
|
||||
n = expr_const();
|
||||
}
|
||||
vat[v] = VT_CONST;
|
||||
vac[v] = n;
|
||||
if (tok != ',')
|
||||
break;
|
||||
next();
|
||||
n++;
|
||||
}
|
||||
skip('}');
|
||||
}
|
||||
t |= VT_ENUM;
|
||||
} else {
|
||||
break;
|
||||
if (tok == TOK_CHAR | tok == TOK_VOID) {
|
||||
t |= VT_BYTE;
|
||||
} else if (tok == TOK_INT |
|
||||
(tok >= TOK_CONST & tok <= TOK_SIGNED)) {
|
||||
/* ignored types */
|
||||
} else if (tok >= TOK_FLOAT & tok <= TOK_UNION) {
|
||||
error("unsupported type");
|
||||
} else if (tok == TOK_EXTERN) {
|
||||
t |= VT_EXTERN;
|
||||
} else if (tok == TOK_STATIC) {
|
||||
t |= VT_STATIC;
|
||||
} else if (tok == TOK_UNSIGNED) {
|
||||
t |= VT_UNSIGNED;
|
||||
} else if (tok == TOK_TYPEDEF) {
|
||||
t |= VT_TYPEDEF;
|
||||
} else {
|
||||
v = vat[tok];
|
||||
if (!(v & VT_TYPEDEF))
|
||||
break;
|
||||
t = v & ~VT_TYPEDEF;
|
||||
}
|
||||
next();
|
||||
}
|
||||
next();
|
||||
t |= 2;
|
||||
}
|
||||
return t;
|
||||
|
@ -630,14 +680,13 @@ int typ(int *v, int t, int *array_size_ptr)
|
|||
if (t & VT_ARRAY)
|
||||
error("multi dimension arrays not supported");
|
||||
next();
|
||||
vc = 0;
|
||||
n = 0;
|
||||
if (tok != ']') {
|
||||
expr();
|
||||
n = expr_const();
|
||||
if (array_size_ptr)
|
||||
*array_size_ptr = vc;
|
||||
*array_size_ptr = n;
|
||||
}
|
||||
if ((vt & (VT_CONST | VT_LVAL)) != VT_CONST |
|
||||
(vc <= 0 & array_size_ptr != 0))
|
||||
if (n <= 0 & array_size_ptr != 0)
|
||||
error("invalid array size");
|
||||
skip(']');
|
||||
t = (t + VT_PTRINC) | VT_ARRAY;
|
||||
|
@ -1030,7 +1079,7 @@ void expr()
|
|||
|
||||
#endif
|
||||
|
||||
void block(int *bsym, int *csym)
|
||||
void block(int *bsym, int *csym, int *case_sym, int *def_sym)
|
||||
{
|
||||
int a, b, c, d;
|
||||
|
||||
|
@ -1041,13 +1090,13 @@ void block(int *bsym, int *csym)
|
|||
expr();
|
||||
skip(')');
|
||||
a = gtst(1, 0);
|
||||
block(bsym, csym);
|
||||
block(bsym, csym, case_sym, def_sym);
|
||||
c = tok;
|
||||
if (c == TOK_ELSE) {
|
||||
next();
|
||||
d = psym(0xe9, 0); /* jmp */
|
||||
gsym(a);
|
||||
block(bsym, csym);
|
||||
block(bsym, csym, case_sym, def_sym);
|
||||
gsym(d); /* patch else jmp */
|
||||
} else
|
||||
gsym(a);
|
||||
|
@ -1059,7 +1108,7 @@ void block(int *bsym, int *csym)
|
|||
skip(')');
|
||||
a = gtst(1, 0);
|
||||
b = 0;
|
||||
block(&a, &b);
|
||||
block(&a, &b, case_sym, def_sym);
|
||||
oad(0xe9, d - ind - 5); /* jmp */
|
||||
gsym(a);
|
||||
gsym_addr(b, d);
|
||||
|
@ -1068,7 +1117,7 @@ void block(int *bsym, int *csym)
|
|||
/* declarations */
|
||||
decl(VT_LOCAL);
|
||||
while (tok != '}')
|
||||
block(bsym, csym);
|
||||
block(bsym, csym, case_sym, def_sym);
|
||||
next();
|
||||
} else if (tok == TOK_RETURN) {
|
||||
next();
|
||||
|
@ -1118,7 +1167,7 @@ void block(int *bsym, int *csym)
|
|||
gsym(e);
|
||||
}
|
||||
skip(')');
|
||||
block(&a, &b);
|
||||
block(&a, &b, case_sym, def_sym);
|
||||
oad(0xe9, c - ind - 5); /* jmp */
|
||||
gsym(a);
|
||||
gsym_addr(b, c);
|
||||
|
@ -1128,7 +1177,7 @@ void block(int *bsym, int *csym)
|
|||
a = 0;
|
||||
b = 0;
|
||||
d = ind;
|
||||
block(&a, &b);
|
||||
block(&a, &b, case_sym, def_sym);
|
||||
skip(TOK_WHILE);
|
||||
skip('(');
|
||||
gsym(b);
|
||||
|
@ -1138,11 +1187,91 @@ void block(int *bsym, int *csym)
|
|||
skip(')');
|
||||
gsym(a);
|
||||
} else
|
||||
if (tok == TOK_SWITCH) {
|
||||
next();
|
||||
skip('(');
|
||||
expr();
|
||||
gv();
|
||||
skip(')');
|
||||
a = 0;
|
||||
b = 0;
|
||||
c = 0;
|
||||
block(&a, csym, &b, &c);
|
||||
/* if no default, jmp after switch */
|
||||
if (c == 0)
|
||||
c = ind;
|
||||
/* default label */
|
||||
gsym_addr(b, c);
|
||||
/* break label */
|
||||
gsym(a);
|
||||
} else
|
||||
if (tok == TOK_CASE) {
|
||||
next();
|
||||
a = expr_const();
|
||||
if (!case_sym)
|
||||
error("switch expected");
|
||||
gsym(*case_sym);
|
||||
oad(0x3d, a); /* cmp $xxx, %eax */
|
||||
*case_sym = psym(0x850f, 0); /* jne xxx */
|
||||
skip(':');
|
||||
block(bsym, csym, case_sym, def_sym);
|
||||
} else
|
||||
if (tok == TOK_DEFAULT) {
|
||||
next();
|
||||
skip(':');
|
||||
if (!def_sym)
|
||||
error("switch expected");
|
||||
if (*def_sym)
|
||||
error("too many 'default'");
|
||||
*def_sym = ind;
|
||||
block(bsym, csym, case_sym, def_sym);
|
||||
} else
|
||||
if (tok == TOK_GOTO) {
|
||||
next();
|
||||
a = vat[tok];
|
||||
if (a == 0) {
|
||||
/* put forward definition */
|
||||
a = VT_LABEL | VT_FORWARD;
|
||||
vat[tok] = a;
|
||||
vac[tok] = 0;
|
||||
} else if (!(a & VT_LABEL))
|
||||
error("invalid label name");
|
||||
/* label already defined */
|
||||
if (a & VT_FORWARD)
|
||||
vac[tok] = psym(0xe9, vac[tok]); /* jmp xxx */
|
||||
else
|
||||
oad(0xe9, vac[tok] - ind - 5); /* jmp xxx */
|
||||
next();
|
||||
skip(';');
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (tok != ';')
|
||||
expr();
|
||||
skip(';');
|
||||
b = tok;
|
||||
next();
|
||||
if (tok == ':') {
|
||||
next();
|
||||
/* label case */
|
||||
a = vat[b];
|
||||
if (a != 0) {
|
||||
if (!(a & VT_LABEL))
|
||||
error("invalid label name");
|
||||
else if (!(a & VT_FORWARD))
|
||||
error("multiple defined label");
|
||||
gsym(vac[b]);
|
||||
}
|
||||
vac[b] = ind;
|
||||
vat[b] = VT_LABEL;
|
||||
block(bsym, csym, case_sym, def_sym);
|
||||
} else {
|
||||
/* expression case: go backward of one token */
|
||||
/* XXX: currently incorrect if number/string/char */
|
||||
tok1 = tok;
|
||||
tok = b;
|
||||
if (tok != ';') {
|
||||
expr();
|
||||
}
|
||||
skip(';');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1152,6 +1281,12 @@ void decl(l)
|
|||
int *a, t, b, s, align, v, u, n;
|
||||
|
||||
while (b = ist()) {
|
||||
if ((b & VT_ENUM) && tok == ';') {
|
||||
/* we accept no variable after */
|
||||
next();
|
||||
continue;
|
||||
}
|
||||
|
||||
while (1) { /* iterate thru each declaration */
|
||||
s = 1;
|
||||
t = typ(&v, b, &s);
|
||||
|
@ -1166,14 +1301,16 @@ void decl(l)
|
|||
o(0xe58955); /* push %ebp, mov %esp, %ebp */
|
||||
a = oad(0xec81, 0); /* sub $xxx, %esp */
|
||||
rsym = 0;
|
||||
block(0, 0);
|
||||
block(0, 0, 0, 0);
|
||||
gsym(rsym);
|
||||
o(0xc3c9); /* leave, ret */
|
||||
*a = (-loc + 3) & -4; /* align local size to word &
|
||||
save local variables */
|
||||
break;
|
||||
} else {
|
||||
if (t & VT_FUNC) {
|
||||
if (t & VT_TYPEDEF) {
|
||||
vat[v] = t; /* save typedefed type */
|
||||
} else if (t & VT_FUNC) {
|
||||
/* external function definition */
|
||||
external_func(v, t);
|
||||
} else {
|
||||
|
|
Loading…
Reference in a new issue