From 607a19b25187ffd579636815b32fd0fac5d8e8ea Mon Sep 17 00:00:00 2001 From: Jim Huang Date: Sat, 2 Aug 2025 23:52:59 +0800 Subject: [PATCH] Implement macro parameter substitution in statement contexts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This enables function-like macros with statement bodies that reference macro parameters. Examples now supported: - ASSIGN_MACRO(variable, val) → variable = variable + val + 10 - COMPOUND_ASSIGN(variable, val) → variable += val + 10 - SET_VAR(var, value) → var = value Implementation uses find_macro_param_src_idx() with careful lexer state management to safely substitute parameter values in statement parsing contexts, matching existing expression context functionality. Close #142 --- src/parser.c | 30 ++++++++++++++++++++++++++++++ tests/driver.sh | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/src/parser.c b/src/parser.c index be032d18..2307a9e0 100644 --- a/src/parser.c +++ b/src/parser.c @@ -2671,6 +2671,36 @@ basic_block_t *read_body_statement(block_t *parent, basic_block_t *bb) if (!lex_peek(T_identifier, token)) error("Unexpected token"); + /* handle macro parameter substitution for statements */ + int macro_param_idx = find_macro_param_src_idx(token, parent); + if (macro_param_idx && parent->macro) { + /* save current state */ + int saved_size = SOURCE->size; + char saved_char = next_char; + int saved_token = next_token; + + /* jump to parameter value */ + SOURCE->size = macro_param_idx; + next_char = SOURCE->elements[SOURCE->size]; + next_token = lex_token(); + + /* extract the parameter value as identifier token */ + if (lex_peek(T_identifier, token)) { + lex_expect(T_identifier); + } else { + /* parameter is not a simple identifier, restore state and continue + */ + SOURCE->size = saved_size; + next_char = saved_char; + next_token = saved_token; + } + + /* restore source position */ + SOURCE->size = saved_size; + next_char = saved_char; + next_token = saved_token; + } + /* is it a variable declaration? */ int find_type_flag = lex_accept(T_struct) ? 2 : 1; type = find_type(token, find_type_flag); diff --git a/tests/driver.sh b/tests/driver.sh index fc1bbfed..27ff4bb6 100755 --- a/tests/driver.sh +++ b/tests/driver.sh @@ -928,6 +928,49 @@ int main() } EOF +# macro parameter substitution works in expression contexts +try_ 15 << EOF +#define ADD_PARAMS(a, b) ((a) + (b)) +int main() +{ + int x = 5, y = 10; + return ADD_PARAMS(x, y); +} +EOF + +# macro with assignment operators +try_ 18 << EOF +#define ASSIGN_MACRO(variable, val) \ + variable = variable + val + 10 +int main() +{ + int x = 5; + ASSIGN_MACRO(x, 3); + return x; +} +EOF + +try_ 27 << EOF +#define COMPOUND_ASSIGN(variable, val) \ + variable += val + 10 +int main() +{ + int y = 10; + COMPOUND_ASSIGN(y, 7); + return y; +} +EOF + +try_ 42 << EOF +#define SET_VAR(var, value) var = value +int main() +{ + int z = 0; + SET_VAR(z, 42); + return z; +} +EOF + try_output 0 "Wrapper: Hello World!" << EOF #define WRAPPER(...) \ do { \