From: Ben Pfaff Date: Thu, 10 Jun 2021 05:20:12 +0000 (-0700) Subject: macro: Implement uniformly in terms of character strings. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?p=pspp;a=commitdiff_plain;h=38757b90fa3ffe47c9d7ad29a4767bb606f51ecd macro: Implement uniformly in terms of character strings. --- diff --git a/src/language/lexer/macro.c b/src/language/lexer/macro.c index 628b83af01..d4d7b322b9 100644 --- a/src/language/lexer/macro.c +++ b/src/language/lexer/macro.c @@ -18,6 +18,7 @@ #include "language/lexer/macro.h" +#include #include #include @@ -28,6 +29,7 @@ #include "libpspp/i18n.h" #include "libpspp/message.h" #include "libpspp/str.h" +#include "libpspp/string-array.h" #include "gettext.h" #define _(msgid) gettext (msgid) @@ -716,12 +718,11 @@ macro_expand (const struct macro_tokens *, static bool expand_macro_function (struct parse_macro_function_ctx *ctx, - struct macro_token *output, - size_t *input_consumed); + struct string *output, size_t *input_consumed); static size_t parse_function_arg (struct parse_macro_function_ctx *ctx, - size_t i, struct macro_token *farg) + size_t i, struct string *farg) { struct macro_token *tokens = ctx->input; const struct token *token = &tokens[i].token; @@ -733,25 +734,11 @@ parse_function_arg (struct parse_macro_function_ctx *ctx, { size_t param_idx = param - ctx->me->macro->params; const struct macro_tokens *marg = ctx->me->args[param_idx]; - if (marg->n == 1) - macro_token_copy (farg, &marg->mts[0]); - else + for (size_t i = 0; i < marg->n; i++) { - struct string s = DS_EMPTY_INITIALIZER; - for (size_t i = 0; i < marg->n; i++) - { - if (i) - ds_put_byte (&s, ' '); - ds_put_substring (&s, marg->mts[i].representation); - } - - struct substring s_copy; - ss_alloc_substring (&s_copy, s.ss); - - *farg = (struct macro_token) { - .token = { .type = T_MACRO_ID, .string = s.ss }, - .representation = s_copy, - }; + if (i) + ds_put_byte (farg, ' '); + ds_put_substring (farg, marg->mts[i].representation); } return 1; } @@ -769,13 +756,13 @@ parse_function_arg (struct parse_macro_function_ctx *ctx, return subinput_consumed; } - macro_token_copy (farg, &tokens[i]); + ds_put_substring (farg, tokens[i].representation); return 1; } static bool parse_macro_function (struct parse_macro_function_ctx *ctx, - struct macro_tokens *args, + struct string_array *args, struct substring function, int min_args, int max_args, size_t *input_consumed) @@ -794,7 +781,7 @@ parse_macro_function (struct parse_macro_function_ctx *ctx, return false; } - *args = (struct macro_tokens) { .n = 0 }; + string_array_init (args); for (size_t i = 2;; ) { @@ -811,9 +798,14 @@ parse_macro_function (struct parse_macro_function_ctx *ctx, return true; } - i += parse_function_arg (ctx, i, macro_tokens_add_uninit (args)); + struct string s = DS_EMPTY_INITIALIZER; + i += parse_function_arg (ctx, i, &s); if (i >= n_tokens) - goto unexpected_end; + { + ds_destroy (&s); + goto unexpected_end; + } + string_array_append_nocopy (args, ds_steal_cstr (&s)); if (tokens[i].token.type == T_COMMA) i++; @@ -829,105 +821,106 @@ unexpected_end: function.string); /* Fall through. */ error: - macro_tokens_uninit (args); + string_array_destroy (args); return false; } +static bool +string_is_quoted_string (const char *s, struct string *content) +{ + struct string_lexer slex; + string_lexer_init (&slex, s, strlen (s), SEG_MODE_INTERACTIVE /* XXX */); + + struct token token1; + if (!string_lexer_next (&slex, &token1)) + return false; + + if (token1.type != T_STRING) + { + token_uninit (&token1); + return false; + } + + struct token token2; + if (string_lexer_next (&slex, &token2)) + { + token_uninit (&token1); + token_uninit (&token2); + return false; + } + + ds_put_substring (content, token1.string); + token_uninit (&token1); + return true; +} + static bool expand_macro_function (struct parse_macro_function_ctx *ctx, - struct macro_token *output, + struct string *output, size_t *input_consumed) { - struct macro_tokens args; + struct string_array args; if (parse_macro_function (ctx, &args, ss_cstr ("!length"), 1, 1, input_consumed)) - { - size_t length = args.mts[0].representation.length; - *output = (struct macro_token) { - .token = { .type = T_POS_NUM, .number = length }, - .representation = ss_cstr (xasprintf ("%zu", length)), - }; - } + ds_put_format (output, "%zu", strlen (args.strings[0])); else if (parse_macro_function (ctx, &args, ss_cstr ("!blanks"), 1, 1, input_consumed)) { - /* XXX this isn't right, it might be a character string containing a - positive integer, e.g. via !CONCAT. */ - if (args.mts[0].token.type != T_POS_NUM) + char *tail; + errno = 0; + int n = strtol (args.strings[0], &tail, 10); + if (*tail != '\0' || n < 0 || errno == ERANGE) { - printf ("argument to !BLANKS must be positive integer\n"); - macro_tokens_uninit (&args); + printf ("argument to !BLANKS must be non-negative integer (not \"%s\")\n", args.strings[0]); + string_array_destroy (&args); return false; } - struct string s = DS_EMPTY_INITIALIZER; - ds_put_byte_multiple (&s, ' ', args.mts[0].token.number); - - struct substring s_copy; - ss_alloc_substring (&s_copy, s.ss); - - *output = (struct macro_token) { - .token = { .type = T_ID, .string = s.ss }, - .representation = s_copy, - }; + ds_put_byte_multiple (output, ' ', n); } else if (parse_macro_function (ctx, &args, ss_cstr ("!concat"), 1, INT_MAX, input_consumed)) { - struct string s = DS_EMPTY_INITIALIZER; for (size_t i = 0; i < args.n; i++) - { - if (args.mts[i].token.type == T_STRING) - ds_put_substring (&s, args.mts[i].token.string); - else - ds_put_substring (&s, args.mts[i].representation); - } - - *output = (struct macro_token) { - .token = { .type = T_MACRO_ID /*XXX*/, .string = s.ss }, - }; - ss_alloc_substring (&output->representation, s.ss); + if (!string_is_quoted_string (args.strings[i], output)) + ds_put_cstr (output, args.strings[i]); } else if (parse_macro_function (ctx, &args, ss_cstr ("!quote"), 1, 1, input_consumed)) { - if (args.mts[0].token.type == T_STRING) - macro_token_copy (output, &args.mts[0]); + if (string_is_quoted_string (args.strings[0], NULL)) + ds_put_cstr (output, args.strings[0]); else { - *output = (struct macro_token) { .token = { .type = T_STRING } }; - ss_alloc_substring (&output->token.string, args.mts[0].representation); - output->representation = ss_cstr (token_to_string (&output->token)); + ds_extend (output, strlen (args.strings[0]) + 2); + ds_put_byte (output, '\''); + for (const char *p = args.strings[0]; *p; p++) + { + if (*p == '\'') + ds_put_byte (output, '\''); + ds_put_byte (output, *p); + } + ds_put_byte (output, '\''); } } else if (parse_macro_function (ctx, &args, ss_cstr ("!unquote"), 1, 1, input_consumed)) { - if (args.mts[0].token.type == T_STRING) - { - *output = (struct macro_token) { .token = { .type = T_MACRO_ID } }; - ss_alloc_substring (&output->token.string, args.mts[0].token.string); - output->representation = ss_cstr (token_to_string (&output->token)); - } - else - macro_token_copy (output, &args.mts[0]); + if (!string_is_quoted_string (args.strings[0], output)) + ds_put_cstr (output, args.strings[0]); } else if (ctx->n_input > 0 && ctx->input[0].token.type == T_MACRO_ID && ss_equals_case (ctx->input[0].token.string, ss_cstr ("!null"))) { *input_consumed = 1; - *output = (struct macro_token) { - .token = { .type = T_MACRO_ID /* XXX*/ }, - }; - ss_alloc_substring (&output->token.string, ss_cstr ("")); return true; } else return false; - macro_tokens_uninit (&args); + string_array_destroy (&args); return true; } @@ -1011,18 +1004,15 @@ macro_expand (const struct macro_tokens *mts, .me = me, .expand = expand, }; - struct macro_token function_output; + struct string function_output = DS_EMPTY_INITIALIZER; size_t function_consumed; if (expand_macro_function (&ctx, &function_output, &function_consumed)) { i += function_consumed - 1; - if (function_output.token.type == T_MACRO_ID) - macro_tokens_from_string (exp, function_output.token.string, - SEG_MODE_INTERACTIVE /* XXX */); - else - macro_tokens_add (exp, &function_output); - macro_token_uninit (&function_output); + macro_tokens_from_string (exp, function_output.ss, + SEG_MODE_INTERACTIVE /* XXX */); + ds_destroy (&function_output); continue; } diff --git a/tests/language/control/define.at b/tests/language/control/define.at index 7a005fc805..0d4ef96b82 100644 --- a/tests/language/control/define.at +++ b/tests/language/control/define.at @@ -370,11 +370,11 @@ PSPP_CHECK_MACRO_EXPANSION([!BLANKS], [!b.], [. ''. - . +. ' '. - . +. ' '. - . +. ' '.]) dnl Keep this test in sync with the examples for !CONCAT in the manual. @@ -390,3 +390,5 @@ PSPP_CHECK_MACRO_EXPANSION([!CONCAT], xy. 1234. 123.]) + +dnl