added #if support
This commit is contained in:
parent
b0bdbb14ef
commit
a254461560
1 changed files with 198 additions and 65 deletions
249
tcc.c
249
tcc.c
|
@ -26,6 +26,7 @@
|
|||
#define SYM_TABLE_SIZE 10000
|
||||
#define MACRO_STACK_SIZE 32
|
||||
#define INCLUDE_STACK_SIZE 32
|
||||
#define IFDEF_STACK_SIZE 64
|
||||
|
||||
#define NB_REGS 3
|
||||
|
||||
|
@ -67,6 +68,7 @@ Sym *define_stack, *global_stack, *local_stack, *label_stack;
|
|||
|
||||
char *macro_stack[MACRO_STACK_SIZE], **macro_stack_ptr, *macro_ptr;
|
||||
IncludeFile include_stack[INCLUDE_STACK_SIZE], *include_stack_ptr;
|
||||
int ifdef_stack[IFDEF_STACK_SIZE], *ifdef_stack_ptr;
|
||||
|
||||
/* The current value can be: */
|
||||
#define VT_VALMASK 0x000f
|
||||
|
@ -103,45 +105,6 @@ IncludeFile include_stack[INCLUDE_STACK_SIZE], *include_stack_ptr;
|
|||
/* Special infos */
|
||||
|
||||
/* token values */
|
||||
#define TOK_INT 256
|
||||
#define TOK_VOID 257
|
||||
#define TOK_CHAR 258
|
||||
#define TOK_IF 259
|
||||
#define TOK_ELSE 260
|
||||
#define TOK_WHILE 261
|
||||
#define TOK_BREAK 262
|
||||
#define TOK_RETURN 263
|
||||
#define TOK_DEFINE 264
|
||||
#define TOK_MAIN 265
|
||||
#define TOK_FOR 266
|
||||
#define TOK_EXTERN 267
|
||||
#define TOK_STATIC 268
|
||||
#define TOK_UNSIGNED 269
|
||||
#define TOK_GOTO 270
|
||||
#define TOK_DO 271
|
||||
#define TOK_CONTINUE 272
|
||||
#define TOK_SWITCH 273
|
||||
#define TOK_CASE 274
|
||||
|
||||
/* ignored types Must have contiguous values */
|
||||
#define TOK_CONST 275
|
||||
#define TOK_VOLATILE 276
|
||||
#define TOK_LONG 277
|
||||
#define TOK_REGISTER 278
|
||||
#define TOK_SIGNED 279
|
||||
#define TOK_AUTO 280
|
||||
#define TOK_INLINE 281
|
||||
|
||||
#define TOK_FLOAT 282 /* unsupported */
|
||||
#define TOK_DOUBLE 283 /* unsupported */
|
||||
|
||||
#define TOK_STRUCT 284
|
||||
#define TOK_UNION 285
|
||||
#define TOK_TYPEDEF 286
|
||||
#define TOK_DEFAULT 287
|
||||
#define TOK_ENUM 288
|
||||
#define TOK_SIZEOF 289
|
||||
#define TOK_INCLUDE 290
|
||||
|
||||
/* warning: the following compare tokens depend on i386 asm code */
|
||||
#define TOK_ULT 0x92
|
||||
|
@ -184,8 +147,61 @@ IncludeFile include_stack[INCLUDE_STACK_SIZE], *include_stack_ptr;
|
|||
#define TOK_A_SHL 0x81
|
||||
#define TOK_A_SAR 0x82
|
||||
|
||||
enum {
|
||||
TOK_INT = 256,
|
||||
TOK_VOID,
|
||||
TOK_CHAR,
|
||||
TOK_IF,
|
||||
TOK_ELSE,
|
||||
TOK_WHILE,
|
||||
TOK_BREAK,
|
||||
TOK_RETURN,
|
||||
TOK_FOR,
|
||||
TOK_EXTERN,
|
||||
TOK_STATIC,
|
||||
TOK_UNSIGNED,
|
||||
TOK_GOTO,
|
||||
TOK_DO,
|
||||
TOK_CONTINUE,
|
||||
TOK_SWITCH,
|
||||
TOK_CASE,
|
||||
|
||||
/* ignored types Must have contiguous values */
|
||||
TOK_CONST,
|
||||
TOK_VOLATILE,
|
||||
TOK_LONG,
|
||||
TOK_REGISTER,
|
||||
TOK_SIGNED,
|
||||
TOK_AUTO,
|
||||
TOK_INLINE,
|
||||
|
||||
/* unsupported type */
|
||||
TOK_FLOAT,
|
||||
TOK_DOUBLE,
|
||||
|
||||
TOK_STRUCT,
|
||||
TOK_UNION,
|
||||
TOK_TYPEDEF,
|
||||
TOK_DEFAULT,
|
||||
TOK_ENUM,
|
||||
TOK_SIZEOF,
|
||||
|
||||
/* preprocessor only */
|
||||
TOK_DEFINE,
|
||||
TOK_INCLUDE,
|
||||
TOK_IFDEF,
|
||||
TOK_IFNDEF,
|
||||
TOK_ELIF,
|
||||
TOK_ENDIF,
|
||||
TOK_DEFINED,
|
||||
|
||||
/* special identifiers */
|
||||
TOK_MAIN,
|
||||
};
|
||||
|
||||
void sum();
|
||||
void next();
|
||||
int expr_const();
|
||||
void expr_eq();
|
||||
void expr();
|
||||
void decl();
|
||||
|
@ -359,7 +375,7 @@ void inp()
|
|||
}
|
||||
if (ch1 == '\n')
|
||||
line_num++;
|
||||
// printf("ch1=%c\n", ch1);
|
||||
// printf("ch1=%c 0x%x\n", ch1, ch1);
|
||||
}
|
||||
|
||||
/* input with '\\n' handling and macro subtitution if in macro state */
|
||||
|
@ -381,9 +397,11 @@ void minp()
|
|||
goto redo;
|
||||
}
|
||||
}
|
||||
// printf("ch=%c 0x%x\n", ch, ch);
|
||||
}
|
||||
|
||||
/* same as minp, but also skip comments */
|
||||
/* XXX: skip strings & chars */
|
||||
void cinp()
|
||||
{
|
||||
int c;
|
||||
|
@ -423,20 +441,40 @@ void skip_spaces()
|
|||
cinp();
|
||||
}
|
||||
|
||||
void preprocess()
|
||||
/* skip block of text until #else, #elif or #endif. skip also pairs of
|
||||
#if/#endif */
|
||||
void preprocess_skip()
|
||||
{
|
||||
int a;
|
||||
a = 0;
|
||||
while (1) {
|
||||
while (ch != '\n') {
|
||||
if (ch == -1)
|
||||
expect("#endif");
|
||||
cinp();
|
||||
}
|
||||
cinp();
|
||||
skip_spaces();
|
||||
if (ch == '#') {
|
||||
cinp();
|
||||
next();
|
||||
if (a == 0 &&
|
||||
(tok == TOK_ELSE || tok == TOK_ELIF || tok == TOK_ENDIF))
|
||||
break;
|
||||
if (tok == TOK_IF || tok == TOK_IFDEF || tok == TOK_IFNDEF)
|
||||
a++;
|
||||
else if (tok == TOK_ENDIF)
|
||||
a--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* parse until eol and add given char */
|
||||
char *get_str(c)
|
||||
{
|
||||
char *str;
|
||||
int size, n, c;
|
||||
char buf[1024], *q, *p;
|
||||
char buf1[1024];
|
||||
FILE *f;
|
||||
int size, n;
|
||||
|
||||
cinp();
|
||||
next(); /* XXX: should pass parameter to avoid macro subst */
|
||||
if (tok == TOK_DEFINE) {
|
||||
next(); /* XXX: should pass parameter to avoid macro subst */
|
||||
skip_spaces();
|
||||
/* now 'tok' is the macro symbol */
|
||||
str = NULL;
|
||||
size = 0;
|
||||
n = 0;
|
||||
|
@ -448,13 +486,62 @@ void preprocess()
|
|||
error("memory full");
|
||||
}
|
||||
if (ch == -1 || ch == '\n') {
|
||||
str[n++] = ' '; /* a space is inserted after each macro */
|
||||
str[n++] = c;
|
||||
str[n++] = '\0';
|
||||
break;
|
||||
}
|
||||
str[n++] = ch;
|
||||
cinp();
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/* return 1 if next token is defined, 0 otherwise. */
|
||||
int is_defined()
|
||||
{
|
||||
Sym *s;
|
||||
/* hack to avoid replacing id by defined value */
|
||||
s = define_stack;
|
||||
define_stack = 0;
|
||||
next();
|
||||
define_stack = s;
|
||||
return sym_find1(define_stack, tok) != 0;
|
||||
}
|
||||
|
||||
/* XXX: not correct yet (need to ensure it is constant) */
|
||||
int expr_preprocess()
|
||||
{
|
||||
int c;
|
||||
|
||||
if ((macro_stack_ptr - macro_stack) >= MACRO_STACK_SIZE)
|
||||
error("too many nested macros");
|
||||
*macro_stack_ptr++ = (char *)'\n';
|
||||
*macro_stack_ptr++ = macro_ptr;
|
||||
macro_ptr = get_str(';');
|
||||
cinp();
|
||||
next();
|
||||
c = expr_const();
|
||||
ch = '\n';
|
||||
return c != 0;
|
||||
}
|
||||
|
||||
void preprocess()
|
||||
{
|
||||
char *str;
|
||||
int size, n, c;
|
||||
char buf[1024], *q, *p;
|
||||
char buf1[1024];
|
||||
FILE *f;
|
||||
|
||||
cinp();
|
||||
next(); /* XXX: should pass parameter to avoid macro subst */
|
||||
redo:
|
||||
if (tok == TOK_DEFINE) {
|
||||
next(); /* XXX: should pass parameter to avoid macro subst */
|
||||
skip_spaces();
|
||||
/* now 'tok' is the macro symbol */
|
||||
/* a space is inserted after each macro */
|
||||
str = get_str(' ');
|
||||
sym_push1(&define_stack, tok, 0, (int)str);
|
||||
} else if (tok == TOK_INCLUDE) {
|
||||
skip_spaces();
|
||||
|
@ -497,6 +584,7 @@ void preprocess()
|
|||
error("include file not found");
|
||||
found:
|
||||
/* push current file in stack */
|
||||
/* XXX: fix current line init */
|
||||
include_stack_ptr->file = file;
|
||||
include_stack_ptr->filename = filename;
|
||||
include_stack_ptr->line_num = line_num;
|
||||
|
@ -505,7 +593,41 @@ void preprocess()
|
|||
filename = strdup(buf1);
|
||||
line_num = 1;
|
||||
}
|
||||
|
||||
} else if (tok == TOK_IFNDEF) {
|
||||
c = !is_defined();
|
||||
goto do_ifdef;
|
||||
} else if (tok == TOK_IF) {
|
||||
/* XXX: incorrect constant parsing now */
|
||||
c = expr_preprocess();
|
||||
goto do_ifdef;
|
||||
} else if (tok == TOK_IFDEF) {
|
||||
c = is_defined();
|
||||
do_ifdef:
|
||||
if (ifdef_stack_ptr >= ifdef_stack + IFDEF_STACK_SIZE)
|
||||
error("memory full");
|
||||
*ifdef_stack_ptr++ = c;
|
||||
goto test_skip;
|
||||
} else if (tok == TOK_ELSE) {
|
||||
if (ifdef_stack_ptr == ifdef_stack ||
|
||||
(ifdef_stack_ptr[-1] & 2))
|
||||
error("#else after #else");
|
||||
c = (ifdef_stack_ptr[-1] ^= 3);
|
||||
goto test_skip;
|
||||
} else if (tok == TOK_ELIF) {
|
||||
if (ifdef_stack_ptr == ifdef_stack ||
|
||||
ifdef_stack_ptr[-1] > 1)
|
||||
error("#elif after #else");
|
||||
c = expr_preprocess();
|
||||
ifdef_stack_ptr[-1] = c;
|
||||
test_skip:
|
||||
if (!(c & 1)) {
|
||||
preprocess_skip();
|
||||
goto redo;
|
||||
}
|
||||
} else if (tok == TOK_ENDIF) {
|
||||
if (ifdef_stack_ptr == ifdef_stack)
|
||||
expect("#if");
|
||||
ifdef_stack_ptr--;
|
||||
}
|
||||
/* ignore other preprocess commands or #! for C scripts */
|
||||
while (ch != '\n' && ch != -1)
|
||||
|
@ -639,6 +761,7 @@ void next()
|
|||
else if (tok == '>')
|
||||
tok = TOK_GT;
|
||||
}
|
||||
// printf("tok=%x\n", tok);
|
||||
}
|
||||
|
||||
void swap(int *p, int *q)
|
||||
|
@ -1121,7 +1244,8 @@ void gen_op(op)
|
|||
gen_opc(op);
|
||||
}
|
||||
} else {
|
||||
if ((t1 | t2) & VT_UNSIGNED) {
|
||||
/* XXX: test types and compute returned value */
|
||||
if ((t1 | t2) & (VT_UNSIGNED | VT_PTR)) {
|
||||
if (op == TOK_SAR)
|
||||
op = TOK_SHR;
|
||||
else if (op == '/')
|
||||
|
@ -1629,6 +1753,13 @@ void unary()
|
|||
vpush();
|
||||
unary();
|
||||
gen_op('-');
|
||||
} else if (t == TOK_DEFINED) {
|
||||
/* XXX: should only be used in preprocess expr parsing */
|
||||
if (tok != '(')
|
||||
expect("(");
|
||||
vset(VT_CONST, is_defined());
|
||||
next();
|
||||
skip(')');
|
||||
} else
|
||||
{
|
||||
s = sym_find(t);
|
||||
|
@ -2103,9 +2234,8 @@ void decl(l)
|
|||
sym_push1(&local_stack, 0, 0, 0);
|
||||
/* define parameters */
|
||||
sym = sym_find((unsigned)t >> VT_STRUCT_SHIFT);
|
||||
while (sym = sym->next) {
|
||||
while (sym = sym->next)
|
||||
sym_push(sym->v & ~SYM_FIELD, sym->t, sym->c);
|
||||
}
|
||||
loc = 0;
|
||||
o(0xe58955); /* push %ebp, mov %esp, %ebp */
|
||||
a = (int *)oad(0xec81, 0); /* sub $xxx, %esp */
|
||||
|
@ -2185,11 +2315,12 @@ int main(int c, char **v)
|
|||
exit(1);
|
||||
}
|
||||
include_stack_ptr = include_stack;
|
||||
ifdef_stack_ptr = ifdef_stack;
|
||||
|
||||
idtable = malloc(SYM_TABLE_SIZE);
|
||||
memcpy(idtable,
|
||||
"int\0void\0char\0if\0else\0while\0break\0return\0define\0main\0for\0extern\0static\0unsigned\0goto\0do\0continue\0switch\0case\0const\0volatile\0long\0register\0signed\0auto\0inline\0float\0double\0struct\0union\0typedef\0default\0enum\0sizeof\0include", 219);
|
||||
idptr = idtable + 219;
|
||||
"int\0void\0char\0if\0else\0while\0break\0return\0for\0extern\0static\0unsigned\0goto\0do\0continue\0switch\0case\0const\0volatile\0long\0register\0signed\0auto\0inline\0float\0double\0struct\0union\0typedef\0default\0enum\0sizeof\0define\0include\0ifdef\0ifndef\0elif\0endif\0defined\0main", 251);
|
||||
idptr = idtable + 251;
|
||||
|
||||
glo = malloc(DATA_SIZE);
|
||||
memset((void *)glo, 0, DATA_SIZE);
|
||||
|
@ -2203,6 +2334,8 @@ int main(int c, char **v)
|
|||
ch = '\n'; /* needed to parse correctly first preprocessor command */
|
||||
next();
|
||||
decl(VT_CONST);
|
||||
if (tok != -1)
|
||||
expect("declaration");
|
||||
#ifdef TEST
|
||||
{
|
||||
FILE *f;
|
||||
|
|
Loading…
Reference in a new issue