X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fexpr.c;h=19e3f1c0387b29ee03fc3984922dd52c726422c3;hb=fd99574ba57795ede14cf8644ab4180facff4f17;hp=8313d95a17b740e4ac46f494bb4a252bb2b73b07;hpb=b041f888acb608ad6d70d30e5a6d19ae23a9b69c;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/expr.c b/gas/expr.c index 8313d95a17..19e3f1c038 100644 --- a/gas/expr.c +++ b/gas/expr.c @@ -1,5 +1,6 @@ /* expr.c -operands, expressions- - Copyright (C) 1987, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 2000 + Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, + 1999, 2000, 2001, 2002 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -24,24 +25,24 @@ (It also gives smaller files to re-compile.) Here, "operand"s are of expressions, not instructions. */ -#include #include #define min(a, b) ((a) < (b) ? (a) : (b)) #include "as.h" +#include "safe-ctype.h" #include "obstack.h" -static void floating_constant PARAMS ((expressionS * expressionP)); -static valueT generic_bignum_to_int32 PARAMS ((void)); +static void floating_constant (expressionS * expressionP); +static valueT generic_bignum_to_int32 (void); #ifdef BFD64 -static valueT generic_bignum_to_int64 PARAMS ((void)); +static valueT generic_bignum_to_int64 (void); #endif -static void integer_constant PARAMS ((int radix, expressionS * expressionP)); -static void mri_char_constant PARAMS ((expressionS *)); -static void current_location PARAMS ((expressionS *)); -static void clean_up_expression PARAMS ((expressionS * expressionP)); -static segT operand PARAMS ((expressionS *)); -static operatorT operator PARAMS ((void)); +static void integer_constant (int radix, expressionS * expressionP); +static void mri_char_constant (expressionS *); +static void current_location (expressionS *); +static void clean_up_expression (expressionS * expressionP); +static segT operand (expressionS *); +static operatorT operator (int *); extern const char EXP_CHARS[], FLT_CHARS[]; @@ -62,11 +63,9 @@ static struct expr_symbol_line *expr_symbol_lines; into the fake section expr_section. */ symbolS * -make_expr_symbol (expressionP) - expressionS *expressionP; +make_expr_symbol (expressionS *expressionP) { expressionS zero; - const char *fake; symbolS *symbolP; struct expr_symbol_line *n; @@ -77,12 +76,12 @@ make_expr_symbol (expressionP) if (expressionP->X_op == O_big) { /* This won't work, because the actual value is stored in - generic_floating_point_number or generic_bignum, and we are - going to lose it if we haven't already. */ + generic_floating_point_number or generic_bignum, and we are + going to lose it if we haven't already. */ if (expressionP->X_add_number > 0) - as_bad (_("bignum invalid; zero assumed")); + as_bad (_("bignum invalid")); else - as_bad (_("floating point number invalid; zero assumed")); + as_bad (_("floating point number invalid")); zero.X_op = O_constant; zero.X_add_number = 0; zero.X_unsigned = 0; @@ -90,13 +89,11 @@ make_expr_symbol (expressionP) expressionP = &zero; } - fake = FAKE_LABEL_NAME; - /* Putting constant symbols in absolute_section rather than expr_section is convenient for the old a.out code, for which S_GET_SEGMENT does not always retrieve the value put in by S_SET_SEGMENT. */ - symbolP = symbol_create (fake, + symbolP = symbol_create (FAKE_LABEL_NAME, (expressionP->X_op == O_constant ? absolute_section : expr_section), @@ -104,7 +101,7 @@ make_expr_symbol (expressionP) symbol_set_value_expression (symbolP, expressionP); if (expressionP->X_op == O_constant) - resolve_symbol_value (symbolP, 1); + resolve_symbol_value (symbolP); n = (struct expr_symbol_line *) xmalloc (sizeof *n); n->sym = symbolP; @@ -120,10 +117,7 @@ make_expr_symbol (expressionP) the symbol. */ int -expr_symbol_where (sym, pfile, pline) - symbolS *sym; - char **pfile; - unsigned int *pline; +expr_symbol_where (symbolS *sym, char **pfile, unsigned int *pline) { register struct expr_symbol_line *l; @@ -153,8 +147,7 @@ expr_symbol_where (sym, pfile, pline) but that seems more clumsy. */ symbolS * -expr_build_uconstant (value) - offsetT value; +expr_build_uconstant (offsetT value) { expressionS e; @@ -167,9 +160,7 @@ expr_build_uconstant (value) /* Build an expression for OP s1. */ symbolS * -expr_build_unary (op, s1) - operatorT op; - symbolS *s1; +expr_build_unary (operatorT op, symbolS *s1) { expressionS e; @@ -182,10 +173,7 @@ expr_build_unary (op, s1) /* Build an expression for s1 OP s2. */ symbolS * -expr_build_binary (op, s1, s2) - operatorT op; - symbolS *s1; - symbolS *s2; +expr_build_binary (operatorT op, symbolS *s1, symbolS *s2) { expressionS e; @@ -199,7 +187,7 @@ expr_build_binary (op, s1, s2) /* Build an expression for the current location ('.'). */ symbolS * -expr_build_dot () +expr_build_dot (void) { expressionS e; @@ -229,8 +217,7 @@ FLONUM_TYPE generic_floating_point_number = { int generic_floating_point_magic; static void -floating_constant (expressionP) - expressionS *expressionP; +floating_constant (expressionS *expressionP) { /* input_line_pointer -> floating-point constant. */ int error_code; @@ -242,11 +229,12 @@ floating_constant (expressionP) { if (error_code == ERROR_EXPONENT_OVERFLOW) { - as_bad (_("bad floating-point constant: exponent overflow, probably assembling junk")); + as_bad (_("bad floating-point constant: exponent overflow")); } else { - as_bad (_("bad floating-point constant: unknown error code=%d."), error_code); + as_bad (_("bad floating-point constant: unknown error code=%d"), + error_code); } } expressionP->X_op = O_big; @@ -256,7 +244,7 @@ floating_constant (expressionP) } static valueT -generic_bignum_to_int32 () +generic_bignum_to_int32 (void) { valueT number = ((generic_bignum[1] & LITTLENUM_MASK) << LITTLENUM_NUMBER_OF_BITS) @@ -267,7 +255,7 @@ generic_bignum_to_int32 () #ifdef BFD64 static valueT -generic_bignum_to_int64 () +generic_bignum_to_int64 (void) { valueT number = ((((((((valueT) generic_bignum[3] & LITTLENUM_MASK) @@ -282,9 +270,7 @@ generic_bignum_to_int64 () #endif static void -integer_constant (radix, expressionP) - int radix; - expressionS *expressionP; +integer_constant (int radix, expressionS *expressionP) { char *start; /* Start of number. */ char *suffix = NULL; @@ -327,11 +313,9 @@ integer_constant (radix, expressionP) int flt = 0; /* In MRI mode, the number may have a suffix indicating the - radix. For that matter, it might actually be a floating - point constant. */ - for (suffix = input_line_pointer; - isalnum ((unsigned char) *suffix); - suffix++) + radix. For that matter, it might actually be a floating + point constant. */ + for (suffix = input_line_pointer; ISALNUM (*suffix); suffix++) { if (*suffix == 'e' || *suffix == 'E') flt = 1; @@ -345,8 +329,7 @@ integer_constant (radix, expressionP) else { c = *--suffix; - if (islower ((unsigned char) c)) - c = toupper (c); + c = TOUPPER (c); if (c == 'B') radix = 2; else if (c == 'D') @@ -402,7 +385,7 @@ integer_constant (radix, expressionP) if (radix == 16 && c == '_') { /* This is literal of the form 0x333_0_12345678_1. - This example is equivalent to 0x00000333000000001234567800000001. */ + This example is equivalent to 0x00000333000000001234567800000001. */ int num_little_digits = 0; int i; @@ -426,7 +409,7 @@ integer_constant (radix, expressionP) /* Check for 8 digit per word max. */ if (ndigit > 8) - as_bad (_("A bignum with underscores may not have more than 8 hex digits in any word.")); + as_bad (_("a bignum with underscores may not have more than 8 hex digits in any word")); /* Add this chunk to the bignum. Shift things down 2 little digits. */ @@ -449,7 +432,7 @@ integer_constant (radix, expressionP) assert (num_little_digits >= 4); if (num_little_digits != 8) - as_bad (_("A bignum with underscores must have exactly 4 words.")); + as_bad (_("a bignum with underscores must have exactly 4 words")); /* We might have some leading zeros. These can be trimmed to give us a change to fit this constant into a small number. */ @@ -572,7 +555,7 @@ integer_constant (radix, expressionP) /* Either not seen or not defined. */ /* @@ Should print out the original string instead of the parsed number. */ - as_bad (_("backw. ref to unknown label \"%d:\", 0 assumed."), + as_bad (_("backward ref to unknown label \"%d:\""), (int) number); expressionP->X_op = O_constant; } @@ -646,8 +629,7 @@ integer_constant (radix, expressionP) /* Parse an MRI multi character constant. */ static void -mri_char_constant (expressionP) - expressionS *expressionP; +mri_char_constant (expressionS *expressionP) { int i; @@ -682,8 +664,8 @@ mri_char_constant (expressionP) if (i < SIZE_OF_LARGE_NUMBER - 1) { /* If there is more than one littlenum, left justify the - last one to make it match the earlier ones. If there is - only one, we can just use the value directly. */ + last one to make it match the earlier ones. If there is + only one, we can just use the value directly. */ for (; j < CHARS_PER_LITTLENUM; j++) generic_bignum[i] <<= 8; } @@ -695,7 +677,7 @@ mri_char_constant (expressionP) if (i < 0) { - as_bad (_("Character constant too large")); + as_bad (_("character constant too large")); i = 0; } @@ -736,8 +718,7 @@ mri_char_constant (expressionP) handles the magic symbol `.'. */ static void -current_location (expressionp) - expressionS *expressionp; +current_location (expressionS *expressionp) { if (now_seg == absolute_section) { @@ -746,13 +727,8 @@ current_location (expressionp) } else { - symbolS *symbolp; - - symbolp = symbol_new (FAKE_LABEL_NAME, now_seg, - (valueT) frag_now_fix (), - frag_now); expressionp->X_op = O_symbol; - expressionp->X_add_symbol = symbolp; + expressionp->X_add_symbol = symbol_temp_new_now (); expressionp->X_add_number = 0; } } @@ -760,13 +736,12 @@ current_location (expressionp) /* In: Input_line_pointer points to 1st char of operand, which may be a space. - Out: A expressionS. + Out: An expressionS. The operand may have been empty: in this case X_op == O_absent. Input_line_pointer->(next non-blank) char after operand. */ static segT -operand (expressionP) - expressionS *expressionP; +operand (expressionS *expressionP) { char c; symbolS *symbolP; /* Points to symbol. */ @@ -804,11 +779,14 @@ operand (expressionP) integer_constant ((NUMBERS_WITH_SUFFIX || flag_m68k_mri) ? 0 : 10, - expressionP); + expressionP); break; #ifdef LITERAL_PREFIXDOLLAR_HEX case '$': + /* $L is the start of a local label, not a hex constant. */ + if (* input_line_pointer == 'L') + goto isname; integer_constant (16, expressionP); break; #endif @@ -826,10 +804,10 @@ operand (expressionP) { char *s; - /* Check for a hex constant. */ + /* Check for a hex or float constant. */ for (s = input_line_pointer; hex_p (*s); s++) ; - if (*s == 'h' || *s == 'H') + if (*s == 'h' || *s == 'H' || *input_line_pointer == '.') { --input_line_pointer; integer_constant (0, expressionP); @@ -857,8 +835,7 @@ operand (expressionP) { input_line_pointer++; floating_constant (expressionP); - expressionP->X_add_number = - - (isupper ((unsigned char) c) ? tolower (c) : c); + expressionP->X_add_number = - TOLOWER (c); } else { @@ -980,8 +957,7 @@ operand (expressionP) case 'G': input_line_pointer++; floating_constant (expressionP); - expressionP->X_add_number = - - (isupper ((unsigned char) c) ? tolower (c) : c); + expressionP->X_add_number = - TOLOWER (c); break; case '$': @@ -1009,7 +985,7 @@ operand (expressionP) #ifdef RELAX_PAREN_GROUPING if (c != '(') #endif - as_bad (_("Missing '%c' assumed"), c == '(' ? ')' : ']'); + as_bad (_("missing '%c'"), c == '(' ? ')' : ']'); } else input_line_pointer++; @@ -1045,6 +1021,9 @@ operand (expressionP) break; case '+': + /* Do not accept ++e as +(+e) */ + if (*input_line_pointer == '+') + goto target_op; (void) operand (expressionP); break; @@ -1062,6 +1041,10 @@ operand (expressionP) case '!': case '-': { + /* Do not accept --e as -(-e) */ + if (c == '-' && *input_line_pointer == '-') + goto target_op; + operand (expressionP); if (expressionP->X_op == O_constant) { @@ -1079,6 +1062,18 @@ operand (expressionP) else expressionP->X_add_number = ! expressionP->X_add_number; } + else if (expressionP->X_op == O_big + && expressionP->X_add_number <= 0 + && c == '-' + && (generic_floating_point_number.sign == '+' + || generic_floating_point_number.sign == 'P')) + { + /* Negative flonum (eg, -1.000e0). */ + if (generic_floating_point_number.sign == '+') + generic_floating_point_number.sign = '-'; + else + generic_floating_point_number.sign = 'N'; + } else if (expressionP->X_op != O_illegal && expressionP->X_op != O_absent) { @@ -1100,7 +1095,7 @@ operand (expressionP) #if defined (DOLLAR_DOT) || defined (TC_M68K) case '$': /* '$' is the program counter when in MRI mode, or when - DOLLAR_DOT is defined. */ + DOLLAR_DOT is defined. */ #ifndef DOLLAR_DOT if (! flag_m68k_mri) goto de_fault; @@ -1108,7 +1103,7 @@ operand (expressionP) if (flag_m68k_mri && hex_p (*input_line_pointer)) { /* In MRI mode, '$' is also used as the prefix for a - hexadecimal constant. */ + hexadecimal constant. */ integer_constant (16, expressionP); break; } @@ -1199,7 +1194,7 @@ operand (expressionP) goto de_fault; /* In MRI mode, this is a floating point constant represented - using hexadecimal digits. */ + using hexadecimal digits. */ ++input_line_pointer; integer_constant (16, expressionP); @@ -1227,10 +1222,10 @@ operand (expressionP) #ifdef md_parse_name /* This is a hook for the backend to parse certain names - specially in certain contexts. If a name always has a - specific value, it can often be handled by simply - entering it in the symbol table. */ - if (md_parse_name (name, expressionP)) + specially in certain contexts. If a name always has a + specific value, it can often be handled by simply + entering it in the symbol table. */ + if (md_parse_name (name, expressionP, &c)) { *input_line_pointer = c; break; @@ -1301,6 +1296,7 @@ operand (expressionP) } else { + target_op: /* Let the target try to parse it. Success is indicated by changing the X_op field to something other than O_absent and pointing input_line_pointer past the expression. If it can't parse the @@ -1311,7 +1307,7 @@ operand (expressionP) if (expressionP->X_op == O_absent) { ++input_line_pointer; - as_bad (_("Bad expression")); + as_bad (_("bad expression")); expressionP->X_op = O_constant; expressionP->X_add_number = 0; } @@ -1342,18 +1338,15 @@ operand (expressionP) /* Internal. Simplify a struct expression for use by expr (). */ -/* In: address of a expressionS. +/* In: address of an expressionS. The X_op field of the expressionS may only take certain values. Elsewise we waste time special-case testing. Sigh. Ditto SEG_ABSENT. Out: expressionS may have been modified: - 'foo-foo' symbol references cancelled to 0, which changes X_op - from O_subtract to O_constant. Unused fields zeroed to help expr (). */ static void -clean_up_expression (expressionP) - expressionS *expressionP; +clean_up_expression (expressionS *expressionP) { switch (expressionP->X_op) { @@ -1371,23 +1364,6 @@ clean_up_expression (expressionP) case O_bit_not: expressionP->X_op_symbol = NULL; break; - case O_subtract: - if (expressionP->X_op_symbol == expressionP->X_add_symbol - || ((symbol_get_frag (expressionP->X_op_symbol) - == symbol_get_frag (expressionP->X_add_symbol)) - && SEG_NORMAL (S_GET_SEGMENT (expressionP->X_add_symbol)) - && (S_GET_VALUE (expressionP->X_op_symbol) - == S_GET_VALUE (expressionP->X_add_symbol)))) - { - addressT diff = (S_GET_VALUE (expressionP->X_add_symbol) - - S_GET_VALUE (expressionP->X_op_symbol)); - - expressionP->X_op = O_constant; - expressionP->X_add_symbol = NULL; - expressionP->X_op_symbol = NULL; - expressionP->X_add_number += diff; - } - break; default: break; } @@ -1399,7 +1375,7 @@ clean_up_expression (expressionP) Unary operators and parenthetical expressions are treated as operands. As usual, Q==quantity==operand, O==operator, X==expression mnemonics. - We used to do a aho/ullman shift-reduce parser, but the logic got so + We used to do an aho/ullman shift-reduce parser, but the logic got so warped that I flushed it and wrote a recursive-descent parser instead. Now things are stable, would anybody like to write a fast parser? Most expressions are either register (which does not even reach here) @@ -1455,7 +1431,7 @@ static const operatorT op_encoding[256] = { 0 operand, (expression) 1 || 2 && - 3 = <> < <= >= > + 3 == <> < <= >= > 4 + - 5 used for * / % in MRI mode 6 & ^ ! | @@ -1469,7 +1445,7 @@ static operator_rankT op_rank[] = { 0, /* O_symbol */ 0, /* O_symbol_rva */ 0, /* O_register */ - 0, /* O_bit */ + 0, /* O_big */ 9, /* O_uminus */ 9, /* O_bit_not */ 9, /* O_logical_not */ @@ -1517,11 +1493,11 @@ static operator_rankT op_rank[] = { mode. Also, MRI uses a different bit_not operator, and this fixes that as well. */ -#define STANDARD_MUL_PRECEDENCE (7) -#define MRI_MUL_PRECEDENCE (5) +#define STANDARD_MUL_PRECEDENCE 8 +#define MRI_MUL_PRECEDENCE 6 void -expr_set_precedence () +expr_set_precedence (void) { if (flag_m68k_mri) { @@ -1540,7 +1516,7 @@ expr_set_precedence () /* Initialize the expression parser. */ void -expr_begin () +expr_begin (void) { expr_set_precedence (); @@ -1552,17 +1528,18 @@ expr_begin () } } -/* Return the encoding for the operator at INPUT_LINE_POINTER. - Advance INPUT_LINE_POINTER to the last character in the operator - (i.e., don't change it for a single character operator). */ +/* Return the encoding for the operator at INPUT_LINE_POINTER, and + sets NUM_CHARS to the number of characters in the operator. + Does not advance INPUT_LINE_POINTER. */ static inline operatorT -operator () +operator (int *num_chars) { int c; operatorT ret; c = *input_line_pointer & 0xff; + *num_chars = 1; if (is_end_of_line[c]) return O_illegal; @@ -1572,6 +1549,13 @@ operator () default: return op_encoding[c]; + case '+': + case '-': + /* Do not allow a++b and a--b to be a + (+b) and a - (-b) */ + if (input_line_pointer[1] != c) + return op_encoding[c]; + return O_illegal; + case '<': switch (input_line_pointer[1]) { @@ -1587,14 +1571,14 @@ operator () ret = O_le; break; } - ++input_line_pointer; + *num_chars = 2; return ret; case '=': if (input_line_pointer[1] != '=') return op_encoding[c]; - ++input_line_pointer; + *num_chars = 2; return O_eq; case '>': @@ -1609,7 +1593,7 @@ operator () ret = O_ge; break; } - ++input_line_pointer; + *num_chars = 2; return ret; case '!': @@ -1620,21 +1604,21 @@ operator () return O_bit_inclusive_or; return op_encoding[c]; } - ++input_line_pointer; + *num_chars = 2; return O_bit_exclusive_or; case '|': if (input_line_pointer[1] != '|') return op_encoding[c]; - ++input_line_pointer; + *num_chars = 2; return O_logical_or; case '&': if (input_line_pointer[1] != '&') return op_encoding[c]; - ++input_line_pointer; + *num_chars = 2; return O_logical_and; } @@ -1644,29 +1628,33 @@ operator () /* Parse an expression. */ segT -expr (rankarg, resultP) - int rankarg; /* Larger # is higher rank. */ - expressionS *resultP; /* Deliver result here. */ +expr (int rankarg, /* Larger # is higher rank. */ + expressionS *resultP /* Deliver result here. */) { operator_rankT rank = (operator_rankT) rankarg; segT retval; expressionS right; operatorT op_left; operatorT op_right; + int op_chars; know (rank >= 0); + /* Save the value of dot for the fixup code. */ + if (rank == 0) + dot_value = frag_now_fix (); + retval = operand (resultP); /* operand () gobbles spaces. */ know (*input_line_pointer != ' '); - op_left = operator (); + op_left = operator (&op_chars); while (op_left != O_illegal && op_rank[(int) op_left] > rank) { segT rightseg; - input_line_pointer++; /* -> after 1st character of operator. */ + input_line_pointer += op_chars; /* -> after operator. */ rightseg = expr (op_rank[(int) op_left], &right); if (right.X_op == O_absent) @@ -1691,22 +1679,7 @@ expr (rankarg, resultP) } } - if (retval == undefined_section) - { - if (SEG_NORMAL (rightseg)) - retval = rightseg; - } - else if (! SEG_NORMAL (retval)) - retval = rightseg; - else if (SEG_NORMAL (rightseg) - && retval != rightseg -#ifdef DIFF_EXPR_OK - && op_left != O_subtract -#endif - ) - as_bad (_("operation combines symbols in different segments")); - - op_right = operator (); + op_right = operator (&op_chars); know (op_right == O_illegal || op_rank[(int) op_right] <= op_rank[(int) op_left]); @@ -1761,8 +1734,8 @@ expr (rankarg, resultP) && resultP->X_op == O_symbol && (symbol_get_frag (right.X_add_symbol) == symbol_get_frag (resultP->X_add_symbol)) - && SEG_NORMAL (S_GET_SEGMENT (right.X_add_symbol))) - + && (SEG_NORMAL (rightseg) + || right.X_add_symbol == resultP->X_add_symbol)) { resultP->X_add_number -= right.X_add_number; resultP->X_add_number += (S_GET_VALUE (resultP->X_add_symbol) @@ -1802,7 +1775,7 @@ expr (rankarg, resultP) case O_left_shift: resultP->X_add_number <<= v; break; case O_right_shift: /* We always use unsigned shifts, to avoid relying on - characteristics of the compiler used to compile gas. */ + characteristics of the compiler used to compile gas. */ resultP->X_add_number = (offsetT) ((valueT) resultP->X_add_number >> (valueT) v); break; @@ -1857,7 +1830,14 @@ expr (rankarg, resultP) if (op_left == O_add) resultP->X_add_number += right.X_add_number; else if (op_left == O_subtract) - resultP->X_add_number -= right.X_add_number; + { + resultP->X_add_number -= right.X_add_number; + if (retval == rightseg && SEG_NORMAL (retval)) + { + retval = absolute_section; + rightseg = absolute_section; + } + } } else { @@ -1869,6 +1849,21 @@ expr (rankarg, resultP) resultP->X_unsigned = 1; } + if (retval != rightseg) + { + if (! SEG_NORMAL (retval)) + { + if (retval != undefined_section || SEG_NORMAL (rightseg)) + retval = rightseg; + } + else if (SEG_NORMAL (rightseg) +#ifdef DIFF_EXPR_OK + && op_left != O_subtract +#endif + ) + as_bad (_("operation combines symbols in different segments")); + } + op_left = op_right; } /* While next operator is >= this rank. */ @@ -1892,7 +1887,7 @@ expr (rankarg, resultP) lines end in end-of-line. */ char -get_symbol_end () +get_symbol_end (void) { char c; @@ -1911,7 +1906,7 @@ get_symbol_end () } unsigned int -get_single_number () +get_single_number (void) { expressionS exp; operand (&exp);