work on PRINT encoding
[pspp] / src / language / data-io / placement-parser.c
index 4f1d062cb8d3b18734afacfc427f1bfd5b1b5408..64bdeec1e6f7f54f3c76bfb5d46311201a911653 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2010, 2011, 2012 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
 
 #include <config.h>
 
-#include <language/data-io/placement-parser.h>
+#include "language/data-io/placement-parser.h"
 
 #include <assert.h>
 
-#include <language/lexer/format-parser.h>
-#include <language/lexer/lexer.h>
-#include <libpspp/message.h>
-#include <libpspp/pool.h>
-#include <libpspp/str.h>
+#include "data/format.h"
+#include "language/lexer/format-parser.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/message.h"
+#include "libpspp/pool.h"
+#include "libpspp/str.h"
 
-#include <data/format.h>
-
-#include "xalloc.h"
-#include "xsize.h"
+#include "gl/xalloc.h"
+#include "gl/xsize.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -43,9 +42,9 @@ enum
     PRS_TYPE_NEW_REC            /* Next record. */
   };
 
-static bool fixed_parse_columns (struct lexer *, struct pool *, size_t var_cnt, bool for_input,
-                                 struct fmt_spec **, size_t *);
-static bool fixed_parse_fortran (struct lexer *l, struct pool *, bool for_input,
+static bool fixed_parse_columns (struct lexer *, struct pool *, size_t var_cnt,
+                                 enum fmt_use, struct fmt_spec **, size_t *);
+static bool fixed_parse_fortran (struct lexer *l, struct pool *, enum fmt_use,
                                  struct fmt_spec **, size_t *);
 
 /* Parses Fortran-like or column-based specifications for placing
@@ -53,6 +52,13 @@ static bool fixed_parse_fortran (struct lexer *l, struct pool *, bool for_input,
    formats like those parsed by DATA LIST or PRINT.  Returns true
    only if successful.
 
+   The formats parsed are either input or output formats, according
+   to USE.
+
+   If USE is FMT_FOR_INPUT, then T, X, and / "formats" are parsed,
+   in addition to regular formats.  If USE is FMT_FOR_OUTPUT, then
+   T and X "formats" are parsed but not /.
+
    If successful, formats for VAR_CNT variables are stored in
    *FORMATS, and the number of formats required is stored in
    *FORMAT_CNT.  *FORMAT_CNT may be greater than VAR_CNT because
@@ -64,18 +70,20 @@ static bool fixed_parse_fortran (struct lexer *l, struct pool *, bool for_input,
    Uses POOL for allocation.  When the caller is finished
    interpreting *FORMATS, POOL may be destroyed. */
 bool
-parse_var_placements (struct lexer *lexer, struct pool *pool, size_t var_cnt, bool for_input,
+parse_var_placements (struct lexer *lexer, struct pool *pool, size_t var_cnt,
+                      enum fmt_use use,
                       struct fmt_spec **formats, size_t *format_cnt)
 {
   assert (var_cnt > 0);
   if (lex_is_number (lexer))
-    return fixed_parse_columns (lexer, pool, var_cnt, for_input, formats, format_cnt);
-  else if (lex_match (lexer, '('))
+    return fixed_parse_columns (lexer, pool, var_cnt, use,
+                                formats, format_cnt);
+  else if (lex_match (lexer, T_LPAREN))
     {
       size_t assignment_cnt;
       size_t i;
 
-      if (!fixed_parse_fortran (lexer, pool, for_input, formats, format_cnt))
+      if (!fixed_parse_fortran (lexer, pool, use, formats, format_cnt))
         return false;
 
       assignment_cnt = 0;
@@ -102,7 +110,8 @@ parse_var_placements (struct lexer *lexer, struct pool *pool, size_t var_cnt, bo
 
 /* Implements parse_var_placements for column-based formats. */
 static bool
-fixed_parse_columns (struct lexer *lexer, struct pool *pool, size_t var_cnt, bool for_input,
+fixed_parse_columns (struct lexer *lexer, struct pool *pool, size_t var_cnt,
+                     enum fmt_use use,
                      struct fmt_spec **formats, size_t *format_cnt)
 {
   struct fmt_spec format;
@@ -123,14 +132,14 @@ fixed_parse_columns (struct lexer *lexer, struct pool *pool, size_t var_cnt, boo
     }
 
   /* Format specifier. */
-  if (lex_match (lexer, '('))
+  if (lex_match (lexer, T_LPAREN))
     {
       /* Get format type. */
       if (lex_token (lexer) == T_ID)
        {
          if (!parse_format_specifier_name (lexer, &format.type))
             return false;
-         lex_match (lexer, ',');
+         lex_match (lexer, T_COMMA);
        }
       else
        format.type = FMT_F;
@@ -144,7 +153,7 @@ fixed_parse_columns (struct lexer *lexer, struct pool *pool, size_t var_cnt, boo
       else
        format.d = 0;
 
-      if (!lex_force_match (lexer, ')'))
+      if (!lex_force_match (lexer, T_RPAREN))
        return false;
     }
   else
@@ -152,7 +161,7 @@ fixed_parse_columns (struct lexer *lexer, struct pool *pool, size_t var_cnt, boo
       format.type = FMT_F;
       format.d = 0;
     }
-  if (!fmt_check (&format, for_input))
+  if (!fmt_check (&format, use))
     return false;
 
   *formats = pool_nalloc (pool, var_cnt + 1, sizeof **formats);
@@ -166,14 +175,14 @@ fixed_parse_columns (struct lexer *lexer, struct pool *pool, size_t var_cnt, boo
 
 /* Implements parse_var_placements for Fortran-like formats. */
 static bool
-fixed_parse_fortran (struct lexer *lexer, struct pool *pool, bool for_input,
+fixed_parse_fortran (struct lexer *lexer, struct pool *pool, enum fmt_use use,
                      struct fmt_spec **formats, size_t *format_cnt)
 {
   size_t formats_allocated = 0;
   size_t formats_used = 0;
 
   *formats = NULL;
-  while (!lex_match (lexer, ')'))
+  while (!lex_match (lexer, T_RPAREN))
     {
       struct fmt_spec f;
       struct fmt_spec *new_formats;
@@ -191,10 +200,10 @@ fixed_parse_fortran (struct lexer *lexer, struct pool *pool, bool for_input,
        count = 1;
 
       /* Parse format specifier. */
-      if (lex_match (lexer, '('))
+      if (lex_match (lexer, T_LPAREN))
         {
           /* Call ourselves recursively to handle parentheses. */
-          if (!fixed_parse_fortran (lexer, pool, for_input,
+          if (!fixed_parse_fortran (lexer, pool, use,
                                     &new_formats, &new_format_cnt))
             return false;
         }
@@ -202,7 +211,7 @@ fixed_parse_fortran (struct lexer *lexer, struct pool *pool, bool for_input,
         {
           new_formats = &f;
           new_format_cnt = 1;
-          if (lex_match (lexer, '/'))
+          if (use == FMT_FOR_INPUT && lex_match (lexer, T_SLASH))
             f.type = PRS_TYPE_NEW_REC;
           else
             {
@@ -226,7 +235,7 @@ fixed_parse_fortran (struct lexer *lexer, struct pool *pool, bool for_input,
                       msg (SE, _("Unknown format type `%s'."), type);
                       return false;
                     }
-                  if (!fmt_check (&f, for_input))
+                  if (!fmt_check (&f, use))
                     return false;
                 }
             }
@@ -253,7 +262,7 @@ fixed_parse_fortran (struct lexer *lexer, struct pool *pool, bool for_input,
           formats_used += new_format_cnt;
         }
 
-      lex_match (lexer, ',');
+      lex_match (lexer, T_COMMA);
     }
 
   *format_cnt = formats_used;
@@ -293,12 +302,10 @@ execute_placement_format (const struct fmt_spec *format,
    stores a 1-based column number into *COLUMN if successful,
    otherwise emits an error message and returns false. */
 static bool
-parse_column (struct lexer *lexer, int base, int *column)
+parse_column (int value, int base, int *column)
 {
   assert (base == 0 || base == 1);
-  if (!lex_force_int (lexer))
-    return false;
-  *column = lex_integer (lexer) - base + 1;
+  *column = value - base + 1;
   if (*column < 1)
     {
       if (base == 1)
@@ -307,7 +314,6 @@ parse_column (struct lexer *lexer, int base, int *column)
         msg (SE, _("Column positions for fields must not be negative."));
       return false;
     }
-  lex_get (lexer);
   return true;
 }
 
@@ -330,15 +336,18 @@ parse_column_range (struct lexer *lexer, int base,
                     bool *range_specified)
 {
   /* First column. */
-  if (!parse_column (lexer, base, first_column))
+  if (!lex_force_int (lexer)
+      || !parse_column (lex_integer (lexer), base, first_column))
     return false;
+  lex_get (lexer);
 
   /* Last column. */
-  lex_negative_to_dash (lexer);
-  if (lex_match (lexer, '-'))
+  if (lex_is_integer (lexer) && lex_integer (lexer) < 0)
     {
-      if (!parse_column (lexer, base, last_column))
+      if (!parse_column (-lex_integer (lexer), base, last_column))
         return false;
+      lex_get (lexer);
+
       if (*last_column < *first_column)
        {
          msg (SE, _("The ending column for a field must be "
@@ -369,7 +378,7 @@ parse_column_range (struct lexer *lexer, int base,
 bool
 parse_record_placement (struct lexer *lexer, int *record, int *column)
 {
-  while (lex_match (lexer, '/'))
+  while (lex_match (lexer, T_SLASH))
     {
       if (lex_is_integer (lexer))
         {