X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flanguage%2Flexer%2Fmacro.c;h=e5805f035670b33e7b6f62aea55b58a623818ad4;hb=2031b99a3f1970a0b9a840652f0aff80ec34b433;hp=22e92ca05e911c32e289aaedf081a664d4fb2c46;hpb=d9f3677d790ba79e58efef7aceda64cfaae451f3;p=pspp diff --git a/src/language/lexer/macro.c b/src/language/lexer/macro.c index 22e92ca05e..e5805f0356 100644 --- a/src/language/lexer/macro.c +++ b/src/language/lexer/macro.c @@ -334,6 +334,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 +343,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 +362,7 @@ classify_token (enum token_type type) return TC_BINOP; case T_COMMA: + case T_SEMICOLON: return TC_COMMA; } @@ -418,24 +422,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 +502,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, @@ -543,12 +528,17 @@ struct macro_call const struct macro *macro; struct macro_tokens **args; const struct macro_expansion_stack *stack; + const struct macro_expander *me; enum mc_state state; size_t n_tokens; const struct macro_param *param; /* Parameter currently being parsed. */ }; +static bool macro_expand_arg (const struct token *, + const struct macro_expander *, + struct macro_tokens *exp); + /* Completes macro expansion by initializing arguments that weren't supplied to their defaults. */ static int @@ -615,48 +605,82 @@ 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); - struct macro_tokens *arg = *argp; - if (p->arg_type == ARG_N_TOKENS) - { - macro_tokens_add (arg, mt); - if (arg->n >= p->n_tokens) - return mc_next_arg (mc); - return 0; - } - else if (p->arg_type == ARG_CMDEND) + + bool add_token; /* Should we add 'mt' to the current arg? */ + bool next_arg; /* Should we advance to the next arg? */ + switch (p->arg_type) { - if (token->type == T_ENDCMD || token->type == T_STOP) - return mc_next_arg (mc); - macro_tokens_add (arg, mt); - return 0; + case ARG_N_TOKENS: + next_arg = (*argp)->n + 1 >= p->n_tokens; + add_token = true; + 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 (); } - else + + if (add_token) { - const struct token *end - = p->arg_type == ARG_CHAREND ? &p->charend : &p->enclose[1]; - if (token_equal (token, end)) - return mc_next_arg (mc); - macro_tokens_add (arg, mt); - return 0; + if (!macro_expand_arg (&mt->token, mc->me, *argp)) + macro_tokens_add (*argp, mt); } + return next_arg ? mc_next_arg (mc) : 0; } static int @@ -673,8 +697,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 @@ -682,15 +705,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 * @@ -724,17 +753,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; @@ -747,11 +773,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; } @@ -762,6 +786,7 @@ mc_equals (struct macro_call *mc, const struct macro_token *mt, static int macro_call_create__ (const struct macro_set *macros, const struct macro_expansion_stack *stack, + const struct macro_expander *me, const struct token *token, struct macro_call **mcp) { @@ -786,6 +811,7 @@ macro_call_create__ (const struct macro_set *macros, .args = macro->n_params ? xcalloc (macro->n_params, sizeof *mc->args) : NULL, .param = macro->params, .stack = stack, + .me = me, }; *mcp = mc; @@ -804,7 +830,7 @@ macro_call_create (const struct macro_set *macros, const struct token *token, struct macro_call **mcp) { - return macro_call_create__ (macros, NULL, token, mcp); + return macro_call_create__ (macros, NULL, NULL, token, mcp); } void @@ -848,9 +874,6 @@ macro_call_add (struct macro_call *mc, const struct macro_token *mt, { switch (mc->state) { - case MC_ERROR: - return -1; - case MC_ARG: return mc_add_arg (mc, mt, loc); @@ -897,16 +920,6 @@ expand_macro_function (const struct macro_expander *me, const struct macro_token *input, size_t n_input, struct string *output); -/* Returns true if the N tokens within MTS start with !*, false otherwise. */ -static bool -is_bang_star (const struct macro_token *mts, size_t n) -{ - return (n > 1 - && mts[0].token.type == T_MACRO_ID - && ss_equals (mts[0].token.string, ss_cstr ("!")) - && mts[1].token.type == T_ASTERISK); -} - /* Parses one function argument from the N_INPUT tokens in INPUT Each argument to a macro function is one of: @@ -941,7 +954,7 @@ parse_function_arg (const struct macro_expander *me, return 1; } - if (is_bang_star (input, n_input)) + if (ss_equals (token->string, ss_cstr ("!*"))) { for (size_t i = 0; i < me->macro->n_params; i++) { @@ -951,7 +964,7 @@ parse_function_arg (const struct macro_expander *me, ds_put_byte (farg, ' '); macro_tokens_to_syntax (me->args[i], farg, NULL, NULL); } - return 2; + return 1; } const char *var = stringi_map_find__ (me->vars, @@ -978,12 +991,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; ) { @@ -1035,7 +1043,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; } @@ -1082,7 +1091,6 @@ expand_macro_function (const struct macro_expander *me, MF_HEAD, MF_INDEX, MF_LENGTH, - MF_NULL, MF_QUOTE, MF_SUBSTR, MF_TAIL, @@ -1096,7 +1104,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 }, @@ -1104,7 +1111,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++) { @@ -1119,13 +1135,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) { @@ -1148,6 +1165,7 @@ expand_macro_function (const struct macro_expander *me, mf->name); else NOT_REACHED (); + string_array_destroy (&args); return 0; } @@ -1826,6 +1844,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) @@ -1903,7 +1922,7 @@ macro_expand_do (const struct macro_token *tokens, size_t n_tokens, } static void -macro_expand_arg (const struct macro_expander *me, size_t idx, +macro_expand_arg__ (const struct macro_expander *me, size_t idx, struct macro_tokens *exp) { const struct macro_param *param = &me->macro->params[idx]; @@ -1935,6 +1954,44 @@ macro_expand_arg (const struct macro_expander *me, size_t idx, macro_tokens_add (exp, &arg->mts[i]); } +static bool +macro_expand_arg (const struct token *token, const struct macro_expander *me, + struct macro_tokens *exp) +{ + if (!me || token->type != T_MACRO_ID) + return false; + + /* Macro arguments. */ + if (me->macro) + { + const struct macro_param *param = macro_find_parameter_by_name ( + me->macro, token->string); + if (param) + { + macro_expand_arg__ (me, param - me->macro->params, exp); + return true; + } + else if (ss_equals (token->string, ss_cstr ("!*"))) + { + for (size_t j = 0; j < me->macro->n_params; j++) + macro_expand_arg__ (me, j, exp); + return true; + } + } + + /* Variables set by !DO or !LET. */ + const char *var = stringi_map_find__ (me->vars, token->string.string, + token->string.length); + if (var) + { + macro_tokens_from_string__ (exp, ss_cstr (var), + me->segmenter_mode, me->stack); + return true; + } + + return false; +} + static size_t macro_expand__ (const struct macro_token *mts, size_t n, const struct macro_expander *me, @@ -1946,7 +2003,8 @@ macro_expand__ (const struct macro_token *mts, size_t n, if (*me->expand) { struct macro_call *submc; - int n_call = macro_call_create__ (me->macros, me->stack, token, &submc); + int n_call = macro_call_create__ (me->macros, me->stack, me, + token, &submc); for (size_t j = 1; !n_call; j++) { const struct macro_token endcmd @@ -1988,33 +2046,9 @@ macro_expand__ (const struct macro_token *mts, size_t n, return 1; } - /* Parameters. */ - if (me->macro) - { - const struct macro_param *param = macro_find_parameter_by_name ( - me->macro, token->string); - if (param) - { - macro_expand_arg (me, param - me->macro->params, exp); - return 1; - } - else if (is_bang_star (mts, n)) - { - for (size_t j = 0; j < me->macro->n_params; j++) - macro_expand_arg (me, j, exp); - return 2; - } - } - - /* Variables set by !DO or !LET. */ - const char *var = stringi_map_find__ (me->vars, token->string.string, - token->string.length); - if (var) - { - macro_tokens_from_string__ (exp, ss_cstr (var), - me->segmenter_mode, me->stack); - return 1; - } + /* Parameters and macro variables. */ + if (macro_expand_arg (token, me, exp)) + return 1; /* Macro functions. */ struct string function_output = DS_EMPTY_INITIALIZER;