aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tcc.c207
1 files changed, 172 insertions, 35 deletions
diff --git a/tcc.c b/tcc.c
index d95257e..fd75f2b 100644
--- a/tcc.c
+++ b/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 {