-/* Parse C expressions for CCCP.
- Copyright (C) 1987, 1992, 1994, 1995 Free Software Foundation.
+/* Parse C expressions for cpplib.
+ Copyright (C) 1987, 92, 94, 95, 97, 98, 1999, 2000 Free Software Foundation.
+ Contributed by Per Bothner, 1994.
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, 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
- what you give them. Help stamp out software-hoarding!
-
-Written by Per Bothner 1994. */
+Boston, MA 02111-1307, USA. */
/* Parse a C expression from text in a string */
#include "config.h"
+#include "system.h"
#include "cpplib.h"
-
-extern char *xmalloc PARAMS ((unsigned));
-extern char *xrealloc PARAMS ((char *, unsigned));
-
-#ifdef MULTIBYTE_CHARS
-#include <stdlib.h>
-#include <locale.h>
-#endif
-
-#include <stdio.h>
-
-/* This is used for communicating lists of keywords with cccp.c. */
-struct arglist {
- struct arglist *next;
- U_CHAR *name;
- int length;
- 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
-
-extern char *xmalloc ();
+#include "cpphash.h"
#ifndef CHAR_TYPE_SIZE
#define CHAR_TYPE_SIZE BITS_PER_UNIT
#define MAX_WCHAR_TYPE_SIZE WCHAR_TYPE_SIZE
#endif
+#define MAX_CHAR_TYPE_MASK (MAX_CHAR_TYPE_SIZE < HOST_BITS_PER_WIDEST_INT \
+ ? (~(~(HOST_WIDEST_INT) 0 << MAX_CHAR_TYPE_SIZE)) \
+ : ~ (HOST_WIDEST_INT) 0)
+
+#define MAX_WCHAR_TYPE_MASK (MAX_WCHAR_TYPE_SIZE < HOST_BITS_PER_WIDEST_INT \
+ ? ~(~(HOST_WIDEST_INT) 0 << MAX_WCHAR_TYPE_SIZE) \
+ : ~ (HOST_WIDEST_INT) 0)
+
/* 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 ();
+typedef int op_t;
+
+static void integer_overflow PARAMS ((cpp_reader *));
+static HOST_WIDEST_INT left_shift PARAMS ((cpp_reader *, HOST_WIDEST_INT,
+ unsigned int,
+ unsigned HOST_WIDEST_INT));
+static HOST_WIDEST_INT right_shift PARAMS ((cpp_reader *, HOST_WIDEST_INT,
+ unsigned int,
+ unsigned HOST_WIDEST_INT));
+static struct operation parse_number PARAMS ((cpp_reader *, U_CHAR *,
+ U_CHAR *));
+static struct operation parse_charconst PARAMS ((cpp_reader *, U_CHAR *,
+ U_CHAR *));
+static struct operation parse_defined PARAMS ((cpp_reader *));
+static struct operation parse_assertion PARAMS ((cpp_reader *));
+static HOST_WIDEST_INT parse_escape PARAMS ((cpp_reader *, U_CHAR **,
+ HOST_WIDEST_INT));
+static struct operation lex PARAMS ((cpp_reader *, int));
+static const char * op_to_str PARAMS ((op_t, char *));
#define ERROR 299
#define OROR 300
#define NAME 308
#define INT 309
#define CHAR 310
+#define FINISHED 311
-#define LEFT_OPERAND_REQUIRED 1
-#define RIGHT_OPERAND_REQUIRED 2
-#define HAVE_VALUE 4
-/*#define UNSIGNEDP 8*/
-
-#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
-
-struct operation {
- short op;
- char rprio; /* Priority of op (relative to it right operand). */
- char flags;
- char unsignedp; /* true if value should be treated as unsigned */
- HOST_WIDE_INT value; /* The value logically "right" of op. */
+struct operation
+{
+ op_t op;
+ U_CHAR prio; /* Priority of op. */
+ U_CHAR flags;
+ U_CHAR unsignedp; /* True if value should be treated as unsigned. */
+ HOST_WIDEST_INT value; /* The value logically "right" of op. */
};
-\f
-/* Take care of parsing a number (anything that starts with a digit).
- LEN is the number of characters in it. */
-/* maybe needs to actually deal with floating point numbers */
+/* With -O2, gcc appears to produce nice code, moving the error
+ message load and subsequent jump completely out of the main path. */
+#define CPP_ICE(msgid) \
+ do { cpp_ice (pfile, msgid); goto syntax_error; } while(0)
+#define SYNTAX_ERROR(msgid) \
+ do { cpp_error (pfile, msgid); goto syntax_error; } while(0)
+#define SYNTAX_ERROR2(msgid, arg) \
+ do { cpp_error (pfile, msgid, arg); goto syntax_error; } while(0)
-struct operation
-parse_number (pfile, start, olen)
+/* Parse and convert an integer for #if. Accepts decimal, hex, or octal
+ with or without size suffixes. */
+
+static struct operation
+parse_number (pfile, start, end)
cpp_reader *pfile;
- char *start;
- int olen;
+ U_CHAR *start;
+ U_CHAR *end;
{
struct operation op;
- register char *p = start;
- register int c;
- register unsigned long n = 0, nd, ULONG_MAX_over_base;
- register int base = 10;
- register int len = olen;
- register int overflow = 0;
- register int digit, largest_digit = 0;
+ U_CHAR *p = start;
+ int c;
+ unsigned HOST_WIDEST_INT n = 0, nd, MAX_over_base;
+ int base = 10;
+ int overflow = 0;
+ int digit, largest_digit = 0;
int spec_long = 0;
op.unsignedp = 0;
- for (c = 0; c < len; c++)
- if (p[c] == '.') {
- /* It's a float since it contains a point. */
- cpp_error (pfile,
- "floating point numbers not allowed in #if expressions");
- op.op = ERROR;
- return op;
+ if (p[0] == '0')
+ {
+ if (end - start >= 3 && (p[1] == 'x' || p[1] == 'X'))
+ {
+ p += 2;
+ base = 16;
+ }
+ else
+ {
+ p += 1;
+ base = 8;
+ }
}
- if (len >= 3 && (!strncmp (p, "0x", 2) || !strncmp (p, "0X", 2))) {
- p += 2;
- base = 16;
- len -= 2;
- }
- else if (*p == '0')
- base = 8;
-
- /* Some buggy compilers (e.g. MPW C) seem to need both casts. */
- ULONG_MAX_over_base = ((unsigned long) -1) / ((unsigned long) base);
-
- for (; len > 0; len--) {
- c = *p++;
-
- 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 (spec_long)
- cpp_error (pfile, "two `l's in integer constant");
- spec_long = 1;
- }
- else if (c == 'u' || c == 'U')
- {
- if (op.unsignedp)
- cpp_error (pfile, "two `u's in integer constant");
- op.unsignedp = 1;
- }
- else
- break;
+ /* Some buggy compilers (e.g. MPW C) seem to need both casts. */
+ MAX_over_base = (((unsigned HOST_WIDEST_INT) -1)
+ / ((unsigned HOST_WIDEST_INT) base));
- if (--len == 0)
+ while (p < end)
+ {
+ c = *p++;
+
+ if (c >= '0' && c <= '9')
+ digit = c - '0';
+ /* FIXME: assumes ASCII */
+ 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 if (c == '.')
+ {
+ /* It's a float since it contains a point. */
+ cpp_error (pfile,
+ "floating point numbers are not allowed in #if expressions");
+ goto error;
+ }
+ else
+ {
+ /* `l' means long, and `u' means unsigned. */
+ for (;;)
+ {
+ if (c == 'l' || c == 'L')
+ spec_long++;
+ else if (c == 'u' || c == 'U')
+ op.unsignedp++;
+ else
+ {
+ /* Decrement p here so that the error for an invalid
+ number will be generated below in the case where
+ this is the last character in the buffer. */
+ p--;
+ break;
+ }
+ if (p == end)
+ break;
+ c = *p++;
+ }
+ /* Don't look for any more digits after the suffixes. */
break;
- c = *p++;
- }
- /* 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 (largest_digit < digit)
- largest_digit = digit;
- nd = n * base + digit;
- overflow |= ULONG_MAX_over_base < n | nd < n;
- n = nd;
- }
- if (len != 0)
+ if (p != end)
{
- cpp_error (pfile, "Invalid number in #if expression");
- op.op = ERROR;
- return op;
+ cpp_error (pfile, "invalid number in #if expression");
+ goto error;
}
-
+ else if (spec_long > (CPP_OPTION (pfile, c89) ? 1 : 2))
+ {
+ cpp_error (pfile, "too many 'l' suffixes in integer constant");
+ goto error;
+ }
+ else if (op.unsignedp > 1)
+ {
+ cpp_error (pfile, "too many 'u' suffixes in integer constant");
+ goto error;
+ }
+
if (base <= largest_digit)
- cpp_warning (pfile, "integer constant contains digits beyond the radix");
+ cpp_pedwarn (pfile,
+ "integer constant contains digits beyond the radix");
if (overflow)
- cpp_warning (pfile, "integer constant out of range");
+ cpp_pedwarn (pfile, "integer constant out of range");
/* If too big to be signed, consider it unsigned. */
- if ((long) n < 0 && ! op.unsignedp)
+ else if ((HOST_WIDEST_INT) n < 0 && ! op.unsignedp)
{
if (base == 10)
- cpp_warning (pfile, "integer constant is so large that it is unsigned");
+ cpp_warning (pfile,
+ "integer constant is so large that it is unsigned");
op.unsignedp = 1;
}
op.value = n;
op.op = INT;
return op;
+
+ error:
+ op.op = ERROR;
+ return op;
+}
+
+/* Parse and convert a character constant for #if. Understands backslash
+ escapes (\n, \031) and multibyte characters (if so configured). */
+static struct operation
+parse_charconst (pfile, start, end)
+ cpp_reader *pfile;
+ U_CHAR *start;
+ U_CHAR *end;
+{
+ struct operation op;
+ HOST_WIDEST_INT result = 0;
+ int num_chars = 0;
+ int num_bits;
+ unsigned int width = MAX_CHAR_TYPE_SIZE, mask = MAX_CHAR_TYPE_MASK;
+ int max_chars;
+ U_CHAR *ptr = start;
+
+ int c = -1;
+
+ if (*ptr == 'L')
+ {
+ ++ptr;
+ width = MAX_WCHAR_TYPE_SIZE, mask = MAX_WCHAR_TYPE_MASK;
+ }
+ max_chars = MAX_LONG_TYPE_SIZE / width;
+
+ ++ptr; /* skip initial quote */
+
+ while (ptr < end)
+ {
+ c = *ptr++;
+ if (c == '\'')
+ break;
+ else if (c == '\\')
+ {
+ c = parse_escape (pfile, &ptr, mask);
+ if (width < HOST_BITS_PER_INT
+ && (unsigned int) c >= (unsigned int)(1 << width))
+ cpp_pedwarn (pfile,
+ "escape sequence out of range for character");
+ }
+
+ /* Merge character into result; ignore excess chars. */
+ if (++num_chars <= max_chars)
+ {
+ if (width < HOST_BITS_PER_INT)
+ result = (result << width) | (c & ((1 << width) - 1));
+ else
+ result = c;
+ }
+ }
+
+ if (num_chars == 0)
+ {
+ cpp_error (pfile, "empty character constant");
+ goto error;
+ }
+ else if (c != '\'')
+ {
+ /* cpp_get_token has already emitted an error if !traditional. */
+ if (! CPP_TRADITIONAL (pfile))
+ cpp_error (pfile, "malformatted character constant");
+ goto error;
+ }
+ else if (num_chars > max_chars)
+ {
+ cpp_error (pfile, "character constant too long");
+ goto error;
+ }
+ else if (num_chars != 1 && ! CPP_TRADITIONAL (pfile))
+ cpp_warning (pfile, "multi-character character constant");
+
+ /* If char type is signed, sign-extend the constant. */
+ num_bits = num_chars * width;
+
+ if (cpp_defined (pfile, U"__CHAR_UNSIGNED__",
+ sizeof ("__CHAR_UNSIGNED__")-1)
+ || ((result >> (num_bits - 1)) & 1) == 0)
+ op.value = result & ((unsigned HOST_WIDEST_INT) ~0
+ >> (HOST_BITS_PER_WIDEST_INT - num_bits));
+ else
+ op.value = result | ~((unsigned HOST_WIDEST_INT) ~0
+ >> (HOST_BITS_PER_WIDEST_INT - num_bits));
+
+ /* This is always a signed type. */
+ op.unsignedp = 0;
+ op.op = CHAR;
+ return op;
+
+ error:
+ op.op = ERROR;
+ return op;
+}
+
+static struct operation
+parse_defined (pfile)
+ cpp_reader *pfile;
+{
+ int paren = 0, len;
+ U_CHAR *tok;
+ enum cpp_ttype token;
+ struct operation op;
+ long old_written = CPP_WRITTEN (pfile);
+
+ op.unsignedp = 0;
+ op.op = INT;
+
+ pfile->no_macro_expand++;
+ token = _cpp_get_directive_token (pfile);
+ if (token == CPP_OPEN_PAREN)
+ {
+ paren++;
+ CPP_SET_WRITTEN (pfile, old_written);
+ token = _cpp_get_directive_token (pfile);
+ }
+
+ if (token != CPP_NAME)
+ goto oops;
+
+ tok = pfile->token_buffer + old_written;
+ len = CPP_PWRITTEN (pfile) - tok;
+ op.value = cpp_defined (pfile, tok, len);
+
+ if (paren)
+ {
+ if (_cpp_get_directive_token (pfile) != CPP_CLOSE_PAREN)
+ goto oops;
+ }
+ CPP_SET_WRITTEN (pfile, old_written);
+ pfile->no_macro_expand--;
+ return op;
+
+ oops:
+ CPP_SET_WRITTEN (pfile, old_written);
+ pfile->no_macro_expand--;
+ cpp_error (pfile, "'defined' without an identifier");
+
+ op.op = ERROR;
+ return op;
+}
+
+static struct operation
+parse_assertion (pfile)
+ cpp_reader *pfile;
+{
+ struct operation op;
+ cpp_hashnode *hp;
+ struct predicate *pred;
+ cpp_toklist query;
+ enum cpp_ttype type;
+ U_CHAR *tok;
+ size_t len;
+ unsigned int old_written;
+ int specific = 0;
+
+ old_written = CPP_WRITTEN (pfile);
+ CPP_PUTC (pfile, '#');
+ pfile->no_macro_expand++;
+ type = _cpp_get_directive_token (pfile);
+ if (type == CPP_VSPACE)
+ SYNTAX_ERROR ("assertion without predicate");
+ else if (type != CPP_NAME)
+ SYNTAX_ERROR ("assertion predicate is not an identifier");
+
+ tok = pfile->token_buffer + old_written;
+ len = CPP_WRITTEN (pfile) - old_written;
+ hp = cpp_lookup (pfile, tok, len);
+
+ /* Look ahead for an open paren. */
+ _cpp_skip_hspace (pfile);
+ if (CPP_BUF_PEEK (CPP_BUFFER (pfile)) == '(')
+ {
+ if (_cpp_get_directive_token (pfile) != CPP_OPEN_PAREN)
+ CPP_ICE ("impossible token, expecting ( in parse_assertion");
+
+ _cpp_init_toklist (&query, NO_DUMMY_TOKEN);
+ specific = 1;
+ if (_cpp_scan_until (pfile, &query, CPP_CLOSE_PAREN) != CPP_CLOSE_PAREN)
+ SYNTAX_ERROR ("missing close paren on assertion answer");
+
+ if (_cpp_get_directive_token (pfile) != CPP_CLOSE_PAREN)
+ CPP_ICE ("impossible token, expecting ) in parse_assertion");
+ }
+
+ /* If we get here, the syntax is valid. */
+ op.op = INT;
+ op.value = 0;
+ /* Has this predicate been asserted at all? */
+ if (hp->type == T_ASSERTION)
+ {
+ if (specific)
+ {
+ for (pred = hp->value.pred; pred; pred = pred->next)
+ if (_cpp_equiv_toklists (&query, &pred->answer))
+ {
+ op.value = 1;
+ break;
+ }
+ _cpp_free_toklist (&query);
+ }
+ else
+ op.value = 1;
+ }
+
+ out:
+ pfile->no_macro_expand--;
+ CPP_SET_WRITTEN (pfile, old_written);
+ return op;
+
+ syntax_error:
+ if (specific)
+ _cpp_free_toklist (&query);
+ op.op = ERROR;
+ goto out;
}
-struct token {
- char *operator;
- int token;
+struct token
+{
+ const char *operator;
+ op_t token;
};
-static struct token tokentab2[] = {
+static const struct token tokentab2[] =
+{
{"&&", ANDAND},
{"||", OROR},
{"<<", LSH},
{NULL, ERROR}
};
-/* Read one token. */
+/* Read one token. */
-struct operation
-cpp_lex (pfile)
-cpp_reader *pfile;
+static struct operation
+lex (pfile, skip_evaluation)
+ cpp_reader *pfile;
+ int skip_evaluation;
{
- register int c;
- register int namelen;
- register struct token *toktab;
- enum cpp_token token;
+ const struct token *toktab;
+ enum cpp_ttype token;
struct operation op;
U_CHAR *tok_start, *tok_end;
- int old_written;
-
- retry:
+ long old_written;
old_written = CPP_WRITTEN (pfile);
- cpp_skip_hspace (pfile);
- c = CPP_BUF_PEEK (CPP_BUFFER (pfile));
- if (c == '#')
- return parse_number (pfile,
- cpp_read_check_assertion (pfile) ? "1" : "0", 1);
+ token = _cpp_get_directive_token (pfile);
- if (c == '\n')
- {
- op.op = 0;
- return op;
- }
-
- token = cpp_get_token (pfile);
tok_start = pfile->token_buffer + old_written;
tok_end = CPP_PWRITTEN (pfile);
- pfile->limit = tok_start;
+ CPP_SET_WRITTEN (pfile, old_written);
switch (token)
- {
- case CPP_EOF: /* Should not happen ... */
+ {
+ case CPP_EOF: /* Should not happen ... */
+ case CPP_VSPACE:
op.op = 0;
return op;
- case CPP_VSPACE:
- case CPP_POP:
- if (CPP_BUFFER (pfile)->fname != NULL)
- {
- op.op = 0;
- return op;
- }
- goto retry;
- case CPP_HSPACE: case CPP_COMMENT:
- goto retry;
case CPP_NUMBER:
- return parse_number (pfile, tok_start, tok_end - tok_start);
+ return parse_number (pfile, tok_start, tok_end);
case CPP_STRING:
- cpp_error (pfile, "string constants not allowed in #if expressions");
+ case CPP_WSTRING:
+ cpp_error (pfile,
+ "string constants are not allowed in #if expressions");
op.op = ERROR;
return op;
- case CPP_CHAR:
- /* This code for reading a character constant
- handles multicharacter constants and wide characters.
- It is mostly copied from c-lex.c. */
- {
- register int result = 0;
- register num_chars = 0;
- unsigned width = MAX_CHAR_TYPE_SIZE;
- int wide_flag = 0;
- int max_chars;
- U_CHAR *ptr = tok_start;
-#ifdef MULTIBYTE_CHARS
- char token_buffer[MAX_LONG_TYPE_SIZE/MAX_CHAR_TYPE_SIZE + MB_CUR_MAX];
-#else
- char token_buffer[MAX_LONG_TYPE_SIZE/MAX_CHAR_TYPE_SIZE + 1];
-#endif
-
- if (*ptr == 'L')
- {
- ptr++;
- wide_flag = 1;
- width = MAX_WCHAR_TYPE_SIZE;
-#ifdef MULTIBYTE_CHARS
- max_chars = MB_CUR_MAX;
-#else
- max_chars = 1;
-#endif
- }
- else
- max_chars = MAX_LONG_TYPE_SIZE / width;
-
- ++ptr;
- while (ptr < tok_end && ((c = *ptr++) != '\''))
- {
- if (c == '\\')
- {
- c = cpp_parse_escape (pfile, &ptr);
- if (width < HOST_BITS_PER_INT
- && (unsigned) c >= (1 << width))
- cpp_pedwarn (pfile,
- "escape sequence out of range for character");
- }
- num_chars++;
-
- /* Merge character into result; ignore excess chars. */
- if (num_chars < max_chars + 1)
- {
- 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 != '\'')
- cpp_error (pfile, "malformatted character constant");
- else if (num_chars == 0)
- cpp_error (pfile, "empty character constant");
- else if (num_chars > max_chars)
- {
- num_chars = max_chars;
- cpp_error (pfile, "character constant too long");
- }
- else if (num_chars != 1 && ! CPP_TRADITIONAL (pfile))
- cpp_warning (pfile, "multi-character character constant");
-
- /* If char type is signed, sign-extend the constant. */
- if (! wide_flag)
- {
- int num_bits = num_chars * width;
+ case CPP_CHAR:
+ case CPP_WCHAR:
+ return parse_charconst (pfile, tok_start, tok_end);
- if (cpp_lookup (pfile, "__CHAR_UNSIGNED__",
- sizeof ("__CHAR_UNSIGNED__")-1, -1)
- || ((result >> (num_bits - 1)) & 1) == 0)
- op.value
- = result & ((unsigned long) ~0 >> (HOST_BITS_PER_LONG - num_bits));
- else
- op.value
- = result | ~((unsigned long) ~0 >> (HOST_BITS_PER_LONG - 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
- cpp_warning (pfile,"Ignoring invalid multibyte character");
- }
-#endif
- op.value = result;
- }
- }
+ case CPP_NAME:
+ if (!ustrncmp (tok_start, U"defined", 7))
+ return parse_defined (pfile);
- /* This is always a signed type. */
+ op.op = INT;
op.unsignedp = 0;
- op.op = CHAR;
-
+ op.value = 0;
+
+ if (CPP_OPTION (pfile, warn_undef) && !skip_evaluation)
+ cpp_warning (pfile, "'%.*s' is not defined",
+ (int) (tok_end - tok_start), tok_start);
return op;
- case CPP_NAME:
- return parse_number (pfile, "0", 0);
+ case CPP_HASH:
+ return parse_assertion (pfile);
case CPP_OTHER:
/* See if it is a special token of length 2. */
&& tok_start[1] == toktab->operator[1])
break;
if (toktab->token == ERROR)
- {
- char *buf = (char *) alloca (40);
- sprintf (buf, "`%s' not allowed in operand of `#if'", tok_start);
- cpp_error (pfile, buf);
- }
+ cpp_error (pfile, "'%.*s' is not allowed in #if expressions",
+ (int) (tok_end - tok_start), tok_start);
op.op = toktab->token;
return op;
}
}
}
+/* Convert an operator ID to a string. BUFF is a buffer at least 5
+ characters long which might be used to store the string. */
+/* XXX FIXME: Remove BUFF when new lexer is implemented. */
+static const char *
+op_to_str (op, buff)
+ op_t op;
+ char *buff;
+{
+ const struct token *toktab;
+
+ /* See if it is a special token of length 2. */
+ for (toktab = tokentab2; toktab->operator != NULL; toktab++)
+ if (op == toktab->token)
+ return toktab->operator;
+
+ if (ISGRAPH (op))
+ sprintf (buff, "%c", (int) op);
+ else
+ sprintf (buff, "\\%03o", (int) op);
+ return buff;
+}
/* Parse a C escape sequence. STRING_PTR points to a variable
containing a pointer to the string to parse. That pointer
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
-cpp_parse_escape (pfile, string_ptr)
+static HOST_WIDEST_INT
+parse_escape (pfile, string_ptr, result_mask)
cpp_reader *pfile;
- char **string_ptr;
+ U_CHAR **string_ptr;
+ HOST_WIDEST_INT result_mask;
{
register int c = *(*string_ptr)++;
switch (c)
case 'e':
case 'E':
if (CPP_PEDANTIC (pfile))
- cpp_pedwarn (pfile, "non-ANSI-standard escape sequence, `\\%c'", c);
- return 033;
+ cpp_pedwarn (pfile, "non-ANSI-standard escape sequence, '\\%c'", c);
+ return TARGET_ESC;
case 'f':
return TARGET_FF;
case 'n':
case '6':
case '7':
{
- register int i = c - '0';
+ register HOST_WIDEST_INT i = c - '0';
register int count = 0;
while (++count < 3)
{
break;
}
}
- if ((i & ~((1 << MAX_CHAR_TYPE_SIZE) - 1)) != 0)
+ if (i != (i & result_mask))
{
- i &= (1 << MAX_CHAR_TYPE_SIZE) - 1;
- cpp_warning (pfile,
- "octal character constant does not fit in a byte");
+ i &= result_mask;
+ cpp_pedwarn (pfile, "octal escape sequence out of range");
}
return i;
}
case 'x':
{
- register unsigned i = 0, overflow = 0, digits_found = 0, digit;
+ register unsigned HOST_WIDEST_INT i = 0, overflow = 0;
+ register int digits_found = 0, digit;
for (;;)
{
c = *(*string_ptr)++;
}
if (!digits_found)
cpp_error (pfile, "\\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;
- cpp_warning (pfile,
- "hex character constant does not fit in a byte");
+ i &= result_mask;
+ cpp_pedwarn (pfile, "hex escape sequence out of range");
}
return i;
}
cpp_pedwarn (pfile, "integer overflow in preprocessor expression");
}
-static long
+static HOST_WIDEST_INT
left_shift (pfile, a, unsignedp, b)
cpp_reader *pfile;
- long a;
- int unsignedp;
- unsigned long b;
+ HOST_WIDEST_INT a;
+ unsigned int unsignedp;
+ unsigned HOST_WIDEST_INT b;
{
- if (b >= HOST_BITS_PER_LONG)
+ if (b >= HOST_BITS_PER_WIDEST_INT)
{
if (! unsignedp && a != 0)
integer_overflow (pfile);
return 0;
}
else if (unsignedp)
- return (unsigned long) a << b;
+ return (unsigned HOST_WIDEST_INT) a << b;
else
{
- long l = a << b;
+ HOST_WIDEST_INT l = a << b;
if (l >> b != a)
integer_overflow (pfile);
return l;
}
}
-static long
+static HOST_WIDEST_INT
right_shift (pfile, a, unsignedp, b)
- cpp_reader *pfile;
- long a;
- int unsignedp;
- unsigned long b;
+ cpp_reader *pfile ATTRIBUTE_UNUSED;
+ HOST_WIDEST_INT a;
+ unsigned int unsignedp;
+ unsigned HOST_WIDEST_INT b;
{
- if (b >= HOST_BITS_PER_LONG)
- return unsignedp ? 0 : a >> (HOST_BITS_PER_LONG - 1);
+ if (b >= HOST_BITS_PER_WIDEST_INT)
+ return unsignedp ? 0 : a >> (HOST_BITS_PER_WIDEST_INT - 1);
else if (unsignedp)
- return (unsigned long) a >> b;
+ return (unsigned HOST_WIDEST_INT) a >> b;
else
return a >> b;
}
\f
-/* These priorities are all even, so we can handle associatively. */
-#define PAREN_INNER_PRIO 0
-#define COMMA_PRIO 4
-#define COND_PRIO (COMMA_PRIO+2)
-#define OROR_PRIO (COND_PRIO+2)
-#define ANDAND_PRIO (OROR_PRIO+2)
-#define OR_PRIO (ANDAND_PRIO+2)
-#define XOR_PRIO (OR_PRIO+2)
-#define AND_PRIO (XOR_PRIO+2)
-#define EQUAL_PRIO (AND_PRIO+2)
-#define LESS_PRIO (EQUAL_PRIO+2)
-#define SHIFT_PRIO (LESS_PRIO+2)
-#define PLUS_PRIO (SHIFT_PRIO+2)
-#define MUL_PRIO (PLUS_PRIO+2)
-#define UNARY_PRIO (MUL_PRIO+2)
-#define PAREN_OUTER_PRIO (UNARY_PRIO+2)
+/* Operator precedence and flags table.
+
+After an operator is returned from the lexer, if it has priority less
+than or equal to the operator on the top of the stack, we reduce the
+stack by one operator and repeat the test. Since equal priorities
+reduce, this is naturally left-associative.
+
+We handle right-associative operators by clearing the lower bit of all
+left-associative operators, and setting it for right-associative ones.
+After the reduction phase of a new operator, just before it is pushed
+onto the stack, its RIGHT_ASSOC bit is cleared. The effect is that
+during the reduction phase, the current right-associative operator has
+a priority one greater than any other operator of otherwise equal
+precedence that has been pushed on the top of the stack. This avoids
+a reduction pass, and effectively makes the logic right-associative.
+
+The remaining cases are '(' and ')'. We handle '(' by skipping the
+reduction phase completely. ')' is given lower priority than
+everything else, including '(', effectively forcing a reduction of the
+parenthesised expression. If there is no matching '(', the stack will
+be reduced all the way to the beginning, exiting the parser in the
+same way as the ultra-low priority end-of-expression dummy operator.
+The exit code checks to see if the operator that caused it is ')', and
+if so outputs an appropriate error message.
+
+The parser assumes all shifted operators require a right operand
+unless the flag NO_R_OPERAND is set, and similarly for NO_L_OPERAND.
+These semantics are automatically checked, any extra semantics need to
+be handled with operator-specific code. */
+
+#define FLAG_BITS 8
+#define FLAG_MASK ((1 << FLAG_BITS) - 1)
+#define PRIO_SHIFT (FLAG_BITS + 1)
+#define EXTRACT_PRIO(cnst) (cnst >> FLAG_BITS)
+#define EXTRACT_FLAGS(cnst) (cnst & FLAG_MASK)
+
+/* Flags. */
+#define HAVE_VALUE (1 << 0)
+#define NO_L_OPERAND (1 << 1)
+#define NO_R_OPERAND (1 << 2)
+#define SHORT_CIRCUIT (1 << 3)
+
+/* Priority and flag combinations. */
+#define RIGHT_ASSOC (1 << FLAG_BITS)
+#define FORCE_REDUCE_PRIO (0 << PRIO_SHIFT)
+#define CLOSE_PAREN_PRIO (1 << PRIO_SHIFT)
+#define OPEN_PAREN_PRIO ((2 << PRIO_SHIFT) | NO_L_OPERAND)
+#define COMMA_PRIO (3 << PRIO_SHIFT)
+#define COND_PRIO ((4 << PRIO_SHIFT) | RIGHT_ASSOC | SHORT_CIRCUIT)
+#define COLON_PRIO ((5 << PRIO_SHIFT) | SHORT_CIRCUIT)
+#define OROR_PRIO ((6 << PRIO_SHIFT) | SHORT_CIRCUIT)
+#define ANDAND_PRIO ((7 << PRIO_SHIFT) | SHORT_CIRCUIT)
+#define OR_PRIO (8 << PRIO_SHIFT)
+#define XOR_PRIO (9 << PRIO_SHIFT)
+#define AND_PRIO (10 << PRIO_SHIFT)
+#define EQUAL_PRIO (11 << PRIO_SHIFT)
+#define LESS_PRIO (12 << PRIO_SHIFT)
+#define SHIFT_PRIO (13 << PRIO_SHIFT)
+#define PLUS_PRIO (14 << PRIO_SHIFT)
+#define MUL_PRIO (15 << PRIO_SHIFT)
+#define UNARY_PRIO ((16 << PRIO_SHIFT) | RIGHT_ASSOC | NO_L_OPERAND)
#define COMPARE(OP) \
- top->unsignedp = 0;\
- top->value = (unsigned1 || unsigned2) ? (unsigned long) v1 OP v2 : (v1 OP v2)
+ top->unsignedp = 0; \
+ top->value = (unsigned1 | unsigned2) \
+ ? (unsigned HOST_WIDEST_INT) v1 OP (unsigned HOST_WIDEST_INT) v2 \
+ : (v1 OP v2)
+#define EQUALITY(OP) \
+ top->value = v1 OP v2; \
+ top->unsignedp = 0;
+#define LOGICAL(OP) \
+ top->value = v1 OP v2; \
+ top->unsignedp = unsigned1 | unsigned2;
/* Parse and evaluate a C expression, reading from PFILE.
- Returns the value of the expression. */
+ Returns the truth value of the expression. */
-HOST_WIDE_INT
-cpp_parse_expr (pfile)
+int
+_cpp_parse_expr (pfile)
cpp_reader *pfile;
{
- /* The implementation is an operator precedence parser,
- i.e. a bottom-up parser, using a stack for not-yet-reduced tokens.
+ /* The implementation is an operator precedence parser, i.e. a
+ bottom-up parser, using a stack for not-yet-reduced tokens.
The stack base is 'stack', and the current stack pointer is 'top'.
There is a stack element for each operator (only),
struct operation init_stack[INIT_STACK_SIZE];
struct operation *stack = init_stack;
struct operation *limit = stack + INIT_STACK_SIZE;
- register struct operation *top = stack;
- int lprio, rprio;
+ register struct operation *top = stack + 1;
+ long old_written = CPP_WRITTEN (pfile);
+ int skip_evaluation = 0;
+ int result;
+ char buff[5];
+
+ /* Save parser state and set it to something sane. */
+ int save_only_seen_white = pfile->only_seen_white;
+ int save_skipping = pfile->skipping;
+ pfile->only_seen_white = 0;
+ pfile->skipping = 0;
+
+ /* We've finished when we try to reduce this. */
+ top->op = FINISHED;
+ /* Nifty way to catch missing '('. */
+ top->prio = EXTRACT_PRIO(CLOSE_PAREN_PRIO);
+ /* Avoid missing right operand checks. */
+ top->flags = NO_R_OPERAND;
- top->rprio = 0;
- top->flags = 0;
for (;;)
{
+ unsigned int prio;
+ unsigned int flags;
struct operation op;
- char flags = 0;
/* Read a token */
- op = cpp_lex (pfile);
-
- /* See if the token is an operand, in which case go to set_value.
- If the token is an operator, figure out its left and right
- priorities, and then goto maybe_reduce. */
+ op = lex (pfile, skip_evaluation);
+ /* If the token is an operand, push its value and get next
+ token. If it is an operator, get its priority and flags, and
+ try to reduce the expression on the stack. */
switch (op.op)
{
case NAME:
- top->value = 0, top->unsignedp = 0;
- goto set_value;
- case INT: case CHAR:
+ CPP_ICE ("lex returns a NAME");
+ case ERROR:
+ goto syntax_error;
+ default:
+ SYNTAX_ERROR ("invalid character in #if");
+
+ push_immediate:
+ case INT:
+ case CHAR:
+ /* Push a value onto the stack. */
+ if (top->flags & HAVE_VALUE)
+ SYNTAX_ERROR ("missing binary operator");
top->value = op.value;
top->unsignedp = op.unsignedp;
- goto set_value;
- case 0:
- lprio = 0; goto maybe_reduce;
- case '+': case '-':
- /* Is this correct if unary ? FIXME */
- flags = RIGHT_OPERAND_REQUIRED;
- lprio = PLUS_PRIO; rprio = lprio + 1; goto maybe_reduce;
- case '!': case '~':
- flags = RIGHT_OPERAND_REQUIRED;
- rprio = UNARY_PRIO; lprio = rprio + 1; goto maybe_reduce;
- case '*': case '/': case '%':
- lprio = MUL_PRIO; goto binop;
- case '<': case '>': case LEQ: case GEQ:
- lprio = LESS_PRIO; goto binop;
- case EQUAL: case NOTEQUAL:
- lprio = EQUAL_PRIO; goto binop;
- case LSH: case RSH:
- lprio = SHIFT_PRIO; goto binop;
- case '&': lprio = AND_PRIO; goto binop;
- case '^': lprio = XOR_PRIO; goto binop;
- case '|': lprio = OR_PRIO; goto binop;
- case ANDAND: lprio = ANDAND_PRIO; goto binop;
- case OROR: lprio = OROR_PRIO; goto binop;
- case ',':
- lprio = COMMA_PRIO; goto binop;
- case '(':
- lprio = PAREN_OUTER_PRIO; rprio = PAREN_INNER_PRIO;
- goto maybe_reduce;
- case ')':
- lprio = PAREN_INNER_PRIO; rprio = PAREN_OUTER_PRIO;
- goto maybe_reduce;
- case ':':
- lprio = COND_PRIO; rprio = COND_PRIO;
- goto maybe_reduce;
- case '?':
- lprio = COND_PRIO + 1; rprio = COND_PRIO;
- goto maybe_reduce;
- binop:
- flags = LEFT_OPERAND_REQUIRED|RIGHT_OPERAND_REQUIRED;
- rprio = lprio + 1;
- goto maybe_reduce;
- default:
- cpp_error (pfile, "invalid character in #if");
- goto syntax_error;
+ top->flags |= HAVE_VALUE;
+ continue;
+
+ case '+':
+ case '-': prio = PLUS_PRIO; if (top->flags & HAVE_VALUE) break;
+ /* else unary; fall through */
+ case '!':
+ case '~': prio = UNARY_PRIO; break;
+
+ case '*':
+ case '/':
+ case '%': prio = MUL_PRIO; break;
+ case '<':
+ case '>':
+ case LEQ:
+ case GEQ: prio = LESS_PRIO; break;
+ case NOTEQUAL:
+ case EQUAL: prio = EQUAL_PRIO; break;
+ case LSH:
+ case RSH: prio = SHIFT_PRIO; break;
+ case '&': prio = AND_PRIO; break;
+ case '^': prio = XOR_PRIO; break;
+ case '|': prio = OR_PRIO; break;
+ case ANDAND: prio = ANDAND_PRIO; break;
+ case OROR: prio = OROR_PRIO; break;
+ case ',': prio = COMMA_PRIO; break;
+ case '(': prio = OPEN_PAREN_PRIO; break;
+ case ')': prio = CLOSE_PAREN_PRIO; break;
+ case ':': prio = COLON_PRIO; break;
+ case '?': prio = COND_PRIO; break;
+ case 0: prio = FORCE_REDUCE_PRIO; break;
}
- set_value:
- /* Push a value onto the stack. */
- if (top->flags & HAVE_VALUE)
- {
- cpp_error (pfile, "syntax error in #if");
- goto syntax_error;
- }
- top->flags |= HAVE_VALUE;
- continue;
+ /* Separate the operator's code into priority and flags. */
+ flags = EXTRACT_FLAGS(prio);
+ prio = EXTRACT_PRIO(prio);
+ if (op.op == '(')
+ goto skip_reduction;
- maybe_reduce:
- /* Push an operator, and check if we can reduce now. */
- while (top->rprio > lprio)
+ /* Check for reductions. Then push the operator. */
+ while (prio <= top->prio)
{
- long v1 = top[-1].value, v2 = top[0].value;
- int unsigned1 = top[-1].unsignedp, unsigned2 = top[0].unsignedp;
- top--;
- if ((top[1].flags & LEFT_OPERAND_REQUIRED)
- && ! (top[0].flags & HAVE_VALUE))
- {
- cpp_error (pfile, "syntax error - missing left operand");
- goto syntax_error;
- }
- if ((top[1].flags & RIGHT_OPERAND_REQUIRED)
- && ! (top[1].flags & HAVE_VALUE))
+ HOST_WIDEST_INT v1, v2;
+ unsigned int unsigned1, unsigned2;
+
+ /* Most operators that can appear on the stack require a
+ right operand. Check this before trying to reduce. */
+ if ((top->flags & (HAVE_VALUE | NO_R_OPERAND)) == 0)
{
- cpp_error (pfile, "syntax error - missing right operand");
- goto syntax_error;
+ if (top->op == '(')
+ SYNTAX_ERROR ("void expression between '(' and ')'");
+ else
+ SYNTAX_ERROR2 ("operator '%s' has no right operand",
+ op_to_str (top->op, buff));
}
- /* top[0].value = (top[1].op)(v1, v2);*/
+
+ unsigned2 = top->unsignedp, v2 = top->value;
+ top--;
+ unsigned1 = top->unsignedp, v1 = top->value;
+
+ /* Now set top->value = (top[1].op)(v1, v2); */
switch (top[1].op)
{
case '+':
else
{
top->value = v1 + v2;
- top->unsignedp = unsigned1 || unsigned2;
- if (! top->unsignedp
+ top->unsignedp = unsigned1 | unsigned2;
+ if (! top->unsignedp && ! skip_evaluation
&& ! possible_sum_sign (v1, v2, top->value))
integer_overflow (pfile);
}
if (!(top->flags & HAVE_VALUE))
{ /* Unary '-' */
top->value = - v2;
- if ((top->value & v2) < 0 && ! unsigned2)
+ if (!skip_evaluation && (top->value & v2) < 0
+ && !unsigned2)
integer_overflow (pfile);
top->unsignedp = unsigned2;
top->flags |= HAVE_VALUE;
else
{ /* Binary '-' */
top->value = v1 - v2;
- top->unsignedp = unsigned1 || unsigned2;
- if (! top->unsignedp
+ top->unsignedp = unsigned1 | unsigned2;
+ if (! top->unsignedp && ! skip_evaluation
&& ! possible_sum_sign (top->value, v2, v1))
integer_overflow (pfile);
}
break;
case '*':
- top->unsignedp = unsigned1 || unsigned2;
+ top->unsignedp = unsigned1 | unsigned2;
if (top->unsignedp)
- top->value = (unsigned long) v1 * v2;
- else
+ top->value = (unsigned HOST_WIDEST_INT) v1 * v2;
+ else if (!skip_evaluation)
{
top->value = v1 * v2;
- if (v1
- && (top->value / v1 != v2
- || (top->value & v1 & v2) < 0))
+ if (v1 && (top->value / v1 != v2
+ || (top->value & v1 & v2) < 0))
integer_overflow (pfile);
}
break;
case '/':
+ case '%':
+ if (skip_evaluation)
+ break;
if (v2 == 0)
+ SYNTAX_ERROR ("division by zero in #if");
+ top->unsignedp = unsigned1 | unsigned2;
+ if (top[1].op == '/')
{
- cpp_error (pfile, "division by zero in #if");
- v2 = 1;
+ if (top->unsignedp)
+ top->value = (unsigned HOST_WIDEST_INT) v1 / v2;
+ else
+ {
+ top->value = v1 / v2;
+ if ((top->value & v1 & v2) < 0)
+ integer_overflow (pfile);
+ }
}
- top->unsignedp = unsigned1 || unsigned2;
- if (top->unsignedp)
- top->value = (unsigned long) v1 / v2;
else
{
- top->value = v1 / v2;
- if ((top->value & v1 & v2) < 0)
- integer_overflow (pfile);
- }
- break;
- case '%':
- if (v2 == 0)
- {
- cpp_error (pfile, "division by zero in #if");
- v2 = 1;
+ if (top->unsignedp)
+ top->value = (unsigned HOST_WIDEST_INT) v1 % v2;
+ else
+ top->value = v1 % v2;
}
- top->unsignedp = unsigned1 || unsigned2;
- if (top->unsignedp)
- top->value = (unsigned long) v1 % v2;
- else
- top->value = v1 % v2;
break;
case '!':
- if (top->flags & HAVE_VALUE)
- {
- cpp_error (pfile, "syntax error");
- goto syntax_error;
- }
top->value = ! v2;
top->unsignedp = 0;
top->flags |= HAVE_VALUE;
break;
case '~':
- if (top->flags & HAVE_VALUE)
- {
- cpp_error (pfile, "syntax error");
- goto syntax_error;
- }
top->value = ~ v2;
top->unsignedp = unsigned2;
top->flags |= HAVE_VALUE;
break;
case '<': COMPARE(<); break;
case '>': COMPARE(>); break;
- case LEQ: COMPARE(<=); break;
- case GEQ: COMPARE(>=); break;
- case EQUAL:
- top->value = (v1 == v2);
- top->unsignedp = 0;
- break;
- case NOTEQUAL:
- top->value = (v1 != v2);
- top->unsignedp = 0;
- break;
+ case LEQ: COMPARE(<=); break;
+ case GEQ: COMPARE(>=); break;
+ case EQUAL: EQUALITY(==); break;
+ case NOTEQUAL: EQUALITY(!=); break;
case LSH:
+ if (skip_evaluation)
+ break;
top->unsignedp = unsigned1;
if (v2 < 0 && ! unsigned2)
top->value = right_shift (pfile, v1, unsigned1, -v2);
top->value = left_shift (pfile, v1, unsigned1, v2);
break;
case RSH:
+ if (skip_evaluation)
+ break;
top->unsignedp = unsigned1;
if (v2 < 0 && ! unsigned2)
top->value = left_shift (pfile, v1, unsigned1, -v2);
else
top->value = right_shift (pfile, v1, unsigned1, v2);
break;
-#define LOGICAL(OP) \
- top->value = v1 OP v2;\
- top->unsignedp = unsigned1 || unsigned2;
case '&': LOGICAL(&); break;
case '^': LOGICAL(^); break;
case '|': LOGICAL(|); break;
case ANDAND:
- top->value = v1 && v2; top->unsignedp = 0; break;
+ top->value = v1 && v2; top->unsignedp = 0;
+ if (!v1) skip_evaluation--;
+ break;
case OROR:
- top->value = v1 || v2; top->unsignedp = 0; break;
+ top->value = v1 || v2; top->unsignedp = 0;
+ if (v1) skip_evaluation--;
+ break;
case ',':
if (CPP_PEDANTIC (pfile))
- cpp_pedwarn (pfile, "comma operator in operand of `#if'");
+ cpp_pedwarn (pfile, "comma operator in operand of #if");
top->value = v2;
top->unsignedp = unsigned2;
break;
- case '(': case '?':
- cpp_error (pfile, "syntax error in #if");
- goto syntax_error;
+ case '?':
+ SYNTAX_ERROR ("syntax error '?' without following ':'");
case ':':
if (top[0].op != '?')
- {
- cpp_error (pfile,
- "syntax error ':' without preceding '?'");
- goto syntax_error;
- }
- else if (! (top[1].flags & HAVE_VALUE)
- || !(top[-1].flags & HAVE_VALUE)
- || !(top[0].flags & HAVE_VALUE))
- {
- cpp_error (pfile, "bad syntax for ?: operator");
- goto syntax_error;
- }
- else
- {
- top--;
- top->value = top->value ? v1 : v2;
- top->unsignedp = unsigned1 || unsigned2;
- }
- break;
- case ')':
- if ((top[1].flags & HAVE_VALUE)
- || ! (top[0].flags & HAVE_VALUE)
- || top[0].op != '('
- || (top[-1].flags & HAVE_VALUE))
- {
- cpp_error (pfile, "mismatched parentheses in #if");
- goto syntax_error;
- }
- else
- {
- top--;
- top->value = v1;
- top->unsignedp = unsigned1;
- top->flags |= HAVE_VALUE;
- }
+ SYNTAX_ERROR ("syntax error ':' without preceding '?'");
+ top--;
+ if (top->value) skip_evaluation--;
+ top->value = top->value ? v1 : v2;
+ top->unsignedp = unsigned1 | unsigned2;
break;
+ case '(':
+ if (op.op != ')')
+ SYNTAX_ERROR ("missing ')' in expression");
+ op.value = v2;
+ op.unsignedp = unsigned2;
+ goto push_immediate;
default:
- fprintf (stderr,
- top[1].op >= ' ' && top[1].op <= '~'
- ? "unimplemented operator '%c'\n"
- : "unimplemented operator '\\%03o'\n",
- top[1].op);
+ SYNTAX_ERROR2 ("unimplemented operator '%s'",
+ op_to_str (top[1].op, buff));
+ case FINISHED:
+ /* Reducing this dummy operator indicates we've finished. */
+ if (op.op == ')')
+ SYNTAX_ERROR ("missing '(' in expression");
+ goto done;
}
}
- if (op.op == 0)
+
+ /* Handle short-circuit evaluations. */
+ if (flags & SHORT_CIRCUIT)
+ switch (op.op)
+ {
+ case OROR: if (top->value) skip_evaluation++; break;
+ case ANDAND:
+ case '?': if (!top->value) skip_evaluation++; break;
+ case ':':
+ if (top[-1].value) /* Was '?' condition true? */
+ skip_evaluation++;
+ else
+ skip_evaluation--;
+ }
+
+ skip_reduction:
+ /* Check we have a left operand iff we need one. */
+ if (flags & NO_L_OPERAND)
{
- if (top != stack)
- cpp_error (pfile, "internal error in #if expression");
- if (stack != init_stack)
- free (stack);
- return top->value;
+ if (top->flags & HAVE_VALUE)
+ SYNTAX_ERROR2 ("missing binary operator before '%s'",
+ op_to_str (op.op, buff));
}
+ else
+ {
+ if (!(top->flags & HAVE_VALUE))
+ SYNTAX_ERROR2 ("operator '%s' has no left operand",
+ op_to_str (op.op, buff));
+ }
+
+ /* Check for and handle stack overflow. */
top++;
-
- /* Check for and handle stack overflow. */
if (top == limit)
{
struct operation *new_stack;
- int old_size = (char*)limit - (char*)stack;
+ int old_size = (char *) limit - (char *) stack;
int new_size = 2 * old_size;
if (stack != init_stack)
- new_stack = (struct operation*) xrealloc (stack, new_size);
+ new_stack = (struct operation *) xrealloc (stack, new_size);
else
{
- new_stack = (struct operation*) xmalloc (new_size);
- bcopy ((char *) stack, (char *) new_stack, old_size);
+ new_stack = (struct operation *) xmalloc (new_size);
+ memcpy (new_stack, stack, old_size);
}
stack = new_stack;
- top = (struct operation*)((char*) new_stack + old_size);
- limit = (struct operation*)((char*) new_stack + new_size);
+ top = (struct operation *) ((char *) new_stack + old_size);
+ limit = (struct operation *) ((char *) new_stack + new_size);
}
top->flags = flags;
- top->rprio = rprio;
+ top->prio = prio & ~EXTRACT_PRIO(RIGHT_ASSOC);
top->op = op.op;
}
- syntax_error:
+
+ done:
+ result = (top[1].value != 0);
+ if (top != stack)
+ CPP_ICE ("unbalanced stack in #if expression");
+ else if (!(top[1].flags & HAVE_VALUE))
+ {
+ SYNTAX_ERROR ("#if with no expression");
+ syntax_error:
+ _cpp_skip_rest_of_line (pfile);
+ result = 0; /* Return 0 on syntax error. */
+ }
+
+ /* Free dynamic stack if we allocated one. */
if (stack != init_stack)
free (stack);
- skip_rest_of_line (pfile);
- return 0;
+ CPP_SET_WRITTEN (pfile, old_written);
+ pfile->only_seen_white = save_only_seen_white;
+ pfile->skipping = save_skipping;
+ return result;
}