/* Bison Grammar Scanner -*- C -*-
- Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of Bison, the GNU Compiler Compiler.
#include "system.h"
#include <mbswidth.h>
-#include <get-errno.h>
#include <quote.h>
#include "complain.h"
#include "gram.h"
#include "quotearg.h"
#include "reader.h"
+#include "verify.h"
#include "uniqstr.h"
#define YY_USER_INIT \
Outside of well-formed rules, RULE_LENGTH has an undefined value. */
static int rule_length;
+static void rule_length_overflow (location) __attribute__ ((__noreturn__));
+
+/* Increment the rule length by one, checking for overflow. */
+static inline void
+increment_rule_length (location loc)
+{
+ rule_length++;
+
+ /* Don't allow rule_length == INT_MAX, since that might cause
+ confusion with strtol if INT_MAX == LONG_MAX. */
+ if (rule_length == INT_MAX)
+ rule_length_overflow (loc);
+}
+
static void handle_dollar (int token_type, char *cp, location loc);
static void handle_at (int token_type, char *cp, location loc);
-static void handle_syncline (char *args);
+static void handle_syncline (char *, location);
static unsigned long int scan_integer (char const *p, int base, location loc);
static int convert_ucn_to_byte (char const *hex_text);
static void unexpected_eof (boundary, char const *);
/* #line directives are not documented, and may be withdrawn or
modified in future versions of Bison. */
^"#line "{int}" \"".*"\"\n" {
- handle_syncline (yytext + sizeof "#line " - 1);
+ handle_syncline (yytext + sizeof "#line " - 1, *loc);
}
}
{id} {
val->symbol = symbol_get (yytext, *loc);
id_loc = *loc;
- rule_length++;
+ increment_rule_length (*loc);
BEGIN SC_AFTER_IDENTIFIER;
}
STRING_FINISH;
loc->start = token_start;
val->chars = last_string;
- rule_length++;
+ increment_rule_length (*loc);
BEGIN INITIAL;
return STRING;
}
val->symbol = symbol_get (quotearg_style (escape_quoting_style,
last_string),
*loc);
- symbol_class_set (val->symbol, token_sym, *loc);
+ symbol_class_set (val->symbol, token_sym, *loc, false);
last_string_1 = last_string[1];
symbol_user_token_number_set (val->symbol, last_string_1, *loc);
STRING_FREE;
- rule_length++;
+ increment_rule_length (*loc);
BEGIN INITIAL;
return ID;
}
<SC_ESCAPED_STRING,SC_ESCAPED_CHARACTER>
{
\\[0-7]{1,3} {
- unsigned long int c = strtoul (yytext + 1, 0, 8);
+ unsigned long int c = strtoul (yytext + 1, NULL, 8);
if (UCHAR_MAX < c)
complain_at (*loc, _("invalid escape sequence: %s"), quote (yytext));
else if (! c)
}
\\x[0-9abcdefABCDEF]+ {
- unsigned long int c;
- set_errno (0);
- c = strtoul (yytext + 2, 0, 16);
- if (UCHAR_MAX < c || get_errno ())
+ verify (UCHAR_MAX < ULONG_MAX);
+ unsigned long int c = strtoul (yytext + 2, NULL, 16);
+ if (UCHAR_MAX < c)
complain_at (*loc, _("invalid escape sequence: %s"), quote (yytext));
else if (! c)
complain_at (*loc, _("invalid null character: %s"), quote (yytext));
if (outer_brace)
{
STRING_FINISH;
- rule_length++;
loc->start = code_start;
val->chars = last_string;
+ increment_rule_length (*loc);
BEGIN INITIAL;
return token_type;
}
semantic actions of this grammar. */
int max_left_semantic_context = 0;
+/* If BUF is null, add BUFSIZE (which in this case must be less than
+ INT_MAX) to COLUMN; otherwise, add mbsnwidth (BUF, BUFSIZE, 0) to
+ COLUMN. If an overflow occurs, or might occur but is undetectable,
+ return INT_MAX. Assume COLUMN is nonnegative. */
+
+static inline int
+add_column_width (int column, char const *buf, size_t bufsize)
+{
+ size_t width;
+ unsigned int remaining_columns = INT_MAX - column;
+
+ if (buf)
+ {
+ if (INT_MAX / 2 <= bufsize)
+ return INT_MAX;
+ width = mbsnwidth (buf, bufsize, 0);
+ }
+ else
+ width = bufsize;
+
+ return width <= remaining_columns ? column + width : INT_MAX;
+}
+
/* Set *LOC and adjust scanner cursor to account for token TOKEN of
size SIZE. */
switch (*p)
{
case '\n':
- line++;
+ line += line < INT_MAX;
column = 1;
p0 = p + 1;
break;
case '\t':
- column += mbsnwidth (p0, p - p0, 0);
- column += 8 - ((column - 1) & 7);
- p0 = p + 1;
- break;
+ {
+ column = add_column_width (column, p0, p - p0);
+ column = add_column_width (column, NULL, 8 - ((column - 1) & 7));
+ p0 = p + 1;
+ break;
+ }
}
scanner_cursor.line = line;
- scanner_cursor.column = column + mbsnwidth (p0, p - p0, 0);
+ scanner_cursor.column = column = add_column_width (column, p0, p - p0);
loc->end = scanner_cursor;
+
+ if (line == INT_MAX && loc->start.line != INT_MAX)
+ warn_at (*loc, _("line number overflow"));
+ if (column == INT_MAX && loc->start.column != INT_MAX)
+ warn_at (*loc, _("column number overflow"));
}
type_name = "";
obstack_fgrow1 (&obstack_for_string,
"]b4_lhs_value([%s])[", type_name);
+ current_rule->used = true;
}
else
{
- long int num;
- set_errno (0);
- num = strtol (cp, 0, 10);
+ long int num = strtol (cp, NULL, 10);
- if (INT_MIN <= num && num <= rule_length && ! get_errno ())
+ if (1 - INT_MAX + rule_length <= num && num <= rule_length)
{
int n = num;
- if (1-n > max_left_semantic_context)
- max_left_semantic_context = 1-n;
- if (!type_name && n > 0)
+ if (max_left_semantic_context < 1 - n)
+ max_left_semantic_context = 1 - n;
+ if (!type_name && 0 < n)
type_name = symbol_list_n_type_name_get (current_rule, loc, n);
if (!type_name && typed)
complain_at (loc, _("$%d of `%s' has no declared type"),
obstack_fgrow3 (&obstack_for_string,
"]b4_rhs_value(%d, %d, [%s])[",
rule_length, n, type_name);
+ symbol_list_n_used_set (current_rule, n, true);
}
else
complain_at (loc, _("integer out of range: %s"), quote (text));
obstack_sgrow (&obstack_for_string, "]b4_lhs_location[");
else
{
- long int num;
- set_errno (0);
- num = strtol (cp, 0, 10);
+ long int num = strtol (cp, NULL, 10);
- if (INT_MIN <= num && num <= rule_length && ! get_errno ())
+ if (1 - INT_MAX + rule_length <= num && num <= rule_length)
{
int n = num;
obstack_fgrow2 (&obstack_for_string, "]b4_rhs_location(%d, %d)[",
static unsigned long int
scan_integer (char const *number, int base, location loc)
{
- unsigned long int num;
- set_errno (0);
- num = strtoul (number, 0, base);
- if (INT_MAX < num || get_errno ())
+ verify (INT_MAX < ULONG_MAX);
+ unsigned long int num = strtoul (number, NULL, base);
+
+ if (INT_MAX < num)
{
complain_at (loc, _("integer out of range: %s"), quote (number));
num = INT_MAX;
}
+
return num;
}
static int
convert_ucn_to_byte (char const *ucn)
{
- unsigned long int code = strtoul (ucn + 2, 0, 16);
+ verify (UCHAR_MAX <= INT_MAX);
+ unsigned long int code = strtoul (ucn + 2, NULL, 16);
/* FIXME: Currently we assume Unicode-compatible unibyte characters
on ASCII hosts (i.e., Latin-1 on hosts with 8-bit bytes). On
`----------------------------------------------------------------*/
static void
-handle_syncline (char *args)
+handle_syncline (char *args, location loc)
{
- int lineno = strtol (args, &args, 10);
- const char *file = NULL;
- file = strchr (args, '"') + 1;
- *strchr (file, '"') = 0;
+ char *after_num;
+ unsigned long int lineno = strtoul (args, &after_num, 10);
+ char *file = strchr (after_num, '"') + 1;
+ *strchr (file, '"') = '\0';
+ if (INT_MAX <= lineno)
+ {
+ warn_at (loc, _("line number overflow"));
+ lineno = INT_MAX;
+ }
scanner_cursor.file = current_file = uniqstr_new (file);
scanner_cursor.line = lineno;
scanner_cursor.column = 1;
}
+/*---------------------------------.
+| Report a rule that is too long. |
+`---------------------------------*/
+
+static void
+rule_length_overflow (location loc)
+{
+ fatal_at (loc, _("rule is too long"));
+}
+
+
/*----------------------------------------------------------------.
| For a token or comment starting at START, report message MSGID, |
| which should say that an end marker was found before |