lexer: New lex_at_phrase(), lex_get_n() functions.
[pspp] / src / language / lexer / lexer.c
index 6d9aec843ab80e94c197a8a7ee825b0e180bf2c1..27d5dedb5464728dd4186c2640b6d1f9531ef5d3 100644 (file)
@@ -379,6 +379,14 @@ lex_get (struct lexer *lexer)
           return;
       }
 }
+
+/* Advances LEXER by N tokens. */
+void
+lex_get_n (struct lexer *lexer, size_t n)
+{
+  while (n-- > 0)
+    lex_get (lexer);
+}
 \f
 /* Issuing errors. */
 
@@ -564,7 +572,8 @@ lex_next_error_valist (struct lexer *lexer, int n0, int n1,
           ds_put_cstr (&s, ": ");
           ds_put_vformat (&s, format, args);
         }
-      ds_put_byte (&s, '.');
+      if (ds_last (&s) != '.')
+        ds_put_byte (&s, '.');
       msg (SE, "%s", ds_cstr (&s));
       ds_destroy (&s);
     }
@@ -821,9 +830,14 @@ lex_force_int (struct lexer *lexer)
 bool
 lex_force_int_range (struct lexer *lexer, const char *name, long min, long max)
 {
+  bool is_number = lex_is_number (lexer);
   bool is_integer = lex_is_integer (lexer);
-  bool too_small = is_integer && lex_integer (lexer) < min;
-  bool too_big = is_integer && lex_integer (lexer) > max;
+  bool too_small = (is_integer ? lex_integer (lexer) < min
+                    : is_number ? lex_number (lexer) < min
+                    : false);
+  bool too_big = (is_integer ? lex_integer (lexer) > max
+                  : is_number ? lex_number (lexer) > max
+                  : false);
   if (is_integer && !too_small && !too_big)
     return true;
 
@@ -883,6 +897,14 @@ lex_force_int_range (struct lexer *lexer, const char *name, long min, long max)
               else
                 lex_error (lexer, _("Expected positive integer."));
             }
+          else
+            {
+              if (name)
+                lex_error (lexer, _("Expected integer %ld or greater for %s."),
+                           min, name);
+              else
+                lex_error (lexer, _("Expected integer %ld or greater."), min);
+            }
         }
       else if (report_upper_bound)
         {
@@ -1123,32 +1145,49 @@ lex_tokens_match (const struct token *actual, const struct token *expected)
     }
 }
 
-/* If LEXER is positioned at the sequence of tokens that may be parsed from S,
-   skips it and returns true.  Otherwise, 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_match_phrase (struct lexer *lexer, const char *s)
+static size_t
+lex_at_phrase__ (struct lexer *lexer, const char *s)
 {
   struct string_lexer slex;
   struct token token;
-  int i;
 
-  i = 0;
+  size_t i = 0;
   string_lexer_init (&slex, s, strlen (s), SEG_MODE_INTERACTIVE, true);
   while (string_lexer_next (&slex, &token))
     {
       bool match = lex_tokens_match (lex_next (lexer, i++), &token);
       token_uninit (&token);
       if (!match)
-        return false;
+        return 0;
     }
+  return i;
+}
 
-  while (i-- > 0)
-    lex_get (lexer);
-  return true;
+/* If LEXER is positioned at the sequence of tokens that may be parsed from S,
+   returns true.  Otherwise, 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_at_phrase (struct lexer *lexer, const char *s)
+{
+  return lex_at_phrase__ (lexer, s) > 0;
+}
+
+/* If LEXER is positioned at the sequence of tokens that may be parsed from S,
+   skips it and returns true.  Otherwise, 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_match_phrase (struct lexer *lexer, const char *s)
+{
+  size_t n = lex_at_phrase__ (lexer, s);
+  if (n > 0)
+    lex_get_n (lexer, n);
+  return n > 0;
 }
 
 static int
@@ -1899,27 +1938,32 @@ lex_source_try_get_merge (const struct lex_source *src_)
                                           _("Macro Expansion")));
 
   /* Append the macro expansion tokens to the lookahead. */
-  char *macro_rep = ds_steal_cstr (&s);
-  size_t *ref_cnt = xmalloc (sizeof *ref_cnt);
-  *ref_cnt = expansion.n;
-  for (size_t i = 0; i < expansion.n; i++)
+  if (expansion.n > 0)
     {
-      struct lex_token *token = xmalloc (sizeof *token);
-      *token = (struct lex_token) {
-        .token = expansion.mts[i].token,
-        .token_pos = c0->token_pos,
-        .token_len = (c1->token_pos + c1->token_len) - c0->token_pos,
-        .line_pos = c0->line_pos,
-        .first_line = c0->first_line,
-        .macro_rep = macro_rep,
-        .ofs = ofs[i],
-        .len = len[i],
-        .ref_cnt = ref_cnt,
-      };
-      lex_stage_push_last (&src->merge, token);
+      char *macro_rep = ds_steal_cstr (&s);
+      size_t *ref_cnt = xmalloc (sizeof *ref_cnt);
+      *ref_cnt = expansion.n;
+      for (size_t i = 0; i < expansion.n; i++)
+        {
+          struct lex_token *token = xmalloc (sizeof *token);
+          *token = (struct lex_token) {
+            .token = expansion.mts[i].token,
+            .token_pos = c0->token_pos,
+            .token_len = (c1->token_pos + c1->token_len) - c0->token_pos,
+            .line_pos = c0->line_pos,
+            .first_line = c0->first_line,
+            .macro_rep = macro_rep,
+            .ofs = ofs[i],
+            .len = len[i],
+            .ref_cnt = ref_cnt,
+          };
+          lex_stage_push_last (&src->merge, token);
 
-      ss_dealloc (&expansion.mts[i].syntax);
+          ss_dealloc (&expansion.mts[i].syntax);
+        }
     }
+  else
+    ds_destroy (&s);
   free (expansion.mts);
   free (ofs);
   free (len);
@@ -1952,6 +1996,7 @@ static bool
 lex_source_get_lookahead (struct lex_source *src)
 {
   struct merger m = MERGER_INIT;
+  struct token out;
   for (size_t i = 0; ; i++)
     {
       while (lex_stage_count (&src->merge) <= i && !lex_source_get_merge (src))
@@ -1963,7 +2008,6 @@ lex_source_get_lookahead (struct lex_source *src)
           return false;
         }
 
-      struct token out;
       int retval = merger_add (&m, &lex_stage_nth (&src->merge, i)->token,
                                &out);
       if (!retval)
@@ -1992,7 +2036,7 @@ lex_source_get_lookahead (struct lex_source *src)
             .macro_rep = macro ? first->macro_rep : NULL,
             .ofs = macro ? first->ofs : 0,
             .len = macro ? (last->ofs - first->ofs) + last->len : 0,
-            .ref_cnt = first->ref_cnt,
+            .ref_cnt = macro ? first->ref_cnt : NULL,
           };
           if (t->ref_cnt)
             ++*t->ref_cnt;