From 3ee68d906e87052ff5e11a3ef50ea184baaeb28e Mon Sep 17 00:00:00 2001 From: tyfkda Date: Sat, 14 Oct 2023 08:52:49 +0900 Subject: [PATCH] Expand macro argument non destructive --- src/cpp/macro.c | 25 +++++++++++++++++++++---- tests/cpptest.sh | 2 ++ tool/pp.js | 18 ++++++++++++++++-- 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/cpp/macro.c b/src/cpp/macro.c index 2fc67392d..1cb18c5d5 100644 --- a/src/cpp/macro.c +++ b/src/cpp/macro.c @@ -1,6 +1,7 @@ #include "../config.h" #include "macro.h" +#include #include #include // INT_MAX #include // malloc @@ -192,6 +193,15 @@ static Vector *subst(Macro *macro, Table *param_table, Vector *args, HideSet *hs if (body == NULL) return os; + Vector **expanded_args = NULL; + if (args != NULL && args->len > 0) { + expanded_args = alloca(sizeof(*expanded_args) * args->len); + if (expanded_args == NULL) + error("alloca failed"); + for (int i = 0; i < args->len; ++i) + expanded_args[i] = NULL; + } + for (int i = 0; i < body->len; ++i) { const Token *tok = body->data[i]; @@ -261,10 +271,17 @@ static Vector *subst(Macro *macro, Table *param_table, Vector *args, HideSet *hs intptr_t j; if (table_try_get(param_table, tok->ident, (void*)&j)) { assert(j < args->len); - Vector *arg = args->data[j]; - macro_expand(arg); - for (int k = 0; k < arg->len; ++k) { - const Token *t = arg->data[k]; + Vector *expanded = expanded_args[j]; + if (expanded == NULL) { + Vector *arg = args->data[j]; + expanded = new_vector(); + for (int i = 0; i < arg->len; ++i) + vec_push(expanded, arg->data[i]); + macro_expand(expanded); + expanded_args[j] = expanded; + } + for (int k = 0; k < expanded->len; ++k) { + const Token *t = expanded->data[k]; vec_push(os, t); } continue; diff --git a/tests/cpptest.sh b/tests/cpptest.sh index 63b3b3eee..ae9ff0c79 100755 --- a/tests/cpptest.sh +++ b/tests/cpptest.sh @@ -144,6 +144,8 @@ test_macro() { try '#if in macro arguments' '{bar}' "#define FOO(x) {x}\nFOO(\n#if 1\nbar\n#else\nqux\n#endif\n)" + try 'expand and stringify' 'a(m_z, "M(z)")' "#define MinM(x) a(x, # x)\n#define M(x) m_ ## x\nMinM(M(z))" + try ', ## empty' 'foo(fmt)' "#define FOO(fmt, ...) foo(fmt, ## __VA_ARGS__)\nFOO(fmt)" try ', ## some' 'foo(fmt,1, 2, 3)' "#define FOO(fmt, ...) foo(fmt, ## __VA_ARGS__)\nFOO(fmt, 1, 2, 3)" diff --git a/tool/pp.js b/tool/pp.js index 76bf977e5..dc2f13446 100755 --- a/tool/pp.js +++ b/tool/pp.js @@ -125,6 +125,7 @@ class MacroExpander { } subst(is, fp, ap, hs) { + const expandedAp = ap.map(_ => null) const os = [] for (let i = 0; i < is.length; ++i) { const tt = is[i] @@ -175,7 +176,11 @@ class MacroExpander { const j = fp.indexOf(tt.t) if (j >= 0) { - os.push(...this.expand(ap[j])) + let expanded = expandedAp[j] + if (expanded == null) { + expanded = expandedAp[j] = this.expand([...ap[j]]) + } + os.push(...expanded) continue } } @@ -212,7 +217,8 @@ class MacroExpander { } stringize(x) { - const s = `"${x}"` // TODO: Escape + const actual = x.map((t) => t.t.toString()).join('') + const s = `"${actual}"` // TODO: Escape return new Token(TK_OTHER, s) } @@ -415,6 +421,14 @@ function main() { 'STR': new Macro(['x'], '# x'), }) + pptest( + 'a(m_z, "M(z)")', + 'MinM(M(z))', + { + 'MinM': new Macro(['x'], 'a(x, # x)'), + 'M': new Macro(['x'], 'm_ ## x'), + }) + process.exit(errorCount === 0 ? 0 : 1) }