summaryrefslogtreecommitdiffstats
path: root/contrib/gcc/cexp.y
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/gcc/cexp.y')
-rw-r--r--contrib/gcc/cexp.y605
1 files changed, 391 insertions, 214 deletions
diff --git a/contrib/gcc/cexp.y b/contrib/gcc/cexp.y
index d83de80..6280aed 100644
--- a/contrib/gcc/cexp.y
+++ b/contrib/gcc/cexp.y
@@ -1,5 +1,5 @@
/* Parse C expressions for CCCP.
- Copyright (C) 1987, 1992, 1994, 1995 Free Software Foundation.
+ Copyright (C) 1987, 1992, 94 - 97, 1998 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
@@ -26,15 +26,25 @@ Boston, MA 02111-1307, USA.
%{
#include "config.h"
+#ifdef __STDC__
+# include <stdarg.h>
+#else
+# include <varargs.h>
+#endif
+
+#define PRINTF_PROTO(ARGS, m, n) PVPROTO (ARGS) ATTRIBUTE_PRINTF(m, n)
+
+#define PRINTF_PROTO_1(ARGS) PRINTF_PROTO(ARGS, 1, 2)
+
+#include "system.h"
#include <setjmp.h>
/* #define YYDEBUG 1 */
#ifdef MULTIBYTE_CHARS
-#include <stdlib.h>
#include <locale.h>
#endif
-#include <stdio.h>
+#include "gansidecl.h"
typedef unsigned char U_CHAR;
@@ -46,42 +56,48 @@ struct arglist {
int argno;
};
-/* Define a generic NULL if one hasn't already been defined. */
-
-#ifndef NULL
-#define NULL 0
+/* Find the largest host integer type and set its size and type.
+ Watch out: on some crazy hosts `long' is shorter than `int'. */
+
+#ifndef HOST_WIDE_INT
+# if HAVE_INTTYPES_H
+# include <inttypes.h>
+# define HOST_WIDE_INT intmax_t
+# define unsigned_HOST_WIDE_INT uintmax_t
+# else
+# if (HOST_BITS_PER_LONG <= HOST_BITS_PER_INT && HOST_BITS_PER_LONGLONG <= HOST_BITS_PER_INT)
+# define HOST_WIDE_INT int
+# else
+# if (HOST_BITS_PER_LONGLONG <= HOST_BITS_PER_LONG || ! (defined LONG_LONG_MAX || defined LLONG_MAX))
+# define HOST_WIDE_INT long
+# else
+# define HOST_WIDE_INT long long
+# endif
+# endif
+# endif
#endif
-#ifndef GENERIC_PTR
-#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
-#define GENERIC_PTR void *
-#else
-#define GENERIC_PTR char *
-#endif
+#ifndef unsigned_HOST_WIDE_INT
+#define unsigned_HOST_WIDE_INT unsigned HOST_WIDE_INT
#endif
-/* Find the largest host integer type and set its size and type. */
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
+#endif
#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
+#define HOST_BITS_PER_WIDE_INT (CHAR_BIT * sizeof (HOST_WIDE_INT))
#endif
-#endif
+HOST_WIDE_INT parse_c_expression PROTO((char *, int));
-#ifndef NULL_PTR
-#define NULL_PTR ((GENERIC_PTR)0)
+static int yylex PROTO((void));
+static void yyerror PROTO((char *)) __attribute__ ((noreturn));
+static HOST_WIDE_INT expression_value;
+#ifdef TEST_EXP_READER
+static int expression_signedp;
#endif
-int yylex ();
-void yyerror ();
-HOST_WIDE_INT expression_value;
-
static jmp_buf parse_return_error;
/* Nonzero means count most punctuation as part of a name. */
@@ -91,10 +107,11 @@ static int keyword_parsing = 0;
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[];
+/* Nonzero means warn if undefined identifiers are evaluated. */
+static int warn_undef;
-extern char *xmalloc ();
+/* some external tables of character types */
+extern unsigned char is_idstart[], is_idchar[], is_space[];
/* Flag for -pedantic. */
extern int pedantic;
@@ -102,6 +119,9 @@ extern int pedantic;
/* Flag for -traditional. */
extern int traditional;
+/* Flag for -lang-c89. */
+extern int c89;
+
#ifndef CHAR_TYPE_SIZE
#define CHAR_TYPE_SIZE BITS_PER_UNIT
#endif
@@ -134,17 +154,46 @@ extern int traditional;
#define MAX_WCHAR_TYPE_SIZE WCHAR_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)
-
-static void integer_overflow ();
-static long left_shift ();
-static long right_shift ();
+#define MAX_CHAR_TYPE_MASK (MAX_CHAR_TYPE_SIZE < HOST_BITS_PER_WIDE_INT \
+ ? (~ (~ (HOST_WIDE_INT) 0 << MAX_CHAR_TYPE_SIZE)) \
+ : ~ (HOST_WIDE_INT) 0)
+
+#define MAX_WCHAR_TYPE_MASK (MAX_WCHAR_TYPE_SIZE < HOST_BITS_PER_WIDE_INT \
+ ? ~ (~ (HOST_WIDE_INT) 0 << MAX_WCHAR_TYPE_SIZE) \
+ : ~ (HOST_WIDE_INT) 0)
+
+/* 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;
}
@@ -174,7 +223,12 @@ static long right_shift ();
%%
start : exp1
- { expression_value = $1.value; }
+ {
+ expression_value = $1.value;
+#ifdef TEST_EXP_READER
+ expression_signedp = $1.signedp;
+#endif
+ }
;
/* Expressions, including the comma operator. */
@@ -188,45 +242,46 @@ exp1 : exp
/* 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)
{
@@ -234,15 +289,16 @@ exp : exp '*' exp
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)
{
@@ -250,88 +306,91 @@ exp : exp '*' exp
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; }
+ $$.signedp = $1.signedp & $3.signedp; }
| exp AND
{ skip_evaluation += !$1.value; }
exp
{ skip_evaluation -= !$1.value;
$$.value = ($1.value && $4.value);
- $$.unsignedp = 0; }
+ $$.signedp = SIGNED; }
| exp OR
{ skip_evaluation += !!$1.value; }
exp
{ skip_evaluation -= !!$1.value;
$$.value = ($1.value || $4.value);
- $$.unsignedp = 0; }
+ $$.signedp = SIGNED; }
| exp '?'
{ skip_evaluation += !$1.value; }
exp ':'
@@ -339,14 +398,17 @@ exp : exp '*' exp
exp
{ skip_evaluation -= !!$1.value;
$$.value = $1.value ? $4.value : $7.value;
- $$.unsignedp = $4.unsignedp || $7.unsignedp; }
+ $$.signedp = $4.signedp & $7.signedp; }
| INT
{ $$ = yylval.integer; }
| CHAR
{ $$ = yylval.integer; }
| NAME
- { $$.value = 0;
- $$.unsignedp = 0; }
+ { if (warn_undef && !skip_evaluation)
+ warning ("`%.*s' is not defined",
+ $1.length, $1.address);
+ $$.value = 0;
+ $$.signedp = SIGNED; }
;
keywords :
@@ -383,37 +445,31 @@ static char *lexptr;
/* maybe needs to actually deal with floating point numbers */
-int
+static int
parse_number (olen)
int olen;
{
register char *p = lexptr;
register int c;
- register unsigned long n = 0, nd, ULONG_MAX_over_base;
+ 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;
+ }
+ }
- ULONG_MAX_over_base = (unsigned long) -1 / base;
+ max_over_base = (unsigned_HOST_WIDE_INT) -1 / base;
for (; len > 0; len--) {
c = *p++;
@@ -429,18 +485,26 @@ parse_number (olen)
while (1) {
if (c == 'l' || c == 'L')
{
- if (spec_long)
- yyerror ("two `l's in integer constant");
- spec_long = 1;
+ if (!pedantic < spec_long)
+ yyerror ("too many `l's in integer constant");
+ spec_long++;
}
else if (c == 'u' || c == 'U')
{
- if (yylval.integer.unsignedp)
+ if (! yylval.integer.signedp)
yyerror ("two `u's in integer constant");
- yylval.integer.unsignedp = 1;
+ yylval.integer.signedp = UNSIGNED;
}
- else
- break;
+ else {
+ if (c == '.' || c == 'e' || c == 'E' || c == 'p' || c == 'P')
+ 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)
break;
@@ -452,27 +516,22 @@ parse_number (olen)
if (largest_digit < digit)
largest_digit = digit;
nd = n * base + digit;
- overflow |= ULONG_MAX_over_base < n | nd < n;
+ 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");
+ pedwarn ("integer constant contains digits beyond the radix");
if (overflow)
- warning ("integer constant out of range");
+ pedwarn ("integer constant out of range");
/* If too big to be signed, consider it unsigned. */
- if ((long) n < 0 && ! yylval.integer.unsignedp)
+ if (((HOST_WIDE_INT) n & yylval.integer.signedp) < 0)
{
if (base == 10)
warning ("integer constant is so large that it is unsigned");
- yylval.integer.unsignedp = 1;
+ yylval.integer.signedp = UNSIGNED;
}
lexptr = p;
@@ -501,7 +560,7 @@ static struct token tokentab2[] = {
/* Read one token, getting characters through lexptr. */
-int
+static int
yylex ()
{
register int c;
@@ -509,6 +568,7 @@ yylex ()
register unsigned char *tokstart;
register struct token *toktab;
int wide_flag;
+ HOST_WIDE_INT mask;
retry:
@@ -529,13 +589,12 @@ yylex ()
}
switch (c) {
- case 0:
+ case '\n':
return 0;
case ' ':
case '\t':
case '\r':
- case '\n':
lexptr++;
goto retry;
@@ -545,18 +604,21 @@ yylex ()
{
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) {
@@ -564,7 +626,7 @@ yylex ()
while (1) {
c = *lexptr++;
if (c == '\\')
- c = parse_escape (&lexptr);
+ c = parse_escape (&lexptr, mask);
else if (c == '\'')
break;
}
@@ -577,8 +639,8 @@ yylex ()
handles multicharacter constants and wide characters.
It is mostly copied from c-lex.c. */
{
- register int result = 0;
- register num_chars = 0;
+ register HOST_WIDE_INT result = 0;
+ register int num_chars = 0;
unsigned width = MAX_CHAR_TYPE_SIZE;
int max_chars;
char *token_buffer;
@@ -606,19 +668,16 @@ yylex ()
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;
@@ -644,13 +703,16 @@ yylex ()
{
int num_bits = num_chars * width;
- if (lookup ("__CHAR_UNSIGNED__", sizeof ("__CHAR_UNSIGNED__")-1, -1)
+ if (lookup ((U_CHAR *) "__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
{
@@ -667,7 +729,7 @@ yylex ()
if (mbtowc (& wc, token_buffer, num_chars) == num_chars)
result = wc;
else
- warning ("Ignoring invalid multibyte character");
+ pedwarn ("Ignoring invalid multibyte character");
}
#endif
yylval.integer.value = result;
@@ -675,7 +737,7 @@ yylex ()
}
/* This is always a signed type. */
- yylval.integer.unsignedp = 0;
+ yylval.integer.signedp = SIGNED;
return CHAR;
@@ -712,6 +774,7 @@ yylex ()
return c;
case '"':
+ mask = MAX_CHAR_TYPE_MASK;
string_constant:
if (keyword_parsing) {
char *start_ptr = lexptr;
@@ -719,7 +782,7 @@ yylex ()
while (1) {
c = *lexptr++;
if (c == '\\')
- c = parse_escape (&lexptr);
+ c = parse_escape (&lexptr, mask);
else if (c == '"')
break;
}
@@ -733,10 +796,16 @@ yylex ()
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'
+ || ((c == 'p' || c == 'P') && ! c89))
+ && ! traditional)))
+ break;
+ c = d;
+ }
return parse_number (namelen);
}
@@ -744,7 +813,7 @@ yylex ()
if (keyword_parsing) {
for (namelen = 0;; namelen++) {
- if (is_hor_space[tokstart[namelen]])
+ if (is_space[tokstart[namelen]])
break;
if (tokstart[namelen] == '(' || tokstart[namelen] == ')')
break;
@@ -773,6 +842,9 @@ yylex ()
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.
@@ -782,9 +854,10 @@ yylex ()
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)
@@ -823,7 +896,7 @@ parse_escape (string_ptr)
case '6':
case '7':
{
- register int i = c - '0';
+ register HOST_WIDE_INT i = c - '0';
register int count = 0;
while (++count < 3)
{
@@ -836,16 +909,17 @@ parse_escape (string_ptr)
break;
}
}
- if ((i & ~((1 << MAX_CHAR_TYPE_SIZE) - 1)) != 0)
+ if (i != (i & result_mask))
{
- i &= (1 << MAX_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 unsigned i = 0, overflow = 0, digits_found = 0, digit;
+ register unsigned_HOST_WIDE_INT i = 0, overflow = 0;
+ register int digits_found = 0, digit;
for (;;)
{
c = *(*string_ptr)++;
@@ -866,10 +940,10 @@ parse_escape (string_ptr)
}
if (!digits_found)
yyerror ("\\x used with no following hex digits");
- if (overflow | (i & ~((1 << BITS_PER_UNIT) - 1)))
+ 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;
}
@@ -878,11 +952,11 @@ parse_escape (string_ptr)
}
}
-void
+static void
yyerror (s)
char *s;
{
- error (s);
+ error ("%s", s);
skip_evaluation = 0;
longjmp (parse_return_error, 1);
}
@@ -894,52 +968,50 @@ integer_overflow ()
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;
{
/* 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_LONG)
+ if (b >= HOST_BITS_PER_WIDE_INT)
return 0;
- else if (a->unsignedp)
- return (unsigned long) a->value << b;
else
- return a->value << b;
+ 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;
}
/* 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. */
-/* We do not support C comments. They should be removed before
+ 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.
+ If WARN_UNDEFINED is nonzero, warn if undefined identifiers are evaluated.
+ We do not support C comments. They should be removed before
this function is called. */
HOST_WIDE_INT
-parse_c_expression (string)
+parse_c_expression (string, warn_undefined)
char *string;
+ int warn_undefined;
{
lexptr = string;
-
- if (lexptr == 0 || *lexptr == 0) {
- error ("empty #if expression");
- return 0; /* don't include the #if group */
- }
+ warn_undef = warn_undefined;
/* if there is some sort of scanning error, just return 0 and assume
the parsing routine has printed an error message somewhere.
@@ -947,55 +1019,92 @@ parse_c_expression (string)
if (setjmp (parse_return_error))
return 0;
- if (yyparse ())
- return 0; /* actually this is never reached
- the way things stand. */
- if (*lexptr)
+ if (yyparse () != 0)
+ abort ();
+
+ if (*lexptr != '\n')
error ("Junk after end of expression.");
return expression_value; /* set by yyparse () */
}
#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));
+static void print_unsigned_host_wide_int PROTO((unsigned_HOST_WIDE_INT));
/* Main program for testing purposes. */
int
-main ()
+main (argc, argv)
+ int argc;
+ char **argv;
{
int n, c;
char buf[1024];
+ unsigned_HOST_WIDE_INT u;
-/*
- 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 %ld\n", parse_c_expression (buf));
+ parse_c_expression (buf, 1);
+ printf ("parser returned ");
+ u = (unsigned_HOST_WIDE_INT) expression_value;
+ if (expression_value < 0 && expression_signedp) {
+ u = -u;
+ printf ("-");
+ }
+ if (u == 0)
+ printf ("0");
+ else
+ print_unsigned_host_wide_int (u);
+ if (! expression_signedp)
+ printf("u");
+ printf ("\n");
}
return 0;
}
+static void
+print_unsigned_host_wide_int (u)
+ unsigned_HOST_WIDE_INT u;
+{
+ if (u) {
+ print_unsigned_host_wide_int (u / 10);
+ putchar ('0' + (int) (u % 10));
+ }
+}
+
/* table to tell if char can be part of a C identifier. */
unsigned char is_idchar[256];
/* table to tell if char can be first char of a c identifier. */
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];
+/* table to tell if c is horizontal or vertical space. */
+unsigned char is_space[256];
/*
* initialize random junk in the hash table and maybe other places
*/
+static void
initialize_random_junk ()
{
register int i;
@@ -1016,32 +1125,100 @@ initialize_random_junk ()
++is_idchar[i];
++is_idchar['_'];
++is_idstart['_'];
-#if DOLLARS_IN_IDENTIFIERS
++is_idchar['$'];
++is_idstart['$'];
+
+ ++is_space[' '];
+ ++is_space['\t'];
+ ++is_space['\v'];
+ ++is_space['\f'];
+ ++is_space['\n'];
+ ++is_space['\r'];
+}
+
+void
+error VPROTO ((char * msg, ...))
+{
+#ifndef __STDC__
+ char * msg;
#endif
+ va_list args;
- /* horizontal space table */
- ++is_hor_space[' '];
- ++is_hor_space['\t'];
+ VA_START (args, msg);
+
+#ifndef __STDC__
+ msg = va_arg (args, char *);
+#endif
+
+ fprintf (stderr, "error: ");
+ vfprintf (stderr, msg, args);
+ fprintf (stderr, "\n");
+ va_end (args);
}
-error (msg)
+void
+pedwarn VPROTO ((char * msg, ...))
{
- printf ("error: %s\n", msg);
+#ifndef __STDC__
+ char * msg;
+#endif
+ va_list args;
+
+ VA_START (args, msg);
+
+#ifndef __STDC__
+ msg = va_arg (args, char *);
+#endif
+
+ fprintf (stderr, "pedwarn: ");
+ vfprintf (stderr, msg, args);
+ fprintf (stderr, "\n");
+ va_end (args);
}
-warning (msg)
+void
+warning VPROTO ((char * msg, ...))
{
- printf ("warning: %s\n", msg);
+#ifndef __STDC__
+ char * msg;
+#endif
+ va_list args;
+
+ VA_START (args, msg);
+
+#ifndef __STDC__
+ msg = va_arg (args, char *);
+#endif
+
+ 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
OpenPOWER on IntegriCloud