Remove unnecessary #include directives
[pspp] / src / language / lexer / lexer.c
index e72a3e47bc9637d93ad3c1f764b7099686df6d3d..b6cab8d6810e4479c9faff807388857809ad0e53 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2013 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -30,7 +30,6 @@
 #include <unistr.h>
 #include <uniwidth.h>
 
-#include "data/file-name.h"
 #include "language/command.h"
 #include "language/lexer/scan.h"
 #include "language/lexer/segment.h"
@@ -129,8 +128,9 @@ lex_reader_init (struct lex_reader *reader,
 {
   reader->class = class;
   reader->syntax = LEX_SYNTAX_AUTO;
-  reader->error = LEX_ERROR_INTERACTIVE;
+  reader->error = LEX_ERROR_CONTINUE;
   reader->file_name = NULL;
+  reader->encoding = NULL;
   reader->line_number = 0;
 }
 
@@ -830,99 +830,58 @@ lex_next_tokss (const struct lexer *lexer, int n)
   return lex_next (lexer, n)->string;
 }
 
-/* If LEXER is positioned at the (pseudo)identifier S, skips it and returns
-   true.  Otherwise, returns false.
-
-   S may consist of an arbitrary number of identifiers, integers, and
-   punctuation e.g. "KRUSKAL-WALLIS", "2SLS", or "END INPUT PROGRAM".
-   Identifiers may be abbreviated to their first three letters.  Currently only
-   hyphens, slashes, and equals signs are supported as punctuation (but it
-   would be easy to add more).
-
-   S must be an ASCII string. */
-bool
-lex_match_phrase (struct lexer *lexer, const char *s)
+static bool
+lex_tokens_match (const struct token *actual, const struct token *expected)
 {
-  int tok_idx;
+  if (actual->type != expected->type)
+    return false;
 
-  for (tok_idx = 0; ; tok_idx++)
+  switch (actual->type)
     {
-      enum token_type token;
-      unsigned char c;
+    case T_POS_NUM:
+    case T_NEG_NUM:
+      return actual->number == expected->number;
 
-      while (c_isspace (*s))
-        s++;
+    case T_ID:
+      return lex_id_match (expected->string, actual->string);
 
-      c = *s;
-      if (c == '\0')
-        {
-          int i;
-
-          for (i = 0; i < tok_idx; i++)
-            lex_get (lexer);
-          return true;
-        }
+    case T_STRING:
+      return (actual->string.length == expected->string.length
+              && !memcmp (actual->string.string, expected->string.string,
+                          actual->string.length));
 
-      token = lex_next_token (lexer, tok_idx);
-      switch (c)
-        {
-        case '-':
-          if (token != T_DASH)
-            return false;
-          s++;
-          break;
-
-        case '/':
-          if (token != T_SLASH)
-            return false;
-          s++;
-          break;
-
-        case '=':
-          if (token != T_EQUALS)
-            return false;
-          s++;
-          break;
-
-        case '0': case '1': case '2': case '3': case '4':
-        case '5': case '6': case '7': case '8': case '9':
-          {
-            unsigned int value;
-
-            if (token != T_POS_NUM)
-              return false;
-
-            value = 0;
-            do
-              {
-                value = value * 10 + (*s++ - '0');
-              }
-            while (c_isdigit (*s));
-
-            if (lex_next_tokval (lexer, tok_idx) != value)
-              return false;
-          }
-          break;
+    default:
+      return true;
+    }
+}
 
-        default:
-          if (lex_is_id1 (c))
-            {
-              int len;
+/* If LEXER is positioned at the sequence of tokens that may be parsed from S,
+   skips it and returns true.  Otherwise, returns false.
 
-              if (token != T_ID)
-                return 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)
+{
+  struct string_lexer slex;
+  struct token token;
+  int i;
 
-              len = lex_id_get_length (ss_cstr (s));
-              if (!lex_id_match (ss_buffer (s, len),
-                                 lex_next_tokss (lexer, tok_idx)))
-                return false;
+  i = 0;
+  string_lexer_init (&slex, s, SEG_MODE_INTERACTIVE);
+  while (string_lexer_next (&slex, &token))
+    if (token.type != SCAN_SKIP)
+      {
+        bool match = lex_tokens_match (lex_next (lexer, i++), &token);
+        token_destroy (&token);
+        if (!match)
+          return false;
+      }
 
-              s += len;
-            }
-          else
-            NOT_REACHED ();
-        }
-    }
+  while (i-- > 0)
+    lex_get (lexer);
+  return true;
 }
 
 static int
@@ -1079,6 +1038,14 @@ lex_get_file_name (const struct lexer *lexer)
   return src == NULL ? NULL : src->reader->file_name;
 }
 
+const char *
+lex_get_encoding (const struct lexer *lexer)
+{
+  struct lex_source *src = lex_source__ (lexer);
+  return src == NULL ? NULL : src->reader->encoding;
+}
+
+
 /* Returns the syntax mode for the syntax file from which the current drawn is
    drawn.  Returns LEX_SYNTAX_AUTO for a T_STOP token or if the command's
    source does not have line numbers.
@@ -1094,7 +1061,7 @@ lex_get_syntax_mode (const struct lexer *lexer)
 }
 
 /* Returns the error mode for the syntax file from which the current drawn is
-   drawn.  Returns LEX_ERROR_INTERACTIVE for a T_STOP token or if the command's
+   drawn.  Returns LEX_ERROR_TERMINAL for a T_STOP token or if the command's
    source does not have line numbers.
 
    There is no version of this function that takes an N argument because
@@ -1104,13 +1071,12 @@ enum lex_error_mode
 lex_get_error_mode (const struct lexer *lexer)
 {
   struct lex_source *src = lex_source__ (lexer);
-  return src == NULL ? LEX_ERROR_INTERACTIVE : src->reader->error;
+  return src == NULL ? LEX_ERROR_TERMINAL : src->reader->error;
 }
 
 /* If the source that LEXER is currently reading has error mode
-   LEX_ERROR_INTERACTIVE, discards all buffered input and tokens, so that the
-   next token to be read comes directly from whatever is next read from the
-   stream.
+   LEX_ERROR_TERMINAL, discards all buffered input and tokens, so that the next
+   token to be read comes directly from whatever is next read from the stream.
 
    It makes sense to call this function after encountering an error in a
    command entered on the console, because usually the user would prefer not to
@@ -1119,7 +1085,7 @@ void
 lex_interactive_reset (struct lexer *lexer)
 {
   struct lex_source *src = lex_source__ (lexer);
-  if (src != NULL && src->reader->error == LEX_ERROR_INTERACTIVE)
+  if (src != NULL && src->reader->error == LEX_ERROR_TERMINAL)
     {
       src->head = src->tail = 0;
       src->journal_pos = src->seg_pos = src->line_pos = 0;
@@ -1141,7 +1107,7 @@ lex_discard_rest_of_command (struct lexer *lexer)
 }
 
 /* Discards all lookahead tokens in LEXER, then discards all input sources
-   until it encounters one with error mode LEX_ERROR_INTERACTIVE or until it
+   until it encounters one with error mode LEX_ERROR_TERMINAL or until it
    runs out of input sources. */
 void
 lex_discard_noninteractive (struct lexer *lexer)
@@ -1153,7 +1119,7 @@ lex_discard_noninteractive (struct lexer *lexer)
       while (!deque_is_empty (&src->deque))
         lex_source_pop__ (src);
 
-      for (; src != NULL && src->reader->error != LEX_ERROR_INTERACTIVE;
+      for (; src != NULL && src->reader->error != LEX_ERROR_TERMINAL;
            src = lex_source__ (lexer))
         lex_source_destroy (src);
     }
@@ -1209,14 +1175,18 @@ lex_source_read__ (struct lex_source *src)
   do
     {
       size_t head_ofs;
+      size_t space;
       size_t n;
 
       lex_source_expand__ (src);
 
       head_ofs = src->head - src->tail;
+      space = src->allocated - head_ofs;
       n = src->reader->class->read (src->reader, &src->buffer[head_ofs],
-                                    src->allocated - head_ofs,
+                                    space,
                                     segmenter_get_prompt (&src->segmenter));
+      assert (n <= space);
+
       if (n == 0)
         {
           /* End of input.
@@ -1565,9 +1535,11 @@ static void
 lex_source_destroy (struct lex_source *src)
 {
   char *file_name = src->reader->file_name;
+  char *encoding = src->reader->encoding;
   if (src->reader->class->destroy != NULL)
     src->reader->class->destroy (src->reader);
   free (file_name);
+  free (encoding);
   free (src->buffer);
   while (!deque_is_empty (&src->deque))
     lex_source_pop__ (src);
@@ -1580,7 +1552,6 @@ struct lex_file_reader
   {
     struct lex_reader reader;
     struct u8_istream *istream;
-    char *file_name;
   };
 
 static struct lex_reader_class lex_file_reader_class;
@@ -1614,9 +1585,9 @@ lex_reader_for_file (const char *file_name, const char *encoding,
   r->reader.syntax = syntax;
   r->reader.error = error;
   r->reader.file_name = xstrdup (file_name);
+  r->reader.encoding = encoding ? xstrdup (encoding) : NULL;
   r->reader.line_number = 1;
   r->istream = istream;
-  r->file_name = xstrdup (file_name);
 
   return &r->reader;
 }
@@ -1635,7 +1606,7 @@ lex_file_read (struct lex_reader *r_, char *buf, size_t n,
   ssize_t n_read = u8_istream_read (r->istream, buf, n);
   if (n_read < 0)
     {
-      msg (ME, _("Error reading `%s': %s."), r->file_name, strerror (errno));
+      msg (ME, _("Error reading `%s': %s."), r_->file_name, strerror (errno));
       return 0;
     }
   return n_read;
@@ -1649,12 +1620,11 @@ lex_file_close (struct lex_reader *r_)
   if (u8_istream_fileno (r->istream) != STDIN_FILENO)
     {
       if (u8_istream_close (r->istream) != 0)
-        msg (ME, _("Error closing `%s': %s."), r->file_name, strerror (errno));
+        msg (ME, _("Error closing `%s': %s."), r_->file_name, strerror (errno));
     }
   else
     u8_istream_free (r->istream);
 
-  free (r->file_name);
   free (r);
 }
 
@@ -1674,16 +1644,17 @@ struct lex_string_reader
 static struct lex_reader_class lex_string_reader_class;
 
 /* Creates and returns a new lex_reader for the contents of S, which must be
-   encoded in UTF-8.  The new reader takes ownership of S and will free it
+   encoded in the given ENCODING.  The new reader takes ownership of S and will free it
    with ss_dealloc() when it is closed. */
 struct lex_reader *
-lex_reader_for_substring_nocopy (struct substring s)
+lex_reader_for_substring_nocopy (struct substring s, const char *encoding)
 {
   struct lex_string_reader *r;
 
   r = xmalloc (sizeof *r);
   lex_reader_init (&r->reader, &lex_string_reader_class);
-  r->reader.syntax = LEX_SYNTAX_INTERACTIVE;
+  r->reader.syntax = LEX_SYNTAX_AUTO;
+  r->reader.encoding = encoding ? xstrdup (encoding) : NULL;
   r->s = s;
   r->offset = 0;
 
@@ -1691,25 +1662,25 @@ lex_reader_for_substring_nocopy (struct substring s)
 }
 
 /* Creates and returns a new lex_reader for a copy of null-terminated string S,
-   which must be encoded in UTF-8.  The caller retains ownership of S. */
+   which must be encoded in ENCODING.  The caller retains ownership of S. */
 struct lex_reader *
-lex_reader_for_string (const char *s)
+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);
+  return lex_reader_for_substring_nocopy (ss, encoding);
 }
 
 /* Formats FORMAT as a printf()-like format string and creates and returns a
    new lex_reader for the formatted result.  */
 struct lex_reader *
-lex_reader_for_format (const char *format, ...)
+lex_reader_for_format (const char *format, const char *encoding, ...)
 {
   struct lex_reader *r;
   va_list args;
 
-  va_start (args, format);
-  r = lex_reader_for_substring_nocopy (ss_cstr (xvasprintf (format, args)));
+  va_start (args, encoding);
+  r = lex_reader_for_substring_nocopy (ss_cstr (xvasprintf (format, args)), encoding);
   va_end (args);
 
   return r;