diff options
author | brolley <brolley@138bc75d-0d04-0410-961f-82ee72b054a4> | 1999-01-25 11:28:11 +0000 |
---|---|---|
committer | brolley <brolley@138bc75d-0d04-0410-961f-82ee72b054a4> | 1999-01-25 11:28:11 +0000 |
commit | 5e5b6df0a703c1b09e590ee884fa9bd970a16e44 (patch) | |
tree | f7399c6915f8c6d06232933a17340674f9617978 /gcc | |
parent | 2029d13ed4a5cc6f83b036532221043ac79fa7c1 (diff) | |
download | ppe42-gcc-5e5b6df0a703c1b09e590ee884fa9bd970a16e44.tar.gz ppe42-gcc-5e5b6df0a703c1b09e590ee884fa9bd970a16e44.zip |
1999-01-25 14:26 -0500 Zack Weinberg <zack@rabi.columbia.edu>
* cppexp.c:
(struct arglist): Removed.
(parse_number): Use HOST_WIDE_INT for the accumulator.
Allow two `l' suffixes unless C89. Clean up. Make
static.
(parse_charconst): New function broken out of cpp_lex.
Code cleaned up drastically. Don't use a token_buffer.
(token_buffer): Removed.
(cpp_lex): Don't call parse_number on a constant string.
Use parse_charconst.
(cpp_parse_expr): Properly handle an ERROR op returned by
cpp_lex.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@24859 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 15 | ||||
-rw-r--r-- | gcc/cppexp.c | 426 |
2 files changed, 229 insertions, 212 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 67142f6a608..7228df49503 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,18 @@ +1999-01-25 14:26 -0500 Zack Weinberg <zack@rabi.columbia.edu> + + * cppexp.c: + (struct arglist): Removed. + (parse_number): Use HOST_WIDE_INT for the accumulator. + Allow two `l' suffixes unless C89. Clean up. Make + static. + (parse_charconst): New function broken out of cpp_lex. + Code cleaned up drastically. Don't use a token_buffer. + (token_buffer): Removed. + (cpp_lex): Don't call parse_number on a constant string. + Use parse_charconst. + (cpp_parse_expr): Properly handle an ERROR op returned by + cpp_lex. + 1999-01-25 14:10 -0500 Zack Weinberg <zack@rabi.phys.columbia.edu> * cpplib.c: Don't include signal.h, sys/times.h, or diff --git a/gcc/cppexp.c b/gcc/cppexp.c index bd8e663b09b..0e5095dd285 100644 --- a/gcc/cppexp.c +++ b/gcc/cppexp.c @@ -32,14 +32,6 @@ Written by Per Bothner 1994. */ #include <locale.h> #endif -/* This is used for communicating lists of keywords with cccp.c. */ -struct arglist { - struct arglist *next; - U_CHAR *name; - int length; - int argno; -}; - #ifndef CHAR_TYPE_SIZE #define CHAR_TYPE_SIZE BITS_PER_UNIT #endif @@ -124,98 +116,110 @@ struct operation { char unsignedp; /* true if value should be treated as unsigned */ HOST_WIDE_INT value; /* The value logically "right" of op. */ }; - -/* 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 */ +/* Parse and convert an integer for #if. Accepts decimal, hex, or octal + with or without size suffixes. */ -struct operation -parse_number (pfile, start, olen) +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_WIDE_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; + MAX_over_base = (((unsigned HOST_WIDE_INT) -1) + / ((unsigned HOST_WIDE_INT) base)); - if (--len == 0) + while (p < end) + { + c = *p++; + + if (c >= '0' && c <= '9') + digit = c - '0'; + else if (base == 16 && c >= 'a' && c <= 'f') /* FIXME: assumes ASCII */ + 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_OPTIONS (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_pedwarn (pfile, "integer constant contains digits beyond the radix"); @@ -223,18 +227,132 @@ parse_number (pfile, start, olen) 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_WIDE_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_WIDE_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; + + /* FIXME: Should use reentrant multibyte functions. */ +#ifdef MULTIBYTE_CHARS + wchar_t c; + (void) mbtowc (NULL_PTR, NULL_PTR, 0); +#else + int c; +#endif + + 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) + { +#ifndef MULTIBYTE_CHARS + c = *ptr++; +#else + ptr += mbtowc (&c, ptr, end - ptr); +#endif + if (c == '\'' || c == '\0') + break; + else if (c == '\\') + { + /* Hopefully valid assumption: if mbtowc returns a backslash, + we are in initial shift state. No valid escape-sequence + character can take us out of initial shift state or begin + an unshifted multibyte char, so cpp_parse_escape doesn't + need to know about multibyte chars. */ + + c = cpp_parse_escape (pfile, (char **) &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_lookup (pfile, (U_CHAR *)"__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)); + + /* This is always a signed type. */ + op.unsignedp = 0; + op.op = CHAR; + return op; + + error: + op.op = ERROR; + return op; +} + + struct token { char *operator; int token; @@ -254,10 +372,6 @@ static struct token tokentab2[] = { {NULL, ERROR} }; -/* This is used to accumulate the value of a character literal. It is static - so that it only gets allocated once per compilation. */ -static char *token_buffer = NULL; - /* Read one token. */ struct operation @@ -265,8 +379,8 @@ cpp_lex (pfile, skip_evaluation) cpp_reader *pfile; int skip_evaluation; { - register HOST_WIDE_INT c; - register struct token *toktab; + U_CHAR c; + struct token *toktab; enum cpp_token token; struct operation op; U_CHAR *tok_start, *tok_end; @@ -308,140 +422,26 @@ cpp_lex (pfile, skip_evaluation) } cpp_pop_buffer (pfile); goto retry; - case CPP_HSPACE: case CPP_COMMENT: + 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"); 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 int num_chars = 0; - unsigned width = MAX_CHAR_TYPE_SIZE; - int wide_flag = 0; - int max_chars; - U_CHAR *ptr = tok_start; - - /* We need to allocate this buffer dynamically since the size is not - a constant expression on all platforms. */ - if (token_buffer == NULL) - { -#ifdef MULTIBYTE_CHARS - token_buffer = xmalloc (MAX_LONG_TYPE_SIZE/MAX_CHAR_TYPE_SIZE - + MB_CUR_MAX); -#else - token_buffer = xmalloc (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, (char **) &ptr, - wide_flag ? MAX_WCHAR_TYPE_MASK - : MAX_CHAR_TYPE_MASK); - if (width < HOST_BITS_PER_INT - && (unsigned) c >= (unsigned)(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; - - if (cpp_lookup (pfile, (U_CHAR *)"__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_pedwarn (pfile,"Ignoring invalid multibyte character"); - } -#endif - op.value = result; - } - } - - /* This is always a signed type. */ - op.unsignedp = 0; - op.op = CHAR; - - return op; + return parse_charconst (pfile, tok_start, tok_end); case CPP_NAME: if (CPP_WARN_UNDEF (pfile) && !skip_evaluation) cpp_warning (pfile, "`%.*s' is not defined", (int) (tok_end - tok_start), tok_start); - return parse_number (pfile, "0", 0); + op.op = INT; + op.unsignedp = 0; + op.value = 0; + return op; case CPP_OTHER: /* See if it is a special token of length 2. */ @@ -733,6 +733,8 @@ cpp_parse_expr (pfile) case '?': lprio = COND_PRIO + 1; rprio = COND_PRIO; goto maybe_reduce; + case ERROR: + goto syntax_error; binop: flags = LEFT_OPERAND_REQUIRED|RIGHT_OPERAND_REQUIRED; rprio = lprio + 1; |