+ /* Weird, maybe a bug in the caller. Just report that we needed an
+ integer. */
+ if (name)
+ lex_error (lexer, _("Integer expected for %s."), name);
+ else
+ lex_error (lexer, _("Integer expected."));
+ }
+ else if (min == max)
+ {
+ if (name)
+ lex_error (lexer, _("Expected %ld for %s."), min, name);
+ else
+ lex_error (lexer, _("Expected %ld."), min);
+ }
+ else if (min + 1 == max)
+ {
+ if (name)
+ lex_error (lexer, _("Expected %ld or %ld for %s."), min, min + 1, name);
+ else
+ lex_error (lexer, _("Expected %ld or %ld."), min, min + 1);
+ }
+ else
+ {
+ bool report_lower_bound = (min > INT_MIN / 2) || too_small;
+ bool report_upper_bound = (max < INT_MAX / 2) || too_big;
+
+ if (report_lower_bound && report_upper_bound)
+ {
+ if (name)
+ lex_error (lexer,
+ _("Expected integer between %ld and %ld for %s."),
+ min, max, name);
+ else
+ lex_error (lexer, _("Expected integer between %ld and %ld."),
+ min, max);
+ }
+ else if (report_lower_bound)
+ {
+ if (min == 0)
+ {
+ if (name)
+ lex_error (lexer, _("Expected non-negative integer for %s."),
+ name);
+ else
+ lex_error (lexer, _("Expected non-negative integer."));
+ }
+ else if (min == 1)
+ {
+ if (name)
+ lex_error (lexer, _("Expected positive integer for %s."),
+ name);
+ 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)
+ {
+ if (name)
+ lex_error (lexer,
+ _("Expected integer less than or equal to %ld for %s."),
+ max, name);
+ else
+ lex_error (lexer, _("Expected integer less than or equal to %ld."),
+ max);
+ }
+ else
+ {
+ if (name)
+ lex_error (lexer, _("Integer expected for %s."), name);
+ else
+ lex_error (lexer, _("Integer expected."));
+ }
+ }
+ return false;
+}
+
+/* If the current token is a number, does nothing and returns true.
+ Otherwise, reports an error and returns false. */
+bool
+lex_force_num (struct lexer *lexer)
+{
+ if (lex_is_number (lexer))
+ return true;
+
+ lex_error (lexer, _("expecting number"));
+ return false;
+}
+
+/* If the current token is an number in the closed range [MIN,MAX], does
+ nothing and returns true. Otherwise, reports an error and returns false.
+ If NAME is nonnull, then it is used in the error message. */
+bool
+lex_force_num_range_closed (struct lexer *lexer, const char *name,
+ double min, double max)
+{
+ bool is_number = lex_is_number (lexer);
+ bool too_small = is_number && lex_number (lexer) < min;
+ bool too_big = is_number && lex_number (lexer) > max;
+ if (is_number && !too_small && !too_big)
+ return true;
+
+ if (min > max)
+ {
+ /* Weird, maybe a bug in the caller. Just report that we needed an
+ number. */
+ if (name)
+ lex_error (lexer, _("Number expected for %s."), name);
+ else
+ lex_error (lexer, _("Number expected."));
+ }
+ else if (min == max)
+ {
+ if (name)
+ lex_error (lexer, _("Expected %g for %s."), min, name);
+ else
+ lex_error (lexer, _("Expected %g."), min);
+ }
+ else
+ {
+ bool report_lower_bound = min > -DBL_MAX || too_small;
+ bool report_upper_bound = max < DBL_MAX || too_big;
+
+ if (report_lower_bound && report_upper_bound)
+ {
+ if (name)
+ lex_error (lexer,
+ _("Expected number between %g and %g for %s."),
+ min, max, name);
+ else
+ lex_error (lexer, _("Expected number between %g and %g."),
+ min, max);
+ }
+ else if (report_lower_bound)
+ {
+ if (min == 0)
+ {
+ if (name)
+ lex_error (lexer, _("Expected non-negative number for %s."),
+ name);
+ else
+ lex_error (lexer, _("Expected non-negative number."));
+ }
+ else
+ {
+ if (name)
+ lex_error (lexer, _("Expected number %g or greater for %s."),
+ min, name);
+ else
+ lex_error (lexer, _("Expected number %g or greater."), min);
+ }
+ }
+ else if (report_upper_bound)
+ {
+ if (name)
+ lex_error (lexer,
+ _("Expected number less than or equal to %g for %s."),
+ max, name);
+ else
+ lex_error (lexer, _("Expected number less than or equal to %g."),
+ max);
+ }
+ else
+ {
+ if (name)
+ lex_error (lexer, _("Number expected for %s."), name);
+ else
+ lex_error (lexer, _("Number expected."));
+ }
+ }
+ return false;
+}
+
+/* If the current token is an number in the half-open range [MIN,MAX), does
+ nothing and returns true. Otherwise, reports an error and returns false.
+ If NAME is nonnull, then it is used in the error message. */
+bool
+lex_force_num_range_halfopen (struct lexer *lexer, const char *name,
+ double min, double max)
+{
+ bool is_number = lex_is_number (lexer);
+ bool too_small = is_number && lex_number (lexer) < min;
+ bool too_big = is_number && lex_number (lexer) >= max;
+ if (is_number && !too_small && !too_big)
+ return true;
+
+ if (min >= max)
+ {
+ /* Weird, maybe a bug in the caller. Just report that we needed an
+ number. */
+ if (name)
+ lex_error (lexer, _("Number expected for %s."), name);
+ else
+ lex_error (lexer, _("Number expected."));
+ }
+ else
+ {
+ bool report_lower_bound = min > -DBL_MAX || too_small;
+ bool report_upper_bound = max < DBL_MAX || too_big;
+
+ if (report_lower_bound && report_upper_bound)
+ {
+ if (name)
+ lex_error (lexer, _("Expected number in [%g,%g) for %s."),
+ min, max, name);
+ else
+ lex_error (lexer, _("Expected number in [%g,%g)."),
+ min, max);
+ }
+ else if (report_lower_bound)
+ {
+ if (min == 0)
+ {
+ if (name)
+ lex_error (lexer, _("Expected non-negative number for %s."),
+ name);
+ else
+ lex_error (lexer, _("Expected non-negative number."));
+ }
+ else
+ {
+ if (name)
+ lex_error (lexer, _("Expected number %g or greater for %s."),
+ min, name);
+ else
+ lex_error (lexer, _("Expected number %g or greater."), min);
+ }
+ }
+ else if (report_upper_bound)
+ {
+ if (name)
+ lex_error (lexer,
+ _("Expected number less than %g for %s."), max, name);
+ else
+ lex_error (lexer, _("Expected number less than %g."), max);
+ }
+ else
+ {
+ if (name)
+ lex_error (lexer, _("Number expected for %s."), name);
+ else
+ lex_error (lexer, _("Number expected."));
+ }
+ }
+ return false;
+}
+
+/* If the current token is an number in the open range (MIN,MAX], does
+ nothing and returns true. Otherwise, reports an error and returns false.
+ If NAME is nonnull, then it is used in the error message. */
+bool
+lex_force_num_range_open (struct lexer *lexer, const char *name,
+ double min, double max)
+{
+ bool is_number = lex_is_number (lexer);
+ bool too_small = is_number && lex_number (lexer) <= min;
+ bool too_big = is_number && lex_number (lexer) >= max;
+ if (is_number && !too_small && !too_big)
+ return true;
+
+ if (min >= max)
+ {
+ /* Weird, maybe a bug in the caller. Just report that we needed an
+ number. */
+ if (name)
+ lex_error (lexer, _("Number expected for %s."), name);
+ else
+ lex_error (lexer, _("Number expected."));
+ }
+ else
+ {
+ bool report_lower_bound = min > -DBL_MAX || too_small;
+ bool report_upper_bound = max < DBL_MAX || too_big;
+
+ if (report_lower_bound && report_upper_bound)
+ {
+ if (name)
+ lex_error (lexer, _("Expected number in (%g,%g) for %s."),
+ min, max, name);
+ else
+ lex_error (lexer, _("Expected number in (%g,%g)."), min, max);
+ }
+ else if (report_lower_bound)
+ {
+ if (min == 0)
+ {
+ if (name)
+ lex_error (lexer, _("Expected positive number for %s."), name);
+ else
+ lex_error (lexer, _("Expected positive number."));
+ }
+ else
+ {
+ if (name)
+ lex_error (lexer, _("Expected number greater than %g for %s."),
+ min, name);
+ else
+ lex_error (lexer, _("Expected number greater than %g."), min);
+ }
+ }
+ else if (report_upper_bound)
+ {
+ if (name)
+ lex_error (lexer, _("Expected number less than %g for %s."),
+ max, name);
+ else
+ lex_error (lexer, _("Expected number less than %g."), max);
+ }
+ else
+ {
+ if (name)
+ lex_error (lexer, _("Number expected for %s."), name);
+ else
+ lex_error (lexer, _("Number expected."));
+ }
+ }
+ return false;
+}
+
+/* If the current token is an identifier, does nothing and returns true.
+ Otherwise, reports an error and returns false. */
+bool
+lex_force_id (struct lexer *lexer)
+{
+ if (lex_token (lexer) == T_ID)
+ return true;
+
+ lex_error (lexer, _("expecting identifier"));
+ return false;
+}
+\f
+/* Token accessors. */
+
+/* Returns the type of LEXER's current token. */
+enum token_type
+lex_token (const struct lexer *lexer)
+{
+ return lex_next_token (lexer, 0);
+}
+
+/* Returns the number in LEXER's current token.
+
+ Only T_NEG_NUM and T_POS_NUM tokens have meaningful values. For other
+ tokens this function will always return zero. */
+double
+lex_tokval (const struct lexer *lexer)
+{
+ return lex_next_tokval (lexer, 0);
+}
+
+/* Returns the null-terminated string in LEXER's current token, UTF-8 encoded.
+
+ Only T_ID and T_STRING tokens have meaningful strings. For other tokens
+ this functions this function will always return NULL.
+
+ The UTF-8 encoding of the returned string is correct for variable names and
+ other identifiers. Use filename_to_utf8() to use it as a filename. Use
+ data_in() to use it in a "union value". */
+const char *
+lex_tokcstr (const struct lexer *lexer)
+{
+ return lex_next_tokcstr (lexer, 0);
+}
+
+/* Returns the string in LEXER's current token, UTF-8 encoded. The string is
+ null-terminated (but the null terminator is not included in the returned
+ substring's 'length').
+
+ Only T_ID and T_STRING tokens have meaningful strings. For other tokens
+ this functions this function will always return NULL.
+
+ The UTF-8 encoding of the returned string is correct for variable names and
+ other identifiers. Use filename_to_utf8() to use it as a filename. Use
+ data_in() to use it in a "union value". */
+struct substring
+lex_tokss (const struct lexer *lexer)
+{
+ return lex_next_tokss (lexer, 0);
+}
+\f
+/* Looking ahead.
+
+ A value of 0 for N as an argument to any of these functions refers to the
+ current token. Lookahead is limited to the current command. Any N greater
+ than the number of tokens remaining in the current command will be treated
+ as referring to a T_ENDCMD token. */
+
+static const struct lex_token *
+lex_next__ (const struct lexer *lexer_, int n)
+{
+ struct lexer *lexer = CONST_CAST (struct lexer *, lexer_);
+ struct lex_source *src = lex_source__ (lexer);
+
+ if (src != NULL)
+ return lex_source_next__ (src, n);
+ else
+ {
+ static const struct lex_token stop_token = { .token = { .type = T_STOP } };
+ return &stop_token;
+ }
+}
+
+static const struct lex_token *
+lex_source_ofs__ (const struct lex_source *src_, int ofs)
+{
+ struct lex_source *src = CONST_CAST (struct lex_source *, src_);
+
+ if (ofs < 0)
+ {
+ static const struct lex_token endcmd_token
+ = { .token = { .type = T_ENDCMD } };
+ return &endcmd_token;
+ }
+
+ while (ofs >= src->n_parse)
+ {
+ if (src->n_parse > 0)