lex_error (lexer, _("String must contain exactly one token."));
return false;
}
+ lex_get (lexer);
return true;
}
+static void
+macro_tokenize (struct macro *m, struct lexer *lexer)
+{
+ struct state
+ {
+ struct segmenter segmenter;
+ struct substring body;
+ };
+
+ struct state state = {
+ .segmenter = SEGMENTER_INIT (lex_get_syntax_mode (lexer)),
+ .body = m->body,
+ };
+ struct state saved = state;
+
+ struct token token = { .type = T_STOP };
+
+ while (state.body.length > 0)
+ {
+ struct scanner scanner;
+ scanner_init (&scanner, &token);
+
+ for (;;)
+ {
+ enum segment_type type;
+ int seg_len = segmenter_push (&state.segmenter, state.body.string,
+ state.body.length, true, &type);
+ assert (seg_len >= 0);
+
+ struct substring segment = ss_head (state.body, seg_len);
+ ss_advance (&state.body, seg_len);
+
+ enum scan_result result = scanner_push (&scanner, type, segment, &token);
+ if (result == SCAN_SAVE)
+ saved = state;
+ else if (result == SCAN_BACK)
+ {
+ state = saved;
+ break;
+ }
+ else if (result == SCAN_DONE)
+ break;
+ }
+
+ /* We have a token in 'token'. */
+ if (is_scan_type (token.type))
+ {
+ if (token.type != SCAN_SKIP)
+ {
+ /* XXX report error */
+ }
+ }
+ else
+ tokens_add (&m->body_tokens, &token);
+ token_destroy (&token);
+ }
+}
+
int
cmd_define (struct lexer *lexer, struct dataset *ds UNUSED)
{
m->params = x2nrealloc (m->params, &allocated_params,
sizeof *m->params);
- struct macro_param *p = &m->params[m->n_params++];
+ size_t param_index = m->n_params++;
+ struct macro_param *p = &m->params[param_index];
*p = (struct macro_param) { .expand_arg = true };
/* Parse parameter name. */
if (match_macro_id (lexer, "!POSITIONAL"))
- p->name = NULL;
+ {
+ if (param_index > 0 && !m->params[param_index - 1].positional)
+ {
+ lex_error (lexer, _("Positional parameters must precede "
+ "keyword parameters."));
+ goto error;
+ }
+
+ p->positional = true;
+ p->name = xasprintf ("!%zu", param_index + 1);
+ }
else
{
- if (!lex_force_id (lexer) || !lex_force_match (lexer, T_EQUALS))
+ if (!lex_force_id (lexer))
goto error;
- p->name = ss_xstrdup (lex_tokss (lexer));
+ p->positional = false;
+ p->name = xasprintf ("!%s", lex_tokcstr (lexer));
lex_get (lexer);
+
+ if (!lex_force_match (lexer, T_EQUALS))
+ goto error;
}
/* Parse default value. */
if (!lex_force_match (lexer, T_LPAREN))
goto error;
- size_t allocated_tokens = 0;
/* XXX Should this handle balanced inner parentheses? */
while (!lex_match (lexer, T_RPAREN))
{
lex_error_expecting (lexer, ")");
goto error;
}
- if (allocated_tokens >= p->def.n)
- p->def.tokens = x2nrealloc (p->def.tokens, &allocated_tokens,
- sizeof *p->def.tokens);
-
- struct token *token = &p->def.tokens[p->def.n++];
- token_copy (token, lex_next (lexer, 0));
+ tokens_add (&p->def, lex_next (lexer, 0));
lex_get (lexer);
}
}
goto error;
}
- size_t allocated_body = 0;
+ struct string body = DS_EMPTY_INITIALIZER;
while (!match_macro_id (lexer, "!ENDDEFINE"))
{
if (lex_token (lexer) != T_STRING)
{
lex_error (lexer, _("Expecting macro body or !ENDDEFINE"));
+ ds_destroy (&body);
goto error;
}
- if (allocated_body >= m->n_body)
- m->body = x2nrealloc (m->body, &allocated_body, sizeof *m->body);
- m->body[m->n_body] = ss_xstrdup (lex_tokss (lexer));
+ ds_put_substring (&body, lex_tokss (lexer));
+ ds_put_byte (&body, '\n');
lex_get (lexer);
}
+ m->body = ds_ss (&body);
+
+ macro_tokenize (m, lexer);
+
+ lex_define_macro (lexer, m);
return CMD_SUCCESS;