/* expr.c -operands, expressions-
Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
+ the Free Software Foundation; either version 3, or (at your option)
any later version.
GAS is distributed in the hope that it will be useful,
(It also gives smaller files to re-compile.)
Here, "operand"s are of expressions, not instructions. */
-#include <string.h>
#define min(a, b) ((a) < (b) ? (a) : (b))
#include "as.h"
{
c = *--suffix;
c = TOUPPER (c);
- if (c == 'B')
+ /* If we have both NUMBERS_WITH_SUFFIX and LOCAL_LABELS_FB,
+ we distinguish between 'B' and 'b'. This is the case for
+ Z80. */
+ if ((NUMBERS_WITH_SUFFIX && LOCAL_LABELS_FB ? *suffix : c) == 'B')
radix = 2;
else if (c == 'D')
radix = 10;
case '-':
case '+':
{
- /* Do not accept ++e or --e as +(+e) or -(-e)
- Disabled, since the preprocessor removes whitespace. */
- if (0 && (c == '-' || c == '+') && *input_line_pointer == c)
- goto target_op;
-
operand (expressionP, mode);
if (expressionP->X_op == O_constant)
{
if (! flag_m68k_mri)
goto de_fault;
#endif
- if (flag_m68k_mri && hex_p (*input_line_pointer))
+ if (DOLLAR_AMBIGU && hex_p (*input_line_pointer))
{
- /* In MRI mode, '$' is also used as the prefix for a
- hexadecimal constant. */
+ /* In MRI mode and on Z80, '$' is also used as the prefix
+ for a hexadecimal constant. */
integer_constant (16, expressionP);
break;
}
}
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
#undef __
#define __ O_illegal
+#ifndef O_SINGLE_EQ
+#define O_SINGLE_EQ O_illegal
+#endif
/* Maps ASCII -> operators. */
static const operatorT op_encoding[256] = {
__, O_bit_or_not, __, __, __, O_modulus, O_bit_and, __,
__, __, O_multiply, O_add, __, O_subtract, __, O_divide,
__, __, __, __, __, __, __, __,
- __, __, __, __, O_lt, __, O_gt, __,
+ __, __, __, __, O_lt, O_SINGLE_EQ, O_gt, __,
__, __, __, __, __, __, __, __,
__, __, __, __, __, __, __, __,
__, __, __, __, __, __, __, __,
case '+':
case '-':
- /* Do not allow a++b and a--b to be a + (+b) and a - (-b)
- Disabled, since the preprocessor removes whitespace. */
- if (1 || input_line_pointer[1] != c)
- return op_encoding[c];
- return O_illegal;
+ return op_encoding[c];
case '<':
switch (input_line_pointer[1])
operatorT op_right;
int op_chars;
- know (rank >= 0);
+ know (rankarg >= 0);
/* Save the value of dot for the fixup code. */
if (rank == 0)
while (op_left != O_illegal && op_rank[(int) op_left] > rank)
{
segT rightseg;
+ bfd_vma frag_off;
input_line_pointer += op_chars; /* -> after operator. */
else if (op_left == O_subtract
&& right.X_op == O_symbol
&& resultP->X_op == O_symbol
- && (symbol_get_frag (right.X_add_symbol)
- == symbol_get_frag (resultP->X_add_symbol))
+ && retval == rightseg
&& (SEG_NORMAL (rightseg)
- || right.X_add_symbol == resultP->X_add_symbol))
+ || right.X_add_symbol == resultP->X_add_symbol)
+ && frag_offset_fixed_p (symbol_get_frag (resultP->X_add_symbol),
+ symbol_get_frag (right.X_add_symbol),
+ &frag_off))
{
resultP->X_add_number -= right.X_add_number;
+ resultP->X_add_number -= frag_off / OCTETS_PER_BYTE;
resultP->X_add_number += (S_GET_VALUE (resultP->X_add_symbol)
- S_GET_VALUE (right.X_add_symbol));
resultP->X_op = O_constant;
case O_bit_or_not: resultP->X_add_number |= ~v; break;
case O_bit_exclusive_or: resultP->X_add_number ^= v; break;
case O_bit_and: resultP->X_add_number &= v; break;
- case O_add: resultP->X_add_number += v; break;
+ /* Constant + constant (O_add) is handled by the
+ previous if statement for constant + X, so is omitted
+ here. */
case O_subtract: resultP->X_add_number -= v; break;
case O_eq:
resultP->X_add_number =
valueT left, right;
segT seg_left, seg_right;
fragS *frag_left, *frag_right;
+ bfd_vma frag_off;
switch (op)
{
case O_symbol:
case O_symbol_rva:
- if (!snapshot_symbol (add_symbol, &left, &seg_left, &frag_left))
+ if (!snapshot_symbol (&add_symbol, &left, &seg_left, &frag_left))
return 0;
break;
case O_uminus:
case O_bit_not:
case O_logical_not:
- if (!snapshot_symbol (add_symbol, &left, &seg_left, &frag_left))
+ if (!snapshot_symbol (&add_symbol, &left, &seg_left, &frag_left))
return 0;
if (seg_left != absolute_section)
case O_gt:
case O_logical_and:
case O_logical_or:
- if (!snapshot_symbol (add_symbol, &left, &seg_left, &frag_left)
- || !snapshot_symbol (op_symbol, &right, &seg_right, &frag_right))
+ if (!snapshot_symbol (&add_symbol, &left, &seg_left, &frag_left)
+ || !snapshot_symbol (&op_symbol, &right, &seg_right, &frag_right))
return 0;
/* Simplify addition or subtraction of a constant by folding the
final_val += left;
left = right;
seg_left = seg_right;
- expressionP->X_add_symbol = expressionP->X_op_symbol;
+ add_symbol = op_symbol;
op = O_symbol;
break;
}
/* Equality and non-equality tests are permitted on anything.
Subtraction, and other comparison operators are permitted if
- both operands are in the same section. Otherwise, both
- operands must be absolute. We already handled the case of
- addition or subtraction of a constant above. */
+ both operands are in the same section.
+ Shifts by constant zero are permitted on anything.
+ Multiplies, bit-ors, and bit-ands with constant zero are
+ permitted on anything.
+ Multiplies and divides by constant one are permitted on
+ anything.
+ Binary operations with both operands being the same register
+ or undefined symbol are permitted if the result doesn't depend
+ on the input value.
+ Otherwise, both operands must be absolute. We already handled
+ the case of addition or subtraction of a constant above. */
+ frag_off = 0;
if (!(seg_left == absolute_section
&& seg_right == absolute_section)
&& !(op == O_eq || op == O_ne)
&& !((op == O_subtract
|| op == O_lt || op == O_le || op == O_ge || op == O_gt)
&& seg_left == seg_right
- && (finalize_syms || frag_left == frag_right)
- && ((seg_left != undefined_section
- && seg_left != reg_section)
- || add_symbol == op_symbol)))
- return 0;
+ && (finalize_syms
+ || frag_offset_fixed_p (frag_left, frag_right, &frag_off))
+ && (seg_left != reg_section || left == right)
+ && (seg_left != undefined_section || add_symbol == op_symbol)))
+ {
+ if ((seg_left == absolute_section && left == 0)
+ || (seg_right == absolute_section && right == 0))
+ {
+ if (op == O_bit_exclusive_or || op == O_bit_inclusive_or)
+ {
+ if (seg_right != absolute_section || right != 0)
+ {
+ seg_left = seg_right;
+ left = right;
+ add_symbol = op_symbol;
+ }
+ op = O_symbol;
+ break;
+ }
+ else if (op == O_left_shift || op == O_right_shift)
+ {
+ if (seg_left != absolute_section || left != 0)
+ {
+ op = O_symbol;
+ break;
+ }
+ }
+ else if (op != O_multiply
+ && op != O_bit_or_not && op != O_bit_and)
+ return 0;
+ }
+ else if (op == O_multiply
+ && seg_left == absolute_section && left == 1)
+ {
+ seg_left = seg_right;
+ left = right;
+ add_symbol = op_symbol;
+ op = O_symbol;
+ break;
+ }
+ else if ((op == O_multiply || op == O_divide)
+ && seg_right == absolute_section && right == 1)
+ {
+ op = O_symbol;
+ break;
+ }
+ else if (left != right
+ || ((seg_left != reg_section || seg_right != reg_section)
+ && (seg_left != undefined_section
+ || seg_right != undefined_section
+ || add_symbol != op_symbol)))
+ return 0;
+ else if (op == O_bit_and || op == O_bit_inclusive_or)
+ {
+ op = O_symbol;
+ break;
+ }
+ else if (op != O_bit_exclusive_or && op != O_bit_or_not)
+ return 0;
+ }
+ right += frag_off / OCTETS_PER_BYTE;
switch (op)
{
case O_add: left += right; break;
left = (left == right
&& seg_left == seg_right
&& (finalize_syms || frag_left == frag_right)
- && ((seg_left != undefined_section
- && seg_left != reg_section)
+ && (seg_left != undefined_section
|| add_symbol == op_symbol)
? ~ (valueT) 0 : 0);
if (op == O_ne)
op = O_constant;
else if (seg_left == reg_section && final_val == 0)
op = O_register;
+ else if (add_symbol != expressionP->X_add_symbol)
+ final_val += left;
+ expressionP->X_add_symbol = add_symbol;
}
expressionP->X_op = op;