fixed \nnn char parsing, added #line, added __VA_ARGS__, added macros in #include, added \xnn parsing, added L'' and L parsing (still not OK), added 0bXX, added ISOC99 initializers handling, added declaration parsing anywhere in block

This commit is contained in:
bellard 2001-11-17 17:22:38 +00:00
parent ef6e8589d1
commit 44b5c9742a

276
tcc.c
View File

@ -233,10 +233,12 @@ enum {
TOK_DEFINED, TOK_DEFINED,
TOK_UNDEF, TOK_UNDEF,
TOK_ERROR, TOK_ERROR,
TOK_LINE,
TOK___LINE__, TOK___LINE__,
TOK___FILE__, TOK___FILE__,
TOK___DATE__, TOK___DATE__,
TOK___TIME__, TOK___TIME__,
TOK___VA_ARGS__,
/* special identifiers */ /* special identifiers */
TOK___FUNC__, TOK___FUNC__,
@ -250,6 +252,7 @@ int expr_const();
void expr_eq(); void expr_eq();
void expr(); void expr();
void decl(); void decl();
void decl_assign(int t, int c, int first);
int gv(); int gv();
void move_reg(); void move_reg();
void save_reg(); void save_reg();
@ -715,6 +718,8 @@ void preprocess()
next_nomacro(); next_nomacro();
ps = &first; ps = &first;
while (tok != ')') { while (tok != ')') {
if (tok == TOK_DOTS)
tok = TOK___VA_ARGS__;
s = sym_push1(&define_stack, tok | SYM_FIELD, 0, 0); s = sym_push1(&define_stack, tok | SYM_FIELD, 0, 0);
*ps = s; *ps = s;
ps = &s->next; ps = &s->next;
@ -763,6 +768,14 @@ void preprocess()
minp(); minp();
} }
*q = '\0'; *q = '\0';
} else {
next();
if (tok != TOK_STR)
error("#include syntax error");
/* XXX: buffer overflow */
strcpy(buf, get_tok_str(tok, tokc));
c = '\"';
}
if (include_stack_ptr >= include_stack + INCLUDE_STACK_SIZE) if (include_stack_ptr >= include_stack + INCLUDE_STACK_SIZE)
error("memory full"); error("memory full");
if (c == '\"') { if (c == '\"') {
@ -800,7 +813,6 @@ void preprocess()
file = f; file = f;
filename = strdup(buf1); filename = strdup(buf1);
line_num = 1; line_num = 1;
}
} else if (tok == TOK_IFNDEF) { } else if (tok == TOK_IFNDEF) {
c = 1; c = 1;
goto do_ifdef; goto do_ifdef;
@ -838,6 +850,19 @@ void preprocess()
if (ifdef_stack_ptr == ifdef_stack) if (ifdef_stack_ptr == ifdef_stack)
expect("#if"); expect("#if");
ifdef_stack_ptr--; ifdef_stack_ptr--;
} else if (tok == TOK_LINE) {
next();
if (tok != TOK_NUM)
error("#line");
line_num = tokc;
skip_spaces();
if (ch != '\n') {
next();
if (tok != TOK_STR)
error("#line");
/* XXX: potential memory leak */
filename = strdup(get_tok_str(tok, tokc));
}
} else if (tok == TOK_ERROR) { } else if (tok == TOK_ERROR) {
error("#error"); error("#error");
} }
@ -877,7 +902,21 @@ int getq()
minp(); minp();
if (c == '\\') { if (c == '\\') {
if (isnum(ch)) { if (isnum(ch)) {
return getn(8); /* at most three octal digits */
c = ch - '0';
minp();
if (isnum(ch)) {
c = c * 8 + ch - '0';
minp();
if (isnum(ch)) {
c = c * 8 + ch - '0';
minp();
}
}
return c;
} else if (ch == 'x') {
minp();
return getn(16);
} else { } else {
if (ch == 'a') if (ch == 'a')
c = '\a'; c = '\a';
@ -926,6 +965,16 @@ void next_nomacro1()
} }
if (isid(ch)) { if (isid(ch)) {
q = token_buf; q = token_buf;
*q++ = ch;
cinp();
if (q[-1] == 'L') {
/* XXX: not supported entirely (needs different
preprocessor architecture) */
if (ch == '\'')
goto char_const;
if (ch == '\"')
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");
@ -944,6 +993,9 @@ void next_nomacro1()
if (ch == 'x' || ch == 'X') { if (ch == 'x' || ch == 'X') {
cinp(); cinp();
b = 16; b = 16;
} else if (ch == 'b' || ch == 'B') {
cinp();
b = 2;
} }
} }
tokc = getn(b); tokc = getn(b);
@ -952,6 +1004,7 @@ void next_nomacro1()
cinp(); cinp();
tok = TOK_NUM; tok = TOK_NUM;
} else if (ch == '\'') { } else if (ch == '\'') {
char_const:
minp(); minp();
tokc = getq(); tokc = getq();
tok = TOK_CCHAR; tok = TOK_CCHAR;
@ -959,6 +1012,7 @@ void next_nomacro1()
expect("\'"); expect("\'");
minp(); minp();
} else if (ch == '\"') { } else if (ch == '\"') {
str_const:
minp(); minp();
q = token_buf; q = token_buf;
while (ch != '\"') { while (ch != '\"') {
@ -1203,7 +1257,10 @@ void macro_subst(int **tok_str, int *tok_len,
len = 0; len = 0;
str = NULL; str = NULL;
parlevel = 0; parlevel = 0;
while ((parlevel > 0 || (tok != ')' && tok != ',')) && while ((parlevel > 0 ||
(tok != ')' &&
(tok != ',' ||
sa->v == (TOK___VA_ARGS__ | SYM_FIELD)))) &&
tok != -1) { tok != -1) {
if (tok == '(') if (tok == '(')
parlevel++; parlevel++;
@ -1916,7 +1973,7 @@ void inc(post, c)
int struct_decl(u) int struct_decl(u)
{ {
int a, t, b, v, size, align, maxalign, c; int a, t, b, v, size, align, maxalign, c;
Sym *slast, *s, *ss; Sym *s, *ss, **ps;
a = tok; /* save decl type */ a = tok; /* save decl type */
next(); next();
@ -1945,7 +2002,7 @@ int struct_decl(u)
/* cannot be empty */ /* cannot be empty */
c = 0; c = 0;
maxalign = 0; maxalign = 0;
slast = NULL; ps = &s->next;
while (1) { while (1) {
if (a == TOK_ENUM) { if (a == TOK_ENUM) {
v = tok; v = tok;
@ -1978,8 +2035,8 @@ int struct_decl(u)
} }
if (align > maxalign) if (align > maxalign)
maxalign = align; maxalign = align;
ss->next = slast; *ps = ss;
slast = ss; ps = &ss->next;
if (tok == ';' || tok == -1) if (tok == ';' || tok == -1)
break; break;
skip(','); skip(',');
@ -1990,7 +2047,6 @@ int struct_decl(u)
break; break;
} }
skip('}'); skip('}');
s->next = slast;
/* size for struct/union, dummy for enum */ /* size for struct/union, dummy for enum */
s->c = (c + maxalign - 1) & -maxalign; s->c = (c + maxalign - 1) & -maxalign;
} }
@ -2215,13 +2271,13 @@ void unary()
} else if (tok == TOK___FUNC__) { } else if (tok == TOK___FUNC__) {
/* special function name identifier */ /* special function name identifier */
/* generate (char *) type */ /* generate (char *) type */
vset(VT_CONST | mk_pointer(VT_TYPE), glo); vset(VT_CONST | mk_pointer(VT_BYTE), glo);
strcpy((void *)glo, funcname); strcpy((void *)glo, funcname);
glo += strlen(funcname) + 1; glo += strlen(funcname) + 1;
} else if (tok == TOK_STR) { } else if (tok == TOK_STR) {
TokenSym *ts; TokenSym *ts;
/* generate (char *) type */ /* generate (char *) type */
vset(VT_CONST | mk_pointer(VT_TYPE), glo); vset(VT_CONST | mk_pointer(VT_BYTE), glo);
while (tok == TOK_STR) { while (tok == TOK_STR) {
ts = (TokenSym *)tokc; ts = (TokenSym *)tokc;
memcpy((void *)glo, ts->str, ts->len); memcpy((void *)glo, ts->str, ts->len);
@ -2296,7 +2352,7 @@ void unary()
s = sym_find(t); s = sym_find(t);
if (!s) { if (!s) {
if (tok != '(') if (tok != '(')
error("undefined symbol"); error("'%s' undeclared", get_tok_str(t, 0));
/* for simple function calls, we tolerate undeclared /* for simple function calls, we tolerate undeclared
external reference */ external reference */
p = anon_sym++; p = anon_sym++;
@ -2637,9 +2693,10 @@ void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_reg)
next(); next();
/* declarations */ /* declarations */
s = local_stack; s = local_stack;
while (tok != '}') {
decl(VT_LOCAL); decl(VT_LOCAL);
while (tok != '}')
block(bsym, csym, case_sym, def_sym, case_reg); block(bsym, csym, case_sym, def_sym, case_reg);
}
/* pop locally defined symbols */ /* pop locally defined symbols */
sym_pop(&local_stack, s); sym_pop(&local_stack, s);
next(); next();
@ -2794,10 +2851,164 @@ void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_reg)
} }
} }
/* t is the array or struct type. c is the array or struct
address. cur_index/cur_field is the pointer to the current value */
void decl_designator(int t, int c, int *cur_index, Sym **cur_field)
{
Sym *s, *f;
int notfirst, index, align;
notfirst = 0;
while (tok == '[' || tok == '.') {
if (tok == '[') {
if (!(t & VT_ARRAY))
expect("array type");
s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT));
next();
index = expr_const();
if (index < 0 || (s->c >= 0 && index >= s->c))
expect("invalid index");
skip(']');
if (!notfirst)
*cur_index = index;
t = pointed_type(t);
c += index * type_size(t, &align);
} else {
if (!(t & VT_STRUCT))
expect("struct/union type");
next();
s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT) | SYM_STRUCT);
tok |= SYM_FIELD;
f = s->next;
while (f) {
if (f->v == tok)
break;
f = f->next;
}
if (!f)
expect("field");
next();
if (!notfirst)
*cur_field = f;
t = f->t | (t & VT_TYPEN);
c += f->c;
}
notfirst = 1;
}
if (notfirst) {
skip('=');
} else {
if (t & VT_ARRAY) {
index = *cur_index;
t = pointed_type(t);
c += index * type_size(t, &align);
} else {
f = *cur_field;
if (!f)
error("too many field init");
t = f->t | (t & VT_TYPEN);
c += f->c;
}
}
decl_assign(t, c, 0);
}
/* 't' contains the type and storage info. c is the address of the
object. 'first' is true if array '{' must be read (multi dimension
implicit array init handling). */
void decl_assign(int t, int c, int first)
{
int v, index, index_max, t1, n, no_oblock;
Sym *s, *f;
TokenSym *ts;
if (t & VT_ARRAY) {
s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT));
n = s->c;
index_max = 0;
if (tok == TOK_STR) {
t1 = pointed_type(t);
if (!(t1 & VT_BYTE))
error("invalid type");
if ((t & VT_VALMASK) == VT_CONST) {
while (tok == TOK_STR) {
ts = (TokenSym *)tokc;
memcpy((void *)c, ts->str, ts->len);
c += ts->len;
index_max += ts->len;
next();
}
*(char *)c++ = 0;
} else {
error("local string init not handled");
}
/* string init */
} else {
no_oblock = 0;
if (!first && tok != '{')
no_oblock = 1;
else
skip('{');
index = 0;
while (tok != '}') {
decl_designator(t, c, &index, NULL);
if (n >= 0 && index >= n)
error("index too large");
if (index > index_max)
index_max = index;
index++;
/* special test for multi dimensional arrays (may not
be strictly correct if designators are used at the
same time) */
if (index >= n && no_oblock)
break;
if (tok == '}')
break;
skip(',');
}
if (!no_oblock)
skip('}');
}
/* patch type size if needed */
if (n < 0)
s->c = index_max + 1;
} else if (t & VT_STRUCT) {
/* XXX: union needs only one init */
skip('{');
s = sym_find(((unsigned)t >> VT_STRUCT_SHIFT) | SYM_STRUCT);
f = s->next;
while (tok != '}') {
decl_designator(t, c, NULL, &f);
if (tok == '}')
break;
skip(',');
f = f->next;
}
skip('}');
} else {
if ((t & VT_VALMASK) == VT_CONST) {
v = expr_const();
printf("v=%d\n", v);
if (t & VT_BYTE)
*(char *)c = v;
else if (t & VT_SHORT)
*(short *)c = v;
else
*(int *)c = v;
} else {
vt = t;
vc = c;
vpush();
expr_eq();
vstore();
}
}
}
/* 'l' is VT_LOCAL or VT_CONST to define default storage type */ /* 'l' is VT_LOCAL or VT_CONST to define default storage type */
void decl(l) void decl(l)
{ {
int *a, t, b, size, align, v, u, n; int *a, t, b, size, align, v, u, n, addr;
Sym *sym; Sym *sym;
while (b = ist()) { while (b = ist()) {
@ -2866,16 +3077,37 @@ void decl(l)
u = VT_CONST; u = VT_CONST;
u |= t; u |= t;
size = type_size(t, &align); size = type_size(t, &align);
if ((u & VT_VALMASK) == VT_LOCAL) {
/* XXX: cannot use implicit size for local
storage */
if (size < 0)
error("size must be known for locals");
loc = (loc - size) & -align;
addr = loc;
} else {
glo = (glo + align - 1) & -align;
addr = glo;
}
if (tok == '=') {
next();
/* special case for non array types */
n = 0;
if (tok == '{' && (u & (VT_ARRAY | VT_STRUCT)) == 0) {
n = 1;
next();
}
decl_assign(u, addr, 1);
if (n)
skip('}');
}
sym_push(v, u, addr);
/* if global, add size */
if ((u & VT_VALMASK) == VT_CONST) {
/* must recompute size if it was an array
with implicit size */
size = type_size(t, &align);
if (size < 0) if (size < 0)
error("invalid size"); error("invalid size");
if ((u & VT_VALMASK) == VT_LOCAL) {
/* allocate space down on the stack */
loc = (loc - size) & -align;
sym_push(v, u, loc);
} else {
/* allocate space up in the data space */
glo = (glo + align - 1) & -align;
sym_push(v, u, glo);
glo += size; glo += size;
} }
} }
@ -2916,7 +3148,7 @@ int main(int argc, char **argv)
nb_include_paths = 3; nb_include_paths = 3;
/* add all tokens */ /* add all tokens */
p = "int\0void\0char\0if\0else\0while\0break\0return\0for\0extern\0static\0unsigned\0goto\0do\0continue\0switch\0case\0const\0volatile\0long\0register\0signed\0auto\0inline\0restrict\0float\0double\0short\0struct\0union\0typedef\0default\0enum\0sizeof\0define\0include\0ifdef\0ifndef\0elif\0endif\0defined\0undef\0error\0__LINE__\0__FILE__\0__DATE__\0__TIME__\0__func__\0main\0"; p = "int\0void\0char\0if\0else\0while\0break\0return\0for\0extern\0static\0unsigned\0goto\0do\0continue\0switch\0case\0const\0volatile\0long\0register\0signed\0auto\0inline\0restrict\0float\0double\0short\0struct\0union\0typedef\0default\0enum\0sizeof\0define\0include\0ifdef\0ifndef\0elif\0endif\0defined\0undef\0error\0line\0__LINE__\0__FILE__\0__DATE__\0__TIME__\0__VA_ARGS__\0__func__\0main\0";
while (*p) { while (*p) {
r = p; r = p;
while (*r++); while (*r++);