while (lex_token (r->lexer) == T_ENDCMD)
lex_get (r->lexer);
- if (!lex_force_match_id (r->lexer, "BEGIN")
- || !lex_force_match_id (r->lexer, "DATA"))
+ if (!lex_force_match_phrase (r->lexer, "BEGIN DATA"))
return false;
lex_match (r->lexer, T_ENDCMD);
size_t n_vars, i;
bool ok;
- if (!lex_force_match_id (lexer, "VARIABLES")
- || !lex_force_match (lexer, T_EQUALS)
+ if (!lex_force_match_phrase (lexer, "VARIABLES=")
|| !parse_variables (lexer, dict, &vars, &n_vars, PV_NONE))
return CMD_FAILURE;
}
else if (type == MRSET_MD && lex_match_id (lexer, "LABELSOURCE"))
{
- if (!lex_force_match (lexer, T_EQUALS)
- || !lex_force_match_id (lexer, "VARLABEL"))
+ if (!lex_force_match_phrase (lexer, "=VARLABEL"))
goto error;
labelsource_varlabel = true;
parse_mrset_names (struct lexer *lexer, struct dictionary *dict,
struct stringi_set *mrset_names)
{
- if (!lex_force_match_id (lexer, "NAME")
- || !lex_force_match (lexer, T_EQUALS))
+ if (!lex_force_match_phrase (lexer, "NAME="))
return false;
stringi_set_init (mrset_names);
static struct msg_point lex_token_end_point (const struct lex_source *,
const struct lex_token *);
-static size_t lex_ofs_at_phrase__ (struct lexer *, int ofs, const char *s);
+static bool lex_ofs_at_phrase__ (struct lexer *, int ofs, const char *s,
+ size_t *n_matchedp);
/* Source offset of the last byte in TOKEN. */
static size_t
/* lex_ofs_at_phrase__() handles subcommand names that are keywords, such as
BY. */
- if (lex_ofs_at_phrase__ (lexer, ofs, sbc))
+ if (lex_ofs_at_phrase__ (lexer, ofs, sbc, NULL))
lex_ofs_error (lexer, ofs, ofs,
_("Subcommand %s may only be specified once."), sbc);
else
}
}
-static size_t
-lex_ofs_at_phrase__ (struct lexer *lexer, int ofs, const char *s)
+static bool
+lex_ofs_at_phrase__ (struct lexer *lexer, int ofs, const char *s,
+ size_t *n_matchedp)
{
struct string_lexer slex;
struct token token;
- size_t i = 0;
+ size_t n_matched = 0;
+ bool all_matched = true;
string_lexer_init (&slex, s, strlen (s), SEG_MODE_INTERACTIVE, true);
while (string_lexer_next (&slex, &token))
{
- bool match = lex_tokens_match (lex_ofs_token (lexer, ofs + i++), &token);
+ bool match = lex_tokens_match (lex_ofs_token (lexer, ofs + n_matched),
+ &token);
token_uninit (&token);
if (!match)
- return 0;
+ {
+ all_matched = false;
+ break;
+ }
+ n_matched++;
}
- return i;
+ if (n_matchedp)
+ *n_matchedp = n_matched;
+ return all_matched;
}
/* If LEXER is positioned at the sequence of tokens that may be parsed from S,
bool
lex_at_phrase (struct lexer *lexer, const char *s)
{
- return lex_ofs_at_phrase__ (lexer, lex_ofs (lexer), s) > 0;
+ return lex_ofs_at_phrase__ (lexer, lex_ofs (lexer), s, NULL);
}
/* If LEXER is positioned at the sequence of tokens that may be parsed from S,
bool
lex_match_phrase (struct lexer *lexer, const char *s)
{
- size_t n = lex_ofs_at_phrase__ (lexer, lex_ofs (lexer), s);
- if (n > 0)
- lex_get_n (lexer, n);
- return n > 0;
+ size_t n_matched;
+ if (!lex_ofs_at_phrase__ (lexer, lex_ofs (lexer), s, &n_matched))
+ return false;
+ lex_get_n (lexer, n_matched);
+ return true;
+}
+
+/* If LEXER is positioned at the sequence of tokens that may be parsed from S,
+ skips it and returns true. Otherwise, issues an error and returns false.
+
+ S may consist of an arbitrary sequence of tokens, e.g. "KRUSKAL-WALLIS",
+ "2SLS", or "END INPUT PROGRAM". Identifiers may be abbreviated to their
+ first three letters. */
+bool
+lex_force_match_phrase (struct lexer *lexer, const char *s)
+{
+ size_t n_matched;
+ bool ok = lex_ofs_at_phrase__ (lexer, lex_ofs (lexer), s, &n_matched);
+ if (ok)
+ lex_get_n (lexer, n_matched);
+ else
+ lex_next_error (lexer, 0, n_matched, _("Syntax error expecting `%s'."), s);
+ return ok;
}
/* Returns the 1-based line number of the source text at the byte OFFSET in
bool lex_match_int (struct lexer *, int);
bool lex_at_phrase (struct lexer *, const char *s);
bool lex_match_phrase (struct lexer *, const char *s);
+bool lex_force_match_phrase (struct lexer *, const char *s);
/* Forcible matching functions. */
bool lex_force_match (struct lexer *, enum token_type) WARN_UNUSED_RESULT;
char *name = ss_xstrdup (lex_tokss (lexer));
lex_get (lexer);
- if (!lex_force_match (lexer, T_EQUALS)
- || !lex_force_match_id (lexer, "EXPR")
- || !lex_force_match (lexer, T_LPAREN))
+ if (!lex_force_match_phrase (lexer, "=EXPR("))
{
free (name);
return false;
return false;
}
- if (!lex_force_match (lexer, T_RPAREN)
- || !lex_force_match (lexer, T_EQUALS))
+ if (!lex_force_match_phrase (lexer, ")="))
return false;
if (!parse_variables_const_pool (lexer, specs->pool, dataset_dict (ds),
if (lex_match (lexer, T_LPAREN))
{
- if (!lex_force_match_id (lexer, "PAIRED")
- || !lex_force_match (lexer, T_RPAREN))
+ if (!lex_force_match_phrase (lexer, "PAIRED)"))
return false;
paired = true;
return CMD_FAILURE;
}
- if (!lex_force_match_id (lexer, "COMMAND")
- || !lex_force_match (lexer, T_EQUALS)
- || !lex_force_match (lexer, T_LBRACK)
+ if (!lex_force_match_phrase (lexer, "COMMAND=[")
|| !lex_force_string (lexer))
return CMD_FAILURE;
DESCRIPTIVES x.
])
AT_CHECK([pspp -O format=csv input-program.sps], [1], [dnl
-error: DESCRIPTIVES: At end of input: Syntax error expecting BEGIN.
+error: DESCRIPTIVES: At end of input: Syntax error expecting `BEGIN DATA'.
])
AT_CLEANUP
17 | AGGREGATE /y=pin(x, 2, 1).
| ^~~~"
-"aggregate.sps:18.1-18.9: error: AGGREGATE: Syntax error expecting BEGIN.
+"aggregate.sps:18.1-18.9: error: AGGREGATE: Syntax error expecting `BEGIN DATA'.
18 | AGGREGATE /y=mean(x)**.
| ^~~~~~~~~"
42 | CTABLES /PCOMPUTE &1.
| ^
-ctables.sps:43.21-43.22: error: CTABLES: Syntax error expecting `='.
+ctables.sps:43.21-43.22: error: CTABLES: Syntax error expecting `=EXPR@{:@'.
43 | CTABLES /PCOMPUTE &k**.
| ^~
-ctables.sps:44.22-44.23: error: CTABLES: Syntax error expecting EXPR.
+ctables.sps:44.21-44.23: error: CTABLES: Syntax error expecting `=EXPR@{:@'.
44 | CTABLES /PCOMPUTE &k=**.
- | ^~
+ | ^~~
-ctables.sps:45.26-45.27: error: CTABLES: Syntax error expecting `@{:@'.
+ctables.sps:45.21-45.27: error: CTABLES: Syntax error expecting `=EXPR@{:@'.
45 | CTABLES /PCOMPUTE &k=EXPR**.
- | ^~
+ | ^~~~~~~
ctables.sps:46.28: error: CTABLES: Syntax error expecting `@:}@'.
46 | CTABLES /PCOMPUTE &k=EXPR(1x).
6 | NPAR TESTS RUNS (**).
| ^~"
-"npar.sps:7.23-7.24: error: NPAR TESTS: Syntax error expecting `@:}@'.
+"npar.sps:7.23-7.24: error: NPAR TESTS: Syntax error expecting `@:}@='.
7 | NPAR TESTS RUNS (MEAN **).
| ^~"
9 | NPAR TESTS CHISQUARE **.
| ^~"
-"npar.sps:10.24-10.25: error: NPAR TESTS: Syntax error expecting BEGIN.
+"npar.sps:10.24-10.25: error: NPAR TESTS: Syntax error expecting `BEGIN DATA'.
10 | NPAR TESTS CHISQUARE x **.
| ^~"
38 | NPAR TESTS MCNEMAR x WITH **.
| ^~"
-"npar.sps:39.30-39.31: error: NPAR TESTS: Syntax error expecting PAIRED.
+"npar.sps:39.30-39.31: error: NPAR TESTS: Syntax error expecting `PAIRED@:}@'.
39 | NPAR TESTS MCNEMAR x WITH y (**).
| ^~"
-"npar.sps:40.37-40.38: error: NPAR TESTS: Syntax error expecting `@:}@'.
+"npar.sps:40.30-40.38: error: NPAR TESTS: Syntax error expecting `PAIRED)'.
40 | NPAR TESTS MCNEMAR x WITH y (PAIRED **).
- | ^~"
+ | ^~~~~~~~~"
"npar.sps:41.20-41.29: error: NPAR TESTS: PAIRED was specified, but the number of variables preceding WITH (1) does not match the number following (2).
41 | NPAR TESTS MCNEMAR x WITH y z (PAIRED).