+Sun Mar 6 19:52:22 2005 Ben Pfaff <blp@gnu.org>
+
+ DATA LIST with free-field formats should not have implied decimal
+ places (bug #12035). Also clean up data-in.c a bit.
+
+ * data-in.h: (enum) Add DI_IMPLIED_DECIMALS.
+
+ * data-in.c: (apply_implied_decimals) New function.
+ (parse_numeric) Don't adjust exponent if DI_IMPLIED_DECIMALS not
+ set. Also, get rid of gotos.
+ (parse_Z) Use apply_implied_decimals() if the field doesn't
+ contain a decimal point.
+ (parse_N) Use apply_implied_decimals().
+ (parse_IB) Ditto.
+ (parse_PIB) Ditto.
+ (parse_P) Ditto.
+ (parse_PK) Ditto.
+ (to_roman) Removed.
+ (parse_enum) New function.
+ (macro CHAR_IS_ROMAN) Removed.
+ (macro ROMAN_VALUE) Removed.
+ (parse_month) Use parse_enum().
+ (parse_weekday) Use parse_enum().
+ (parse_DATETIME) Use long for weekday.
+
+ * data-list.c: (read_from_data_list_fixed) Use
+ DI_IMPLIED_DECIMALS.
+
Sun Mar 6 17:07:20 2005 Ben Pfaff <blp@gnu.org>
When the lexer sees something like `-5' in the input, it has to
* lexer.h: (enum) Add T_POS_NUM, T_NEG_NUM. Remove T_NUM.
+Sun Mar 6 22:09:20 2005 Ben Pfaff <blp@gnu.org>
+
+ * operations.def: (NUMBER) Use DI_IMPLIED_DECIMALS.
+
+Sun Mar 6 19:33:24 2005 Ben Pfaff <blp@gnu.org>
+
+ * operations.def: (VEC_ELEM_NUM) Treat user-missing values as
+ system-missing.
+
+ * parse.c: (parse_vector_element) Fix order of arguments in call
+ to expr_allocate_binary().
+
+Sun Mar 6 17:51:05 2005 Ben Pfaff <blp@gnu.org>
+
+ * optimize.c: (optimize_tree) Fix optimization bug for x**2.
+
+ * parse.c: (type_coercion_core) Set *node to NULL on failure, as
+ indicated by function comment.
+ (parse_binary_operators) Always return NULL on type_coercion()
+ failure. Should have been doing this anyway, but bug in
+ type_coercion_core() filtered through.
+ (parse_add) Fix typo in user message.
+ (parse_primary) Understand T_NEG_NUM and T_POS_NUM.
+
+Sun Mar 6 10:47:13 2005 Ben Pfaff <blp@gnu.org>
+
+ * operations.def: Add VALUE function.
+
+ * parse.c: (parse_function) Need an unary composite node for
+ variables in A TO B, not a variable node. Use
+ allocate_unary_variable().
+ (parse_primary) Use allocate_unary_variable().
+ (allocate_unary_variable) New function.
+
+Thu Mar 3 23:53:32 2005 Ben Pfaff <blp@gnu.org>
+
+ * PSPP_expressions.pm: Renamed it back to generate.pl but fixed
+ the real problem that was preventing the build from a separate
+ directory. I liked it my way better ;-)
+
+Thu Mar 3 23:17:51 2005 Ben Pfaff <blp@gnu.org>
+
+ * parse.c: (expr_parse) Fix parameter type. Thanks to John
+ Darrington <john@darrington.wattle.id.au> for reporting this bug.
+
+Thu Mar 3 22:10:25 WST 2005 John Darrington <john@darrington.wattle.id.au>
+
+ * Makefile.am evaluate.h.pl evaluate.inc.pl operations.h.pl
+ optimize.inc.pl parse.inc.p:
+
+ Renamed generate.pl to PSPP_expressions.pm and adjusted *.pl
+ to suit.
+
+ Fixed everything so that it can be built from an arbitrary
+ directory.
+
Thu Mar 3 22:08:35 WST 2005 John Darrington <john@darrington.wattle.id.au>
* Makefile.am : Fixed up CLEANFILES target.
vdls_error (i, format, args);
va_end (args);
}
+\f
+/* Parsing utility functions. */
/* Excludes leading and trailing whitespace from I by adjusting
pointers. */
{
return i->s < i->e;
}
+
+/* If implied decimal places are enabled, apply them to
+ I->v->f. */
+static void
+apply_implied_decimals (struct data_in *i)
+{
+ if ((i->flags & DI_IMPLIED_DECIMALS) && i->format.d > 0)
+ i->v->f /= pow (10., i->format.d);
+}
\f
/* Format parsers. */
static int
parse_numeric (struct data_in *i)
{
- short int sign; /* +1 or -1. */
+ int sign; /* +1 or -1. */
double num; /* The number so far. */
int got_dot; /* Found a decimal point. */
i->v->f = SYSMIS;
return 1;
}
- goto noconv;
+ dls_error (i, _("Field does not form a valid floating-point constant."));
+ i->v->f = SYSMIS;
+ return 0;
}
if (have_char (i)
if (isalpha (*i->s))
i->s++;
if (!parse_int (i, &exp))
- goto noconv;
+ {
+ i->v->f = SYSMIS;
+ return 0;
+ }
exponent += exp;
}
- else if (!got_dot)
+ else if (!got_dot && (i->flags & DI_IMPLIED_DECIMALS))
exponent -= i->format.d;
if (type == FMT_PCT && have_char (i) && *i->s == '%')
/* Multiply NUM by 10 to the EXPONENT power, checking for overflow
and underflow. */
-
if (exponent < 0)
{
if (-exponent + got_digit > -(DBL_MIN_10_EXP) + 5
- || num < DBL_MIN * pow (10.0, (double) -exponent))
- goto underflow;
+ || num < DBL_MIN * pow (10.0, (double) -exponent))
+ {
+ dls_error (i, _("Underflow in floating-point constant."));
+ i->v->f = 0.0;
+ return 0;
+ }
+
num *= pow (10.0, (double) exponent);
}
else if (exponent > 0)
{
if (num > DBL_MAX * pow (10.0, (double) -exponent))
- goto overflow;
+ {
+ dls_error (i, _("Overflow in floating-point constant."));
+ i->v->f = SYSMIS;
+ return 0;
+ }
+
num *= pow (10.0, (double) exponent);
}
- i->v->f = sign * num;
+ i->v->f = sign > 0 ? num : -num;
return 1;
-
-overflow:
- /* Return an overflow error. */
- dls_error (i, _("Overflow in floating-point constant."));
- i->v->f = SYSMIS;
- return 0;
-
-underflow:
- /* Return an underflow error. */
- dls_error (i, _("Underflow in floating-point constant."));
- i->v->f = 0.0;
- return 0;
-
-noconv:
- /* There was no number. */
- dls_error (i, _("Field does not form a valid floating-point constant."));
- i->v->f = SYSMIS;
- return 0;
}
/* Returns the integer value of hex digit C. */
i->v->f = i->v->f * 10.0 + *cp - '0';
}
- if (i->format.d)
- i->v->f /= pow (10.0, i->format.d);
+ apply_implied_decimals (i);
return 1;
}
parse_Z (struct data_in *i)
{
char buf[64];
+ bool got_dot = false;
/* Warn user that we suck. */
{
char *dp;
for (sp = i->s, dp = buf + 1; sp < i->e - 1; sp++, dp++)
- if (*sp == '.')
- *dp = '.';
+ if (*sp == '.')
+ {
+ *dp = '.';
+ got_dot = true;
+ }
else if ((*sp & 0xf0) == 0xf0 && (*sp & 0xf) < 10)
*dp = (*sp & 0xf) + '0';
else
return 0;
}
}
-
+
+ if (!got_dot)
+ apply_implied_decimals (i);
+
return 1;
}
if (p[0] & 0x80)
i->v->f = -(i->v->f + 1.0);
- if (i->format.d)
- i->v->f /= pow (10.0, i->format.d);
+ apply_implied_decimals (i);
return 1;
}
i->v->f = i->v->f * 256.0 + i->s[j];
#endif
- if (i->format.d)
- i->v->f /= pow (10.0, i->format.d);
+ apply_implied_decimals (i);
return 1;
}
if ((*cp ^ (*cp >> 1)) & 0x10)
i->v->f = -i->v->f;
- if (i->format.d)
- i->v->f /= pow (10.0, i->format.d);
+ apply_implied_decimals (i);
return 1;
}
i->v->f = i->v->f * 10 + (*cp & 15);
}
- if (i->format.d)
- i->v->f /= pow (10.0, i->format.d);
+ apply_implied_decimals (i);
return 1;
}
return 0;
}
-/* Formats NUMBER as Roman numerals in ROMAN, or as Arabic numerals if
- the Roman expansion would be too long. */
-static void
-to_roman (int number, char roman[32])
-{
- int save_number = number;
-
- struct roman_digit
- {
- int value; /* Value corresponding to this digit. */
- char name; /* Digit name. */
- };
-
- static const struct roman_digit roman_tab[7] =
+/* Association between a name and a value. */
+struct enum_name
{
- {1000, 'M'},
- {500, 'D'},
- {100, 'C'},
- {50, 'L'},
- {10, 'X'},
- {5, 'V'},
- {1, 'I'},
+ const char *name; /* Name. */
+ bool can_abbreviate; /* True if name may be abbreviated. */
+ int value; /* Value associated with name. */
};
- char *cp = roman;
-
- int i, j;
-
- assert (32 >= INT_DIGITS + 1);
- if (number == 0)
- goto arabic;
-
- if (number < 0)
+/* Reads a name from I and sets *OUTPUT to the value associated
+ with that name. Returns true if successful, false otherwise. */
+static bool
+parse_enum (struct data_in *i, const char *what,
+ const struct enum_name *enum_names,
+ long *output)
+{
+ const char *name;
+ size_t length;
+ const struct enum_name *ep;
+
+ /* Consume alphabetic characters. */
+ name = i->s;
+ length = 0;
+ while (have_char (i) && isalpha (*i->s))
{
- *cp++ = '-';
- number = -number;
+ length++;
+ i->s++;
}
-
- for (i = 0; i < 7; i++)
+ if (length == 0)
{
- int digit = roman_tab[i].value;
- while (number >= digit)
- {
- number -= digit;
- if (cp > &roman[30])
- goto arabic;
- *cp++ = roman_tab[i].name;
- }
-
- for (j = i + 1; j < 7; j++)
- {
- if (i == 4 && j == 5) /* VX is not a shortened form of V. */
- break;
-
- digit = roman_tab[i].value - roman_tab[j].value;
- while (number >= digit)
- {
- number -= digit;
- if (cp > &roman[29])
- goto arabic;
- *cp++ = roman_tab[j].name;
- *cp++ = roman_tab[i].name;
- }
- }
+ dls_error (i, _("Parse error at `%c' expecting %s."), *i->s, what);
+ return 0;
}
- *cp = 0;
- return;
-
-arabic:
- sprintf (roman, "%d", save_number);
-}
-/* Returns true if C is a (lowercase) roman numeral. */
-#define CHAR_IS_ROMAN(C) \
- ((C) == 'x' || (C) == 'v' || (C) == 'i')
+ for (ep = enum_names; ep->name != NULL; ep++)
+ if ((ep->can_abbreviate
+ && lex_id_match_len (ep->name, strlen (ep->name), name, length))
+ || (!ep->can_abbreviate && length == strlen (ep->name)
+ && !memcmp (name, ep->name, length)))
+ {
+ *output = ep->value;
+ return 1;
+ }
-/* Returns the value of a single (lowercase) roman numeral. */
-#define ROMAN_VALUE(C) \
- ((C) == 'x' ? 10 : ((C) == 'v' ? 5 : 1))
+ dls_error (i, _("Unknown %s `%.*s'."), what, (int) length, name);
+ return 0;
+}
static int
parse_month (struct data_in *i, long *month)
{
+ static const struct enum_name month_names[] =
+ {
+ {"january", true, 1},
+ {"february", true, 2},
+ {"march", true, 3},
+ {"april", true, 4},
+ {"may", true, 5},
+ {"june", true, 6},
+ {"july", true, 7},
+ {"august", true, 8},
+ {"september", true, 9},
+ {"october", true, 10},
+ {"november", true, 11},
+ {"december", true, 12},
+
+ {"i", false, 1},
+ {"ii", false, 2},
+ {"iii", false, 3},
+ {"iv", false, 4},
+ {"iiii", false, 4},
+ {"v", false, 5},
+ {"vi", false, 6},
+ {"vii", false, 7},
+ {"viii", false, 8},
+ {"ix", false, 9},
+ {"viiii", false, 9},
+ {"x", false, 10},
+ {"xi", false, 11},
+ {"xii", false, 12},
+
+ {NULL, false, 0},
+ };
+
if (!force_have_char (i))
return 0;
dls_error (i, _("Month (%ld) must be between 1 and 12."), *month);
return 0;
}
-
- if (CHAR_IS_ROMAN (tolower (*i->s)))
- {
- int last = ROMAN_VALUE (tolower (*i->s));
-
- *month = 0;
- for (;;)
- {
- int value;
-
- i->s++;
- if (!have_char || !CHAR_IS_ROMAN (tolower (*i->s)))
- {
- if (last != INT_MAX)
- *month += last;
- break;
- }
-
- value = ROMAN_VALUE (tolower (*i->s));
- if (last == INT_MAX)
- *month += value;
- else if (value > last)
- {
- *month += value - last;
- last = INT_MAX;
- }
- else
- {
- *month += last;
- last = value;
- }
- }
-
- if (*month < 1 || *month > 12)
- {
- char buf[32];
-
- to_roman (*month, buf);
- dls_error (i, _("Month (%s) must be between I and XII."), buf);
- return 0;
- }
-
- return 1;
- }
-
- {
- static const char *months[12] =
- {
- "january", "february", "march", "april", "may", "june",
- "july", "august", "september", "october", "november", "december",
- };
-
- char month_buf[32];
- char *mp;
-
- int j;
-
- for (mp = month_buf;
- have_char (i) && isalpha (*i->s) && mp < &month_buf[31];
- i->s++)
- *mp++ = tolower (*i->s);
- *mp = '\0';
-
- if (have_char (i) && isalpha (*i->s))
- {
- dls_error (i, _("Month name (%s...) is too long."), month_buf);
- return 0;
- }
-
- for (j = 0; j < 12; j++)
- if (lex_id_match (months[j], month_buf))
- {
- *month = j + 1;
- return 1;
- }
-
- dls_error (i, _("Bad month name (%s)."), month_buf);
- return 0;
- }
+ else
+ return parse_enum (i, _("month"), month_names, month);
}
static int
static int
-parse_weekday (struct data_in *i, int *weekday)
+parse_weekday (struct data_in *i, long *weekday)
{
- /* PORTME */
- #define TUPLE(A,B) \
- (((A) << 8) + (B))
-
- if (i->s + 1 >= i->e)
- {
- dls_error (i, _("Day of the week expected in date value."));
- return 0;
- }
-
- switch (TUPLE (tolower (i->s[0]), tolower (i->s[1])))
+ static const struct enum_name weekday_names[] =
{
- case TUPLE ('s', 'u'):
- *weekday = 1;
- break;
-
- case TUPLE ('m', 'o'):
- *weekday = 2;
- break;
-
- case TUPLE ('t', 'u'):
- *weekday = 3;
- break;
-
- case TUPLE ('w', 'e'):
- *weekday = 4;
- break;
-
- case TUPLE ('t', 'h'):
- *weekday = 5;
- break;
-
- case TUPLE ('f', 'r'):
- *weekday = 6;
- break;
-
- case TUPLE ('s', 'a'):
- *weekday = 7;
- break;
-
- default:
- dls_error (i, _("Day of the week expected in date value."));
- return 0;
- }
-
- while (have_char (i) && isalpha (*i->s))
- i->s++;
-
- return 1;
+ {"sunday", true, 1},
+ {"su", true, 1},
+ {"monday", true, 2},
+ {"mo", true, 2},
+ {"tuesday", true, 3},
+ {"tu", true, 3},
+ {"wednesday", true, 4},
+ {"we", true, 4},
+ {"thursday", true, 5},
+ {"th", true, 5},
+ {"friday", true, 6},
+ {"fr", true, 6},
+ {"saturday", true, 7},
+ {"sa", true, 7},
+
+ {NULL, false, 0},
+ };
- #undef TUPLE
+ return parse_enum (i, _("weekday"), weekday_names, weekday);
}
static int
static int
parse_WKDAY (struct data_in *i)
{
- int weekday;
+ long weekday;
if (!parse_leader (i)
|| !parse_weekday (i, &weekday)
+++ /dev/null
-Sun Mar 6 19:33:24 2005 Ben Pfaff <blp@gnu.org>
-
- * operations.def: (VEC_ELEM_NUM) Treat user-missing values as
- system-missing.
-
- * parse.c: (parse_vector_element) Fix order of arguments in call
- to expr_allocate_binary().
-
-Sun Mar 6 17:51:05 2005 Ben Pfaff <blp@gnu.org>
-
- * optimize.c: (optimize_tree) Fix optimization bug for x**2.
-
- * parse.c: (type_coercion_core) Set *node to NULL on failure, as
- indicated by function comment.
- (parse_binary_operators) Always return NULL on type_coercion()
- failure. Should have been doing this anyway, but bug in
- type_coercion_core() filtered through.
- (parse_add) Fix typo in user message.
- (parse_primary) Understand T_NEG_NUM and T_POS_NUM.
-
-Sun Mar 6 10:47:13 2005 Ben Pfaff <blp@gnu.org>
-
- * operations.def: Add VALUE function.
-
- * parse.c: (parse_function) Need an unary composite node for
- variables in A TO B, not a variable node. Use
- allocate_unary_variable().
- (parse_primary) Use allocate_unary_variable().
- (allocate_unary_variable) New function.
-
-Thu Mar 3 23:53:32 2005 Ben Pfaff <blp@gnu.org>
-
- * PSPP_expressions.pm: Renamed it back to generate.pl but fixed
- the real problem that was preventing the build from a separate
- directory. I liked it my way better ;-)
-
-Thu Mar 3 23:17:51 2005 Ben Pfaff <blp@gnu.org>
-
- * parse.c: (expr_parse) Fix parameter type. Thanks to John
- Darrington <john@darrington.wattle.id.au> for reporting this bug.
-
-Thu Mar 3 22:10:25 WST 2005 John Darrington <john@darrington.wattle.id.au>
-
- * Makefile.am evaluate.h.pl evaluate.inc.pl operations.h.pl
- optimize.inc.pl parse.inc.p:
-
- Renamed generate.pl to PSPP_expressions.pm and adjusted *.pl
- to suit.
-
- Fixed everything so that it can be built from an arbitrary
- directory.
-
-
-Mon Feb 28 23:52:21 2005 Ben Pfaff <blp@gnu.org>
-
- * New directory.
-
-----------------------------------------------------------------------
-Local Variables:
-mode: change-log
-version-control: never
-End: