/* Parse C expressions for CCCP.
- Copyright (C) 1987, 1992, 1994, 1995, 1996 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
%{
#include "config.h"
-#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) */
+#define PRINTF_PROTO(ARGS, m, n) PVPROTO (ARGS) ATTRIBUTE_PRINTF(m, n)
-#if STDC_HEADERS
-# include <string.h>
-#endif
+#define PRINTF_PROTO_1(ARGS) PRINTF_PROTO(ARGS, 1, 2)
-#if HAVE_STDLIB_H || defined (MULTIBYTE_CHARS)
-# include <stdlib.h>
-#endif
+#include "system.h"
+#include <setjmp.h>
+/* #define YYDEBUG 1 */
+#include "gansidecl.h"
#ifdef MULTIBYTE_CHARS
+#include "mbchar.h"
#include <locale.h>
-#endif
-
-#include <stdio.h>
+#endif /* MULTIBYTE_CHARS */
typedef unsigned char U_CHAR;
int argno;
};
-/* Define a generic NULL if one hasn't already been defined. */
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-#ifndef GENERIC_PTR
-#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
-#define GENERIC_PTR void *
-#else
-#define GENERIC_PTR char *
-#endif
-#endif
-
-#ifndef NULL_PTR
-#define NULL_PTR ((GENERIC_PTR)0)
-#endif
-
/* 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
+ 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
-#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 6)
-# define __attribute__(x)
+#ifndef unsigned_HOST_WIDE_INT
+#define unsigned_HOST_WIDE_INT unsigned HOST_WIDE_INT
#endif
-#ifndef PROTO
-# if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
-# define PROTO(ARGS) ARGS
-# else
-# define PROTO(ARGS) ()
-# endif
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
#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); \
- }
+#ifndef HOST_BITS_PER_WIDE_INT
+#define HOST_BITS_PER_WIDE_INT (CHAR_BIT * sizeof (HOST_WIDE_INT))
#endif
-#define PRINTF_PROTO_1(ARGS) PRINTF_PROTO(ARGS, 1, 2)
-
-HOST_WIDE_INT parse_c_expression PROTO((char *));
+HOST_WIDE_INT parse_c_expression PROTO((char *, int));
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
static jmp_buf parse_return_error;
This is a count, since unevaluated expressions can nest. */
static int skip_evaluation;
+/* Nonzero means warn if undefined identifiers are evaluated. */
+static int warn_undef;
+
/* some external tables of character types */
-extern unsigned char is_idstart[], is_idchar[], is_hor_space[];
+extern unsigned char is_idstart[], is_idchar[], is_space[];
/* Flag for -pedantic. */
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
#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
+#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)
-#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
+#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.
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 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 */
%%
start : exp1
- { expression_value = $1.value; }
+ {
+ expression_value = $1.value;
+#ifdef TEST_EXP_READER
+ expression_signedp = $1.signedp;
+#endif
+ }
;
/* Expressions, including the comma operator. */
integer_overflow ();
}
else
- $$.value = ((unsigned HOST_WIDE_INT) $1.value
+ $$.value = ((unsigned_HOST_WIDE_INT) $1.value
* $3.value); }
| exp '/' exp
{ if ($3.value == 0)
integer_overflow ();
}
else
- $$.value = ((unsigned HOST_WIDE_INT) $1.value
+ $$.value = ((unsigned_HOST_WIDE_INT) $1.value
/ $3.value); }
| exp '%' exp
{ if ($3.value == 0)
if ($$.signedp)
$$.value = $1.value % $3.value;
else
- $$.value = ((unsigned HOST_WIDE_INT) $1.value
+ $$.value = ((unsigned_HOST_WIDE_INT) $1.value
% $3.value); }
| exp '+' exp
{ $$.value = $1.value + $3.value;
if ($1.signedp & $3.signedp)
$$.value = $1.value <= $3.value;
else
- $$.value = ((unsigned HOST_WIDE_INT) $1.value
+ $$.value = ((unsigned_HOST_WIDE_INT) $1.value
<= $3.value); }
| exp GEQ exp
{ $$.signedp = SIGNED;
if ($1.signedp & $3.signedp)
$$.value = $1.value >= $3.value;
else
- $$.value = ((unsigned HOST_WIDE_INT) $1.value
+ $$.value = ((unsigned_HOST_WIDE_INT) $1.value
>= $3.value); }
| exp '<' exp
{ $$.signedp = SIGNED;
if ($1.signedp & $3.signedp)
$$.value = $1.value < $3.value;
else
- $$.value = ((unsigned HOST_WIDE_INT) $1.value
+ $$.value = ((unsigned_HOST_WIDE_INT) $1.value
< $3.value); }
| exp '>' exp
{ $$.signedp = SIGNED;
if ($1.signedp & $3.signedp)
$$.value = $1.value > $3.value;
else
- $$.value = ((unsigned HOST_WIDE_INT) $1.value
+ $$.value = ((unsigned_HOST_WIDE_INT) $1.value
> $3.value); }
| exp '&' exp
{ $$.value = $1.value & $3.value;
| CHAR
{ $$ = yylval.integer; }
| NAME
- { $$.value = 0;
+ { if (warn_undef && !skip_evaluation)
+ warning ("`%.*s' is not defined",
+ $1.length, $1.address);
+ $$.value = 0;
$$.signedp = SIGNED; }
;
{
register char *p = lexptr;
register int c;
- register unsigned HOST_WIDE_INT n = 0, nd, 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;
}
}
- max_over_base = (unsigned HOST_WIDE_INT) -1 / base;
+ max_over_base = (unsigned_HOST_WIDE_INT) -1 / base;
for (; len > 0; len--) {
c = *p++;
yylval.integer.signedp = UNSIGNED;
}
else {
- if (c == '.' || c == 'e' || c == 'E')
+ 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);
}
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 (((HOST_WIDE_INT) n & yylval.integer.signedp) < 0)
It is mostly copied from c-lex.c. */
{
register HOST_WIDE_INT result = 0;
- register num_chars = 0;
+ register int num_chars = 0;
+ int chars_seen = 0;
unsigned width = MAX_CHAR_TYPE_SIZE;
int max_chars;
- char *token_buffer;
-
- if (wide_flag)
- {
- width = MAX_WCHAR_TYPE_SIZE;
#ifdef MULTIBYTE_CHARS
- max_chars = MB_CUR_MAX;
-#else
- max_chars = 1;
+ int longest_char = local_mb_cur_max ();
+ char *token_buffer = (char *) alloca (longest_char);
+ (void) local_mbtowc (NULL_PTR, NULL_PTR, 0);
#endif
- }
- else
- max_chars = MAX_LONG_TYPE_SIZE / width;
- token_buffer = (char *) alloca (max_chars + 1);
+ max_chars = MAX_LONG_TYPE_SIZE / width;
+ if (wide_flag)
+ width = MAX_WCHAR_TYPE_SIZE;
while (1)
{
if (c == '\'' || c == EOF)
break;
+ ++chars_seen;
if (c == '\\')
{
c = parse_escape (&lexptr, mask);
}
+ else
+ {
+#ifdef MULTIBYTE_CHARS
+ wchar_t wc;
+ int i;
+ int char_len = -1;
+ for (i = 1; i <= longest_char; ++i)
+ {
+ token_buffer[i - 1] = c;
+ char_len = local_mbtowc (& wc, token_buffer, i);
+ if (char_len != -1)
+ break;
+ c = *lexptr++;
+ }
+ if (char_len > 1)
+ {
+ /* mbtowc sometimes needs an extra char before accepting */
+ if (char_len < i)
+ lexptr--;
+ if (! wide_flag)
+ {
+ /* Merge character into result; ignore excess chars. */
+ for (i = 1; i <= char_len; ++i)
+ {
+ if (i > max_chars)
+ break;
+ if (width < HOST_BITS_PER_INT)
+ result = (result << width)
+ | (token_buffer[i - 1]
+ & ((1 << width) - 1));
+ else
+ result = token_buffer[i - 1];
+ }
+ num_chars += char_len;
+ continue;
+ }
+ }
+ else
+ {
+ if (char_len == -1)
+ warning ("Ignoring invalid multibyte character");
+ }
+ if (wide_flag)
+ c = wc;
+#endif /* ! MULTIBYTE_CHARS */
+ }
- num_chars++;
+ if (wide_flag)
+ {
+ if (chars_seen == 1) /* only keep the first one */
+ result = c;
+ continue;
+ }
/* Merge character into result; ignore excess chars. */
+ num_chars++;
if (num_chars <= max_chars)
{
- if (width < HOST_BITS_PER_WIDE_INT)
- result = (result << width) | c;
+ if (width < HOST_BITS_PER_INT)
+ result = (result << width) | (c & ((1 << width) - 1));
else
result = c;
- token_buffer[num_chars - 1] = c;
}
}
- token_buffer[num_chars] = 0;
-
if (c != '\'')
error ("malformatted character constant");
- else if (num_chars == 0)
+ else if (chars_seen == 0)
error ("empty character constant");
else if (num_chars > max_chars)
{
num_chars = max_chars;
error ("character constant too long");
}
- else if (num_chars != 1 && ! traditional)
+ else if (chars_seen != 1 && ! traditional)
warning ("multi-character character constant");
/* If char type is signed, sign-extend the constant. */
if (! wide_flag)
{
int num_bits = num_chars * width;
-
- if (lookup ("__CHAR_UNSIGNED__", sizeof ("__CHAR_UNSIGNED__")-1, -1)
+ if (num_bits == 0)
+ /* We already got an error; avoid invalid shift. */
+ yylval.integer.value = 0;
+ else if (lookup ((U_CHAR *) "__CHAR_UNSIGNED__",
+ sizeof ("__CHAR_UNSIGNED__") - 1, -1)
|| ((result >> (num_bits - 1)) & 1) == 0)
yylval.integer.value
- = result & (~ (unsigned HOST_WIDE_INT) 0
+ = result & (~ (unsigned_HOST_WIDE_INT) 0
>> (HOST_BITS_PER_WIDE_INT - num_bits));
else
yylval.integer.value
- = result | ~(~ (unsigned HOST_WIDE_INT) 0
+ = result | ~(~ (unsigned_HOST_WIDE_INT) 0
>> (HOST_BITS_PER_WIDE_INT - num_bits));
}
else
{
-#ifdef MULTIBYTE_CHARS
- /* Set the initial shift state and convert the next sequence. */
- result = 0;
- /* In all locales L'\0' is zero and mbtowc will return zero,
- so don't use it. */
- if (num_chars > 1
- || (num_chars == 1 && token_buffer[0] != '\0'))
- {
- wchar_t wc;
- (void) mbtowc (NULL_PTR, NULL_PTR, 0);
- if (mbtowc (& wc, token_buffer, num_chars) == num_chars)
- result = wc;
- else
- warning ("Ignoring invalid multibyte character");
- }
-#endif
yylval.integer.value = result;
}
}
for (namelen = 1; ; namelen++) {
int d = tokstart[namelen];
if (! ((is_idchar[d] || d == '.')
- || ((d == '-' || d == '+') && (c == 'e' || c == 'E')
+ || ((d == '-' || d == '+')
+ && (c == 'e' || c == 'E'
+ || ((c == 'p' || c == 'P') && ! c89))
&& ! traditional)))
break;
c = d;
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;
}
case 'x':
{
- register unsigned HOST_WIDE_INT i = 0, overflow = 0;
+ register unsigned_HOST_WIDE_INT i = 0, overflow = 0;
register int digits_found = 0, digit;
for (;;)
{
static HOST_WIDE_INT
left_shift (a, b)
struct constant *a;
- unsigned HOST_WIDE_INT 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
if (b >= HOST_BITS_PER_WIDE_INT)
return 0;
else
- return (unsigned HOST_WIDE_INT) a->value << b;
+ return (unsigned_HOST_WIDE_INT) a->value << b;
}
static HOST_WIDE_INT
right_shift (a, b)
struct constant *a;
- unsigned HOST_WIDE_INT b;
+ unsigned_HOST_WIDE_INT b;
{
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;
+ 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
+ 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.
if (setjmp (parse_return_error))
return 0;
- if (yyparse ())
- return 0; /* actually this is never reached
- the way things stand. */
+ if (yyparse () != 0)
+ abort ();
+
if (*lexptr != '\n')
error ("Junk after end of expression.");
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
{
int n, c;
char buf[1024];
+ unsigned_HOST_WIDE_INT u;
pedantic = 1 < argc;
traditional = 2 < argc;
n++;
if (c == EOF)
break;
- printf ("parser returned %ld\n", (long) 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. */
-unsigned 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
++is_idchar[i];
++is_idchar['_'];
++is_idstart['_'];
-#if DOLLARS_IN_IDENTIFIERS
++is_idchar['$'];
++is_idstart['$'];
-#endif
- /* horizontal space table */
- ++is_hor_space[' '];
- ++is_hor_space['\t'];
+ ++is_space[' '];
+ ++is_space['\t'];
+ ++is_space['\v'];
+ ++is_space['\f'];
+ ++is_space['\n'];
+ ++is_space['\r'];
}
void
-error (PRINTF_ALIST (msg))
- PRINTF_DCL (msg)
+error VPROTO ((char * msg, ...))
{
+#ifndef __STDC__
+ char * msg;
+#endif
va_list args;
VA_START (args, msg);
+
+#ifndef __STDC__
+ msg = va_arg (args, char *);
+#endif
+
fprintf (stderr, "error: ");
vfprintf (stderr, msg, args);
fprintf (stderr, "\n");
}
void
-pedwarn (PRINTF_ALIST (msg))
- PRINTF_DCL (msg)
+pedwarn VPROTO ((char * 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");
}
void
-warning (PRINTF_ALIST (msg))
- PRINTF_DCL (msg)
+warning VPROTO ((char * 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");