X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gas%2Fexpr.c;h=47e69332f9abd0897c02b444034a69bfcc33eb9a;hb=f1b8b0f4f15a5ea3106dc0d64ff3bf65886a83cc;hp=b73066785118ed55fa0d26ab679e7d76bf469e41;hpb=219deb70ce2c2e92c12d476ec0cefa69fbf6c78b;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/expr.c b/gas/expr.c index b730667851..47e69332f9 100644 --- a/gas/expr.c +++ b/gas/expr.c @@ -1,5 +1,6 @@ /* expr.c -operands, expressions- - Copyright (C) 1987, 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc. + Copyright (C) 1987, 90, 91, 92, 93, 94, 95, 96, 97, 1998 + Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -14,8 +15,9 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with GAS; see the file COPYING. If not, write to - the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ /* * This is really a branch office of as-read.c. I split it out to clearly @@ -26,17 +28,33 @@ #include #include +#define min(a, b) ((a) < (b) ? (a) : (b)) #include "as.h" -#include "libiberty.h" #include "obstack.h" static void floating_constant PARAMS ((expressionS * expressionP)); 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)); extern const char EXP_CHARS[], FLT_CHARS[]; + +/* We keep a mapping of expression symbols to file positions, so that + we can provide better error messages. */ + +struct expr_symbol_line +{ + struct expr_symbol_line *next; + symbolS *sym; + char *file; + unsigned int line; +}; + +static struct expr_symbol_line *expr_symbol_lines; /* Build a dummy symbol to hold a complex expression. This is how we build expressions up out of other expressions. The symbol is put @@ -48,13 +66,12 @@ make_expr_symbol (expressionP) { const char *fake; symbolS *symbolP; + struct expr_symbol_line *n; if (expressionP->X_op == O_symbol && expressionP->X_add_number == 0) return expressionP->X_add_symbol; - /* FIXME: This should be something which decode_local_label_name - will handle. */ fake = FAKE_LABEL_NAME; /* Putting constant symbols in absolute_section rather than @@ -69,10 +86,97 @@ make_expr_symbol (expressionP) symbolP->sy_value = *expressionP; if (expressionP->X_op == O_constant) - resolve_symbol_value (symbolP); + resolve_symbol_value (symbolP, 1); + + n = (struct expr_symbol_line *) xmalloc (sizeof *n); + n->sym = symbolP; + as_where (&n->file, &n->line); + n->next = expr_symbol_lines; + expr_symbol_lines = n; return symbolP; } + +/* Return the file and line number for an expr symbol. Return + non-zero if something was found, 0 if no information is known for + the symbol. */ + +int +expr_symbol_where (sym, pfile, pline) + symbolS *sym; + char **pfile; + unsigned int *pline; +{ + register struct expr_symbol_line *l; + + for (l = expr_symbol_lines; l != NULL; l = l->next) + { + if (l->sym == sym) + { + *pfile = l->file; + *pline = l->line; + return 1; + } + } + + return 0; +} + +/* Utilities for building expressions. + Since complex expressions are recorded as symbols for use in other + expressions these return a symbolS * and not an expressionS *. + These explicitly do not take an "add_number" argument. */ +/* ??? For completeness' sake one might want expr_build_symbol. + It would just return its argument. */ + +/* Build an expression for an unsigned constant. + The corresponding one for signed constants is missing because + there's currently no need for it. One could add an unsigned_p flag + but that seems more clumsy. */ + +symbolS * +expr_build_uconstant (value) + offsetT value; +{ + expressionS e; + + e.X_op = O_constant; + e.X_add_number = value; + e.X_unsigned = 1; + return make_expr_symbol (&e); +} + +/* Build an expression for OP s1. */ + +symbolS * +expr_build_unary (op, s1) + operatorT op; + symbolS *s1; +{ + expressionS e; + + e.X_op = op; + e.X_add_symbol = s1; + e.X_add_number = 0; + return make_expr_symbol (&e); +} + +/* Build an expression for s1 OP s2. */ + +symbolS * +expr_build_binary (op, s1, s2) + operatorT op; + symbolS *s1; + symbolS *s2; +{ + expressionS e; + + e.X_op = op; + e.X_add_symbol = s1; + e.X_op_symbol = s2; + e.X_add_number = 0; + return make_expr_symbol (&e); +} /* * Build any floating-point literal here. @@ -124,6 +228,32 @@ floating_constant (expressionP) expressionP->X_add_number = -1; } +static valueT +generic_bignum_to_int32 () +{ + valueT number = + ((generic_bignum[1] & LITTLENUM_MASK) << LITTLENUM_NUMBER_OF_BITS) + | (generic_bignum[0] & LITTLENUM_MASK); + number &= 0xffffffff; + return number; +} + +#ifdef BFD64 +static valueT +generic_bignum_to_int64 () +{ + valueT number = + ((((((((valueT) generic_bignum[3] & LITTLENUM_MASK) + << LITTLENUM_NUMBER_OF_BITS) + | ((valueT) generic_bignum[2] & LITTLENUM_MASK)) + << LITTLENUM_NUMBER_OF_BITS) + | ((valueT) generic_bignum[1] & LITTLENUM_MASK)) + << LITTLENUM_NUMBER_OF_BITS) + | ((valueT) generic_bignum[0] & LITTLENUM_MASK)); + return number; +} +#endif + static void integer_constant (radix, expressionP) int radix; @@ -165,14 +295,16 @@ integer_constant (radix, expressionP) #define valuesize 32 #endif - if (flag_mri && radix == 0) + if (flag_m68k_mri && radix == 0) { 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 (*suffix); suffix++) + for (suffix = input_line_pointer; + isalnum ((unsigned char) *suffix); + suffix++) { if (*suffix == 'e' || *suffix == 'E') flt = 1; @@ -186,7 +318,7 @@ integer_constant (radix, expressionP) else { c = *--suffix; - if (islower (c)) + if (islower ((unsigned char) c)) c = toupper (c); if (c == 'B') radix = 2; @@ -239,7 +371,83 @@ integer_constant (radix, expressionP) /* c contains character after number. */ /* input_line_pointer->char after c. */ small = (input_line_pointer - start - 1) < too_many_digits; - if (!small) + + if (radix == 16 && c == '_') + { + /* This is literal of the form 0x333_0_12345678_1. + This example is equivalent to 0x00000333000000001234567800000001. */ + + int num_little_digits = 0; + int i; + input_line_pointer = start; /*->1st digit. */ + + know (LITTLENUM_NUMBER_OF_BITS == 16); + + for (c = '_'; c == '_'; num_little_digits+=2) + { + + /* Convert one 64-bit word. */ + int ndigit = 0; + number = 0; + for (c = *input_line_pointer++; + (digit = hex_value (c)) < maxdig; + c = *(input_line_pointer++)) + { + number = number * radix + digit; + ndigit++; + } + + /* Check for 8 digit per word max. */ + if (ndigit > 8) + as_bad ("An 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.*/ + know (LITTLENUM_NUMBER_OF_BITS == 16); + for (i = min (num_little_digits + 1, SIZE_OF_LARGE_NUMBER - 1); i >= 2; i--) + generic_bignum[i] = generic_bignum[i-2]; + + /* Add the new digits as the least significant new ones. */ + generic_bignum[0] = number & 0xffffffff; + generic_bignum[1] = number >> 16; + } + + /* Again, c is char after number, input_line_pointer->after c. */ + + if (num_little_digits > SIZE_OF_LARGE_NUMBER - 1) + num_little_digits = SIZE_OF_LARGE_NUMBER - 1; + + assert (num_little_digits >= 4); + + if (num_little_digits != 8) + 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. + */ + while (generic_bignum[num_little_digits-1] == 0 && num_little_digits > 1) + num_little_digits--; + + if (num_little_digits <= 2) + { + /* will fit into 32 bits. */ + number = generic_bignum_to_int32 (); + small = 1; + } +#ifdef BFD64 + else if (num_little_digits <= 4) + { + /* Will fit into 64 bits. */ + number = generic_bignum_to_int64 (); + small = 1; + } +#endif + else + { + small = 0; + number = num_little_digits; /* number of littlenums in the bignum. */ + } + } + else if (!small) { /* * we saw a lot of digits. manufacture a bignum the hard way. @@ -251,6 +459,8 @@ integer_constant (radix, expressionP) leader = generic_bignum; generic_bignum[0] = 0; generic_bignum[1] = 0; + generic_bignum[2] = 0; + generic_bignum[3] = 0; input_line_pointer = start; /*->1st digit. */ c = *input_line_pointer++; for (; @@ -282,18 +492,24 @@ integer_constant (radix, expressionP) if (leader < generic_bignum + 2) { /* will fit into 32 bits. */ - number = - ((generic_bignum[1] & LITTLENUM_MASK) << LITTLENUM_NUMBER_OF_BITS) - | (generic_bignum[0] & LITTLENUM_MASK); + number = generic_bignum_to_int32 (); small = 1; } +#ifdef BFD64 + else if (leader < generic_bignum + 4) + { + /* Will fit into 64 bits. */ + number = generic_bignum_to_int64 (); + small = 1; + } +#endif else { number = leader - generic_bignum + 1; /* number of littlenums in the bignum. */ } } - if (flag_mri && suffix != NULL && input_line_pointer - 1 == suffix) + if (flag_m68k_mri && suffix != NULL && input_line_pointer - 1 == suffix) c = *input_line_pointer++; if (small) @@ -491,6 +707,31 @@ mri_char_constant (expressionP) ++input_line_pointer; } +/* Return an expression representing the current location. This + handles the magic symbol `.'. */ + +static void +current_location (expressionp) + expressionS *expressionp; +{ + if (now_seg == absolute_section) + { + expressionp->X_op = O_constant; + expressionp->X_add_number = abs_section_offset; + } + 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_number = 0; + } +} + /* * Summary of operand(). * @@ -537,13 +778,13 @@ operand (expressionP) case '9': input_line_pointer--; - integer_constant (flag_mri ? 0 : 10, expressionP); + integer_constant (flag_m68k_mri ? 0 : 10, expressionP); break; case '0': /* non-decimal radix */ - if (flag_mri) + if (flag_m68k_mri) { char *s; @@ -561,13 +802,26 @@ operand (expressionP) c = *input_line_pointer; switch (c) { + case 'o': + case 'O': + case 'q': + case 'Q': + case '8': + case '9': + if (flag_m68k_mri) + { + integer_constant (0, expressionP); + break; + } + /* Fall through. */ default: default_case: if (c && strchr (FLT_CHARS, c)) { input_line_pointer++; floating_constant (expressionP); - expressionP->X_add_number = -(isupper (c) ? tolower (c) : c); + expressionP->X_add_number = + - (isupper ((unsigned char) c) ? tolower (c) : c); } else { @@ -580,52 +834,36 @@ operand (expressionP) case 'x': case 'X': - if (flag_mri) + if (flag_m68k_mri) goto default_case; input_line_pointer++; integer_constant (16, expressionP); break; case 'b': - if (LOCAL_LABELS_FB) + if (LOCAL_LABELS_FB && ! flag_m68k_mri) { - switch (input_line_pointer[1]) + /* This code used to check for '+' and '-' here, and, in + some conditions, fall through to call + integer_constant. However, that didn't make sense, + as integer_constant only accepts digits. */ + /* Some of our code elsewhere does permit digits greater + than the expected base; for consistency, do the same + here. */ + if (input_line_pointer[1] < '0' + || input_line_pointer[1] > '9') { - case '+': - case '-': - /* If unambiguously a difference expression, treat - it as one by indicating a label; otherwise, it's - always a binary number. */ - { - char *cp = input_line_pointer + 1; - while (strchr ("0123456789", *++cp)) - ; - if (*cp == 'b' || *cp == 'f') - goto is_0b_label; - } - goto is_0b_binary; - case '0': case '1': - /* Some of our code elsewhere does permit digits - greater than the expected base; for consistency, - do the same here. */ - case '2': case '3': case '4': case '5': - case '6': case '7': case '8': case '9': - goto is_0b_binary; - case 0: - goto is_0b_label; - default: - goto is_0b_label; + /* Parse this as a back reference to label 0. */ + input_line_pointer--; + integer_constant (10, expressionP); + break; } - is_0b_label: - input_line_pointer--; - integer_constant (10, expressionP); - break; - is_0b_binary: - ; + /* Otherwise, parse this as a binary number. */ } + /* Fall through. */ case 'B': input_line_pointer++; - if (flag_mri) + if (flag_m68k_mri) goto default_case; integer_constant (2, expressionP); break; @@ -638,7 +876,7 @@ operand (expressionP) case '5': case '6': case '7': - integer_constant (flag_mri ? 0 : 8, expressionP); + integer_constant (flag_m68k_mri ? 0 : 8, expressionP); break; case 'f': @@ -684,6 +922,12 @@ operand (expressionP) case 'd': case 'D': + if (flag_m68k_mri) + { + integer_constant (0, expressionP); + break; + } + /* Fall through. */ case 'F': case 'r': case 'e': @@ -692,7 +936,8 @@ operand (expressionP) case 'G': input_line_pointer++; floating_constant (expressionP); - expressionP->X_add_number = -(isupper (c) ? tolower (c) : c); + expressionP->X_add_number = + - (isupper ((unsigned char) c) ? tolower (c) : c); break; case '$': @@ -718,21 +963,22 @@ operand (expressionP) as_bad ("Missing ')' assumed"); input_line_pointer--; } + SKIP_WHITESPACE (); /* here with input_line_pointer->char after "(...)" */ return segment; case 'E': - if (! flag_mri || *input_line_pointer != '\'') + if (! flag_m68k_mri || *input_line_pointer != '\'') goto de_fault; as_bad ("EBCDIC constants are not supported"); /* Fall through. */ case 'A': - if (! flag_mri || *input_line_pointer != '\'') + if (! flag_m68k_mri || *input_line_pointer != '\'') goto de_fault; ++input_line_pointer; /* Fall through. */ case '\'': - if (! flag_mri) + if (! flag_m68k_mri) { /* Warning: to conform to other people's assemblers NO ESCAPEMENT is permitted for a single quote. The next @@ -751,11 +997,15 @@ operand (expressionP) break; case '"': - /* Double quote is the logical not operator in MRI mode. */ - if (! flag_mri) + /* Double quote is the bitwise not operator in MRI mode. */ + if (! flag_m68k_mri) goto de_fault; /* Fall through. */ case '~': + /* ~ is permitted to start a label on the Delta. */ + if (is_name_beginner (c)) + goto isname; + case '!': case '-': { operand (expressionP); @@ -769,8 +1019,10 @@ operand (expressionP) compatible with other people's assemblers. Sigh. */ expressionP->X_unsigned = 0; } - else + else if (c == '~' || c == '"') expressionP->X_add_number = ~ expressionP->X_add_number; + else + expressionP->X_add_number = ! expressionP->X_add_number; } else if (expressionP->X_op != O_illegal && expressionP->X_op != O_absent) @@ -778,8 +1030,10 @@ operand (expressionP) expressionP->X_add_symbol = make_expr_symbol (expressionP); if (c == '-') expressionP->X_op = O_uminus; - else + else if (c == '~' || c == '"') expressionP->X_op = O_bit_not; + else + expressionP->X_op = O_logical_not; expressionP->X_add_number = 0; } else @@ -792,33 +1046,70 @@ operand (expressionP) /* $ is the program counter when in MRI mode, or when DOLLAR_DOT is defined. */ #ifndef DOLLAR_DOT - if (! flag_mri) + if (! flag_m68k_mri) goto de_fault; #endif - if (flag_mri && hex_p (*input_line_pointer)) + if (flag_m68k_mri && hex_p (*input_line_pointer)) { /* In MRI mode, $ is also used as the prefix for a hexadecimal constant. */ integer_constant (16, expressionP); break; } - /* Fall through. */ + + if (is_part_of_name (*input_line_pointer)) + goto isname; + + current_location (expressionP); + break; + case '.': if (!is_part_of_name (*input_line_pointer)) { - const char *fake; + current_location (expressionP); + break; + } + else if ((strncasecmp (input_line_pointer, "startof.", 8) == 0 + && ! is_part_of_name (input_line_pointer[8])) + || (strncasecmp (input_line_pointer, "sizeof.", 7) == 0 + && ! is_part_of_name (input_line_pointer[7]))) + { + int start; + + start = (input_line_pointer[1] == 't' + || input_line_pointer[1] == 'T'); + input_line_pointer += start ? 8 : 7; + SKIP_WHITESPACE (); + if (*input_line_pointer != '(') + as_bad ("syntax error in .startof. or .sizeof."); + else + { + char *buf; - /* JF: '.' is pseudo symbol with value of current location - in current segment. */ - fake = FAKE_LABEL_NAME; - symbolP = symbol_new (fake, - now_seg, - (valueT) frag_now_fix (), - frag_now); + ++input_line_pointer; + SKIP_WHITESPACE (); + name = input_line_pointer; + c = get_symbol_end (); + + buf = (char *) xmalloc (strlen (name) + 10); + if (start) + sprintf (buf, ".startof.%s", name); + else + sprintf (buf, ".sizeof.%s", name); + symbolP = symbol_make (buf); + free (buf); - expressionP->X_op = O_symbol; - expressionP->X_add_symbol = symbolP; - expressionP->X_add_number = 0; + expressionP->X_op = O_symbol; + expressionP->X_add_symbol = symbolP; + expressionP->X_add_number = 0; + + *input_line_pointer = c; + SKIP_WHITESPACE (); + if (*input_line_pointer != ')') + as_bad ("syntax error in .startof. or .sizeof."); + else + ++input_line_pointer; + } break; } else @@ -835,19 +1126,19 @@ operand (expressionP) break; case '%': - if (! flag_mri) + if (! flag_m68k_mri) goto de_fault; integer_constant (2, expressionP); break; case '@': - if (! flag_mri) + if (! flag_m68k_mri) goto de_fault; integer_constant (8, expressionP); break; case ':': - if (! flag_mri) + if (! flag_m68k_mri) goto de_fault; /* In MRI mode, this is a floating point constant represented @@ -857,6 +1148,13 @@ operand (expressionP) integer_constant (16, expressionP); break; + case '*': + if (! flag_m68k_mri || is_part_of_name (*input_line_pointer)) + goto de_fault; + + current_location (expressionP); + break; + default: de_fault: if (is_end_of_line[(unsigned char) c]) @@ -870,6 +1168,58 @@ operand (expressionP) isname: name = --input_line_pointer; c = get_symbol_end (); + +#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)) + { + *input_line_pointer = c; + break; + } +#endif + +#ifdef TC_I960 + /* The MRI i960 assembler permits + lda sizeof code,g13 + FIXME: This should use md_parse_name. */ + if (flag_mri + && (strcasecmp (name, "sizeof") == 0 + || strcasecmp (name, "startof") == 0)) + { + int start; + char *buf; + + start = (name[1] == 't' + || name[1] == 'T'); + + *input_line_pointer = c; + SKIP_WHITESPACE (); + + name = input_line_pointer; + c = get_symbol_end (); + + buf = (char *) xmalloc (strlen (name) + 10); + if (start) + sprintf (buf, ".startof.%s", name); + else + sprintf (buf, ".sizeof.%s", name); + symbolP = symbol_make (buf); + free (buf); + + expressionP->X_op = O_symbol; + expressionP->X_add_symbol = symbolP; + expressionP->X_add_number = 0; + + *input_line_pointer = c; + SKIP_WHITESPACE (); + + break; + } +#endif + symbolP = symbol_find_or_make (name); /* If we have an absolute symbol or a reg, then we know its @@ -1016,13 +1366,13 @@ clean_up_expression (expressionP) #undef __ #define __ O_illegal -static const operatorT op_encoding[256] = +static operatorT op_encoding[256] = { /* maps ASCII->operators */ __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, - __, O_bit_or_not, O_bit_not, __, __, O_modulus, O_bit_and, __, + __, O_bit_or_not, __, __, __, O_modulus, O_bit_and, __, __, __, O_multiply, O_add, __, O_subtract, __, O_divide, __, __, __, __, __, __, __, __, __, __, __, __, O_lt, __, O_gt, __, @@ -1049,12 +1399,14 @@ static const operatorT op_encoding[256] = /* * Rank Examples * 0 operand, (expression) - * 1 = <> < <= >= > - * 2 + - - * 3 used for * / % in MRI mode - * 4 & ^ ! | - * 5 * / % << >> - * 6 unary - unary ~ + * 1 || + * 2 && + * 3 = <> < <= >= > + * 4 + - + * 5 used for * / % in MRI mode + * 6 & ^ ! | + * 7 * / % << >> + * 8 unary - unary ~ */ static operator_rankT op_rank[] = { @@ -1062,27 +1414,31 @@ static operator_rankT op_rank[] = 0, /* O_absent */ 0, /* O_constant */ 0, /* O_symbol */ + 0, /* O_symbol_rva */ 0, /* O_register */ 0, /* O_bit */ - 6, /* O_uminus */ - 6, /* O_bit_not */ - 5, /* O_multiply */ - 5, /* O_divide */ - 5, /* O_modulus */ - 5, /* O_left_shift */ - 5, /* O_right_shift */ - 4, /* O_bit_inclusive_or */ - 4, /* O_bit_or_not */ - 4, /* O_bit_exclusive_or */ - 4, /* O_bit_and */ - 2, /* O_add */ - 2, /* O_subtract */ - 1, /* O_eq */ - 1, /* O_ne */ - 1, /* O_lt */ - 1, /* O_le */ - 1, /* O_ge */ - 1 /* O_gt */ + 8, /* O_uminus */ + 8, /* O_bit_not */ + 8, /* O_logical_not */ + 7, /* O_multiply */ + 7, /* O_divide */ + 7, /* O_modulus */ + 7, /* O_left_shift */ + 7, /* O_right_shift */ + 6, /* O_bit_inclusive_or */ + 6, /* O_bit_or_not */ + 6, /* O_bit_exclusive_or */ + 6, /* O_bit_and */ + 4, /* O_add */ + 4, /* O_subtract */ + 3, /* O_eq */ + 3, /* O_ne */ + 3, /* O_lt */ + 3, /* O_le */ + 3, /* O_ge */ + 3, /* O_gt */ + 2, /* O_logical_and */ + 1 /* O_logical_or */ }; /* Initialize the expression parser. */ @@ -1090,14 +1446,22 @@ static operator_rankT op_rank[] = void expr_begin () { - /* In MRI mode, multiplication and division have lower precedence - than the bit wise operators. */ - if (flag_mri) + /* In MRI mode for the m68k, multiplication and division have lower + precedence than the bit wise operators. */ + if (flag_m68k_mri) { - op_rank[O_multiply] = 3; - op_rank[O_divide] = 3; - op_rank[O_modulus] = 3; + op_rank[O_multiply] = 5; + op_rank[O_divide] = 5; + op_rank[O_modulus] = 5; + op_encoding['"'] = O_bit_not; } + + /* Verify that X_op field is wide enough. */ + { + expressionS e; + e.X_op = O_max; + assert (e.X_op == O_max); + } } /* Return the encoding for the operator at INPUT_LINE_POINTER. @@ -1135,6 +1499,13 @@ operator () ++input_line_pointer; return ret; + case '=': + if (input_line_pointer[1] != '=') + return op_encoding[c]; + + ++input_line_pointer; + return O_eq; + case '>': switch (input_line_pointer[1]) { @@ -1154,16 +1525,30 @@ operator () /* We accept !! as equivalent to ^ for MRI compatibility. */ if (input_line_pointer[1] != '!') { - if (flag_mri) + if (flag_m68k_mri) return O_bit_inclusive_or; return op_encoding[c]; } ++input_line_pointer; return O_bit_exclusive_or; + + case '|': + if (input_line_pointer[1] != '|') + return op_encoding[c]; + + ++input_line_pointer; + return O_logical_or; + + case '&': + if (input_line_pointer[1] != '&') + return op_encoding[c]; + + ++input_line_pointer; + return O_logical_and; } /*NOTREACHED*/ -} +} /* Parse an expression. */ @@ -1220,7 +1605,8 @@ expr (rank, resultP) op_right = operator (); know (op_right == O_illegal || op_rank[(int) op_right] <= op_rank[(int) op_left]); - know ((int) op_left >= (int) O_multiply && (int) op_left <= (int) O_subtract); + know ((int) op_left >= (int) O_multiply + && (int) op_left <= (int) O_logical_or); /* input_line_pointer->after right-hand quantity. */ /* left-hand quantity in resultP */ @@ -1261,7 +1647,7 @@ expr (rank, resultP) && SEG_NORMAL (S_GET_SEGMENT (right.X_add_symbol))) { - resultP->X_add_number += right.X_add_number; + resultP->X_add_number -= right.X_add_number; resultP->X_add_number += (S_GET_VALUE (resultP->X_add_symbol) - S_GET_VALUE (right.X_add_symbol)); resultP->X_op = O_constant; @@ -1297,7 +1683,12 @@ expr (rank, resultP) case O_divide: resultP->X_add_number /= v; break; case O_modulus: resultP->X_add_number %= v; break; case O_left_shift: resultP->X_add_number <<= v; break; - case O_right_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. */ + resultP->X_add_number = + (offsetT) ((valueT) resultP->X_add_number >> (valueT) v); + break; case O_bit_inclusive_or: resultP->X_add_number |= v; break; case O_bit_or_not: resultP->X_add_number |= ~v; break; case O_bit_exclusive_or: resultP->X_add_number ^= v; break; @@ -1328,6 +1719,12 @@ expr (rank, resultP) resultP->X_add_number = resultP->X_add_number > v ? ~ (offsetT) 0 : 0; break; + case O_logical_and: + resultP->X_add_number = resultP->X_add_number && v; + break; + case O_logical_or: + resultP->X_add_number = resultP->X_add_number || v; + break; } } else if (resultP->X_op == O_symbol @@ -1385,8 +1782,12 @@ get_symbol_end () { char c; - while (is_part_of_name (c = *input_line_pointer++)) - ; + /* We accept \001 in a name in case this is being called with a + constructed string. */ + if (is_name_beginner (c = *input_line_pointer++) || c == '\001') + while (is_part_of_name (c = *input_line_pointer++) + || c == '\001') + ; *--input_line_pointer = 0; return (c); }