added #if support
This commit is contained in:
parent
b0bdbb14ef
commit
a254461560
1 changed files with 198 additions and 65 deletions
261
tcc.c
261
tcc.c
|
@ -26,6 +26,7 @@
|
||||||
#define SYM_TABLE_SIZE 10000
|
#define SYM_TABLE_SIZE 10000
|
||||||
#define MACRO_STACK_SIZE 32
|
#define MACRO_STACK_SIZE 32
|
||||||
#define INCLUDE_STACK_SIZE 32
|
#define INCLUDE_STACK_SIZE 32
|
||||||
|
#define IFDEF_STACK_SIZE 64
|
||||||
|
|
||||||
#define NB_REGS 3
|
#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;
|
char *macro_stack[MACRO_STACK_SIZE], **macro_stack_ptr, *macro_ptr;
|
||||||
IncludeFile include_stack[INCLUDE_STACK_SIZE], *include_stack_ptr;
|
IncludeFile include_stack[INCLUDE_STACK_SIZE], *include_stack_ptr;
|
||||||
|
int ifdef_stack[IFDEF_STACK_SIZE], *ifdef_stack_ptr;
|
||||||
|
|
||||||
/* The current value can be: */
|
/* The current value can be: */
|
||||||
#define VT_VALMASK 0x000f
|
#define VT_VALMASK 0x000f
|
||||||
|
@ -103,45 +105,6 @@ IncludeFile include_stack[INCLUDE_STACK_SIZE], *include_stack_ptr;
|
||||||
/* Special infos */
|
/* Special infos */
|
||||||
|
|
||||||
/* token values */
|
/* 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 */
|
/* warning: the following compare tokens depend on i386 asm code */
|
||||||
#define TOK_ULT 0x92
|
#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_SHL 0x81
|
||||||
#define TOK_A_SAR 0x82
|
#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 sum();
|
||||||
void next();
|
void next();
|
||||||
|
int expr_const();
|
||||||
void expr_eq();
|
void expr_eq();
|
||||||
void expr();
|
void expr();
|
||||||
void decl();
|
void decl();
|
||||||
|
@ -359,7 +375,7 @@ void inp()
|
||||||
}
|
}
|
||||||
if (ch1 == '\n')
|
if (ch1 == '\n')
|
||||||
line_num++;
|
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 */
|
/* input with '\\n' handling and macro subtitution if in macro state */
|
||||||
|
@ -381,9 +397,11 @@ void minp()
|
||||||
goto redo;
|
goto redo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// printf("ch=%c 0x%x\n", ch, ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* same as minp, but also skip comments */
|
/* same as minp, but also skip comments */
|
||||||
|
/* XXX: skip strings & chars */
|
||||||
void cinp()
|
void cinp()
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
|
@ -423,6 +441,90 @@ void skip_spaces()
|
||||||
cinp();
|
cinp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
str = NULL;
|
||||||
|
size = 0;
|
||||||
|
n = 0;
|
||||||
|
while (1) {
|
||||||
|
if ((n + 1) >= size) {
|
||||||
|
size += 128;
|
||||||
|
str = realloc(str, size);
|
||||||
|
if (!str)
|
||||||
|
error("memory full");
|
||||||
|
}
|
||||||
|
if (ch == -1 || ch == '\n') {
|
||||||
|
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()
|
void preprocess()
|
||||||
{
|
{
|
||||||
char *str;
|
char *str;
|
||||||
|
@ -433,28 +535,13 @@ void preprocess()
|
||||||
|
|
||||||
cinp();
|
cinp();
|
||||||
next(); /* XXX: should pass parameter to avoid macro subst */
|
next(); /* XXX: should pass parameter to avoid macro subst */
|
||||||
|
redo:
|
||||||
if (tok == TOK_DEFINE) {
|
if (tok == TOK_DEFINE) {
|
||||||
next(); /* XXX: should pass parameter to avoid macro subst */
|
next(); /* XXX: should pass parameter to avoid macro subst */
|
||||||
skip_spaces();
|
skip_spaces();
|
||||||
/* now 'tok' is the macro symbol */
|
/* now 'tok' is the macro symbol */
|
||||||
str = NULL;
|
/* a space is inserted after each macro */
|
||||||
size = 0;
|
str = get_str(' ');
|
||||||
n = 0;
|
|
||||||
while (1) {
|
|
||||||
if ((n + 1) >= size) {
|
|
||||||
size += 128;
|
|
||||||
str = realloc(str, size);
|
|
||||||
if (!str)
|
|
||||||
error("memory full");
|
|
||||||
}
|
|
||||||
if (ch == -1 || ch == '\n') {
|
|
||||||
str[n++] = ' '; /* a space is inserted after each macro */
|
|
||||||
str[n++] = '\0';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
str[n++] = ch;
|
|
||||||
cinp();
|
|
||||||
}
|
|
||||||
sym_push1(&define_stack, tok, 0, (int)str);
|
sym_push1(&define_stack, tok, 0, (int)str);
|
||||||
} else if (tok == TOK_INCLUDE) {
|
} else if (tok == TOK_INCLUDE) {
|
||||||
skip_spaces();
|
skip_spaces();
|
||||||
|
@ -497,6 +584,7 @@ void preprocess()
|
||||||
error("include file not found");
|
error("include file not found");
|
||||||
found:
|
found:
|
||||||
/* push current file in stack */
|
/* push current file in stack */
|
||||||
|
/* XXX: fix current line init */
|
||||||
include_stack_ptr->file = file;
|
include_stack_ptr->file = file;
|
||||||
include_stack_ptr->filename = filename;
|
include_stack_ptr->filename = filename;
|
||||||
include_stack_ptr->line_num = line_num;
|
include_stack_ptr->line_num = line_num;
|
||||||
|
@ -505,7 +593,41 @@ void preprocess()
|
||||||
filename = strdup(buf1);
|
filename = strdup(buf1);
|
||||||
line_num = 1;
|
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 */
|
/* ignore other preprocess commands or #! for C scripts */
|
||||||
while (ch != '\n' && ch != -1)
|
while (ch != '\n' && ch != -1)
|
||||||
|
@ -639,6 +761,7 @@ void next()
|
||||||
else if (tok == '>')
|
else if (tok == '>')
|
||||||
tok = TOK_GT;
|
tok = TOK_GT;
|
||||||
}
|
}
|
||||||
|
// printf("tok=%x\n", tok);
|
||||||
}
|
}
|
||||||
|
|
||||||
void swap(int *p, int *q)
|
void swap(int *p, int *q)
|
||||||
|
@ -1121,7 +1244,8 @@ void gen_op(op)
|
||||||
gen_opc(op);
|
gen_opc(op);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ((t1 | t2) & VT_UNSIGNED) {
|
/* XXX: test types and compute returned value */
|
||||||
|
if ((t1 | t2) & (VT_UNSIGNED | VT_PTR)) {
|
||||||
if (op == TOK_SAR)
|
if (op == TOK_SAR)
|
||||||
op = TOK_SHR;
|
op = TOK_SHR;
|
||||||
else if (op == '/')
|
else if (op == '/')
|
||||||
|
@ -1629,6 +1753,13 @@ void unary()
|
||||||
vpush();
|
vpush();
|
||||||
unary();
|
unary();
|
||||||
gen_op('-');
|
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
|
} else
|
||||||
{
|
{
|
||||||
s = sym_find(t);
|
s = sym_find(t);
|
||||||
|
@ -2103,9 +2234,8 @@ void decl(l)
|
||||||
sym_push1(&local_stack, 0, 0, 0);
|
sym_push1(&local_stack, 0, 0, 0);
|
||||||
/* define parameters */
|
/* define parameters */
|
||||||
sym = sym_find((unsigned)t >> VT_STRUCT_SHIFT);
|
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);
|
sym_push(sym->v & ~SYM_FIELD, sym->t, sym->c);
|
||||||
}
|
|
||||||
loc = 0;
|
loc = 0;
|
||||||
o(0xe58955); /* push %ebp, mov %esp, %ebp */
|
o(0xe58955); /* push %ebp, mov %esp, %ebp */
|
||||||
a = (int *)oad(0xec81, 0); /* sub $xxx, %esp */
|
a = (int *)oad(0xec81, 0); /* sub $xxx, %esp */
|
||||||
|
@ -2185,11 +2315,12 @@ int main(int c, char **v)
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
include_stack_ptr = include_stack;
|
include_stack_ptr = include_stack;
|
||||||
|
ifdef_stack_ptr = ifdef_stack;
|
||||||
|
|
||||||
idtable = malloc(SYM_TABLE_SIZE);
|
idtable = malloc(SYM_TABLE_SIZE);
|
||||||
memcpy(idtable,
|
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);
|
"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 + 219;
|
idptr = idtable + 251;
|
||||||
|
|
||||||
glo = malloc(DATA_SIZE);
|
glo = malloc(DATA_SIZE);
|
||||||
memset((void *)glo, 0, 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 */
|
ch = '\n'; /* needed to parse correctly first preprocessor command */
|
||||||
next();
|
next();
|
||||||
decl(VT_CONST);
|
decl(VT_CONST);
|
||||||
|
if (tok != -1)
|
||||||
|
expect("declaration");
|
||||||
#ifdef TEST
|
#ifdef TEST
|
||||||
{
|
{
|
||||||
FILE *f;
|
FILE *f;
|
||||||
|
|
Loading…
Reference in a new issue