diff options
| -rw-r--r-- | src/preprocess.c | 55 | ||||
| -rw-r--r-- | tests/112.sh | 35 |
2 files changed, 75 insertions, 15 deletions
diff --git a/src/preprocess.c b/src/preprocess.c index cfccbcc..9e33ac5 100644 --- a/src/preprocess.c +++ b/src/preprocess.c @@ -601,10 +601,7 @@ static Token* next_pp_token(Preprocessor* pp) { static void skip_pp_token(Preprocessor* pp, TokenKind expected) { Token* tok = next_pp_token(pp); - // TODO: currently function-like macro expansion supports only one token. - // assert(tok->kind == expected); - BOOL ok = tok->kind == expected; - assert(ok); + assert(tok->kind == expected); } static Token* consume_pp_token_if(Preprocessor* pp, TokenKind expected) { @@ -798,17 +795,41 @@ static MacroArgArray* pp_parse_macro_arguments(Preprocessor* pp, BOOL skip_newli expect_pp_token(pp, TokenKind_paren_r); } if (tok->kind != TokenKind_paren_r) { - next_pp_token(pp); MacroArg* arg = macroargs_push_new(args); - tokens_init(&arg->tokens, 1); - *tokens_push_new(&arg->tokens) = *tok; - skip_whitespaces_or_newlines(pp, skip_newline); - while (consume_pp_token_if(pp, TokenKind_comma)) { - skip_whitespaces_or_newlines(pp, skip_newline); + tokens_init(&arg->tokens, 4); + + // Parse argument tokens, handling nested parentheses. + int nesting = 0; + while (TRUE) { + tok = peek_pp_token(pp); + + if (nesting == 0) { + if (tok->kind == TokenKind_paren_r) { + break; + } + if (tok->kind == TokenKind_comma) { + next_pp_token(pp); + skip_whitespaces_or_newlines(pp, skip_newline); + + arg = macroargs_push_new(args); + tokens_init(&arg->tokens, 4); + continue; + } + } + + if (tok->kind == TokenKind_paren_l) { + nesting++; + } else if (tok->kind == TokenKind_paren_r) { + nesting--; + if (nesting < 0) { + break; + } + } + tok = next_pp_token(pp); - arg = macroargs_push_new(args); - tokens_init(&arg->tokens, 1); *tokens_push_new(&arg->tokens) = *tok; + + skip_whitespaces_or_newlines(pp, skip_newline); } } expect_pp_token(pp, TokenKind_paren_r); @@ -874,12 +895,16 @@ static BOOL expand_macro(Preprocessor* pp, BOOL skip_newline) { // Parameter substitution size_t token_count = 0; + size_t offset = 0; for (size_t i = 0; i < macro->replacements.len; ++i) { - Token* tok = pp_token_at(pp, macro_name_pos + i); + Token* tok = pp_token_at(pp, macro_name_pos + i + offset); int macro_param_idx = macro_find_param(macro, tok); if (macro_param_idx != -1) { - replace_pp_tokens(pp, macro_name_pos + i, macro_name_pos + i + 1, &args->data[macro_param_idx].tokens); - token_count += args->data[macro_param_idx].tokens.len; + size_t arg_token_count = args->data[macro_param_idx].tokens.len; + replace_pp_tokens(pp, macro_name_pos + i + offset, macro_name_pos + i + offset + 1, + &args->data[macro_param_idx].tokens); + token_count += arg_token_count; + offset += arg_token_count - 1; } else { ++token_count; } diff --git a/tests/112.sh b/tests/112.sh new file mode 100644 index 0000000..c56e0d6 --- /dev/null +++ b/tests/112.sh @@ -0,0 +1,35 @@ +cat <<'EOF' > expected +42 +100 200 +300 +0 +1 2 3 +15 +42 +123 +879 +EOF + +test_diff <<'EOF' +int printf(); + +#define ADD(a, b) ((a) + (b)) +#define PRINT_TWO(x, y) printf("%d %d\n", x, y) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define NESTED(x) (x) +#define CONCAT3(a, b, c) a ## b ## c + +int main() { + printf("%d\n", ADD(40, 2)); + PRINT_TWO(100, 200); + printf("%d\n", MAX(100 + 200, 250)); + printf("%d\n"); + NESTED((printf("1 "), printf("2 "), printf("3\n"), 0)); + + int x = 5, y = 10; + printf("%d\n", ADD(x + 2, y - 2)); + printf("%d\n", ADD(MAX(10, 20), MAX(15 + 5, 22))); + printf("%d\n", ADD( 100 , 23 )); + printf("%d\n", ADD(NESTED((100 + 200)), MAX((123 + 456), (111 + 222)))); +} +EOF |
