placement-parser: Improve error messages for format assignment.
[pspp] / src / language / data-io / placement-parser.c
index dddbb05767390ed0f4f1585ab98d35deb06c6138..983bec84929b62fbace8791592ce4ca36d011670 100644 (file)
@@ -81,21 +81,21 @@ parse_var_placements (struct lexer *lexer, struct pool *pool, size_t n_vars,
                                 formats, n_formats);
   else if (lex_match (lexer, T_LPAREN))
     {
-      size_t n_assignments;
-      size_t i;
-
+      int start_ofs = lex_ofs (lexer);
       if (!fixed_parse_fortran (lexer, pool, use, formats, n_formats))
         return false;
+      int end_ofs = lex_ofs (lexer) - 1;
 
-      n_assignments = 0;
-      for (i = 0; i < *n_formats; i++)
+      size_t n_assignments = 0;
+      for (size_t i = 0; i < *n_formats; i++)
         n_assignments += (*formats)[i].type < FMT_NUMBER_OF_FORMATS;
 
       if (n_assignments != n_vars)
         {
-          msg (SE, _("Number of variables specified (%zu) "
-                     "differs from number of variable formats (%zu)."),
-               n_vars, n_assignments);
+          lex_ofs_error (lexer, start_ofs, end_ofs,
+                         _("Number of variables specified (%zu) "
+                           "differs from number of variable formats (%zu)."),
+                         n_vars, n_assignments);
           return false;
         }
 
@@ -103,8 +103,8 @@ parse_var_placements (struct lexer *lexer, struct pool *pool, size_t n_vars,
     }
   else
     {
-      msg (SE, _("SPSS-like or Fortran-like format "
-                 "specification expected after variable names."));
+      lex_error (lexer, _("SPSS-like or Fortran-like format "
+                          "specification expected after variable names."));
       return false;
     }
 }
@@ -115,61 +115,71 @@ fixed_parse_columns (struct lexer *lexer, struct pool *pool, size_t n_vars,
                      enum fmt_use use,
                      struct fmt_spec **formats, size_t *n_formats)
 {
-  struct fmt_spec format;
-  int fc, lc;
-  size_t i;
+  int start_ofs = lex_ofs (lexer);
 
+  int fc, lc;
   if (!parse_column_range (lexer, 1, &fc, &lc, NULL))
     return false;
 
   /* Divide columns evenly. */
-  format.w = (lc - fc + 1) / n_vars;
+  int w = (lc - fc + 1) / n_vars;
   if ((lc - fc + 1) % n_vars)
     {
-      msg (SE, _("The %d columns %d-%d "
-                "can't be evenly divided into %zu fields."),
-          lc - fc + 1, fc, lc, n_vars);
+      lex_ofs_error (lexer, start_ofs, lex_ofs (lexer) - 1,
+                     _("The %d columns %d-%d "
+                       "can't be evenly divided into %zu fields."),
+                     lc - fc + 1, fc, lc, n_vars);
       return false;
     }
 
   /* Format specifier. */
+  enum fmt_type type;
+  int d;
   if (lex_match (lexer, T_LPAREN))
     {
       /* Get format type. */
       if (lex_token (lexer) == T_ID)
        {
-         if (!parse_format_specifier_name (lexer, &format.type))
+         if (!parse_format_specifier_name (lexer, &type))
             return false;
          lex_match (lexer, T_COMMA);
        }
       else
-       format.type = FMT_F;
+       type = FMT_F;
 
       /* Get decimal places. */
       if (lex_is_integer (lexer))
        {
-         format.d = lex_integer (lexer);
+         d = lex_integer (lexer);
          lex_get (lexer);
        }
       else
-       format.d = 0;
+       d = 0;
 
       if (!lex_force_match (lexer, T_RPAREN))
        return false;
     }
   else
     {
-      format.type = FMT_F;
-      format.d = 0;
+      type = FMT_F;
+      d = 0;
+    }
+  int end_ofs = lex_ofs (lexer) - 1;
+
+  struct fmt_spec format = { .type = type, .w = w, .d = d };
+  char *error = fmt_check__ (&format, use);
+  if (error)
+    {
+      lex_ofs_error (lexer, start_ofs, end_ofs, "%s", error);
+      free (error);
+      return false;
     }
-  if (!fmt_check (&format, use))
-    return false;
 
   *formats = pool_nalloc (pool, n_vars + 1, sizeof **formats);
   *n_formats = n_vars + 1;
   (*formats)[0].type = (enum fmt_type) PRS_TYPE_T;
   (*formats)[0].w = fc;
-  for (i = 1; i <= n_vars; i++)
+  for (size_t i = 1; i <= n_vars; i++)
     (*formats)[i] = format;
   return true;
 }
@@ -216,8 +226,8 @@ fixed_parse_fortran (struct lexer *lexer, struct pool *pool, enum fmt_use use,
             f.type = (enum fmt_type) PRS_TYPE_NEW_REC;
           else
             {
+              int ofs = lex_ofs (lexer);
               char type[FMT_TYPE_LEN_MAX + 1];
-
               if (!parse_abstract_format_specifier (lexer, type, &f.w, &f.d))
                 return false;
 
@@ -233,11 +243,17 @@ fixed_parse_fortran (struct lexer *lexer, struct pool *pool, enum fmt_use use,
                 {
                   if (!fmt_from_name (type, &f.type))
                     {
-                      msg (SE, _("Unknown format type `%s'."), type);
+                      lex_ofs_error (lexer, ofs, ofs,
+                                     _("Unknown format type `%s'."), type);
+                      return false;
+                    }
+                  char *error = fmt_check__ (&f, use);
+                  if (error)
+                    {
+                      lex_ofs_error (lexer, ofs, ofs, "%s", error);
+                      free (error);
                       return false;
                     }
-                  if (!fmt_check (&f, use))
-                    return false;
                 }
             }
         }
@@ -300,16 +316,26 @@ execute_placement_format (const struct fmt_spec *format,
 }
 
 static bool
-parse_column__ (int value, int base, int *column)
+parse_column__ (struct lexer *lexer, bool negative, int base, int *column)
 {
   assert (base == 0 || base == 1);
+
+  if (!lex_force_int (lexer))
+    return false;
+  long int value = lex_integer (lexer);
+  if (negative)
+    value = -value;
+  lex_get (lexer);
+
   *column = value - base + 1;
   if (*column < 1)
     {
       if (base == 1)
-        msg (SE, _("Column positions for fields must be positive."));
+        lex_next_error (lexer, -1, -1,
+                        _("Column positions for fields must be positive."));
       else
-        msg (SE, _("Column positions for fields must not be negative."));
+        lex_next_error (lexer, -1, -1,
+                        _("Column positions for fields must not be negative."));
       return false;
     }
   return true;
@@ -326,14 +352,7 @@ parse_column__ (int value, int base, int *column)
 bool
 parse_column (struct lexer *lexer, int base, int *column)
 {
-  assert (base == 0 || base == 1);
-
-  if (!lex_force_int (lexer)
-      || !parse_column__ (lex_integer (lexer), base, column))
-    return false;
-
-  lex_get (lexer);
-  return true;
+  return parse_column__ (lexer, false, base, column);
 }
 
 /* Parse a column or a range of columns, specified as a single
@@ -354,23 +373,23 @@ parse_column_range (struct lexer *lexer, int base,
                     int *first_column, int *last_column,
                     bool *range_specified)
 {
+  int start_ofs = lex_ofs (lexer);
+
   /* First column. */
-  if (!lex_force_int (lexer)
-      || !parse_column__ (lex_integer (lexer), base, first_column))
+  if (!parse_column__ (lexer, false, base, first_column))
     return false;
-  lex_get (lexer);
 
   /* Last column. */
   if (lex_is_integer (lexer) && lex_integer (lexer) < 0)
     {
-      if (!parse_column__ (-lex_integer (lexer), base, last_column))
+      if (!parse_column__ (lexer, true, base, last_column))
         return false;
-      lex_get (lexer);
 
       if (*last_column < *first_column)
        {
-         msg (SE, _("The ending column for a field must be "
-                    "greater than the starting column."));
+         lex_ofs_error (lexer, start_ofs, lex_ofs (lexer) - 1,
+                         _("The ending column for a field must be "
+                           "greater than the starting column."));
          return false;
        }