lexer: New function lex_force_match_phrase().
authorBen Pfaff <blp@cs.stanford.edu>
Sun, 25 Sep 2022 23:01:26 +0000 (16:01 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Sun, 6 Nov 2022 19:23:27 +0000 (11:23 -0800)
12 files changed:
src/language/data-io/data-reader.c
src/language/dictionary/attributes.c
src/language/dictionary/mrsets.c
src/language/lexer/lexer.c
src/language/lexer/lexer.h
src/language/stats/ctables.c
src/language/stats/npar.c
src/language/utilities/host.c
tests/language/data-io/inpt-pgm.at
tests/language/stats/aggregate.at
tests/language/stats/ctables.at
tests/language/stats/npar.at

index d34067e81910005d088c0410f711091e1b6e22dd..6e8c82bf0b673b41ec6a23ae83fa14ebcfadced4 100644 (file)
@@ -216,8 +216,7 @@ read_inline_record (struct dfm_reader *r)
       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);
index 954314ef4fb07339f599e8f6974582e5b1cf00c3..e646af3847ed45e8cc4ec58d98c583838e850562 100644 (file)
@@ -59,8 +59,7 @@ cmd_variable_attribute (struct lexer *lexer, struct dataset *ds)
       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;
 
index ffd97b68002342f4513ba9881ead70dd5bc86ec8..9c91ba9861f5aebcb00b0689bbbf34fe8bc8a2e7 100644 (file)
@@ -147,8 +147,7 @@ parse_group (struct lexer *lexer, struct dictionary *dict,
         }
       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;
@@ -504,8 +503,7 @@ static bool
 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);
index a2a0da9713c8f044398af94c0cb5c94580a095a7..35a9afa381f038968fafb27c05a87d57e408b176 100644 (file)
@@ -85,7 +85,8 @@ static struct msg_point lex_token_start_point (const struct lex_source *,
 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
@@ -618,7 +619,7 @@ lex_sbc_only_once (struct lexer *lexer, const char *sbc)
 
   /* 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
@@ -1634,22 +1635,31 @@ lex_tokens_match (const struct token *actual, const struct token *expected)
     }
 }
 
-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,
@@ -1661,7 +1671,7 @@ lex_ofs_at_phrase__ (struct lexer *lexer, int ofs, const char *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,
@@ -1673,10 +1683,29 @@ lex_at_phrase (struct lexer *lexer, const char *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
index b172ac610fb80c119f5b12db11a7492786c11ac0..ae40a87a04253894669fb6e274d6307ea507a4c7 100644 (file)
@@ -127,6 +127,7 @@ bool lex_match_id_n (struct lexer *, const char *, size_t n);
 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;
index dd0978731bbce5da5c4910ed7e837d9d18334437..5359c4cabd3d010a8dd2c6ef55eeb44c31108ee7 100644 (file)
@@ -5710,9 +5710,7 @@ ctables_parse_pcompute (struct lexer *lexer, struct dictionary *dict,
   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;
index 5dabe25a16d6802a76720699e75328d1a9fb3d29..713c543d08e3f4e5ea3aec0b22a20a57e17e049f 100644 (file)
@@ -423,8 +423,7 @@ npar_runs (struct lexer *lexer, struct dataset *ds,
       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),
@@ -756,8 +755,7 @@ parse_two_sample_related_test (struct lexer *lexer,
 
       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;
 
index 45fca6175b86b17934c9417d746a19d4fa0ca10d..22d25c0eb09711e45cf5d07ce4fa84b0ac862416 100644 (file)
@@ -293,9 +293,7 @@ cmd_host (struct lexer *lexer, struct dataset *ds UNUSED)
       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;
 
index a0054588dad8dfd5d24993daca36d7f068e6f71b..1c61d52fe73caa922f59b1cde5ffd67c3efe250a 100644 (file)
@@ -46,7 +46,7 @@ END INPUT PROGRAM.
 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
 
index f4f0fee6650f6fd09d486e55944eeb9a4c77b38f..a76870289b79df96bfa7a4c5d5dc868f66d47569 100644 (file)
@@ -502,7 +502,7 @@ aggregate.sps:16: error: AGGREGATE: Number of source variables (1) does not matc
    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)**.
       | ^~~~~~~~~"
 
index 63a8cdfd288c11625d0269a4d49e190f057efc03..7aca64e3a9bfb73b179c94eb601f492a820f0e08 100644 (file)
@@ -413,17 +413,17 @@ ctables.sps:42.20: error: CTABLES: Syntax error expecting identifier.
    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).
index 2836b4685b0fd4156e432b2af0faf8ff52001e54..1857a04606ea005934c2cd7e9b1c73dc81dc270f 100644 (file)
@@ -2007,7 +2007,7 @@ AT_CHECK([pspp -O format=csv npar.sps], [1], [dnl
     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 **).
       |                       ^~"
 
@@ -2019,7 +2019,7 @@ AT_CHECK([pspp -O format=csv npar.sps], [1], [dnl
     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 **.
       |                        ^~"
 
@@ -2139,13 +2139,13 @@ AT_CHECK([pspp -O format=csv npar.sps], [1], [dnl
    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).