X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flanguage%2Fcontrol%2Fdefine.c;h=c439c64571b75d2637c3e79df5980584e71ba9a7;hb=f41e87501f3a3c600f4443033799b1689f84270a;hp=f33e885925a807b67071d1832b2de8442f3c7845;hpb=0fde6afee3c995bf264c24c438f43eeb58b859b5;p=pspp diff --git a/src/language/control/define.c b/src/language/control/define.c index f33e885925..c439c64571 100644 --- a/src/language/control/define.c +++ b/src/language/control/define.c @@ -77,8 +77,9 @@ dup_arg_type (struct lexer *lexer, bool *saw_arg_type) { if (*saw_arg_type) { - lex_error (lexer, _("Only one of !TOKENS, !CHAREND, !ENCLOSE, or " - "!CMDEND is allowed.")); + lex_next_error (lexer, -1, -1, + _("Only one of !TOKENS, !CHAREND, !ENCLOSE, or " + "!CMDEND is allowed.")); return false; } else @@ -88,6 +89,80 @@ dup_arg_type (struct lexer *lexer, bool *saw_arg_type) } } +static bool +parse_macro_body (struct lexer *lexer, struct macro_tokens *mts) +{ + *mts = (struct macro_tokens) { .n = 0 }; + struct string body = DS_EMPTY_INITIALIZER; + struct msg_point start = lex_ofs_start_point (lexer, lex_ofs (lexer)); + while (!match_macro_id (lexer, "!ENDDEFINE")) + { + if (lex_token (lexer) != T_STRING) + { + lex_error (lexer, + _("Syntax error expecting macro body or !ENDDEFINE.")); + ds_destroy (&body); + return false; + } + + ds_put_substring (&body, lex_tokss (lexer)); + ds_put_byte (&body, '\n'); + lex_get (lexer); + } + + struct segmenter segmenter = segmenter_init (lex_get_syntax_mode (lexer), + true); + struct substring p = body.ss; + bool ok = true; + while (p.length > 0) + { + enum segment_type type; + int seg_len = segmenter_push (&segmenter, p.string, + p.length, true, &type); + assert (seg_len >= 0); + + struct macro_token mt = { + .token = { .type = T_STOP }, + .syntax = ss_head (p, seg_len), + }; + enum tokenize_result result + = token_from_segment (type, mt.syntax, &mt.token); + ss_advance (&p, seg_len); + + switch (result) + { + case TOKENIZE_EMPTY: + break; + + case TOKENIZE_TOKEN: + macro_tokens_add (mts, &mt); + break; + + case TOKENIZE_ERROR: + { + size_t start_offset = mt.syntax.string - body.ss.string; + size_t end_offset = start_offset + (mt.syntax.length ? mt.syntax.length - 1 : 0); + + const struct msg_location loc = { + .file_name = intern_new_if_nonnull (lex_get_file_name (lexer)), + .start = msg_point_advance (start, ss_buffer (body.ss.string, start_offset)), + .end = msg_point_advance (start, ss_buffer (body.ss.string, end_offset)), + .src = CONST_CAST (struct lex_source *, lex_source (lexer)), + }; + msg_at (SE, &loc, "%s", mt.token.string.string); + intern_unref (loc.file_name); + + ok = false; + } + break; + } + + token_uninit (&mt.token); + } + ds_destroy (&body); + return ok; +} + int cmd_define (struct lexer *lexer, struct dataset *ds UNUSED) { @@ -98,31 +173,26 @@ cmd_define (struct lexer *lexer, struct dataset *ds UNUSED) macro-expanded. */ if (lex_token (lexer) != T_STRING) { - lex_error (lexer, _("expecting identifier")); + lex_error (lexer, _("Syntax error expecting identifier.")); return CMD_FAILURE; } const char *name = lex_tokcstr (lexer); - if (!id_is_plausible (name + (name[0] == '!'), false)) + if (!id_is_plausible (name + (name[0] == '!'))) { - lex_error (lexer, _("expecting identifier")); + lex_error (lexer, _("Syntax error expecting identifier.")); return CMD_FAILURE; } struct macro *m = xmalloc (sizeof *m); - *m = (struct macro) { - .name = xstrdup (name), - .location = xmalloc (sizeof *m->location), - }; - *m->location = (struct msg_location) { - .file_name = intern_new_if_nonnull (lex_get_file_name (lexer)), - .first_line = lex_get_first_line_number (lexer, 0), - }; + *m = (struct macro) { .name = xstrdup (name) }; + struct msg_point macro_start = lex_ofs_start_point (lexer, lex_ofs (lexer)); lex_get (lexer); if (!lex_force_match (lexer, T_LPAREN)) goto error; size_t allocated_params = 0; + int keyword_ofs = 0; while (!lex_match (lexer, T_RPAREN)) { if (m->n_params >= allocated_params) @@ -138,8 +208,11 @@ cmd_define (struct lexer *lexer, struct dataset *ds UNUSED) { if (param_index > 0 && !m->params[param_index - 1].positional) { - lex_error (lexer, _("Positional parameters must precede " - "keyword parameters.")); + lex_next_error (lexer, -1, -1, + _("Positional parameters must precede " + "keyword parameters.")); + lex_ofs_msg (lexer, SN, keyword_ofs, keyword_ofs, + _("Here is a previous keyword parameter.")); goto error; } @@ -148,6 +221,8 @@ cmd_define (struct lexer *lexer, struct dataset *ds UNUSED) } else { + if (keyword_ofs == 0) + keyword_ofs = lex_ofs (lexer); if (lex_token (lexer) == T_MACRO_ID) { lex_error (lexer, _("Keyword macro parameter must be named in " @@ -179,8 +254,9 @@ cmd_define (struct lexer *lexer, struct dataset *ds UNUSED) { if (saw_default) { - lex_error (lexer, - _("!DEFAULT is allowed only once per argument.")); + lex_next_error ( + lexer, -1, -1, + _("!DEFAULT is allowed only once per argument.")); goto error; } saw_default = true; @@ -268,24 +344,16 @@ cmd_define (struct lexer *lexer, struct dataset *ds UNUSED) goto error; } - 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; - } - - ds_put_substring (&body, lex_tokss (lexer)); - ds_put_byte (&body, '\n'); - lex_get (lexer); - } - m->location->last_line = lex_get_last_line_number (lexer, 0); + if (!parse_macro_body (lexer, &m->body)) + goto error; - macro_tokens_from_string (&m->body, body.ss, lex_get_syntax_mode (lexer)); - ds_destroy (&body); + struct msg_point macro_end = lex_ofs_end_point (lexer, lex_ofs (lexer) - 1); + m->location = xmalloc (sizeof *m->location); + *m->location = (struct msg_location) { + .file_name = intern_new_if_nonnull (lex_get_file_name (lexer)), + .start = { .line = macro_start.line }, + .end = { .line = macro_end.line }, + }; lex_define_macro (lexer, m);