table: Drop support for -1 as style to table_hline(), table_vline().
[pspp] / src / language / lexer / lexer.c
index cdfc84836085377fd006518301491eed087269d3..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
@@ -519,18 +520,22 @@ void
 void
 lex_error_expecting_valist (struct lexer *lexer, va_list args)
 {
-  enum { MAX_OPTIONS = 9 };
-  const char *options[MAX_OPTIONS];
-  int n = 0;
-  while (n < MAX_OPTIONS)
+  const char **options = NULL;
+  size_t allocated = 0;
+  size_t n = 0;
+
+  for (;;)
     {
       const char *option = va_arg (args, const char *);
       if (!option)
         break;
 
+      if (n >= allocated)
+        options = x2nrealloc (options, &allocated, sizeof *options);
       options[n++] = option;
     }
   lex_error_expecting_array (lexer, options, n);
+  free (options);
 }
 
 void
@@ -614,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
@@ -1630,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,
@@ -1657,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,
@@ -1669,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
@@ -1866,9 +1899,11 @@ void
 lex_discard_noninteractive (struct lexer *lexer)
 {
   struct lex_source *src = lex_source__ (lexer);
-
   if (src != NULL)
     {
+      if (src->reader->error == LEX_ERROR_IGNORE)
+        return;
+
       lex_stage_clear (&src->pp);
       lex_stage_clear (&src->merge);
       lex_source_clear_parse (src);
@@ -1923,6 +1958,12 @@ lex_source__ (const struct lexer *lexer)
           : ll_data (ll_head (&lexer->sources), struct lex_source, ll));
 }
 
+const struct lex_source *
+lex_source (const struct lexer *lexer)
+{
+  return lex_source__ (lexer);
+}
+
 /* Returns the text of the syntax in SRC for tokens with offsets OFS0 through
    OFS1 in the current command, inclusive.  (For example, if OFS0 and OFS1 are
    both zero, this requests the syntax for the first token in the current
@@ -2590,9 +2631,7 @@ lex_reader_for_substring_nocopy (struct substring s, const char *encoding)
 struct lex_reader *
 lex_reader_for_string (const char *s, const char *encoding)
 {
-  struct substring ss;
-  ss_alloc_substring (&ss, ss_cstr (s));
-  return lex_reader_for_substring_nocopy (ss, encoding);
+  return lex_reader_for_substring_nocopy (ss_clone (ss_cstr (s)), encoding);
 }
 
 /* Formats FORMAT as a printf()-like format string and creates and returns a