From: Ben Pfaff Date: Thu, 10 Jun 2021 06:23:28 +0000 (-0700) Subject: Implemented all the functions except !EVAL and !UPCASE. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?p=pspp;a=commitdiff_plain;h=4861d99229da266945dc2dfcbda2acc9bd7b9b42 Implemented all the functions except !EVAL and !UPCASE. --- diff --git a/src/language/lexer/macro.c b/src/language/lexer/macro.c index d4d7b322b9..b17d467faa 100644 --- a/src/language/lexer/macro.c +++ b/src/language/lexer/macro.c @@ -826,7 +826,7 @@ error: } static bool -string_is_quoted_string (const char *s, struct string *content) +unquote_string (const char *s, struct string *content) { struct string_lexer slex; string_lexer_init (&slex, s, strlen (s), SEG_MODE_INTERACTIVE /* XXX */); @@ -854,6 +854,18 @@ string_is_quoted_string (const char *s, struct string *content) return true; } +static bool +parse_integer (const char *s, int *np) +{ + errno = 0; + + char *tail; + long int n = strtol (s, &tail, 10); + *np = n < INT_MIN ? INT_MIN : n > INT_MAX ? INT_MAX : n; + tail += strspn (tail, CC_SPACES); + return *tail == '\0' && errno != ERANGE && n == *np; +} + static bool expand_macro_function (struct parse_macro_function_ctx *ctx, struct string *output, @@ -867,10 +879,8 @@ expand_macro_function (struct parse_macro_function_ctx *ctx, else if (parse_macro_function (ctx, &args, ss_cstr ("!blanks"), 1, 1, input_consumed)) { - char *tail; - errno = 0; - int n = strtol (args.strings[0], &tail, 10); - if (*tail != '\0' || n < 0 || errno == ERANGE) + int n; + if (!parse_integer (args.strings[0], &n)) { printf ("argument to !BLANKS must be non-negative integer (not \"%s\")\n", args.strings[0]); string_array_destroy (&args); @@ -883,13 +893,34 @@ expand_macro_function (struct parse_macro_function_ctx *ctx, input_consumed)) { for (size_t i = 0; i < args.n; i++) - if (!string_is_quoted_string (args.strings[i], output)) + if (!unquote_string (args.strings[i], output)) ds_put_cstr (output, args.strings[i]); } + else if (parse_macro_function (ctx, &args, ss_cstr ("!head"), 1, 1, + input_consumed)) + { + struct string content = DS_EMPTY_INITIALIZER; + const char *s = (unquote_string (args.strings[0], &content) + ? ds_cstr (&content) : args.strings[0]); + + struct macro_tokens mts = { .n = 0 }; + macro_tokens_from_string (&mts, ss_cstr (s), SEG_MODE_INTERACTIVE /* XXX */); + if (mts.n > 0) + ds_put_substring (output, mts.mts[0].representation); + macro_tokens_uninit (&mts); + ds_destroy (&content); + } + else if (parse_macro_function (ctx, &args, ss_cstr ("!index"), 2, 2, + input_consumed)) + { + const char *haystack = args.strings[0]; + const char *needle = strstr (haystack, args.strings[1]); + ds_put_format (output, "%zu", needle ? needle - haystack + 1 : 0); + } else if (parse_macro_function (ctx, &args, ss_cstr ("!quote"), 1, 1, input_consumed)) { - if (string_is_quoted_string (args.strings[0], NULL)) + if (unquote_string (args.strings[0], NULL)) ds_put_cstr (output, args.strings[0]); else { @@ -904,10 +935,49 @@ expand_macro_function (struct parse_macro_function_ctx *ctx, ds_put_byte (output, '\''); } } + else if (parse_macro_function (ctx, &args, ss_cstr ("!substr"), 2, 3, + input_consumed)) + { + int start; + if (!parse_integer (args.strings[1], &start) || start < 1) + { + printf ("second argument to !SUBSTR must be positive integer (not \"%s\")\n", args.strings[1]); + string_array_destroy (&args); + return false; + } + + int count = INT_MAX; + if (args.n > 2 && (!parse_integer (args.strings[2], &count) || count < 0)) + { + printf ("third argument to !SUBSTR must be non-negative integer (not \"%s\")\n", args.strings[1]); + string_array_destroy (&args); + return false; + } + + struct substring s = ss_cstr (args.strings[0]); + ds_put_substring (output, ss_substr (s, start - 1, count)); + } + else if (parse_macro_function (ctx, &args, ss_cstr ("!tail"), 1, 1, + input_consumed)) + { + struct string content = DS_EMPTY_INITIALIZER; + const char *s = (unquote_string (args.strings[0], &content) + ? ds_cstr (&content) : args.strings[0]); + + struct macro_tokens mts = { .n = 0 }; + macro_tokens_from_string (&mts, ss_cstr (s), SEG_MODE_INTERACTIVE /* XXX */); + if (mts.n > 1) + { + struct macro_tokens tail = { .mts = mts.mts + 1, .n = mts.n - 1 }; + macro_tokens_to_representation (&tail, output); + } + macro_tokens_uninit (&mts); + ds_destroy (&content); + } else if (parse_macro_function (ctx, &args, ss_cstr ("!unquote"), 1, 1, input_consumed)) { - if (!string_is_quoted_string (args.strings[0], output)) + if (!unquote_string (args.strings[0], output)) ds_put_cstr (output, args.strings[0]); } else if (ctx->n_input > 0 diff --git a/tests/language/control/define.at b/tests/language/control/define.at index c192beee05..9a13ea45cd 100644 --- a/tests/language/control/define.at +++ b/tests/language/control/define.at @@ -391,6 +391,52 @@ xy. 1234. 123.]) +dnl Keep this test in sync with the examples for !HEAD in the manual. +PSPP_CHECK_MACRO_EXPANSION([!HEAD], + [DEFINE !h() +!HEAD('a b c'). +!HEAD('a'). +!HEAD(!NULL). +!HEAD(''). +!ENDDEFINE], + [!h.], + [a. +a. +. +.]) + +dnl Keep this test in sync with the examples for !TAIL in the manual. +PSPP_CHECK_MACRO_EXPANSION([!TAIL], + [DEFINE !t() +!TAIL('a b c'). +!TAIL('a'). +!TAIL(!NULL). +!TAIL(''). +!ENDDEFINE], + [!t.], + [b c. +. +. +.]) + +dnl Keep this test in sync with the examples for !INDEX in the manual. +PSPP_CHECK_MACRO_EXPANSION([!INDEX], + [DEFINE !i() +!INDEX(banana, an). +!INDEX(banana, nan). +!INDEX(banana, apple). +!INDEX("banana", nan). +!INDEX("banana", "nan"). +!INDEX(!UNQUOTE("banana"), !UNQUOTE("nan")). +!ENDDEFINE], + [!i.], + [2. +3. +0. +4. +0. +3.]) + dnl Keep this test in sync with the examples for !LENGTH in the manual. PSPP_CHECK_MACRO_EXPANSION([!LENGTH], [DEFINE !l() @@ -423,3 +469,25 @@ DEFINE !la(!positional !enclose('(',')')) 0. 5. 0.]) + +dnl Keep this test in sync with the examples for !SUBSTR in the manual. +PSPP_CHECK_MACRO_EXPANSION([!SUBSTR], + [DEFINE !s() +!SUBSTR(banana, 3). +!SUBSTR(banana, 3, 3). +!SUBSTR("banana", 3). +!SUBSTR("banana", 3, 3). +!SUBSTR(banana, 3, 0). +!SUBSTR(banana, 3, 10). +!SUBSTR(banana, 10, 3). +!ENDDEFINE.], + [!s.], + [nana. +nan. +anana". dnl" + +ana. +. +nana. +.]) +