X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flanguage%2Flexer%2Fmacro.c;h=9536727a0f78d08b047feaeb1b639597462934cc;hb=f41e87501f3a3c600f4443033799b1689f84270a;hp=d20b74c9fe20e9f2c8b6d8ec71078313d9ead6fd;hpb=440613afbc2b901f51020c36afd59255a4988aa6;p=pspp diff --git a/src/language/lexer/macro.c b/src/language/lexer/macro.c index d20b74c9fe..9536727a0f 100644 --- a/src/language/lexer/macro.c +++ b/src/language/lexer/macro.c @@ -136,7 +136,7 @@ void macro_token_copy (struct macro_token *dst, const struct macro_token *src) { token_copy (&dst->token, &src->token); - ss_alloc_substring (&dst->syntax, src->syntax); + dst->syntax = ss_clone (src->syntax); } void @@ -220,31 +220,29 @@ macro_tokens_add (struct macro_tokens *mts, const struct macro_token *mt) macro_token_copy (macro_tokens_add_uninit (mts), mt); } -/* Tokenizes SRC according to MODE and appends the tokens to MTS. Uses STACK, - if nonull, for error reporting. */ +/* Tokenizes SRC according to MODE and appends the tokens to MTS, using STACK + for error reporting. */ static void -macro_tokens_from_string__ (struct macro_tokens *mts, const struct substring src, - enum segmenter_mode mode, - const struct macro_expansion_stack *stack) +macro_tokens_from_string (struct macro_tokens *mts, const struct substring src, + enum segmenter_mode mode, + const struct macro_expansion_stack *stack) { struct segmenter segmenter = segmenter_init (mode, true); struct substring body = src; while (body.length > 0) { - struct macro_token mt = { - .token = { .type = T_STOP }, - .syntax = { .string = body.string }, - }; - struct token *token = &mt.token; - enum segment_type type; int seg_len = segmenter_push (&segmenter, body.string, body.length, true, &type); assert (seg_len >= 0); - struct substring segment = ss_head (body, seg_len); - enum tokenize_result result = token_from_segment (type, segment, token); + struct macro_token mt = { + .token = { .type = T_STOP }, + .syntax = ss_head (body, seg_len), + }; + enum tokenize_result result + = token_from_segment (type, mt.syntax, &mt.token); ss_advance (&body, seg_len); switch (result) @@ -253,28 +251,18 @@ macro_tokens_from_string__ (struct macro_tokens *mts, const struct substring src break; case TOKENIZE_TOKEN: - mt.syntax.length = body.string - mt.syntax.string; macro_tokens_add (mts, &mt); break; case TOKENIZE_ERROR: - mt.syntax.length = body.string - mt.syntax.string; - macro_error (stack, &mt, "%s", token->string.string); + macro_error (stack, &mt, "%s", mt.token.string.string); break; } - token_uninit (token); + token_uninit (&mt.token); } } -/* Tokenizes SRC according to MODE and appends the tokens to MTS. */ -void -macro_tokens_from_string (struct macro_tokens *mts, const struct substring src, - enum segmenter_mode mode) -{ - macro_tokens_from_string__ (mts, src, mode, NULL); -} - void macro_tokens_print (const struct macro_tokens *mts, FILE *stream) { @@ -334,6 +322,8 @@ classify_token (enum token_type type) case T_RPAREN: case T_LBRACK: case T_RBRACK: + case T_LCURLY: + case T_RCURLY: return TC_PUNCT; case T_PLUS: @@ -341,6 +331,7 @@ classify_token (enum token_type type) case T_ASTERISK: case T_SLASH: case T_EQUALS: + case T_COLON: case T_AND: case T_OR: case T_NOT: @@ -359,6 +350,7 @@ classify_token (enum token_type type) return TC_BINOP; case T_COMMA: + case T_SEMICOLON: return TC_COMMA; } @@ -418,24 +410,8 @@ macro_destroy (struct macro *m) free (p->name); macro_tokens_uninit (&p->def); - - switch (p->arg_type) - { - case ARG_N_TOKENS: - break; - - case ARG_CHAREND: - token_uninit (&p->charend); - break; - - case ARG_ENCLOSE: - token_uninit (&p->enclose[0]); - token_uninit (&p->enclose[1]); - break; - - case ARG_CMDEND: - break; - } + token_uninit (&p->start); + token_uninit (&p->end); } free (m->params); macro_tokens_uninit (&m->body); @@ -514,9 +490,6 @@ macro_set_add (struct macro_set *set, struct macro *m) enum mc_state { - /* Error state. */ - MC_ERROR, - /* Accumulating tokens in mc->params toward the end of any type of argument. */ MC_ARG, @@ -620,39 +593,74 @@ mc_add_arg (struct macro_call *mc, const struct macro_token *mt, const struct msg_location *loc) { const struct macro_param *p = mc->param; + struct macro_tokens **argp = &mc->args[p - mc->macro->params]; const struct token *token = &mt->token; - if ((token->type == T_ENDCMD || token->type == T_STOP) - && p->arg_type != ARG_CMDEND) + if (token->type == T_ENDCMD || token->type == T_STOP) { - mc_error (mc, loc, - _("Unexpected end of command reading argument %s " - "to macro %s."), mc->param->name, mc->macro->name); + if (*argp) + { + switch (p->arg_type) + { + case ARG_CMDEND: + /* This is OK, it's the expected way to end the argument. */ + break; - mc->state = MC_ERROR; - return -1; + case ARG_N_TOKENS: + mc_error (mc, loc, + ngettext (_("Reached end of command expecting %zu " + "more token in argument %s to macro %s."), + _("Reached end of command expecting %zu " + "more tokens in argument %s to macro %s."), + p->n_tokens - (*argp)->n), + p->n_tokens - (*argp)->n, p->name, mc->macro->name); + break; + + case ARG_CHAREND: + case ARG_ENCLOSE: + { + char *end = token_to_string (&p->end); + mc_error (mc, loc, _("Reached end of command expecting \"%s\" " + "in argument %s to macro %s."), + end, p->name, mc->macro->name); + free (end); + } + break; + } + } + + /* The end of a command ends the current argument, precludes any further + arguments, and is not itself part of the argument. */ + return mc_finished (mc); } mc->n_tokens++; - struct macro_tokens **argp = &mc->args[p - mc->macro->params]; if (!*argp) *argp = xzalloc (sizeof **argp); bool add_token; /* Should we add 'mt' to the current arg? */ bool next_arg; /* Should we advance to the next arg? */ - if (p->arg_type == ARG_N_TOKENS) + switch (p->arg_type) { + case ARG_N_TOKENS: next_arg = (*argp)->n + 1 >= p->n_tokens; add_token = true; - } - else - { - next_arg = (p->arg_type == ARG_CMDEND - ? token->type == T_ENDCMD || token->type == T_STOP - : token_equal (token, (p->arg_type == ARG_CHAREND - ? &p->charend : &p->enclose[1]))); + break; + + case ARG_CHAREND: + case ARG_ENCLOSE: + next_arg = token_equal (token, &p->end); add_token = !next_arg; + break; + + case ARG_CMDEND: + next_arg = false; + add_token = true; + break; + + default: + NOT_REACHED (); } if (add_token) @@ -677,8 +685,7 @@ mc_expected (struct macro_call *mc, const struct macro_token *actual, mc->param->name, mc->macro->name); free (expected_s); - mc->state = MC_ERROR; - return -1; + return mc_finished (mc); } static int @@ -686,15 +693,21 @@ mc_enclose (struct macro_call *mc, const struct macro_token *mt, const struct msg_location *loc) { const struct token *token = &mt->token; - mc->n_tokens++; - - if (token_equal (&mc->param->enclose[0], token)) + const struct macro_param *p = mc->param; + if (token_equal (&p->start, token)) { + mc->n_tokens++; + + struct macro_tokens **argp = &mc->args[p - mc->macro->params]; + if (!*argp) + *argp = xzalloc (sizeof **argp); mc->state = MC_ARG; return 0; } - - return mc_expected (mc, mt, loc, &mc->param->enclose[0]); + else if (p->positional && (token->type == T_ENDCMD || token->type == T_STOP)) + return mc_finished (mc); + else + return mc_expected (mc, mt, loc, &p->start); } static const struct macro_param * @@ -728,17 +741,14 @@ mc_keyword (struct macro_call *mc, const struct macro_token *mt, token->string); if (p) { - size_t arg_index = p - mc->macro->params; - mc->param = p; - if (mc->args[arg_index]) - { - mc_error (mc, loc, - _("Argument %s multiply specified in call to macro %s."), - p->name, mc->macro->name); - mc->state = MC_ERROR; - return -1; - } + struct macro_tokens **argp = &mc->args[p - mc->macro->params]; + if (*argp) + mc_error (mc, loc, + _("Argument %s multiply specified in call to macro %s."), + p->name, mc->macro->name); + *argp = xzalloc (sizeof **argp); + mc->param = p; mc->n_tokens++; mc->state = MC_EQUALS; return 0; @@ -751,11 +761,9 @@ static int mc_equals (struct macro_call *mc, const struct macro_token *mt, const struct msg_location *loc) { - const struct token *token = &mt->token; - mc->n_tokens++; - - if (token->type == T_EQUALS) + if (mt->token.type == T_EQUALS) { + mc->n_tokens++; mc->state = mc->param->arg_type == ARG_ENCLOSE ? MC_ENCLOSE : MC_ARG; return 0; } @@ -801,7 +809,7 @@ macro_call_create__ (const struct macro_set *macros, /* If TOKEN is the first token of a call to a macro in MACROS, create a new macro expander, initializes *MCP to it. Returns 0 if more tokens are needed and should be added via macro_call_add() or 1 if the caller should next call - macro_call_get_expansion(). + macro_call_expand(). If TOKEN is not the first token of a macro call, returns -1 and sets *MCP to NULL. */ @@ -846,17 +854,14 @@ macro_call_destroy (struct macro_call *mc) Returns a positive number to indicate that the returned number of tokens invoke a macro. The number returned might be less than the number of tokens added because it can take a few tokens of lookahead to determine whether the - macro invocation is finished. The caller should call - macro_call_get_expansion() to obtain the expansion. */ + macro invocation is finished. The caller should call macro_call_expand() to + obtain the expansion. */ int macro_call_add (struct macro_call *mc, const struct macro_token *mt, const struct msg_location *loc) { switch (mc->state) { - case MC_ERROR: - return -1; - case MC_ARG: return mc_add_arg (mc, mt, loc); @@ -974,12 +979,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; ) { @@ -1031,7 +1031,8 @@ unquote_string (const char *s, enum segmenter_mode segmenter_mode, return false; } - ds_put_substring (content, token1.string); + if (content) + ds_put_substring (content, token1.string); token_uninit (&token1); return true; } @@ -1078,7 +1079,6 @@ expand_macro_function (const struct macro_expander *me, MF_HEAD, MF_INDEX, MF_LENGTH, - MF_NULL, MF_QUOTE, MF_SUBSTR, MF_TAIL, @@ -1092,7 +1092,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 }, @@ -1100,7 +1099,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++) { @@ -1115,13 +1123,14 @@ 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); if (!n_consumed) - return 0; + { + string_array_destroy (&args); + return 0; + } if (args.n < mf->min_args || args.n > mf->max_args) { @@ -1144,6 +1153,7 @@ expand_macro_function (const struct macro_expander *me, mf->name); else NOT_REACHED (); + string_array_destroy (&args); return 0; } @@ -1182,8 +1192,8 @@ expand_macro_function (const struct macro_expander *me, me->segmenter_mode, &tmp); struct macro_tokens mts = { .n = 0 }; - macro_tokens_from_string__ (&mts, ss_cstr (s), me->segmenter_mode, - me->stack); + macro_tokens_from_string (&mts, ss_cstr (s), me->segmenter_mode, + me->stack); if (mts.n > 0) ds_put_substring (output, mts.mts[0].syntax); macro_tokens_uninit (&mts); @@ -1252,8 +1262,8 @@ expand_macro_function (const struct macro_expander *me, me->segmenter_mode, &tmp); struct macro_tokens mts = { .n = 0 }; - macro_tokens_from_string__ (&mts, ss_cstr (s), me->segmenter_mode, - me->stack); + macro_tokens_from_string (&mts, ss_cstr (s), me->segmenter_mode, + me->stack); if (mts.n > 1) { struct macro_tokens tail = { .mts = mts.mts + 1, .n = mts.n - 1 }; @@ -1284,8 +1294,8 @@ expand_macro_function (const struct macro_expander *me, case MF_EVAL: { struct macro_tokens mts = { .n = 0 }; - macro_tokens_from_string__ (&mts, ss_cstr (args.strings[0]), - me->segmenter_mode, me->stack); + macro_tokens_from_string (&mts, ss_cstr (args.strings[0]), + me->segmenter_mode, me->stack); struct macro_tokens exp = { .n = 0 }; struct macro_expansion_stack stack = { .name = "!EVAL", @@ -1553,7 +1563,7 @@ macro_evaluate_number (const struct macro_token **tokens, size_t n_tokens, return false; struct macro_tokens mts = { .n = 0 }; - macro_tokens_from_string__ (&mts, ss_cstr (s), me->segmenter_mode, me->stack); + macro_tokens_from_string (&mts, ss_cstr (s), me->segmenter_mode, me->stack); if (mts.n != 1 || !token_is_number (&mts.mts[0].token)) { macro_error (me->stack, mts.n > 0 ? &mts.mts[0] : NULL, @@ -1795,8 +1805,8 @@ macro_expand_do (const struct macro_token *tokens, size_t n_tokens, return 0; struct macro_tokens items = { .n = 0 }; - macro_tokens_from_string__ (&items, ss_cstr (list), me->segmenter_mode, - me->stack); + macro_tokens_from_string (&items, ss_cstr (list), me->segmenter_mode, + me->stack); free (list); const struct macro_token *do_end = find_doend (subme.stack, p, end); @@ -1822,6 +1832,7 @@ macro_expand_do (const struct macro_token *tokens, size_t n_tokens, macro_expand (p, do_end - p, &subme, exp); } + macro_tokens_uninit (&items); return do_end - tokens + 1; } else if (p < end && p->token.type == T_EQUALS) @@ -1961,8 +1972,8 @@ macro_expand_arg (const struct token *token, const struct macro_expander *me, token->string.length); if (var) { - macro_tokens_from_string__ (exp, ss_cstr (var), - me->segmenter_mode, me->stack); + macro_tokens_from_string (exp, ss_cstr (var), + me->segmenter_mode, me->stack); return true; } @@ -2032,8 +2043,8 @@ macro_expand__ (const struct macro_token *mts, size_t n, size_t n_function = expand_macro_function (me, mts, n, &function_output); if (n_function) { - macro_tokens_from_string__ (exp, function_output.ss, - me->segmenter_mode, me->stack); + macro_tokens_from_string (exp, function_output.ss, + me->segmenter_mode, me->stack); ds_destroy (&function_output); return n_function;