From 679339657851a4be1321d63a5a46f4d8a32926a4 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Thu, 26 Aug 2021 09:32:31 -0700 Subject: [PATCH] DEFINE: Only expand macro functions when the name is followed by '('. Frans Houweling reported that PSPP was flagging an error for !EVAL(!len) when !len was the name of a defined macro. This was because !len is short for the !LENGTH macro function. This commit fixes the problem. --- src/language/lexer/macro.c | 22 ++++++++++----------- tests/language/control/define.at | 34 +++++++++++++++++++------------- 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/src/language/lexer/macro.c b/src/language/lexer/macro.c index 977436a604..742b8771ac 100644 --- a/src/language/lexer/macro.c +++ b/src/language/lexer/macro.c @@ -986,12 +986,7 @@ parse_function_args (const struct macro_expander *me, const char *function, struct string_array *args) { - if (n < 2 || mts[1].token.type != T_LPAREN) - { - macro_error (me->stack, n > 1 ? &mts[1] : NULL, - _("`(' expected following %s."), function); - return 0; - } + assert (n >= 2 && mts[1].token.type == T_LPAREN); for (size_t i = 2; i < n; ) { @@ -1090,7 +1085,6 @@ expand_macro_function (const struct macro_expander *me, MF_HEAD, MF_INDEX, MF_LENGTH, - MF_NULL, MF_QUOTE, MF_SUBSTR, MF_TAIL, @@ -1104,7 +1098,6 @@ expand_macro_function (const struct macro_expander *me, [MF_HEAD] = { "!HEAD", 1, 1 }, [MF_INDEX] = { "!INDEX", 2, 2 }, [MF_LENGTH] = { "!LENGTH", 1, 1 }, - [MF_NULL] = { "!NULL", 0, 0 }, [MF_QUOTE] = { "!QUOTE", 1, 1 }, [MF_SUBSTR] = { "!SUBSTR", 2, 3 }, [MF_TAIL] = { "!TAIL", 1, 1 }, @@ -1112,7 +1105,16 @@ expand_macro_function (const struct macro_expander *me, [MF_UPCASE] = { "!UPCASE", 1, 1 }, }; - /* Is this a macro function? */ + if (lex_id_match_n (ss_cstr ("!NULL"), input[0].token.string, 4)) + return 1; + + if (n_input < 2 || input[1].token.type != T_LPAREN) + { + /* Only consider macro functions when the name is followed by '('. */ + return 0; + } + + /* Is this a macro function name? */ const struct macro_function *mf; for (mf = mfs; ; mf++) { @@ -1127,8 +1129,6 @@ expand_macro_function (const struct macro_expander *me, } enum macro_function_id id = mf - mfs; - if (id == MF_NULL) - return 1; struct string_array args = STRING_ARRAY_INITIALIZER; size_t n_consumed = parse_function_args (me, input, n_input, mf->name, &args); diff --git a/tests/language/control/define.at b/tests/language/control/define.at index 3c940c1513..9a7594b81b 100644 --- a/tests/language/control/define.at +++ b/tests/language/control/define.at @@ -1633,10 +1633,26 @@ not a multiple of 2. ]) AT_CLEANUP +AT_SETUP([macro name overlaps with macro function name]) +dnl !len is short for macro function !LENGTH. PSPP used to +dnl reject the following with "`(' expected following !LENGTH". +dnl Now PSPP only consider macro functions when the name is +dnl followed by '('. +AT_DATA([define.sps], [dnl +DEFINE !len() 5 !ENDDEFINE. +DEFINE !x() !eval(!len) !ENDDEFINE. +DEBUG EXPAND. +!x +]) +AT_CHECK([pspp -O format=csv define.sps --testing-mode], [0], [dnl +5 +]) +AT_CLEANUP + AT_SETUP([generic macro function syntax errors]) AT_DATA([define.sps], [dnl -DEFINE !a() !SUBSTR !ENDDEFINE. -DEFINE !b() !SUBSTR x !ENDDEFINE. + + DEFINE !c() !SUBSTR(1x) !ENDDEFINE. DEFINE !d() !SUBSTR(1 !ENDDEFINE. DEFINE !narg_blanks() !BLANKS() !ENDDEFINE. @@ -1653,8 +1669,8 @@ DEFINE !narg_unquote() !UNQUOTE() !ENDDEFINE. DEFINE !narg_upcase() !UPCASE() !ENDDEFINE. dnl ) DEBUG EXPAND. -!a. -!b. + + !c. !d. !narg_blanks. @@ -1671,16 +1687,6 @@ DEBUG EXPAND. !narg_upcase. ]) AT_CHECK([pspp --testing-mode define.sps], [1], [dnl -define.sps:1: In the expansion of `!a', -define.sps:18.1-18.2: error: DEBUG EXPAND: `@{:@' expected following !SUBSTR. - -!SUBSTR - -define.sps:2: At `x' in the expansion of `!b', -define.sps:19.1-19.2: error: DEBUG EXPAND: `@{:@' expected following !SUBSTR. - -!SUBSTR x - define.sps:3: At `x' in the expansion of `!c', define.sps:20.1-20.2: error: DEBUG EXPAND: `,' or `@:}@' expected in call to macro function !SUBSTR. -- 2.30.2