Commit cf00a885 by Zack Weinberg Committed by Zack Weinberg

cppexp.c: Update all code for new lexer interface.

	* cppexp.c: Update all code for new lexer interface.
	(op_t, operator codes, struct token, tokentab2, op_to_str): Remove.
	(struct suffix, vsuf_1, vsuf_2, vsuf_3, op_to_prio): New.
	* cpplex.c (token_names): Trim leading CPP_ from names; make
	the strings unsigned.
	(_cpp_spell_operator): New.
	(is_macro_disabled): Disable all macros if rescanning
	preprocessed text.
	(_cpp_get_directive_token): Remove.

	* cppinit.c: Don't set no_macro_expand.
	* cpplib.c (read_line_number, do_line): Check only for EOF,
	not VSPACE.
	* cpphash.h: Update prototypes.
	* cpplib.h (CPP_VSPACE): Remove.
	(struct cpp_reader): Remove no_macro_expand.

testsuite:
	* gcc.dg/cpp/19951227-1.c, gcc.dg/cpp/assert2.c,
	gcc.dg/cpp/if-1.c, gcc.dg/cpp/if-4.c: Tweak error regexps.

From-SVN: r34920
parent 563dd08a
2000-07-07 Zack Weinberg <zack@wolery.cumb.org>
* cppexp.c: Update all code for new lexer interface.
(op_t, operator codes, struct token, tokentab2, op_to_str): Remove.
(struct suffix, vsuf_1, vsuf_2, vsuf_3, op_to_prio): New.
* cpplex.c (token_names): Trim leading CPP_ from names; make
the strings unsigned.
(_cpp_spell_operator): New.
(is_macro_disabled): Disable all macros if rescanning
preprocessed text.
(_cpp_get_directive_token): Remove.
* cppinit.c: Don't set no_macro_expand.
* cpplib.c (read_line_number, do_line): Check only for EOF,
not VSPACE.
* cpphash.h: Update prototypes.
* cpplib.h (CPP_VSPACE): Remove.
(struct cpp_reader): Remove no_macro_expand.
2000-07-08 Neil Booth <NeilB@earthling.net> 2000-07-08 Neil Booth <NeilB@earthling.net>
* cpphash.c (is__va_args__): New function. * cpphash.c (is__va_args__): New function.
......
...@@ -68,8 +68,6 @@ Boston, MA 02111-1307, USA. */ ...@@ -68,8 +68,6 @@ Boston, MA 02111-1307, USA. */
number with SUM's sign, where A, B, and SUM are all C integers. */ 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) #define possible_sum_sign(a, b, sum) ((((a) ^ (b)) | ~ ((a) ^ (sum))) < 0)
typedef int op_t;
static void integer_overflow PARAMS ((cpp_reader *)); static void integer_overflow PARAMS ((cpp_reader *));
static HOST_WIDEST_INT left_shift PARAMS ((cpp_reader *, HOST_WIDEST_INT, static HOST_WIDEST_INT left_shift PARAMS ((cpp_reader *, HOST_WIDEST_INT,
unsigned int, unsigned int,
...@@ -77,40 +75,27 @@ static HOST_WIDEST_INT left_shift PARAMS ((cpp_reader *, HOST_WIDEST_INT, ...@@ -77,40 +75,27 @@ static HOST_WIDEST_INT left_shift PARAMS ((cpp_reader *, HOST_WIDEST_INT,
static HOST_WIDEST_INT right_shift PARAMS ((cpp_reader *, HOST_WIDEST_INT, static HOST_WIDEST_INT right_shift PARAMS ((cpp_reader *, HOST_WIDEST_INT,
unsigned int, unsigned int,
unsigned HOST_WIDEST_INT)); unsigned HOST_WIDEST_INT));
static struct operation parse_number PARAMS ((cpp_reader *, U_CHAR *, static struct op parse_number PARAMS ((cpp_reader *, const cpp_token *));
U_CHAR *)); static struct op parse_charconst PARAMS ((cpp_reader *, const cpp_token *));
static struct operation parse_charconst PARAMS ((cpp_reader *, U_CHAR *, static struct op parse_defined PARAMS ((cpp_reader *));
U_CHAR *)); static struct op parse_assertion PARAMS ((cpp_reader *));
static struct operation parse_defined PARAMS ((cpp_reader *)); static HOST_WIDEST_INT parse_escape PARAMS ((cpp_reader *, const U_CHAR **,
static struct operation parse_assertion PARAMS ((cpp_reader *)); const U_CHAR *, HOST_WIDEST_INT));
static HOST_WIDEST_INT parse_escape PARAMS ((cpp_reader *, U_CHAR **, static struct op lex PARAMS ((cpp_reader *, int));
HOST_WIDEST_INT));
static struct operation lex PARAMS ((cpp_reader *, int)); struct op
static const char * op_to_str PARAMS ((op_t, char *));
#define ERROR 299
#define OROR 300
#define ANDAND 301
#define EQUAL 302
#define NOTEQUAL 303
#define LEQ 304
#define GEQ 305
#define LSH 306
#define RSH 307
#define NAME 308
#define INT 309
#define CHAR 310
#define FINISHED 311
struct operation
{ {
op_t op; enum cpp_ttype op;
U_CHAR prio; /* Priority of op. */ U_CHAR prio; /* Priority of op. */
U_CHAR flags; U_CHAR flags;
U_CHAR unsignedp; /* True if value should be treated as unsigned. */ U_CHAR unsignedp; /* True if value should be treated as unsigned. */
HOST_WIDEST_INT value; /* The value logically "right" of op. */ HOST_WIDEST_INT value; /* The value logically "right" of op. */
}; };
/* There is no "error" token, but we can't get comments in #if, so we can
abuse that token type. */
#define CPP_ERROR CPP_COMMENT
/* With -O2, gcc appears to produce nice code, moving the error /* With -O2, gcc appears to produce nice code, moving the error
message load and subsequent jump completely out of the main path. */ message load and subsequent jump completely out of the main path. */
#define CPP_ICE(msgid) \ #define CPP_ICE(msgid) \
...@@ -122,21 +107,45 @@ struct operation ...@@ -122,21 +107,45 @@ struct operation
/* Parse and convert an integer for #if. Accepts decimal, hex, or octal /* Parse and convert an integer for #if. Accepts decimal, hex, or octal
with or without size suffixes. */ with or without size suffixes. */
struct suffix
{
unsigned char s[4];
unsigned char u;
unsigned char l;
};
const struct suffix vsuf_1[] = {
{ "u", 1, 0 }, { "U", 1, 0 },
{ "l", 0, 1 }, { "L", 0, 1 }
};
const struct suffix vsuf_2[] = {
{ "ul", 1, 1 }, { "UL", 1, 1 }, { "uL", 1, 1 }, { "Ul", 1, 1 },
{ "lu", 1, 1 }, { "LU", 1, 1 }, { "Lu", 1, 1 }, { "lU", 1, 1 },
{ "ll", 0, 2 }, { "LL", 0, 2 }
};
static struct operation const struct suffix vsuf_3[] = {
parse_number (pfile, start, end) { "ull", 1, 2 }, { "ULL", 1, 2 }, { "uLL", 1, 2 }, { "Ull", 1, 2 },
{ "llu", 1, 2 }, { "LLU", 1, 2 }, { "LLu", 1, 2 }, { "llU", 1, 2 }
};
#define Nsuff(tab) (sizeof tab / sizeof (struct suffix))
static struct op
parse_number (pfile, tok)
cpp_reader *pfile; cpp_reader *pfile;
U_CHAR *start; const cpp_token *tok;
U_CHAR *end;
{ {
struct operation op; struct op op;
U_CHAR *p = start; const U_CHAR *start = tok->val.name.text;
int c; const U_CHAR *end = start + tok->val.name.len;
const U_CHAR *p = start;
int c, i, nsuff;
unsigned HOST_WIDEST_INT n = 0, nd, MAX_over_base; unsigned HOST_WIDEST_INT n = 0, nd, MAX_over_base;
int base = 10; int base = 10;
int overflow = 0; int overflow = 0;
int digit, largest_digit = 0; int digit, largest_digit = 0;
int spec_long = 0; const struct suffix *sufftab;
op.unsignedp = 0; op.unsignedp = 0;
...@@ -158,49 +167,21 @@ parse_number (pfile, start, end) ...@@ -158,49 +167,21 @@ parse_number (pfile, start, end)
MAX_over_base = (((unsigned HOST_WIDEST_INT) -1) MAX_over_base = (((unsigned HOST_WIDEST_INT) -1)
/ ((unsigned HOST_WIDEST_INT) base)); / ((unsigned HOST_WIDEST_INT) base));
while (p < end) for(; p < end; p++)
{ {
c = *p++; c = *p;
if (c >= '0' && c <= '9') if (c >= '0' && c <= '9')
digit = c - '0'; digit = c - '0';
/* FIXME: assumes ASCII */ /* We believe that in all live character sets, a-f are
consecutive, and so are A-F. */
else if (base == 16 && c >= 'a' && c <= 'f') else if (base == 16 && c >= 'a' && c <= 'f')
digit = c - 'a' + 10; digit = c - 'a' + 10;
else if (base == 16 && c >= 'A' && c <= 'F') else if (base == 16 && c >= 'A' && c <= 'F')
digit = c - 'A' + 10; 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 else
{ break;
/* `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;
}
if (largest_digit < digit) if (largest_digit < digit)
largest_digit = digit; largest_digit = digit;
nd = n * base + digit; nd = n * base + digit;
...@@ -208,25 +189,41 @@ parse_number (pfile, start, end) ...@@ -208,25 +189,41 @@ parse_number (pfile, start, end)
n = nd; n = nd;
} }
if (p != end) if (p < end)
{
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"); /* Check for a floating point constant. Note that float constants
goto error; with an exponent or suffix but no decimal point are technically
} illegal (C99 6.4.4.2) but accepted elsewhere. */
else if (op.unsignedp > 1) if ((c == '.' || c == 'F' || c == 'f')
{ || (base == 10 && (c == 'E' || c == 'e')
cpp_error (pfile, "too many 'u' suffixes in integer constant"); && p+1 < end && (p[1] == '+' || p[1] == '-'))
goto error; || (base == 16 && (c == 'P' || c == 'p')
&& p+1 < end && (p[1] == '+' || p[1] == '-')))
SYNTAX_ERROR ("floating point numbers are not valid in #if");
/* Determine the suffix. l means long, and u means unsigned.
See the suffix tables, above. */
switch (end - p)
{
case 1: sufftab = vsuf_1; nsuff = Nsuff(vsuf_1); break;
case 2: sufftab = vsuf_2; nsuff = Nsuff(vsuf_2); break;
case 3: sufftab = vsuf_3; nsuff = Nsuff(vsuf_3); break;
default: goto invalid_suffix;
}
for (i = 0; i < nsuff; i++)
if (memcmp (p, sufftab[i].s, end - p) == 0)
break;
if (i == nsuff)
goto invalid_suffix;
op.unsignedp = sufftab[i].u;
if (CPP_OPTION (pfile, c89) && sufftab[i].l == 2)
SYNTAX_ERROR ("too many 'l' suffixes in integer constant");
} }
if (base <= largest_digit) if (base <= largest_digit)
cpp_pedwarn (pfile, cpp_pedwarn (pfile, "integer constant contains digits beyond the radix");
"integer constant contains digits beyond the radix");
if (overflow) if (overflow)
cpp_pedwarn (pfile, "integer constant out of range"); cpp_pedwarn (pfile, "integer constant out of range");
...@@ -235,55 +232,52 @@ parse_number (pfile, start, end) ...@@ -235,55 +232,52 @@ parse_number (pfile, start, end)
else if ((HOST_WIDEST_INT) n < 0 && ! op.unsignedp) else if ((HOST_WIDEST_INT) n < 0 && ! op.unsignedp)
{ {
if (base == 10) if (base == 10)
cpp_warning (pfile, cpp_warning (pfile, "integer constant is so large that it is unsigned");
"integer constant is so large that it is unsigned");
op.unsignedp = 1; op.unsignedp = 1;
} }
op.value = n; op.value = n;
op.op = INT; op.op = CPP_INT;
return op; return op;
error: invalid_suffix:
op.op = ERROR; cpp_error (pfile, "invalid suffix '%.*s' on integer constant",
(int) (end - p), p);
syntax_error:
op.op = CPP_ERROR;
return op; return op;
} }
/* Parse and convert a character constant for #if. Understands backslash /* Parse and convert a character constant for #if. Understands backslash
escapes (\n, \031) and multibyte characters (if so configured). */ escapes (\n, \031) and multibyte characters (if so configured). */
static struct operation static struct op
parse_charconst (pfile, start, end) parse_charconst (pfile, tok)
cpp_reader *pfile; cpp_reader *pfile;
U_CHAR *start; const cpp_token *tok;
U_CHAR *end;
{ {
struct operation op; struct op op;
HOST_WIDEST_INT result = 0; HOST_WIDEST_INT result = 0;
int num_chars = 0; int num_chars = 0;
int num_bits; int num_bits;
unsigned int width = MAX_CHAR_TYPE_SIZE, mask = MAX_CHAR_TYPE_MASK; unsigned int width = MAX_CHAR_TYPE_SIZE, mask = MAX_CHAR_TYPE_MASK;
int max_chars; int max_chars;
U_CHAR *ptr = start; const U_CHAR *ptr = tok->val.name.text;
const U_CHAR *end = ptr + tok->val.name.len;
int c = -1; int c = -1;
if (*ptr == 'L') if (tok->type == CPP_WCHAR)
{ width = MAX_WCHAR_TYPE_SIZE, mask = MAX_WCHAR_TYPE_MASK;
++ptr;
width = MAX_WCHAR_TYPE_SIZE, mask = MAX_WCHAR_TYPE_MASK;
}
max_chars = MAX_LONG_TYPE_SIZE / width; max_chars = MAX_LONG_TYPE_SIZE / width;
++ptr; /* skip initial quote */
while (ptr < end) while (ptr < end)
{ {
c = *ptr++; c = *ptr++;
if (c == '\'') if (c == '\'')
break; CPP_ICE ("unescaped ' in character constant");
else if (c == '\\') else if (c == '\\')
{ {
c = parse_escape (pfile, &ptr, mask); c = parse_escape (pfile, &ptr, end, mask);
if (width < HOST_BITS_PER_INT if (width < HOST_BITS_PER_INT
&& (unsigned int) c >= (unsigned int)(1 << width)) && (unsigned int) c >= (unsigned int)(1 << width))
cpp_pedwarn (pfile, cpp_pedwarn (pfile,
...@@ -301,22 +295,9 @@ parse_charconst (pfile, start, end) ...@@ -301,22 +295,9 @@ parse_charconst (pfile, start, end)
} }
if (num_chars == 0) if (num_chars == 0)
{ SYNTAX_ERROR ("empty character constant");
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) else if (num_chars > max_chars)
{ SYNTAX_ERROR ("character constant too long");
cpp_error (pfile, "character constant too long");
goto error;
}
else if (num_chars != 1 && ! CPP_TRADITIONAL (pfile)) else if (num_chars != 1 && ! CPP_TRADITIONAL (pfile))
cpp_warning (pfile, "multi-character character constant"); cpp_warning (pfile, "multi-character character constant");
...@@ -334,75 +315,61 @@ parse_charconst (pfile, start, end) ...@@ -334,75 +315,61 @@ parse_charconst (pfile, start, end)
/* This is always a signed type. */ /* This is always a signed type. */
op.unsignedp = 0; op.unsignedp = 0;
op.op = CHAR; op.op = CPP_INT;
return op; return op;
error: syntax_error:
op.op = ERROR; op.op = CPP_ERROR;
return op; return op;
} }
static struct operation static struct op
parse_defined (pfile) parse_defined (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
int paren = 0, len; int paren;
U_CHAR *tok; const cpp_token *tok;
enum cpp_ttype token; struct op op;
struct operation op;
long old_written = CPP_WRITTEN (pfile);
op.unsignedp = 0; paren = 0;
op.op = INT; tok = _cpp_get_raw_token (pfile);
if (tok->type == CPP_OPEN_PAREN)
pfile->no_macro_expand++;
token = _cpp_get_directive_token (pfile);
if (token == CPP_OPEN_PAREN)
{ {
paren++; paren = 1;
CPP_SET_WRITTEN (pfile, old_written); tok = _cpp_get_raw_token (pfile);
token = _cpp_get_directive_token (pfile);
} }
if (token != CPP_NAME) if (tok->type != CPP_NAME)
goto oops; SYNTAX_ERROR ("\"defined\" without an identifier");
tok = pfile->token_buffer + old_written; if (paren && _cpp_get_raw_token (pfile)->type != CPP_CLOSE_PAREN)
len = CPP_PWRITTEN (pfile) - tok; SYNTAX_ERROR ("missing close paren after \"defined\"");
op.value = cpp_defined (pfile, tok, len);
if (paren) op.unsignedp = 0;
{ op.op = CPP_INT;
if (_cpp_get_directive_token (pfile) != CPP_CLOSE_PAREN) op.value = cpp_defined (pfile, tok->val.name.text, tok->val.name.len);
goto oops;
}
CPP_SET_WRITTEN (pfile, old_written);
pfile->no_macro_expand--;
return op; return op;
oops: syntax_error:
CPP_SET_WRITTEN (pfile, old_written); op.op = CPP_ERROR;
pfile->no_macro_expand--;
cpp_error (pfile, "'defined' without an identifier");
op.op = ERROR;
return op; return op;
} }
static struct operation static struct op
parse_assertion (pfile) parse_assertion (pfile)
cpp_reader *pfile; cpp_reader *pfile;
{ {
struct operation op; struct op op;
struct answer *answer; struct answer *answer;
cpp_hashnode *hp; cpp_hashnode *hp;
op.op = ERROR; op.op = CPP_ERROR;
hp = _cpp_parse_assertion (pfile, &answer); hp = _cpp_parse_assertion (pfile, &answer);
if (hp) if (hp)
{ {
/* If we get here, the syntax is valid. */ /* If we get here, the syntax is valid. */
op.op = INT; op.op = CPP_INT;
op.unsignedp = 0;
op.value = (hp->type == T_ASSERTION && op.value = (hp->type == T_ASSERTION &&
(answer == 0 || *_cpp_find_answer (hp, &answer->list) != 0)); (answer == 0 || *_cpp_find_answer (hp, &answer->list) != 0));
...@@ -412,132 +379,76 @@ parse_assertion (pfile) ...@@ -412,132 +379,76 @@ parse_assertion (pfile)
return op; return op;
} }
struct token
{
const char *operator;
op_t token;
};
static const struct token tokentab2[] =
{
{"&&", ANDAND},
{"||", OROR},
{"<<", LSH},
{">>", RSH},
{"==", EQUAL},
{"!=", NOTEQUAL},
{"<=", LEQ},
{">=", GEQ},
{NULL, ERROR}
};
/* Read one token. */ /* Read one token. */
static struct operation static struct op
lex (pfile, skip_evaluation) lex (pfile, skip_evaluation)
cpp_reader *pfile; cpp_reader *pfile;
int skip_evaluation; int skip_evaluation;
{ {
const struct token *toktab; struct op op;
enum cpp_ttype token; const cpp_token *tok;
struct operation op;
U_CHAR *tok_start, *tok_end;
long old_written = CPP_WRITTEN (pfile);
retry: retry:
token = _cpp_get_directive_token (pfile); tok = cpp_get_token (pfile);
tok_start = pfile->token_buffer + old_written;
tok_end = CPP_PWRITTEN (pfile);
CPP_SET_WRITTEN (pfile, old_written);
switch (token) switch (tok->type)
{ {
case CPP_PLACEMARKER: case CPP_PLACEMARKER:
CPP_SET_WRITTEN (pfile, old_written); /* XXX These shouldn't be visible outside cpplex.c. */
goto retry; goto retry;
case CPP_EOF: /* Should not happen ... */ case CPP_INT:
case CPP_VSPACE:
op.op = 0;
return op;
case CPP_NUMBER: case CPP_NUMBER:
return parse_number (pfile, tok_start, tok_end); return parse_number (pfile, tok);
case CPP_CHAR:
case CPP_WCHAR:
return parse_charconst (pfile, tok);
case CPP_STRING: case CPP_STRING:
case CPP_WSTRING: case CPP_WSTRING:
cpp_error (pfile, SYNTAX_ERROR ("string constants are not valid in #if");
"string constants are not allowed in #if expressions");
op.op = ERROR;
return op;
case CPP_CHAR: case CPP_FLOAT:
case CPP_WCHAR: SYNTAX_ERROR ("floating point numbers are not valid in #if");
return parse_charconst (pfile, tok_start, tok_end);
case CPP_OTHER:
if (ISGRAPH (tok->val.aux))
SYNTAX_ERROR2 ("invalid character '%c' in #if", tok->val.aux);
else
SYNTAX_ERROR2 ("invalid character '\\%03o' in #if", tok->val.aux);
case CPP_NAME: case CPP_NAME:
/* FIXME: could this not overflow the tok_start buffer? */ if (!cpp_idcmp (tok->val.name.text, tok->val.name.len, "defined"))
if (!ustrncmp (tok_start, U"defined", 7))
return parse_defined (pfile); return parse_defined (pfile);
op.op = INT; op.op = CPP_INT;
op.unsignedp = 0; op.unsignedp = 0;
op.value = 0; op.value = 0;
if (CPP_OPTION (pfile, warn_undef) && !skip_evaluation) if (CPP_OPTION (pfile, warn_undef) && !skip_evaluation)
cpp_warning (pfile, "'%.*s' is not defined", cpp_warning (pfile, "\"%.*s\" is not defined",
(int) (tok_end - tok_start), tok_start); (int) tok->val.name.len, tok->val.name.text);
return op; return op;
case CPP_HASH: case CPP_HASH:
return parse_assertion (pfile); return parse_assertion (pfile);
case CPP_AND_AND: op.op = ANDAND; return op;
case CPP_OR_OR: op.op = OROR; return op;
case CPP_LSHIFT: op.op = LSH; return op;
case CPP_RSHIFT: op.op = RSH; return op;
case CPP_EQ_EQ: op.op = EQUAL; return op;
case CPP_NOT_EQ: op.op = NOTEQUAL; return op;
case CPP_LESS_EQ: op.op = LEQ; return op;
case CPP_GREATER_EQ:op.op = GEQ; return op;
default: default:
/* See if it is a special token of length 2. */ if ((tok->type > CPP_EQ && tok->type < CPP_PLUS_EQ)
if (tok_start + 2 == tok_end) || tok->type == CPP_EOF)
{ {
for (toktab = tokentab2; toktab->operator != NULL; toktab++) op.op = tok->type;
if (tok_start[0] == toktab->operator[0]
&& tok_start[1] == toktab->operator[1])
break;
if (toktab->token == ERROR)
cpp_error (pfile, "'%.*s' is not allowed in #if expressions",
(int) (tok_end - tok_start), tok_start);
op.op = toktab->token;
return op; return op;
} }
op.op = *tok_start;
return op;
}
}
/* Convert an operator ID to a string. BUFF is a buffer at least 5 SYNTAX_ERROR2("'%s' is not valid in #if expressions",
characters long which might be used to store the string. */ _cpp_spell_operator (tok->type));
/* 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)) syntax_error:
sprintf (buff, "%c", (int) op); op.op = CPP_ERROR;
else return op;
sprintf (buff, "\\%03o", (int) op);
return buff;
} }
/* Parse a C escape sequence. STRING_PTR points to a variable /* Parse a C escape sequence. STRING_PTR points to a variable
...@@ -545,85 +456,69 @@ op_to_str (op, buff) ...@@ -545,85 +456,69 @@ op_to_str (op, buff)
is updated past the characters we use. The value of the is updated past the characters we use. The value of the
escape sequence is returned. escape sequence is returned.
A negative value means the sequence \ newline was seen,
which is supposed to be equivalent to nothing at all.
If \ is followed by a null character, we return a negative
value and leave the string pointer pointing at the null character.
If \ is followed by 000, we return 0 and leave the string 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. */ after the zeros. A value of 0 does not mean end of string. */
static HOST_WIDEST_INT static HOST_WIDEST_INT
parse_escape (pfile, string_ptr, result_mask) parse_escape (pfile, string_ptr, limit, result_mask)
cpp_reader *pfile; cpp_reader *pfile;
U_CHAR **string_ptr; const U_CHAR **string_ptr;
const U_CHAR *limit;
HOST_WIDEST_INT result_mask; HOST_WIDEST_INT result_mask;
{ {
register int c = *(*string_ptr)++; const U_CHAR *ptr = *string_ptr;
/* We know we have at least one following character. */
int c = *ptr++;
switch (c) switch (c)
{ {
case 'a': case 'a': c = TARGET_BELL; break;
return TARGET_BELL; case 'b': c = TARGET_BS; break;
case 'b': case 'f': c = TARGET_FF; break;
return TARGET_BS; case 'n': c = TARGET_NEWLINE; break;
case 'e': case 'r': c = TARGET_CR; break;
case 'E': case 't': c = TARGET_TAB; break;
case 'v': c = TARGET_VT; break;
case 'e': case 'E':
if (CPP_PEDANTIC (pfile)) if (CPP_PEDANTIC (pfile))
cpp_pedwarn (pfile, "non-ISO-standard escape sequence, '\\%c'", c); cpp_pedwarn (pfile, "non-ISO-standard escape sequence, '\\%c'", c);
return TARGET_ESC; c = TARGET_ESC;
case 'f': break;
return TARGET_FF;
case 'n':
return TARGET_NEWLINE;
case 'r':
return TARGET_CR;
case 't':
return TARGET_TAB;
case 'v':
return TARGET_VT;
case '\n':
return -2;
case 0:
(*string_ptr)--;
return 0;
case '0': case '0': case '1': case '2': case '3':
case '1': case '4': case '5': case '6': case '7':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
{ {
register HOST_WIDEST_INT i = c - '0'; unsigned int i = c - '0';
register int count = 0; int count = 0;
while (++count < 3) while (++count < 3)
{ {
c = *(*string_ptr)++; if (ptr >= limit)
if (c >= '0' && c <= '7') break;
i = (i << 3) + c - '0';
else c = *ptr;
{ if (c < '0' || c > '7')
(*string_ptr)--; break;
break; ptr++;
} i = (i << 3) + c - '0';
} }
if (i != (i & result_mask)) if (i != (i & result_mask))
{ {
i &= result_mask; i &= result_mask;
cpp_pedwarn (pfile, "octal escape sequence out of range"); cpp_pedwarn (pfile, "octal escape sequence out of range");
} }
return i; c = i;
break;
} }
case 'x': case 'x':
{ {
register unsigned HOST_WIDEST_INT i = 0, overflow = 0; unsigned int i = 0, overflow = 0;
register int digits_found = 0, digit; int digits_found = 0, digit;
for (;;) for (;;)
{ {
c = *(*string_ptr)++; if (ptr >= limit)
break;
c = *ptr;
if (c >= '0' && c <= '9') if (c >= '0' && c <= '9')
digit = c - '0'; digit = c - '0';
else if (c >= 'a' && c <= 'f') else if (c >= 'a' && c <= 'f')
...@@ -631,10 +526,8 @@ parse_escape (pfile, string_ptr, result_mask) ...@@ -631,10 +526,8 @@ parse_escape (pfile, string_ptr, result_mask)
else if (c >= 'A' && c <= 'F') else if (c >= 'A' && c <= 'F')
digit = c - 'A' + 10; digit = c - 'A' + 10;
else else
{ break;
(*string_ptr)--; ptr++;
break;
}
overflow |= i ^ (i << 4 >> 4); overflow |= i ^ (i << 4 >> 4);
i = (i << 4) + digit; i = (i << 4) + digit;
digits_found = 1; digits_found = 1;
...@@ -646,11 +539,12 @@ parse_escape (pfile, string_ptr, result_mask) ...@@ -646,11 +539,12 @@ parse_escape (pfile, string_ptr, result_mask)
i &= result_mask; i &= result_mask;
cpp_pedwarn (pfile, "hex escape sequence out of range"); cpp_pedwarn (pfile, "hex escape sequence out of range");
} }
return i; c = i;
break;
} }
default:
return c;
} }
*string_ptr = ptr;
return c;
} }
static void static void
...@@ -762,6 +656,40 @@ be handled with operator-specific code. */ ...@@ -762,6 +656,40 @@ be handled with operator-specific code. */
#define MUL_PRIO (15 << PRIO_SHIFT) #define MUL_PRIO (15 << PRIO_SHIFT)
#define UNARY_PRIO ((16 << PRIO_SHIFT) | RIGHT_ASSOC | NO_L_OPERAND) #define UNARY_PRIO ((16 << PRIO_SHIFT) | RIGHT_ASSOC | NO_L_OPERAND)
/* Operator to priority map. Must be in the same order as the first
N entries of enum cpp_ttype. */
static const short
op_to_prio[] =
{
/* EQ */ 0, /* dummy entry - can't happen */
/* NOT */ UNARY_PRIO,
/* GREATER */ LESS_PRIO,
/* LESS */ LESS_PRIO,
/* PLUS */ UNARY_PRIO, /* note these two can be unary */
/* MINUS */ UNARY_PRIO, /* or binary */
/* MULT */ MUL_PRIO,
/* DIV */ MUL_PRIO,
/* MOD */ MUL_PRIO,
/* AND */ AND_PRIO,
/* OR */ OR_PRIO,
/* XOR */ XOR_PRIO,
/* RSHIFT */ SHIFT_PRIO,
/* LSHIFT */ SHIFT_PRIO,
/* COMPL */ UNARY_PRIO,
/* AND_AND */ ANDAND_PRIO,
/* OR_OR */ OROR_PRIO,
/* QUERY */ COND_PRIO,
/* COLON */ COLON_PRIO,
/* COMMA */ COMMA_PRIO,
/* OPEN_PAREN */ OPEN_PAREN_PRIO,
/* CLOSE_PAREN */ CLOSE_PAREN_PRIO,
/* EQ_EQ */ EQUAL_PRIO,
/* NOT_EQ */ EQUAL_PRIO,
/* GREATER_EQ */ LESS_PRIO,
/* LESS_EQ */ LESS_PRIO
};
#define COMPARE(OP) \ #define COMPARE(OP) \
top->unsignedp = 0; \ top->unsignedp = 0; \
top->value = (unsigned1 | unsigned2) \ top->value = (unsigned1 | unsigned2) \
...@@ -770,9 +698,25 @@ be handled with operator-specific code. */ ...@@ -770,9 +698,25 @@ be handled with operator-specific code. */
#define EQUALITY(OP) \ #define EQUALITY(OP) \
top->value = v1 OP v2; \ top->value = v1 OP v2; \
top->unsignedp = 0; top->unsignedp = 0;
#define LOGICAL(OP) \ #define BITWISE(OP) \
top->value = v1 OP v2; \ top->value = v1 OP v2; \
top->unsignedp = unsigned1 | unsigned2; top->unsignedp = unsigned1 | unsigned2;
#define UNARY(OP) \
top->value = OP v2; \
top->unsignedp = unsigned2; \
top->flags |= HAVE_VALUE;
#define LOGICAL(OP, NEG) \
top->value = v1 OP v2; \
top->unsignedp = 0; \
if (NEG v1) skip_evaluation--;
#define SHIFT(PSH, MSH) \
if (skip_evaluation) \
break; \
top->unsignedp = unsigned1; \
if (v2 < 0 && ! unsigned2) \
top->value = MSH (pfile, v1, unsigned1, -v2); \
else \
top->value = PSH (pfile, v1, unsigned1, v2);
/* Parse and evaluate a C expression, reading from PFILE. /* Parse and evaluate a C expression, reading from PFILE.
Returns the truth value of the expression. */ Returns the truth value of the expression. */
...@@ -792,21 +736,19 @@ _cpp_parse_expr (pfile) ...@@ -792,21 +736,19 @@ _cpp_parse_expr (pfile)
In that case the 'flags' field has the HAVE_VALUE flag set. */ In that case the 'flags' field has the HAVE_VALUE flag set. */
#define INIT_STACK_SIZE 20 #define INIT_STACK_SIZE 20
struct operation init_stack[INIT_STACK_SIZE]; struct op init_stack[INIT_STACK_SIZE];
struct operation *stack = init_stack; struct op *stack = init_stack;
struct operation *limit = stack + INIT_STACK_SIZE; struct op *limit = stack + INIT_STACK_SIZE;
register struct operation *top = stack + 1; register struct op *top = stack + 1;
long old_written = CPP_WRITTEN (pfile);
int skip_evaluation = 0; int skip_evaluation = 0;
int result; int result;
char buff[5];
/* Save parser state and set it to something sane. */ /* Save parser state and set it to something sane. */
int save_skipping = pfile->skipping; int save_skipping = pfile->skipping;
pfile->skipping = 0; pfile->skipping = 0;
/* We've finished when we try to reduce this. */ /* We've finished when we try to reduce this. */
top->op = FINISHED; top->op = CPP_EOF;
/* Nifty way to catch missing '('. */ /* Nifty way to catch missing '('. */
top->prio = EXTRACT_PRIO(CLOSE_PAREN_PRIO); top->prio = EXTRACT_PRIO(CLOSE_PAREN_PRIO);
/* Avoid missing right operand checks. */ /* Avoid missing right operand checks. */
...@@ -816,7 +758,7 @@ _cpp_parse_expr (pfile) ...@@ -816,7 +758,7 @@ _cpp_parse_expr (pfile)
{ {
unsigned int prio; unsigned int prio;
unsigned int flags; unsigned int flags;
struct operation op; struct op op;
/* Read a token */ /* Read a token */
op = lex (pfile, skip_evaluation); op = lex (pfile, skip_evaluation);
...@@ -826,17 +768,10 @@ _cpp_parse_expr (pfile) ...@@ -826,17 +768,10 @@ _cpp_parse_expr (pfile)
try to reduce the expression on the stack. */ try to reduce the expression on the stack. */
switch (op.op) switch (op.op)
{ {
case NAME: case CPP_ERROR:
CPP_ICE ("lex returns a NAME");
case ERROR:
goto syntax_error; goto syntax_error;
default:
SYNTAX_ERROR2 ("invalid character '%s' in #if",
op_to_str (op.op, buff));
push_immediate: push_immediate:
case INT: case CPP_INT:
case CHAR:
/* Push a value onto the stack. */ /* Push a value onto the stack. */
if (top->flags & HAVE_VALUE) if (top->flags & HAVE_VALUE)
SYNTAX_ERROR ("missing binary operator"); SYNTAX_ERROR ("missing binary operator");
...@@ -845,40 +780,17 @@ _cpp_parse_expr (pfile) ...@@ -845,40 +780,17 @@ _cpp_parse_expr (pfile)
top->flags |= HAVE_VALUE; top->flags |= HAVE_VALUE;
continue; continue;
case '+': case CPP_EOF: prio = FORCE_REDUCE_PRIO; break;
case '-': prio = PLUS_PRIO; if (top->flags & HAVE_VALUE) break; case CPP_PLUS:
case CPP_MINUS: prio = PLUS_PRIO; if (top->flags & HAVE_VALUE) break;
/* else unary; fall through */ /* else unary; fall through */
case '!': default: prio = op_to_prio[op.op]; break;
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;
} }
/* Separate the operator's code into priority and flags. */ /* Separate the operator's code into priority and flags. */
flags = EXTRACT_FLAGS(prio); flags = EXTRACT_FLAGS(prio);
prio = EXTRACT_PRIO(prio); prio = EXTRACT_PRIO(prio);
if (op.op == '(') if (prio == EXTRACT_PRIO(OPEN_PAREN_PRIO))
goto skip_reduction; goto skip_reduction;
/* Check for reductions. Then push the operator. */ /* Check for reductions. Then push the operator. */
...@@ -891,11 +803,11 @@ _cpp_parse_expr (pfile) ...@@ -891,11 +803,11 @@ _cpp_parse_expr (pfile)
right operand. Check this before trying to reduce. */ right operand. Check this before trying to reduce. */
if ((top->flags & (HAVE_VALUE | NO_R_OPERAND)) == 0) if ((top->flags & (HAVE_VALUE | NO_R_OPERAND)) == 0)
{ {
if (top->op == '(') if (top->op == CPP_OPEN_PAREN)
SYNTAX_ERROR ("void expression between '(' and ')'"); SYNTAX_ERROR ("void expression between '(' and ')'");
else else
SYNTAX_ERROR2 ("operator '%s' has no right operand", SYNTAX_ERROR2 ("operator '%s' has no right operand",
op_to_str (top->op, buff)); _cpp_spell_operator (top->op));
} }
unsigned2 = top->unsignedp, v2 = top->value; unsigned2 = top->unsignedp, v2 = top->value;
...@@ -905,12 +817,31 @@ _cpp_parse_expr (pfile) ...@@ -905,12 +817,31 @@ _cpp_parse_expr (pfile)
/* Now set top->value = (top[1].op)(v1, v2); */ /* Now set top->value = (top[1].op)(v1, v2); */
switch (top[1].op) switch (top[1].op)
{ {
case '+': default:
cpp_ice (pfile, "impossible operator type %s",
_cpp_spell_operator (op.op));
goto syntax_error;
case CPP_NOT: UNARY(!); break;
case CPP_COMPL: UNARY(~); break;
case CPP_LESS: COMPARE(<); break;
case CPP_GREATER: COMPARE(>); break;
case CPP_LESS_EQ: COMPARE(<=); break;
case CPP_GREATER_EQ: COMPARE(>=); break;
case CPP_EQ_EQ: EQUALITY(==); break;
case CPP_NOT_EQ: EQUALITY(!=); break;
case CPP_AND: BITWISE(&); break;
case CPP_XOR: BITWISE(^); break;
case CPP_OR: BITWISE(|); break;
case CPP_AND_AND: LOGICAL(&&,!); break;
case CPP_OR_OR: LOGICAL(||,); break;
case CPP_LSHIFT: SHIFT(left_shift, right_shift); break;
case CPP_RSHIFT: SHIFT(right_shift, left_shift); break;
case CPP_PLUS:
if (!(top->flags & HAVE_VALUE)) if (!(top->flags & HAVE_VALUE))
{ /* Unary '+' */ {
top->value = v2; UNARY(+);
top->unsignedp = unsigned2;
top->flags |= HAVE_VALUE;
} }
else else
{ {
...@@ -921,15 +852,12 @@ _cpp_parse_expr (pfile) ...@@ -921,15 +852,12 @@ _cpp_parse_expr (pfile)
integer_overflow (pfile); integer_overflow (pfile);
} }
break; break;
case '-': case CPP_MINUS:
if (!(top->flags & HAVE_VALUE)) if (!(top->flags & HAVE_VALUE))
{ /* Unary '-' */ {
top->value = - v2; UNARY(-);
if (!skip_evaluation && (top->value & v2) < 0 if (!skip_evaluation && (top->value & v2) < 0 && !unsigned2)
&& !unsigned2)
integer_overflow (pfile); integer_overflow (pfile);
top->unsignedp = unsigned2;
top->flags |= HAVE_VALUE;
} }
else else
{ /* Binary '-' */ { /* Binary '-' */
...@@ -940,7 +868,7 @@ _cpp_parse_expr (pfile) ...@@ -940,7 +868,7 @@ _cpp_parse_expr (pfile)
integer_overflow (pfile); integer_overflow (pfile);
} }
break; break;
case '*': case CPP_MULT:
top->unsignedp = unsigned1 | unsigned2; top->unsignedp = unsigned1 | unsigned2;
if (top->unsignedp) if (top->unsignedp)
top->value = (unsigned HOST_WIDEST_INT) v1 * v2; top->value = (unsigned HOST_WIDEST_INT) v1 * v2;
...@@ -952,14 +880,14 @@ _cpp_parse_expr (pfile) ...@@ -952,14 +880,14 @@ _cpp_parse_expr (pfile)
integer_overflow (pfile); integer_overflow (pfile);
} }
break; break;
case '/': case CPP_DIV:
case '%': case CPP_MOD:
if (skip_evaluation) if (skip_evaluation)
break; break;
if (v2 == 0) if (v2 == 0)
SYNTAX_ERROR ("division by zero in #if"); SYNTAX_ERROR ("division by zero in #if");
top->unsignedp = unsigned1 | unsigned2; top->unsignedp = unsigned1 | unsigned2;
if (top[1].op == '/') if (top[1].op == CPP_DIV)
{ {
if (top->unsignedp) if (top->unsignedp)
top->value = (unsigned HOST_WIDEST_INT) v1 / v2; top->value = (unsigned HOST_WIDEST_INT) v1 / v2;
...@@ -978,79 +906,32 @@ _cpp_parse_expr (pfile) ...@@ -978,79 +906,32 @@ _cpp_parse_expr (pfile)
top->value = v1 % v2; top->value = v1 % v2;
} }
break; break;
case '!':
top->value = ! v2; case CPP_COMMA:
top->unsignedp = 0;
top->flags |= HAVE_VALUE;
break;
case '~':
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: 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);
else
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;
case '&': LOGICAL(&); break;
case '^': LOGICAL(^); break;
case '|': LOGICAL(|); break;
case ANDAND:
top->value = v1 && v2; top->unsignedp = 0;
if (!v1) skip_evaluation--;
break;
case OROR:
top->value = v1 || v2; top->unsignedp = 0;
if (v1) skip_evaluation--;
break;
case ',':
if (CPP_PEDANTIC (pfile)) 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->value = v2;
top->unsignedp = unsigned2; top->unsignedp = unsigned2;
break; break;
case '?': case CPP_QUERY:
SYNTAX_ERROR ("syntax error '?' without following ':'"); SYNTAX_ERROR ("syntax error '?' without following ':'");
case ':': case CPP_COLON:
if (top[0].op != '?') if (top[0].op != CPP_QUERY)
SYNTAX_ERROR ("syntax error ':' without preceding '?'"); SYNTAX_ERROR ("syntax error ':' without preceding '?'");
top--; top--;
if (top->value) skip_evaluation--; if (top->value) skip_evaluation--;
top->value = top->value ? v1 : v2; top->value = top->value ? v1 : v2;
top->unsignedp = unsigned1 | unsigned2; top->unsignedp = unsigned1 | unsigned2;
break; break;
case '(': case CPP_OPEN_PAREN:
if (op.op != ')') if (op.op != CPP_CLOSE_PAREN)
SYNTAX_ERROR ("missing ')' in expression"); SYNTAX_ERROR ("missing ')' in expression");
op.value = v2; op.value = v2;
op.unsignedp = unsigned2; op.unsignedp = unsigned2;
goto push_immediate; goto push_immediate;
default: case CPP_EOF:
SYNTAX_ERROR2 ("unimplemented operator '%s'",
op_to_str (top[1].op, buff));
case FINISHED:
/* Reducing this dummy operator indicates we've finished. */ /* Reducing this dummy operator indicates we've finished. */
if (op.op == ')') if (op.op == CPP_CLOSE_PAREN)
SYNTAX_ERROR ("missing '(' in expression"); SYNTAX_ERROR ("missing '(' in expression");
goto done; goto done;
} }
...@@ -1060,14 +941,16 @@ _cpp_parse_expr (pfile) ...@@ -1060,14 +941,16 @@ _cpp_parse_expr (pfile)
if (flags & SHORT_CIRCUIT) if (flags & SHORT_CIRCUIT)
switch (op.op) switch (op.op)
{ {
case OROR: if (top->value) skip_evaluation++; break; case CPP_OR_OR: if (top->value) skip_evaluation++; break;
case ANDAND: case CPP_AND_AND:
case '?': if (!top->value) skip_evaluation++; break; case CPP_QUERY: if (!top->value) skip_evaluation++; break;
case ':': case CPP_COLON:
if (top[-1].value) /* Was '?' condition true? */ if (top[-1].value) /* Was '?' condition true? */
skip_evaluation++; skip_evaluation++;
else else
skip_evaluation--; skip_evaluation--;
default:
break;
} }
skip_reduction: skip_reduction:
...@@ -1076,32 +959,32 @@ _cpp_parse_expr (pfile) ...@@ -1076,32 +959,32 @@ _cpp_parse_expr (pfile)
{ {
if (top->flags & HAVE_VALUE) if (top->flags & HAVE_VALUE)
SYNTAX_ERROR2 ("missing binary operator before '%s'", SYNTAX_ERROR2 ("missing binary operator before '%s'",
op_to_str (op.op, buff)); _cpp_spell_operator (op.op));
} }
else else
{ {
if (!(top->flags & HAVE_VALUE)) if (!(top->flags & HAVE_VALUE))
SYNTAX_ERROR2 ("operator '%s' has no left operand", SYNTAX_ERROR2 ("operator '%s' has no left operand",
op_to_str (op.op, buff)); _cpp_spell_operator (op.op));
} }
/* Check for and handle stack overflow. */ /* Check for and handle stack overflow. */
top++; top++;
if (top == limit) if (top == limit)
{ {
struct operation *new_stack; struct op *new_stack;
int old_size = (char *) limit - (char *) stack; int old_size = (char *) limit - (char *) stack;
int new_size = 2 * old_size; int new_size = 2 * old_size;
if (stack != init_stack) if (stack != init_stack)
new_stack = (struct operation *) xrealloc (stack, new_size); new_stack = (struct op *) xrealloc (stack, new_size);
else else
{ {
new_stack = (struct operation *) xmalloc (new_size); new_stack = (struct op *) xmalloc (new_size);
memcpy (new_stack, stack, old_size); memcpy (new_stack, stack, old_size);
} }
stack = new_stack; stack = new_stack;
top = (struct operation *) ((char *) new_stack + old_size); top = (struct op *) ((char *) new_stack + old_size);
limit = (struct operation *) ((char *) new_stack + new_size); limit = (struct op *) ((char *) new_stack + new_size);
} }
top->flags = flags; top->flags = flags;
...@@ -1112,19 +995,17 @@ _cpp_parse_expr (pfile) ...@@ -1112,19 +995,17 @@ _cpp_parse_expr (pfile)
done: done:
result = (top[1].value != 0); result = (top[1].value != 0);
if (top != stack) if (top != stack)
CPP_ICE ("unbalanced stack in #if expression"); CPP_ICE ("unbalanced stack in #if");
else if (!(top[1].flags & HAVE_VALUE)) else if (!(top[1].flags & HAVE_VALUE))
{ {
SYNTAX_ERROR ("#if with no expression"); SYNTAX_ERROR ("#if with no expression");
syntax_error: syntax_error:
_cpp_skip_rest_of_line (pfile);
result = 0; /* Return 0 on syntax error. */ result = 0; /* Return 0 on syntax error. */
} }
/* Free dynamic stack if we allocated one. */ /* Free dynamic stack if we allocated one. */
if (stack != init_stack) if (stack != init_stack)
free (stack); free (stack);
CPP_SET_WRITTEN (pfile, old_written);
pfile->skipping = save_skipping; pfile->skipping = save_skipping;
return result; return result;
} }
...@@ -213,8 +213,6 @@ extern void _cpp_skip_rest_of_line PARAMS ((cpp_reader *)); ...@@ -213,8 +213,6 @@ extern void _cpp_skip_rest_of_line PARAMS ((cpp_reader *));
extern void _cpp_free_temp_tokens PARAMS ((cpp_reader *)); extern void _cpp_free_temp_tokens PARAMS ((cpp_reader *));
extern void _cpp_init_input_buffer PARAMS ((cpp_reader *)); extern void _cpp_init_input_buffer PARAMS ((cpp_reader *));
extern void _cpp_grow_token_buffer PARAMS ((cpp_reader *, long)); extern void _cpp_grow_token_buffer PARAMS ((cpp_reader *, long));
extern enum cpp_ttype _cpp_get_directive_token
PARAMS ((cpp_reader *));
extern void _cpp_init_toklist PARAMS ((cpp_toklist *, int)); extern void _cpp_init_toklist PARAMS ((cpp_toklist *, int));
extern void _cpp_clear_toklist PARAMS ((cpp_toklist *)); extern void _cpp_clear_toklist PARAMS ((cpp_toklist *));
extern void _cpp_free_toklist PARAMS ((const cpp_toklist *)); extern void _cpp_free_toklist PARAMS ((const cpp_toklist *));
...@@ -238,6 +236,7 @@ extern unsigned int _cpp_get_line PARAMS ((cpp_reader *, ...@@ -238,6 +236,7 @@ extern unsigned int _cpp_get_line PARAMS ((cpp_reader *,
extern const cpp_token *_cpp_get_raw_token PARAMS ((cpp_reader *)); extern const cpp_token *_cpp_get_raw_token PARAMS ((cpp_reader *));
extern void _cpp_push_token PARAMS ((cpp_reader *, const cpp_token*)); extern void _cpp_push_token PARAMS ((cpp_reader *, const cpp_token*));
extern const cpp_token *_cpp_glue_header_name PARAMS ((cpp_reader *)); extern const cpp_token *_cpp_glue_header_name PARAMS ((cpp_reader *));
extern const U_CHAR *_cpp_spell_operator PARAMS ((enum cpp_ttype));
/* In cpplib.c */ /* In cpplib.c */
extern const struct directive *_cpp_check_directive extern const struct directive *_cpp_check_directive
......
...@@ -776,11 +776,6 @@ cpp_start_read (pfile, print, fname) ...@@ -776,11 +776,6 @@ cpp_start_read (pfile, print, fname)
if (user_label_prefix == NULL) if (user_label_prefix == NULL)
user_label_prefix = USER_LABEL_PREFIX; user_label_prefix = USER_LABEL_PREFIX;
/* Don't bother trying to do macro expansion if we've already done
preprocessing. */
if (CPP_OPTION (pfile, preprocessed))
pfile->no_macro_expand++;
/* Figure out if we need to save function macro parameter spellings. /* Figure out if we need to save function macro parameter spellings.
We don't use CPP_PEDANTIC() here because that depends on whether We don't use CPP_PEDANTIC() here because that depends on whether
or not the current file is a system header, and there is no or not the current file is a system header, and there is no
......
...@@ -167,13 +167,13 @@ token_spellings [N_TTYPES + 1] = {TTYPE_TABLE {0, 0} }; ...@@ -167,13 +167,13 @@ token_spellings [N_TTYPES + 1] = {TTYPE_TABLE {0, 0} };
#undef N #undef N
/* For debugging: the internal names of the tokens. */ /* For debugging: the internal names of the tokens. */
#define T(e, s) STRINGX(e), #define T(e, s) U STRINGX(e) + 4,
#define I(e, s) STRINGX(e), #define I(e, s) U STRINGX(e) + 4,
#define S(e, s) STRINGX(e), #define S(e, s) U STRINGX(e) + 4,
#define C(e, s) STRINGX(e), #define C(e, s) U STRINGX(e) + 4,
#define N(e, s) STRINGX(e), #define N(e, s) U STRINGX(e) + 4,
const char * const token_names[N_TTYPES] = { TTYPE_TABLE }; const U_CHAR *const token_names[N_TTYPES] = { TTYPE_TABLE };
#undef T #undef T
#undef I #undef I
...@@ -1872,10 +1872,9 @@ output_token (pfile, token, prev) ...@@ -1872,10 +1872,9 @@ output_token (pfile, token, prev)
} }
/* Write the spelling of a token TOKEN to BUFFER. The buffer must /* Write the spelling of a token TOKEN to BUFFER. The buffer must
already contain the enough space to hold the token's spelling. If already contain the enough space to hold the token's spelling.
WHITESPACE is true, and the token was preceded by whitespace, Returns a pointer to the character after the last character
output a single space before the token proper. Returns a pointer written. */
to the character after the last character written. */
static unsigned char * static unsigned char *
spell_token (pfile, token, buffer) spell_token (pfile, token, buffer)
...@@ -1933,6 +1932,19 @@ spell_token (pfile, token, buffer) ...@@ -1933,6 +1932,19 @@ spell_token (pfile, token, buffer)
return buffer; return buffer;
} }
/* Return the spelling of a token known to be an operator.
Does not distinguish digraphs from their counterparts. */
const unsigned char *
_cpp_spell_operator (type)
enum cpp_ttype type;
{
if (token_spellings[type].type == SPELL_OPERATOR)
return token_spellings[type].spelling;
else
return token_names[type];
}
/* Macro expansion algorithm. TODO. */ /* Macro expansion algorithm. TODO. */
static const cpp_token placemarker_token = {0, 0, CPP_PLACEMARKER, 0 UNION_INIT_ZERO}; static const cpp_token placemarker_token = {0, 0, CPP_PLACEMARKER, 0 UNION_INIT_ZERO};
...@@ -2022,6 +2034,10 @@ is_macro_disabled (pfile, expansion, token) ...@@ -2022,6 +2034,10 @@ is_macro_disabled (pfile, expansion, token)
{ {
cpp_context *context = CURRENT_CONTEXT (pfile); cpp_context *context = CURRENT_CONTEXT (pfile);
/* Don't expand anything if this file has already been preprocessed. */
if (CPP_OPTION (pfile, preprocessed))
return 1;
/* Arguments on either side of ## are inserted in place without /* Arguments on either side of ## are inserted in place without
macro expansion (6.10.3.3.2). Conceptually, any macro expansion macro expansion (6.10.3.3.2). Conceptually, any macro expansion
occurs during a later rescan pass. The effect is that we expand occurs during a later rescan pass. The effect is that we expand
...@@ -3275,26 +3291,6 @@ _cpp_dump_list (pfile, list, token, flush) ...@@ -3275,26 +3291,6 @@ _cpp_dump_list (pfile, list, token, flush)
cpp_output_tokens (pfile, pfile->printer, pfile->token_list.line); cpp_output_tokens (pfile, pfile->printer, pfile->token_list.line);
} }
/* Stub function during conversion, mainly for cppexp.c's benefit. */
enum cpp_ttype
_cpp_get_directive_token (pfile)
cpp_reader *pfile;
{
const cpp_token *tok;
if (pfile->no_macro_expand)
tok = _cpp_get_raw_token (pfile);
else
tok = cpp_get_token (pfile);
if (tok->type == CPP_EOF)
return CPP_VSPACE; /* backward compat; and don't try to spell EOF */
CPP_RESERVE (pfile, TOKEN_LEN (tok));
pfile->limit = spell_token (pfile, tok, pfile->limit);
return tok->type;
}
/* Allocate pfile->input_buffer, and initialize trigraph_map[] /* Allocate pfile->input_buffer, and initialize trigraph_map[]
if it hasn't happened already. */ if it hasn't happened already. */
......
...@@ -476,7 +476,7 @@ read_line_number (pfile, num) ...@@ -476,7 +476,7 @@ read_line_number (pfile, num)
} }
else else
{ {
if (type != CPP_VSPACE && type != CPP_EOF) if (type != CPP_EOF)
cpp_error (pfile, "invalid format #line"); cpp_error (pfile, "invalid format #line");
return 0; return 0;
} }
...@@ -545,7 +545,7 @@ do_line (pfile) ...@@ -545,7 +545,7 @@ do_line (pfile)
str = tok->val.name.text; str = tok->val.name.text;
len = tok->val.name.len; len = tok->val.name.len;
if (type == CPP_VSPACE || type == CPP_EOF) if (type == CPP_EOF)
goto done; goto done;
else if (type != CPP_STRING) else if (type != CPP_STRING)
{ {
......
...@@ -123,10 +123,7 @@ typedef struct cpp_hashnode cpp_hashnode; ...@@ -123,10 +123,7 @@ typedef struct cpp_hashnode cpp_hashnode;
I(CPP_COMMENT, 0) /* Only if output comments. */ \ I(CPP_COMMENT, 0) /* Only if output comments. */ \
N(CPP_MACRO_ARG, 0) /* Macro argument. */ \ N(CPP_MACRO_ARG, 0) /* Macro argument. */ \
N(CPP_EOF, 0) /* End of file. */ \ N(CPP_EOF, 0) /* End of file. */ \
I(CPP_HEADER_NAME, 0) /* <stdio.h> in #include */ \ I(CPP_HEADER_NAME, 0) /* <stdio.h> in #include */
\
/* Obsolete - will be removed when no code uses them still. */ \
T(CPP_VSPACE, "\n") /* End of line. */
#define T(e, s) e, #define T(e, s) e,
#define I(e, s) e, #define I(e, s) e,
...@@ -542,9 +539,6 @@ struct cpp_reader ...@@ -542,9 +539,6 @@ struct cpp_reader
containing files that matches the current status. */ containing files that matches the current status. */
unsigned char input_stack_listing_current; unsigned char input_stack_listing_current;
/* If non-zero, macros are not expanded. */
unsigned char no_macro_expand;
/* We're printed a warning recommending against using #import. */ /* We're printed a warning recommending against using #import. */
unsigned char import_warning; unsigned char import_warning;
...@@ -555,7 +549,8 @@ struct cpp_reader ...@@ -555,7 +549,8 @@ struct cpp_reader
/* True if we are skipping a failed conditional group. */ /* True if we are skipping a failed conditional group. */
unsigned char skipping; unsigned char skipping;
/* Do we need to save paramter spellings. */ /* True if we need to save parameter spellings - only if -pedantic,
or we might need to write out definitions. */
unsigned char save_parameter_spellings; unsigned char save_parameter_spellings;
/* If we're in lex_line. */ /* If we're in lex_line. */
......
2000-07-07 Zack Weinberg <zack@wolery.cumb.org>
* gcc.dg/cpp/19951227-1.c, gcc.dg/cpp/assert2.c,
gcc.dg/cpp/if-1.c, gcc.dg/cpp/if-4.c: Tweak error regexps.
2000-07-08 Neil Booth <NeilB@earthling.net> 2000-07-08 Neil Booth <NeilB@earthling.net>
* gcc.dg/cpp/macsyntx.c: New tests. * gcc.dg/cpp/macsyntx.c: New tests.
......
/* { dg-do preprocess } */ /* { dg-do preprocess } */
#if 0xe-1 /* { dg-error "invalid number" } */ #if 0xe-1 /* { dg-error "invalid suffix" } */
#endif #endif
...@@ -20,5 +20,5 @@ ...@@ -20,5 +20,5 @@
#error /* { dg-bogus "error" "test w/o answer" } */ #error /* { dg-bogus "error" "test w/o answer" } */
#endif #endif
#if #abc[def] /* { dg-error "invalid char" "test with malformed answer" } */ #if #abc[def] /* { dg-error "is not valid" "test with malformed answer" } */
#endif #endif
...@@ -9,22 +9,29 @@ ...@@ -9,22 +9,29 @@
#error 077 != 63 /* { dg-bogus "#error" "normal conversion" } */ #error 077 != 63 /* { dg-bogus "#error" "normal conversion" } */
#endif #endif
#if 12wrt /* { dg-error "nvalid number|missing white" "invalid number" } */ #if 12wrt /* { dg-error "invalid suffix" "invalid number" } */
#endif #endif
#if 0abc /* { dg-error "nvalid number|missing white" "invalid number" } */ #if 0abc /* { dg-error "invalid suffix" "invalid number" } */
#endif #endif
#if 42abc /* { dg-error "nvalid number|missing white" "invalid number" } */ #if 42abc /* { dg-error "invalid suffix" "invalid number" } */
#endif
#if 0xabc != 2748
#error 0xabc /* { dg-bogus "#error" "normal conversion" } */
#endif #endif
#if 1.2 /* { dg-error "loating point numbers" "floating point in #if" } */ #if 1.2 /* { dg-error "loating point numbers" "floating point in #if" } */
#endif #endif
#if 4uu /* { dg-error "too many 'u'" "too many suffixes" } */ #if 4uu /* { dg-error "invalid suffix" "too many suffixes" } */
#endif
#if 124123231lll /* { dg-error "invalid suffix" "too many suffixes" } */
#endif #endif
#if 124123231lll /* { dg-error "too many 'l'" "too many suffixes" } */ #if 1234lul /* { dg-error "invalid suffix" "u between ls" } */
#endif #endif
#if 099 /* { dg-error "digits beyond the radix" "decimal in octal constant" } */ #if 099 /* { dg-error "digits beyond the radix" "decimal in octal constant" } */
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
NUL terminated, so we would print garbage after it. */ NUL terminated, so we would print garbage after it. */
/* { dg-do compile } */ /* { dg-do compile } */
#if 1 += 2 /* { dg-error "'\\+=' is not allowed" "+= in if" } */ #if 1 += 2 /* { dg-error "'\\+=' is not valid" "+= in if" } */
syntax_error syntax_error
#endif #endif
int foo; int foo;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment