diff --git a/lib/c.c b/lib/c.c index 98a6d27d..1211065b 100644 --- a/lib/c.c +++ b/lib/c.c @@ -2,16 +2,15 @@ #define NULL 0 -#ifdef __arm__ +#if defined(__arm__) #define __syscall_exit 1 #define __syscall_read 3 #define __syscall_write 4 #define __syscall_close 6 #define __syscall_open 5 #define __syscall_brk 45 -#endif -#ifdef __riscv +#elif defined(__riscv) #define __syscall_exit 93 #define __syscall_read 63 #define __syscall_write 64 @@ -19,6 +18,7 @@ #define __syscall_open 1024 #define __syscall_openat 56 #define __syscall_brk 214 + #endif typedef int FILE; @@ -326,19 +326,17 @@ void abort() FILE *fopen(char *filename, char *mode) { if (!strcmp(mode, "wb")) -#ifdef __arm__ +#if defined(__arm__) return __syscall(__syscall_open, filename, 65, 0x1fd); -#endif -/* FIXME: mode not work currently in RISC-V */ -#ifdef __riscv - return __syscall(__syscall_openat, -100, filename, 65, 0x1fd); +#elif defined(__riscv) + /* FIXME: mode not work currently in RISC-V */ + return __syscall(__syscall_openat, -100, filename, 65, 0x1fd); #endif if (!strcmp(mode, "rb")) -#ifdef __arm__ +#if defined(__arm__) return __syscall(__syscall_open, filename, 0, 0); -#endif -#ifdef __riscv - return __syscall(__syscall_openat, -100, filename, 0, 0); +#elif defined(__riscv) + return __syscall(__syscall_openat, -100, filename, 0, 0); #endif abort(); diff --git a/src/cfront.c b/src/cfront.c index 2cd8dfc4..e5a10ff4 100644 --- a/src/cfront.c +++ b/src/cfront.c @@ -112,6 +112,8 @@ char token_str[MAX_TOKEN_LEN]; token_t next_token; char next_char; +int preproc_match; + void skip_whitespace() { while (is_whitespace(next_char)) @@ -126,6 +128,28 @@ char read_char(int is_skip_space) return next_char; } +/* + * get alias name from defined() directive + * i.e., get __arm__ from defined(__arm__) + */ +void read_alias_name_from_defined(char *alias_name, char *src) +{ + int i; + + src = src + 8; /* skip defined( */ + i = 0; + while (src[i] != ')') { + alias_name[i] = src[i]; + i++; + } + alias_name[i] = 0; +} + +char peek_char(int offset) +{ + return SOURCE[source_idx + offset]; +} + token_t get_next_token() { token_str[0] = 0; @@ -133,6 +157,10 @@ token_t get_next_token() /* partial preprocessor */ if (next_char == '#') { int i = 0; + char *alias = NULL; + char alias_name[MAX_TOKEN_LEN]; + char peek_c; + do { token_str[i++] = next_char; } while (is_alnum(read_char(0))); @@ -150,8 +178,84 @@ token_t get_next_token() skip_whitespace(); return T_define; } + if (!strcmp(token_str, "#if")) { + preproc_match = 0; + i = 0; + do { + token_str[i++] = next_char; + } while (read_char(0) != '\n'); + token_str[i] = 0; + + if (!strncmp(token_str, "defined", 7)) { + read_alias_name_from_defined(alias_name, token_str); + alias = find_alias(alias_name); + if (alias) { + preproc_match = 1; + skip_whitespace(); + return get_next_token(); + } + /* skip lines until #elif or #else or #endif */ + do { + skip_whitespace(); + i = 0; + do { + token_str[i++] = next_char; + } while (read_char(0) != '\n'); + token_str[i] = 0; + read_char(1); + peek_c = peek_char(1); + } while (next_char != '#' || + (next_char == '#' && peek_c == 'd')); + skip_whitespace(); + return get_next_token(); + } + } + if (!strcmp(token_str, "#elif")) { + if (preproc_match) { + do { + skip_whitespace(); + i = 0; + do { + token_str[i++] = next_char; + } while (read_char(0) != '\n'); + token_str[i] = 0; + } while (strcmp(token_str, "#endif")); + skip_whitespace(); + return get_next_token(); + } + + i = 0; + do { + token_str[i++] = next_char; + } while (read_char(0) != '\n'); + token_str[i] = 0; + + if (!strncmp(token_str, "defined", 7)) { + read_alias_name_from_defined(alias_name, token_str); + alias = find_alias(alias_name); + if (alias) { + preproc_match = 1; + skip_whitespace(); + return get_next_token(); + } + /* skip lines until #elif or #else or #endif */ + do { + skip_whitespace(); + i = 0; + do { + token_str[i++] = next_char; + } while (read_char(0) != '\n'); + token_str[i] = 0; + read_char(1); + peek_c = peek_char(1); + } while (next_char != '#' || + (next_char == '#' && peek_c == 'd')); + skip_whitespace(); + return get_next_token(); + } + } if (!strcmp(token_str, "#ifdef")) { - char *alias = NULL; + preproc_match = 0; i = 0; do { token_str[i++] = next_char; @@ -161,6 +265,7 @@ token_t get_next_token() alias = find_alias(token_str); if (alias) { /* ignore #else directive */ + preproc_match = 1; skip_whitespace(); return get_next_token(); } @@ -177,8 +282,17 @@ token_t get_next_token() return get_next_token(); } if (!strcmp(token_str, "#else")) { - /* reach here means previous alias is defined so skip lines until - * #endif */ + /* + * reach here has 2 possible cases: + * 1. reach #ifdef preprocessor directive + * 2. conditional expression in #elif is false + */ + + if (!preproc_match) { + skip_whitespace(); + return get_next_token(); + } + /* skip lines until #else or #endif */ do { skip_whitespace(); i = 0; @@ -191,6 +305,7 @@ token_t get_next_token() return get_next_token(); } if (!strcmp(token_str, "#endif")) { + preproc_match = 0; skip_whitespace(); return get_next_token(); } diff --git a/tests/driver.sh b/tests/driver.sh index 61c26fb8..49e057f4 100755 --- a/tests/driver.sh +++ b/tests/driver.sh @@ -339,4 +339,22 @@ int main() } EOF +# #if defined(...) ... #elif defined(...) ... #else ... #endif +try_ 0 << EOF +#define A 0 +#define B 0xDEAD +int main() +{ + int x; +#if defined(A) + x = A; +#elif defined(B) + x = B; +#else + x = 0xCAFE +#endif + return x; +} +EOF + echo OK