X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flanguage%2Fcontrol%2Fdefine.c;h=2f5ffd9d6b7d0ed9b6b4516c2792a7bd5bd1f5a0;hb=84e4c83cf9efa6e41f0514c3cb885f54d1030386;hp=958ae5035cdb8890c6b4c6038fee43f693727132;hpb=237ba2110e3ceef00deffa01bd87189a269ca387;p=pspp diff --git a/src/language/control/define.c b/src/language/control/define.c index 958ae5035c..2f5ffd9d6b 100644 --- a/src/language/control/define.c +++ b/src/language/control/define.c @@ -68,9 +68,68 @@ parse_quoted_token (struct lexer *lexer, struct token *token) 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) { @@ -92,19 +151,34 @@ 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. */ @@ -113,7 +187,6 @@ cmd_define (struct lexer *lexer, struct dataset *ds UNUSED) 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)) { @@ -122,12 +195,7 @@ cmd_define (struct lexer *lexer, struct dataset *ds UNUSED) 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); } } @@ -181,20 +249,25 @@ cmd_define (struct lexer *lexer, struct dataset *ds UNUSED) 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;