Skip to content

Commit

Permalink
Implement #if defined(...) and #elif defined(...) and #else
Browse files Browse the repository at this point in the history
Now only support simple conditional expression which is defined(...) after #if and #elif.
More complex conditional expression might be supported in the future.

Refactor 'lib/c.c' to improve readability.

Also, add a simple test case to 'tests/driver.sh'
  • Loading branch information
ChinYikMing committed Jul 25, 2023
1 parent ae435af commit 357fa9b
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 15 deletions.
22 changes: 10 additions & 12 deletions lib/c.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,23 @@

#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
#define __syscall_close 57
#define __syscall_open 1024
#define __syscall_openat 56
#define __syscall_brk 214

#endif

typedef int FILE;
Expand Down Expand Up @@ -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();
Expand Down
121 changes: 118 additions & 3 deletions src/cfront.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand All @@ -126,13 +128,39 @@ 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;

/* 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)));
Expand All @@ -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;
Expand All @@ -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();
}
Expand All @@ -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;
Expand All @@ -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();
}
Expand Down
18 changes: 18 additions & 0 deletions tests/driver.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit 357fa9b

Please sign in to comment.