diff options
author | Jim Kingdon <jkingdon@engr.sgi.com> | 1994-01-15 17:14:18 +0000 |
---|---|---|
committer | Jim Kingdon <jkingdon@engr.sgi.com> | 1994-01-15 17:14:18 +0000 |
commit | a9b32d6192a3f30e3e7f34881f4914875a383f92 (patch) | |
tree | a87c58b4cebd5dc459e2b4c35f4fe06b81b90989 /gdb/c-exp.y | |
parent | 2069bd10d59f4d2e6bc14ce7be5c2df0ca79751e (diff) | |
download | gdb-a9b32d6192a3f30e3e7f34881f4914875a383f92.zip gdb-a9b32d6192a3f30e3e7f34881f4914875a383f92.tar.gz gdb-a9b32d6192a3f30e3e7f34881f4914875a383f92.tar.bz2 |
* c-exp.y (parse_number): Check for overflow regardless of range
checking. Fix overflow check to use unsigned LONGEST, not
unsigned int.
* c-exp.y (parse_number): Make it so that integer constants are
builtin_type_long_long if builtin_type_long isn't big enough or if
an "LL" suffix is used. Properly handle "UL" or "LU" suffixes.
Diffstat (limited to 'gdb/c-exp.y')
-rw-r--r-- | gdb/c-exp.y | 130 |
1 files changed, 85 insertions, 45 deletions
diff --git a/gdb/c-exp.y b/gdb/c-exp.y index ebc1ca6..6a96eb1 100644 --- a/gdb/c-exp.y +++ b/gdb/c-exp.y @@ -899,13 +899,22 @@ parse_number (p, len, parsed_float, putithere) int parsed_float; YYSTYPE *putithere; { + /* FIXME: Shouldn't these be unsigned? We don't deal with negative values + here, and we do kind of silly things like cast to unsigned. */ register LONGEST n = 0; register LONGEST prevn = 0; + register int i = 0; register int c; register int base = input_radix; int unsigned_p = 0; + + /* Number of "L" suffixes encountered. */ int long_p = 0; + + /* We have found a "L" or "U" suffix. */ + int found_suffix = 0; + unsigned LONGEST high_bit; struct type *signed_type; struct type *unsigned_type; @@ -956,15 +965,29 @@ parse_number (p, len, parsed_float, putithere) if (c != 'l' && c != 'u') n *= base; if (c >= '0' && c <= '9') - n += i = c - '0'; + { + if (found_suffix) + return ERROR; + n += i = c - '0'; + } else { if (base > 10 && c >= 'a' && c <= 'f') - n += i = c - 'a' + 10; - else if (len == 0 && c == 'l') - long_p = 1; - else if (len == 0 && c == 'u') - unsigned_p = 1; + { + if (found_suffix) + return ERROR; + n += i = c - 'a' + 10; + } + else if (c == 'l') + { + ++long_p; + found_suffix = 1; + } + else if (c == 'u') + { + unsigned_p = 1; + found_suffix = 1; + } else return ERROR; /* Char not a digit */ } @@ -972,44 +995,61 @@ parse_number (p, len, parsed_float, putithere) return ERROR; /* Invalid digit in this base */ /* Portably test for overflow (only works for nonzero values, so make - a second check for zero). */ - if((prevn >= n) && n != 0) - unsigned_p=1; /* Try something unsigned */ - /* If range checking enabled, portably test for unsigned overflow. */ - if(RANGE_CHECK && n!=0) - { - if((unsigned_p && (unsigned)prevn >= (unsigned)n)) - range_error("Overflow on numeric constant."); - } - prevn=n; + a second check for zero). FIXME: Can't we just make n and prevn + unsigned and avoid this? */ + if (c != 'l' && c != 'u' && (prevn >= n) && n != 0) + unsigned_p = 1; /* Try something unsigned */ + + /* Portably test for unsigned overflow. + FIXME: This check is wrong; for example it doesn't find overflow + on 0x123456789 when LONGEST is 32 bits. */ + if (c != 'l' && c != 'u' && n != 0) + { + if ((unsigned_p && (unsigned LONGEST) prevn >= (unsigned LONGEST) n)) + error ("Numeric constant too large."); + } + prevn = n; + } + + /* An integer constant is an int, a long, or a long long. An L + suffix forces it to be long; an LL suffix forces it to be long + long. If not forced to a larger size, it gets the first type of + the above that it fits in. To figure out whether it fits, we + shift it right and see whether anything remains. Note that we + can't shift sizeof (LONGEST) * HOST_CHAR_BIT bits or more in one + operation, because many compilers will warn about such a shift + (which always produces a zero result). Sometimes TARGET_INT_BIT + or TARGET_LONG_BIT will be that big, sometimes not. To deal with + the case where it is we just always shift the value more than + once, with fewer bits each time. */ + + if (long_p == 0 + && (((unsigned LONGEST)n >> 2) >> (TARGET_INT_BIT - 2)) == 0) + { + high_bit = ((unsigned LONGEST)1) << (TARGET_INT_BIT-1); + + /* A large decimal (not hex or octal) constant (between INT_MAX + and UINT_MAX) is a long or unsigned long, according to ANSI, + never an unsigned int, but this code treats it as unsigned + int. This probably should be fixed. GCC gives a warning on + such constants. */ + + unsigned_type = builtin_type_unsigned_int; + signed_type = builtin_type_int; + } + else if (long_p <= 1 + && (((unsigned LONGEST)n >> 2) >> (TARGET_LONG_BIT - 2)) == 0) + { + high_bit = ((unsigned LONGEST)1) << (TARGET_LONG_BIT-1); + unsigned_type = builtin_type_unsigned_long; + signed_type = builtin_type_long; + } + else + { + high_bit = ((unsigned LONGEST)1) << (TARGET_LONG_LONG_BIT - 1); + unsigned_type = builtin_type_unsigned_long_long; + signed_type = builtin_type_long_long; } - - /* If the number is too big to be an int, or it's got an l suffix - then it's a long. Work out if this has to be a long by - shifting right and and seeing if anything remains, and the - target int size is different to the target long size. - - In the expression below, we could have tested - (n >> TARGET_INT_BIT) - to see if it was zero, - but too many compilers warn about that, when ints and longs - are the same size. So we shift it twice, with fewer bits - each time, for the same result. */ - - if ( (TARGET_INT_BIT != TARGET_LONG_BIT - && ((n >> 2) >> (TARGET_INT_BIT-2))) /* Avoid shift warning */ - || long_p) - { - high_bit = ((unsigned LONGEST)1) << (TARGET_LONG_BIT-1); - unsigned_type = builtin_type_unsigned_long; - signed_type = builtin_type_long; - } - else - { - high_bit = ((unsigned LONGEST)1) << (TARGET_INT_BIT-1); - unsigned_type = builtin_type_unsigned_int; - signed_type = builtin_type_int; - } putithere->typed_val.val = n; @@ -1018,11 +1058,11 @@ parse_number (p, len, parsed_float, putithere) if (unsigned_p || (n & high_bit)) { - putithere->typed_val.type = unsigned_type; + putithere->typed_val.type = unsigned_type; } else { - putithere->typed_val.type = signed_type; + putithere->typed_val.type = signed_type; } return INT; |