/* Parse C expressions for CCCP.
- Copyright (C) 1987, 1992 Free Software Foundation.
+ Copyright (C) 1987, 1992, 1994, 1995, 1996 Free Software Foundation.
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 the
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
-Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
In other words, you are welcome to use, share and improve this program.
You are forbidden to forbid anyone else to use, share and improve
#include <setjmp.h>
/* #define YYDEBUG 1 */
+/* The following symbols should be autoconfigured:
+ HAVE_STDLIB_H
+ STDC_HEADERS
+ In the mean time, we'll get by with approximations based
+ on existing GCC configuration symbols. */
+
+#ifdef POSIX
+# ifndef HAVE_STDLIB_H
+# define HAVE_STDLIB_H 1
+# endif
+# ifndef STDC_HEADERS
+# define STDC_HEADERS 1
+# endif
+#endif /* defined (POSIX) */
+
+#if STDC_HEADERS
+# include <string.h>
+#endif
+
+#if HAVE_STDLIB_H || defined (MULTIBYTE_CHARS)
+# include <stdlib.h>
+#endif
+
#ifdef MULTIBYTE_CHARS
-#include <stdlib.h>
#include <locale.h>
#endif
#define NULL_PTR ((GENERIC_PTR)0)
#endif
-int yylex ();
-void yyerror ();
-int expression_value;
+/* Find the largest host integer type and set its size and type.
+ Don't blindly use `long'; on some crazy hosts it is shorter than `int'. */
+
+#ifndef HOST_BITS_PER_WIDE_INT
+
+#if HOST_BITS_PER_LONG > HOST_BITS_PER_INT
+#define HOST_BITS_PER_WIDE_INT HOST_BITS_PER_LONG
+#define HOST_WIDE_INT long
+#else
+#define HOST_BITS_PER_WIDE_INT HOST_BITS_PER_INT
+#define HOST_WIDE_INT int
+#endif
+
+#endif
+
+#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 6)
+# define __attribute__(x)
+#endif
+
+#ifndef PROTO
+# if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
+# define PROTO(ARGS) ARGS
+# else
+# define PROTO(ARGS) ()
+# endif
+#endif
+
+#if defined (__STDC__) && defined (HAVE_VPRINTF)
+# include <stdarg.h>
+# define VA_START(va_list, var) va_start (va_list, var)
+# define PRINTF_ALIST(msg) char *msg, ...
+# define PRINTF_DCL(msg)
+# define PRINTF_PROTO(ARGS, m, n) PROTO (ARGS) __attribute__ ((format (printf, m, n)))
+#else
+# include <varargs.h>
+# define VA_START(va_list, var) va_start (va_list)
+# define PRINTF_ALIST(msg) msg, va_alist
+# define PRINTF_DCL(msg) char *msg; va_dcl
+# define PRINTF_PROTO(ARGS, m, n) () __attribute__ ((format (printf, m, n)))
+# define vfprintf(file, msg, args) \
+ { \
+ char *a0 = va_arg(args, char *); \
+ char *a1 = va_arg(args, char *); \
+ char *a2 = va_arg(args, char *); \
+ char *a3 = va_arg(args, char *); \
+ fprintf (file, msg, a0, a1, a2, a3); \
+ }
+#endif
+
+#define PRINTF_PROTO_1(ARGS) PRINTF_PROTO(ARGS, 1, 2)
+
+HOST_WIDE_INT parse_c_expression PROTO((char *));
+
+static int yylex PROTO((void));
+static void yyerror PROTO((char *)) __attribute__ ((noreturn));
+static HOST_WIDE_INT expression_value;
static jmp_buf parse_return_error;
/* Nonzero means count most punctuation as part of a name. */
static int keyword_parsing = 0;
+/* Nonzero means do not evaluate this expression.
+ This is a count, since unevaluated expressions can nest. */
+static int skip_evaluation;
+
/* some external tables of character types */
extern unsigned char is_idstart[], is_idchar[], is_hor_space[];
-extern char *xmalloc ();
-
/* Flag for -pedantic. */
extern int pedantic;
#define WCHAR_TYPE_SIZE INT_TYPE_SIZE
#endif
-/* Yield nonzero if adding two numbers with A's and B's signs can yield a
- number with SUM's sign, where A, B, and SUM are all C integers. */
-#define possible_sum_sign(a, b, sum) ((((a) ^ (b)) | ~ ((a) ^ (sum))) < 0)
+#ifndef MAX_CHAR_TYPE_SIZE
+#define MAX_CHAR_TYPE_SIZE CHAR_TYPE_SIZE
+#endif
+
+#ifndef MAX_INT_TYPE_SIZE
+#define MAX_INT_TYPE_SIZE INT_TYPE_SIZE
+#endif
+
+#ifndef MAX_LONG_TYPE_SIZE
+#define MAX_LONG_TYPE_SIZE LONG_TYPE_SIZE
+#endif
+
+#ifndef MAX_WCHAR_TYPE_SIZE
+#define MAX_WCHAR_TYPE_SIZE WCHAR_TYPE_SIZE
+#endif
+
+#if MAX_CHAR_TYPE_SIZE < HOST_BITS_PER_WIDE_INT
+#define MAX_CHAR_TYPE_MASK (~ (~ (HOST_WIDE_INT) 0 << MAX_CHAR_TYPE_SIZE))
+#else
+#define MAX_CHAR_TYPE_MASK (~ (HOST_WIDE_INT) 0)
+#endif
+
+#if MAX_WCHAR_TYPE_SIZE < HOST_BITS_PER_WIDE_INT
+#define MAX_WCHAR_TYPE_MASK (~ (~ (HOST_WIDE_INT) 0 << MAX_WCHAR_TYPE_SIZE))
+#else
+#define MAX_WCHAR_TYPE_MASK (~ (HOST_WIDE_INT) 0)
+#endif
-static void integer_overflow ();
-static long left_shift ();
-static long right_shift ();
+/* Suppose A1 + B1 = SUM1, using 2's complement arithmetic ignoring overflow.
+ Suppose A, B and SUM have the same respective signs as A1, B1, and SUM1.
+ Suppose SIGNEDP is negative if the result is signed, zero if unsigned.
+ Then this yields nonzero if overflow occurred during the addition.
+ Overflow occurs if A and B have the same sign, but A and SUM differ in sign,
+ and SIGNEDP is negative.
+ Use `^' to test whether signs differ, and `< 0' to isolate the sign. */
+#define overflow_sum_sign(a, b, sum, signedp) \
+ ((~((a) ^ (b)) & ((a) ^ (sum)) & (signedp)) < 0)
+
+struct constant;
+
+GENERIC_PTR xmalloc PROTO((size_t));
+HOST_WIDE_INT parse_escape PROTO((char **, HOST_WIDE_INT));
+int check_assertion PROTO((U_CHAR *, int, int, struct arglist *));
+struct hashnode *lookup PROTO((U_CHAR *, int, int));
+void error PRINTF_PROTO_1((char *, ...));
+void pedwarn PRINTF_PROTO_1((char *, ...));
+void warning PRINTF_PROTO_1((char *, ...));
+
+static int parse_number PROTO((int));
+static HOST_WIDE_INT left_shift PROTO((struct constant *, unsigned HOST_WIDE_INT));
+static HOST_WIDE_INT right_shift PROTO((struct constant *, unsigned HOST_WIDE_INT));
+static void integer_overflow PROTO((void));
+
+/* `signedp' values */
+#define SIGNED (~0)
+#define UNSIGNED 0
%}
%union {
- struct constant {long value; int unsignedp;} integer;
+ struct constant {HOST_WIDE_INT value; int signedp;} integer;
struct name {U_CHAR *address; int length;} name;
struct arglist *keywords;
- int voidval;
- char *sval;
}
%type <integer> exp exp1 start
/* Expressions, not including the comma operator. */
exp : '-' exp %prec UNARY
{ $$.value = - $2.value;
- if (($$.value & $2.value) < 0 && ! $2.unsignedp)
- integer_overflow ();
- $$.unsignedp = $2.unsignedp; }
+ $$.signedp = $2.signedp;
+ if (($$.value & $2.value & $$.signedp) < 0)
+ integer_overflow (); }
| '!' exp %prec UNARY
{ $$.value = ! $2.value;
- $$.unsignedp = 0; }
+ $$.signedp = SIGNED; }
| '+' exp %prec UNARY
{ $$ = $2; }
| '~' exp %prec UNARY
{ $$.value = ~ $2.value;
- $$.unsignedp = $2.unsignedp; }
+ $$.signedp = $2.signedp; }
| '#' NAME
{ $$.value = check_assertion ($2.address, $2.length,
0, NULL_PTR);
- $$.unsignedp = 0; }
+ $$.signedp = SIGNED; }
| '#' NAME
{ keyword_parsing = 1; }
'(' keywords ')'
{ $$.value = check_assertion ($2.address, $2.length,
1, $5);
keyword_parsing = 0;
- $$.unsignedp = 0; }
+ $$.signedp = SIGNED; }
| '(' exp1 ')'
{ $$ = $2; }
;
/* Binary operators in order of decreasing precedence. */
exp : exp '*' exp
- { $$.unsignedp = $1.unsignedp || $3.unsignedp;
- if ($$.unsignedp)
- $$.value = (unsigned long) $1.value * $3.value;
- else
+ { $$.signedp = $1.signedp & $3.signedp;
+ if ($$.signedp)
{
$$.value = $1.value * $3.value;
if ($1.value
&& ($$.value / $1.value != $3.value
|| ($$.value & $1.value & $3.value) < 0))
integer_overflow ();
- } }
+ }
+ else
+ $$.value = ((unsigned HOST_WIDE_INT) $1.value
+ * $3.value); }
| exp '/' exp
{ if ($3.value == 0)
{
- error ("division by zero in #if");
+ if (!skip_evaluation)
+ error ("division by zero in #if");
$3.value = 1;
}
- $$.unsignedp = $1.unsignedp || $3.unsignedp;
- if ($$.unsignedp)
- $$.value = (unsigned long) $1.value / $3.value;
- else
+ $$.signedp = $1.signedp & $3.signedp;
+ if ($$.signedp)
{
$$.value = $1.value / $3.value;
if (($$.value & $1.value & $3.value) < 0)
integer_overflow ();
- } }
+ }
+ else
+ $$.value = ((unsigned HOST_WIDE_INT) $1.value
+ / $3.value); }
| exp '%' exp
{ if ($3.value == 0)
{
- error ("division by zero in #if");
+ if (!skip_evaluation)
+ error ("division by zero in #if");
$3.value = 1;
}
- $$.unsignedp = $1.unsignedp || $3.unsignedp;
- if ($$.unsignedp)
- $$.value = (unsigned long) $1.value % $3.value;
+ $$.signedp = $1.signedp & $3.signedp;
+ if ($$.signedp)
+ $$.value = $1.value % $3.value;
else
- $$.value = $1.value % $3.value; }
+ $$.value = ((unsigned HOST_WIDE_INT) $1.value
+ % $3.value); }
| exp '+' exp
{ $$.value = $1.value + $3.value;
- $$.unsignedp = $1.unsignedp || $3.unsignedp;
- if (! $$.unsignedp
- && ! possible_sum_sign ($1.value, $3.value,
- $$.value))
+ $$.signedp = $1.signedp & $3.signedp;
+ if (overflow_sum_sign ($1.value, $3.value,
+ $$.value, $$.signedp))
integer_overflow (); }
| exp '-' exp
{ $$.value = $1.value - $3.value;
- $$.unsignedp = $1.unsignedp || $3.unsignedp;
- if (! $$.unsignedp
- && ! possible_sum_sign ($$.value, $3.value,
- $1.value))
+ $$.signedp = $1.signedp & $3.signedp;
+ if (overflow_sum_sign ($$.value, $3.value,
+ $1.value, $$.signedp))
integer_overflow (); }
| exp LSH exp
- { $$.unsignedp = $1.unsignedp;
- if ($3.value < 0 && ! $3.unsignedp)
+ { $$.signedp = $1.signedp;
+ if (($3.value & $3.signedp) < 0)
$$.value = right_shift (&$1, -$3.value);
else
$$.value = left_shift (&$1, $3.value); }
| exp RSH exp
- { $$.unsignedp = $1.unsignedp;
- if ($3.value < 0 && ! $3.unsignedp)
+ { $$.signedp = $1.signedp;
+ if (($3.value & $3.signedp) < 0)
$$.value = left_shift (&$1, -$3.value);
else
$$.value = right_shift (&$1, $3.value); }
| exp EQUAL exp
{ $$.value = ($1.value == $3.value);
- $$.unsignedp = 0; }
+ $$.signedp = SIGNED; }
| exp NOTEQUAL exp
{ $$.value = ($1.value != $3.value);
- $$.unsignedp = 0; }
+ $$.signedp = SIGNED; }
| exp LEQ exp
- { $$.unsignedp = 0;
- if ($1.unsignedp || $3.unsignedp)
- $$.value = (unsigned long) $1.value <= $3.value;
+ { $$.signedp = SIGNED;
+ if ($1.signedp & $3.signedp)
+ $$.value = $1.value <= $3.value;
else
- $$.value = $1.value <= $3.value; }
+ $$.value = ((unsigned HOST_WIDE_INT) $1.value
+ <= $3.value); }
| exp GEQ exp
- { $$.unsignedp = 0;
- if ($1.unsignedp || $3.unsignedp)
- $$.value = (unsigned long) $1.value >= $3.value;
+ { $$.signedp = SIGNED;
+ if ($1.signedp & $3.signedp)
+ $$.value = $1.value >= $3.value;
else
- $$.value = $1.value >= $3.value; }
+ $$.value = ((unsigned HOST_WIDE_INT) $1.value
+ >= $3.value); }
| exp '<' exp
- { $$.unsignedp = 0;
- if ($1.unsignedp || $3.unsignedp)
- $$.value = (unsigned long) $1.value < $3.value;
+ { $$.signedp = SIGNED;
+ if ($1.signedp & $3.signedp)
+ $$.value = $1.value < $3.value;
else
- $$.value = $1.value < $3.value; }
+ $$.value = ((unsigned HOST_WIDE_INT) $1.value
+ < $3.value); }
| exp '>' exp
- { $$.unsignedp = 0;
- if ($1.unsignedp || $3.unsignedp)
- $$.value = (unsigned long) $1.value > $3.value;
+ { $$.signedp = SIGNED;
+ if ($1.signedp & $3.signedp)
+ $$.value = $1.value > $3.value;
else
- $$.value = $1.value > $3.value; }
+ $$.value = ((unsigned HOST_WIDE_INT) $1.value
+ > $3.value); }
| exp '&' exp
{ $$.value = $1.value & $3.value;
- $$.unsignedp = $1.unsignedp || $3.unsignedp; }
+ $$.signedp = $1.signedp & $3.signedp; }
| exp '^' exp
{ $$.value = $1.value ^ $3.value;
- $$.unsignedp = $1.unsignedp || $3.unsignedp; }
+ $$.signedp = $1.signedp & $3.signedp; }
| exp '|' exp
{ $$.value = $1.value | $3.value;
- $$.unsignedp = $1.unsignedp || $3.unsignedp; }
- | exp AND exp
- { $$.value = ($1.value && $3.value);
- $$.unsignedp = 0; }
- | exp OR exp
- { $$.value = ($1.value || $3.value);
- $$.unsignedp = 0; }
- | exp '?' exp ':' exp
- { $$.value = $1.value ? $3.value : $5.value;
- $$.unsignedp = $3.unsignedp || $5.unsignedp; }
+ $$.signedp = $1.signedp & $3.signedp; }
+ | exp AND
+ { skip_evaluation += !$1.value; }
+ exp
+ { skip_evaluation -= !$1.value;
+ $$.value = ($1.value && $4.value);
+ $$.signedp = SIGNED; }
+ | exp OR
+ { skip_evaluation += !!$1.value; }
+ exp
+ { skip_evaluation -= !!$1.value;
+ $$.value = ($1.value || $4.value);
+ $$.signedp = SIGNED; }
+ | exp '?'
+ { skip_evaluation += !$1.value; }
+ exp ':'
+ { skip_evaluation += !!$1.value - !$1.value; }
+ exp
+ { skip_evaluation -= !!$1.value;
+ $$.value = $1.value ? $4.value : $7.value;
+ $$.signedp = $4.signedp & $7.signedp; }
| INT
{ $$ = yylval.integer; }
| CHAR
{ $$ = yylval.integer; }
| NAME
{ $$.value = 0;
- $$.unsignedp = 0; }
+ $$.signedp = SIGNED; }
;
keywords :
/* maybe needs to actually deal with floating point numbers */
-int
+static int
parse_number (olen)
int olen;
{
register char *p = lexptr;
- register long n = 0;
register int c;
+ register unsigned HOST_WIDE_INT n = 0, nd, max_over_base;
register int base = 10;
register int len = olen;
+ register int overflow = 0;
+ register int digit, largest_digit = 0;
+ int spec_long = 0;
- for (c = 0; c < len; c++)
- if (p[c] == '.') {
- /* It's a float since it contains a point. */
- yyerror ("floating point numbers not allowed in #if expressions");
- return ERROR;
- }
-
- yylval.integer.unsignedp = 0;
+ yylval.integer.signedp = SIGNED;
- if (len >= 3 && (!strncmp (p, "0x", 2) || !strncmp (p, "0X", 2))) {
- p += 2;
- base = 16;
- len -= 2;
- }
- else if (*p == '0')
+ if (*p == '0') {
base = 8;
+ if (len >= 3 && (p[1] == 'x' || p[1] == 'X')) {
+ p += 2;
+ base = 16;
+ len -= 2;
+ }
+ }
+
+ max_over_base = (unsigned HOST_WIDE_INT) -1 / base;
- while (len > 0) {
+ for (; len > 0; len--) {
c = *p++;
- len--;
- if (c >= 'A' && c <= 'Z') c += 'a' - 'A';
-
- if (c >= '0' && c <= '9') {
- n *= base;
- n += c - '0';
- } else if (base == 16 && c >= 'a' && c <= 'f') {
- n *= base;
- n += c - 'a' + 10;
- } else {
+
+ if (c >= '0' && c <= '9')
+ digit = c - '0';
+ else if (base == 16 && c >= 'a' && c <= 'f')
+ digit = c - 'a' + 10;
+ else if (base == 16 && c >= 'A' && c <= 'F')
+ digit = c - 'A' + 10;
+ else {
/* `l' means long, and `u' means unsigned. */
while (1) {
if (c == 'l' || c == 'L')
- ;
+ {
+ if (!pedantic < spec_long)
+ yyerror ("too many `l's in integer constant");
+ spec_long++;
+ }
else if (c == 'u' || c == 'U')
- yylval.integer.unsignedp = 1;
- else
- break;
+ {
+ if (! yylval.integer.signedp)
+ yyerror ("two `u's in integer constant");
+ yylval.integer.signedp = UNSIGNED;
+ }
+ else {
+ if (c == '.' || c == 'e' || c == 'E')
+ yyerror ("Floating point numbers not allowed in #if expressions");
+ else {
+ char *buf = (char *) alloca (p - lexptr + 40);
+ sprintf (buf, "missing white space after number `%.*s'",
+ (int) (p - lexptr - 1), lexptr);
+ yyerror (buf);
+ }
+ }
- if (len == 0)
+ if (--len == 0)
break;
c = *p++;
- len--;
}
/* Don't look for any more digits after the suffixes. */
break;
}
+ if (largest_digit < digit)
+ largest_digit = digit;
+ nd = n * base + digit;
+ overflow |= (max_over_base < n) | (nd < n);
+ n = nd;
}
- if (len != 0) {
- yyerror ("Invalid number in #if expression");
- return ERROR;
- }
+ if (base <= largest_digit)
+ warning ("integer constant contains digits beyond the radix");
+
+ if (overflow)
+ warning ("integer constant out of range");
/* If too big to be signed, consider it unsigned. */
- if (n < 0)
- yylval.integer.unsignedp = 1;
+ if (((HOST_WIDE_INT) n & yylval.integer.signedp) < 0)
+ {
+ if (base == 10)
+ warning ("integer constant is so large that it is unsigned");
+ yylval.integer.signedp = UNSIGNED;
+ }
lexptr = p;
yylval.integer.value = n;
/* Read one token, getting characters through lexptr. */
-int
+static int
yylex ()
{
register int c;
register int namelen;
- register char *tokstart;
+ register unsigned char *tokstart;
register struct token *toktab;
int wide_flag;
+ HOST_WIDE_INT mask;
retry:
- tokstart = lexptr;
+ tokstart = (unsigned char *) lexptr;
c = *tokstart;
/* See if it is a special token of length 2. */
if (! keyword_parsing)
}
switch (c) {
- case 0:
+ case '\n':
return 0;
case ' ':
case '\t':
case '\r':
- case '\n':
lexptr++;
goto retry;
{
lexptr++;
wide_flag = 1;
+ mask = MAX_WCHAR_TYPE_MASK;
goto char_constant;
}
if (lexptr[1] == '"')
{
lexptr++;
wide_flag = 1;
+ mask = MAX_WCHAR_TYPE_MASK;
goto string_constant;
}
break;
case '\'':
wide_flag = 0;
+ mask = MAX_CHAR_TYPE_MASK;
char_constant:
lexptr++;
if (keyword_parsing) {
while (1) {
c = *lexptr++;
if (c == '\\')
- c = parse_escape (&lexptr);
+ c = parse_escape (&lexptr, mask);
else if (c == '\'')
break;
}
- yylval.name.address = (U_CHAR *) tokstart;
+ yylval.name.address = tokstart;
yylval.name.length = lexptr - start_ptr;
return NAME;
}
handles multicharacter constants and wide characters.
It is mostly copied from c-lex.c. */
{
- register int result = 0;
+ register HOST_WIDE_INT result = 0;
register num_chars = 0;
- unsigned width = CHAR_TYPE_SIZE;
+ unsigned width = MAX_CHAR_TYPE_SIZE;
int max_chars;
char *token_buffer;
if (wide_flag)
{
- width = WCHAR_TYPE_SIZE;
+ width = MAX_WCHAR_TYPE_SIZE;
#ifdef MULTIBYTE_CHARS
max_chars = MB_CUR_MAX;
#else
#endif
}
else
- max_chars = LONG_TYPE_SIZE / width;
+ max_chars = MAX_LONG_TYPE_SIZE / width;
token_buffer = (char *) alloca (max_chars + 1);
if (c == '\\')
{
- c = parse_escape (&lexptr);
- if (width < HOST_BITS_PER_INT
- && (unsigned) c >= (1 << width))
- pedwarn ("escape sequence out of range for character");
+ c = parse_escape (&lexptr, mask);
}
num_chars++;
/* Merge character into result; ignore excess chars. */
- if (num_chars < max_chars + 1)
+ if (num_chars <= max_chars)
{
- if (width < HOST_BITS_PER_INT)
- result = (result << width) | (c & ((1 << width) - 1));
+ if (width < HOST_BITS_PER_WIDE_INT)
+ result = (result << width) | c;
else
result = c;
token_buffer[num_chars - 1] = c;
if (lookup ("__CHAR_UNSIGNED__", sizeof ("__CHAR_UNSIGNED__")-1, -1)
|| ((result >> (num_bits - 1)) & 1) == 0)
yylval.integer.value
- = result & ((unsigned long) ~0 >> (HOST_BITS_PER_LONG - num_bits));
+ = result & (~ (unsigned HOST_WIDE_INT) 0
+ >> (HOST_BITS_PER_WIDE_INT - num_bits));
else
yylval.integer.value
- = result | ~((unsigned long) ~0 >> (HOST_BITS_PER_LONG - num_bits));
+ = result | ~(~ (unsigned HOST_WIDE_INT) 0
+ >> (HOST_BITS_PER_WIDE_INT - num_bits));
}
else
{
}
/* This is always a signed type. */
- yylval.integer.unsignedp = 0;
+ yylval.integer.signedp = SIGNED;
return CHAR;
return c;
case '"':
+ mask = MAX_CHAR_TYPE_MASK;
string_constant:
if (keyword_parsing) {
char *start_ptr = lexptr;
while (1) {
c = *lexptr++;
if (c == '\\')
- c = parse_escape (&lexptr);
+ c = parse_escape (&lexptr, mask);
else if (c == '"')
break;
}
- yylval.name.address = (U_CHAR *) tokstart;
+ yylval.name.address = tokstart;
yylval.name.length = lexptr - start_ptr;
return NAME;
}
if (c >= '0' && c <= '9' && !keyword_parsing) {
/* It's a number */
- for (namelen = 0;
- c = tokstart[namelen], is_idchar[c] || c == '.';
- namelen++)
- ;
+ for (namelen = 1; ; namelen++) {
+ int d = tokstart[namelen];
+ if (! ((is_idchar[d] || d == '.')
+ || ((d == '-' || d == '+') && (c == 'e' || c == 'E')
+ && ! traditional)))
+ break;
+ c = d;
+ }
return parse_number (namelen);
}
}
lexptr += namelen;
- yylval.name.address = (U_CHAR *) tokstart;
+ yylval.name.address = tokstart;
yylval.name.length = namelen;
return NAME;
}
is updated past the characters we use. The value of the
escape sequence is returned.
+ RESULT_MASK is used to mask out the result;
+ an error is reported if bits are lost thereby.
+
A negative value means the sequence \ newline was seen,
which is supposed to be equivalent to nothing at all.
If \ is followed by 000, we return 0 and leave the string pointer
after the zeros. A value of 0 does not mean end of string. */
-int
-parse_escape (string_ptr)
+HOST_WIDE_INT
+parse_escape (string_ptr, result_mask)
char **string_ptr;
+ HOST_WIDE_INT result_mask;
{
register int c = *(*string_ptr)++;
switch (c)
case 'b':
return TARGET_BS;
case 'e':
+ case 'E':
+ if (pedantic)
+ pedwarn ("non-ANSI-standard escape sequence, `\\%c'", c);
return 033;
case 'f':
return TARGET_FF;
case 0:
(*string_ptr)--;
return 0;
- case '^':
- c = *(*string_ptr)++;
- if (c == '\\')
- c = parse_escape (string_ptr);
- if (c == '?')
- return 0177;
- return (c & 0200) | (c & 037);
case '0':
case '1':
case '6':
case '7':
{
- register int i = c - '0';
+ register HOST_WIDE_INT i = c - '0';
register int count = 0;
while (++count < 3)
{
break;
}
}
- if ((i & ~((1 << CHAR_TYPE_SIZE) - 1)) != 0)
+ if (i != (i & result_mask))
{
- i &= (1 << CHAR_TYPE_SIZE) - 1;
- warning ("octal character constant does not fit in a byte");
+ i &= result_mask;
+ pedwarn ("octal escape sequence out of range");
}
return i;
}
case 'x':
{
- register int i = 0;
+ register unsigned HOST_WIDE_INT i = 0, overflow = 0;
+ register int digits_found = 0, digit;
for (;;)
{
c = *(*string_ptr)++;
if (c >= '0' && c <= '9')
- i = (i << 4) + c - '0';
+ digit = c - '0';
else if (c >= 'a' && c <= 'f')
- i = (i << 4) + c - 'a' + 10;
+ digit = c - 'a' + 10;
else if (c >= 'A' && c <= 'F')
- i = (i << 4) + c - 'A' + 10;
+ digit = c - 'A' + 10;
else
{
(*string_ptr)--;
break;
}
+ overflow |= i ^ (i << 4 >> 4);
+ i = (i << 4) + digit;
+ digits_found = 1;
}
- if ((i & ~((1 << BITS_PER_UNIT) - 1)) != 0)
+ if (!digits_found)
+ yyerror ("\\x used with no following hex digits");
+ if (overflow | (i != (i & result_mask)))
{
- i &= (1 << BITS_PER_UNIT) - 1;
- warning ("hex character constant does not fit in a byte");
+ i &= result_mask;
+ pedwarn ("hex escape sequence out of range");
}
return i;
}
}
}
-void
+static void
yyerror (s)
char *s;
{
- error (s);
+ error ("%s", s);
+ skip_evaluation = 0;
longjmp (parse_return_error, 1);
}
static void
integer_overflow ()
{
- pedwarn ("integer overflow in preprocessor expression");
+ if (!skip_evaluation && pedantic)
+ pedwarn ("integer overflow in preprocessor expression");
}
-static long
+static HOST_WIDE_INT
left_shift (a, b)
struct constant *a;
- unsigned long b;
+ unsigned HOST_WIDE_INT b;
{
- if (b >= HOST_BITS_PER_LONG)
- {
- if (! a->unsignedp && a->value != 0)
- integer_overflow ();
- return 0;
- }
- else if (a->unsignedp)
- return (unsigned long) a->value << b;
+ /* It's unclear from the C standard whether shifts can overflow.
+ The following code ignores overflow; perhaps a C standard
+ interpretation ruling is needed. */
+ if (b >= HOST_BITS_PER_WIDE_INT)
+ return 0;
else
- {
- long l = a->value << b;
- if (l >> b != a->value)
- integer_overflow ();
- return l;
- }
+ return (unsigned HOST_WIDE_INT) a->value << b;
}
-static long
+static HOST_WIDE_INT
right_shift (a, b)
struct constant *a;
- unsigned long b;
+ unsigned HOST_WIDE_INT b;
{
- if (b >= HOST_BITS_PER_LONG)
- return a->unsignedp ? 0 : a->value >> (HOST_BITS_PER_LONG - 1);
- else if (a->unsignedp)
- return (unsigned long) a->value >> b;
- else
+ if (b >= HOST_BITS_PER_WIDE_INT)
+ return a->signedp ? a->value >> (HOST_BITS_PER_WIDE_INT - 1) : 0;
+ else if (a->signedp)
return a->value >> b;
+ else
+ return (unsigned HOST_WIDE_INT) a->value >> b;
}
\f
/* This page contains the entry point to this file. */
/* Parse STRING as an expression, and complain if this fails
to use up all of the contents of STRING. */
+/* STRING may contain '\0' bytes; it is terminated by the first '\n'
+ outside a string constant, so that we can diagnose '\0' properly. */
/* We do not support C comments. They should be removed before
this function is called. */
-int
+HOST_WIDE_INT
parse_c_expression (string)
char *string;
{
if (yyparse ())
return 0; /* actually this is never reached
the way things stand. */
- if (*lexptr)
+ if (*lexptr != '\n')
error ("Junk after end of expression.");
return expression_value; /* set by yyparse () */
}
\f
#ifdef TEST_EXP_READER
+
+#if YYDEBUG
extern int yydebug;
+#endif
+
+int pedantic;
+int traditional;
+
+int main PROTO((int, char **));
+static void initialize_random_junk PROTO((void));
/* Main program for testing purposes. */
int
-main ()
+main (argc, argv)
+ int argc;
+ char **argv;
{
int n, c;
char buf[1024];
-/*
- yydebug = 1;
-*/
+ pedantic = 1 < argc;
+ traditional = 2 < argc;
+#if YYDEBUG
+ yydebug = 3 < argc;
+#endif
initialize_random_junk ();
for (;;) {
printf ("enter expression: ");
n = 0;
- while ((buf[n] = getchar ()) != '\n' && buf[n] != EOF)
+ while ((buf[n] = c = getchar ()) != '\n' && c != EOF)
n++;
- if (buf[n] == EOF)
+ if (c == EOF)
break;
- buf[n] = '\0';
- printf ("parser returned %d\n", parse_c_expression (buf));
+ printf ("parser returned %ld\n", (long) parse_c_expression (buf));
}
return 0;
unsigned char is_idstart[256];
/* table to tell if c is horizontal space. isspace () thinks that
newline is space; this is not a good idea for this program. */
-char is_hor_space[256];
+unsigned char is_hor_space[256];
/*
* initialize random junk in the hash table and maybe other places
*/
+static void
initialize_random_junk ()
{
register int i;
++is_hor_space['\t'];
}
-error (msg)
+void
+error (PRINTF_ALIST (msg))
+ PRINTF_DCL (msg)
{
- printf ("error: %s\n", msg);
+ va_list args;
+
+ VA_START (args, msg);
+ fprintf (stderr, "error: ");
+ vfprintf (stderr, msg, args);
+ fprintf (stderr, "\n");
+ va_end (args);
}
-warning (msg)
+void
+pedwarn (PRINTF_ALIST (msg))
+ PRINTF_DCL (msg)
{
- printf ("warning: %s\n", msg);
+ va_list args;
+
+ VA_START (args, msg);
+ fprintf (stderr, "pedwarn: ");
+ vfprintf (stderr, msg, args);
+ fprintf (stderr, "\n");
+ va_end (args);
+}
+
+void
+warning (PRINTF_ALIST (msg))
+ PRINTF_DCL (msg)
+{
+ va_list args;
+
+ VA_START (args, msg);
+ fprintf (stderr, "warning: ");
+ vfprintf (stderr, msg, args);
+ fprintf (stderr, "\n");
+ va_end (args);
+}
+
+int
+check_assertion (name, sym_length, tokens_specified, tokens)
+ U_CHAR *name;
+ int sym_length;
+ int tokens_specified;
+ struct arglist *tokens;
+{
+ return 0;
}
struct hashnode *
lookup (name, len, hash)
- char *name;
+ U_CHAR *name;
int len;
int hash;
{
return (DEFAULT_SIGNED_CHAR) ? 0 : ((struct hashnode *) -1);
}
+
+GENERIC_PTR
+xmalloc (size)
+ size_t size;
+{
+ return (GENERIC_PTR) malloc (size);
+}
#endif