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