+/* Expression parser. */
+
+/* We allow an empty expression, and just assume (absolute,0) silently.
+ Unary operators and parenthetical expressions are treated as operands.
+ As usual, Q==quantity==operand, O==operator, X==expression mnemonics.
+
+ 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)
+ or 1 symbol. Then "symbol+constant" and "symbol-symbol" are common.
+ So I guess it doesn't really matter how inefficient more complex expressions
+ are parsed.
+
+ After expr(RANK,resultP) input_line_pointer->operator of rank <= RANK.
+ Also, we have consumed any leading or trailing spaces (operand does that)
+ and done all intervening operators.
+
+ This returns the segment of the result, which will be
+ absolute_section or the segment of a symbol. */
+
+#undef __
+#define __ O_illegal
+
+/* 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, __,
+ __, __, __, __, __, __, __, __,
+ __, __, __, __, __, __, __, __,
+ __, __, __, __, __, __, __, __,
+ __, __, __,
+#ifdef NEED_INDEX_OPERATOR
+ O_index,
+#else
+ __,
+#endif
+ __, __, O_bit_exclusive_or, __,
+ __, __, __, __, __, __, __, __,
+ __, __, __, __, __, __, __, __,
+ __, __, __, __, __, __, __, __,
+ __, __, __, __, O_bit_inclusive_or, __, __, __,
+
+ __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+ __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+ __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+ __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+ __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+ __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+ __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
+ __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __
+};
+
+/* Rank Examples
+ 0 operand, (expression)
+ 1 ||
+ 2 &&
+ 3 == <> < <= >= >
+ 4 + -
+ 5 used for * / % in MRI mode
+ 6 & ^ ! |
+ 7 * / % << >>
+ 8 unary - unary ~
+*/
+static operator_rankT op_rank[] = {
+ 0, /* O_illegal */
+ 0, /* O_absent */
+ 0, /* O_constant */
+ 0, /* O_symbol */
+ 0, /* O_symbol_rva */
+ 0, /* O_register */
+ 0, /* O_big */
+ 9, /* O_uminus */
+ 9, /* O_bit_not */
+ 9, /* O_logical_not */
+ 8, /* O_multiply */
+ 8, /* O_divide */
+ 8, /* O_modulus */
+ 8, /* O_left_shift */
+ 8, /* O_right_shift */
+ 7, /* O_bit_inclusive_or */
+ 7, /* O_bit_or_not */
+ 7, /* O_bit_exclusive_or */
+ 7, /* O_bit_and */
+ 5, /* O_add */
+ 5, /* O_subtract */
+ 4, /* O_eq */
+ 4, /* O_ne */
+ 4, /* O_lt */
+ 4, /* O_le */
+ 4, /* O_ge */
+ 4, /* O_gt */
+ 3, /* O_logical_and */
+ 2, /* O_logical_or */
+ 1, /* O_index */
+ 0, /* O_md1 */
+ 0, /* O_md2 */
+ 0, /* O_md3 */
+ 0, /* O_md4 */
+ 0, /* O_md5 */
+ 0, /* O_md6 */
+ 0, /* O_md7 */
+ 0, /* O_md8 */
+ 0, /* O_md9 */
+ 0, /* O_md10 */
+ 0, /* O_md11 */
+ 0, /* O_md12 */
+ 0, /* O_md13 */
+ 0, /* O_md14 */
+ 0, /* O_md15 */
+ 0, /* O_md16 */
+};
+
+/* Unfortunately, in MRI mode for the m68k, multiplication and
+ division have lower precedence than the bit wise operators. This
+ function sets the operator precedences correctly for the current
+ mode. Also, MRI uses a different bit_not operator, and this fixes
+ that as well. */
+
+#define STANDARD_MUL_PRECEDENCE 8
+#define MRI_MUL_PRECEDENCE 6
+
+void
+expr_set_precedence (void)
+{
+ if (flag_m68k_mri)
+ {
+ op_rank[O_multiply] = MRI_MUL_PRECEDENCE;
+ op_rank[O_divide] = MRI_MUL_PRECEDENCE;
+ op_rank[O_modulus] = MRI_MUL_PRECEDENCE;
+ }
+ else
+ {
+ op_rank[O_multiply] = STANDARD_MUL_PRECEDENCE;
+ op_rank[O_divide] = STANDARD_MUL_PRECEDENCE;
+ op_rank[O_modulus] = STANDARD_MUL_PRECEDENCE;
+ }
+}
+
+/* Initialize the expression parser. */
+
+void
+expr_begin (void)
+{
+ expr_set_precedence ();
+
+ /* Verify that X_op field is wide enough. */
+ {
+ expressionS e;
+ e.X_op = O_max;
+ assert (e.X_op == O_max);
+ }
+}
+\f
+/* 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 (int *num_chars)
+{
+ int c;
+ operatorT ret;
+
+ c = *input_line_pointer & 0xff;
+ *num_chars = 1;
+
+ if (is_end_of_line[c])
+ return O_illegal;
+
+ switch (c)
+ {
+ 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])
+ {
+ default:
+ return op_encoding[c];
+ case '<':
+ ret = O_left_shift;
+ break;
+ case '>':
+ ret = O_ne;
+ break;
+ case '=':
+ ret = O_le;
+ break;
+ }
+ *num_chars = 2;
+ return ret;
+
+ case '=':
+ if (input_line_pointer[1] != '=')
+ return op_encoding[c];
+
+ *num_chars = 2;
+ return O_eq;
+
+ case '>':
+ switch (input_line_pointer[1])
+ {
+ default:
+ return op_encoding[c];
+ case '>':
+ ret = O_right_shift;
+ break;
+ case '=':
+ ret = O_ge;
+ break;
+ }
+ *num_chars = 2;
+ return ret;
+
+ case '!':
+ /* We accept !! as equivalent to ^ for MRI compatibility. */
+ if (input_line_pointer[1] != '!')
+ {
+ if (flag_m68k_mri)
+ return O_bit_inclusive_or;
+ return op_encoding[c];
+ }
+ *num_chars = 2;
+ return O_bit_exclusive_or;
+
+ case '|':
+ if (input_line_pointer[1] != '|')
+ return op_encoding[c];
+
+ *num_chars = 2;
+ return O_logical_or;
+
+ case '&':
+ if (input_line_pointer[1] != '&')
+ return op_encoding[c];
+
+ *num_chars = 2;
+ return O_logical_and;
+ }
+
+ /* NOTREACHED */
+}
+
+/* Parse an expression. */
+
+segT
+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_chars);
+ while (op_left != O_illegal && op_rank[(int) op_left] > rank)
+ {
+ segT rightseg;
+
+ input_line_pointer += op_chars; /* -> after operator. */
+
+ rightseg = expr (op_rank[(int) op_left], &right);
+ if (right.X_op == O_absent)
+ {
+ as_warn (_("missing operand; zero assumed"));
+ right.X_op = O_constant;
+ right.X_add_number = 0;
+ right.X_add_symbol = NULL;
+ right.X_op_symbol = NULL;
+ }
+
+ know (*input_line_pointer != ' ');
+
+ if (op_left == O_index)
+ {
+ if (*input_line_pointer != ']')
+ as_bad ("missing right bracket");
+ else
+ {
+ ++input_line_pointer;
+ SKIP_WHITESPACE ();
+ }
+ }
+
+ op_right = operator (&op_chars);
+
+ 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_logical_or);
+
+ /* input_line_pointer->after right-hand quantity. */
+ /* left-hand quantity in resultP. */
+ /* right-hand quantity in right. */
+ /* operator in op_left. */
+
+ if (resultP->X_op == O_big)
+ {
+ if (resultP->X_add_number > 0)
+ as_warn (_("left operand is a bignum; integer 0 assumed"));
+ else
+ as_warn (_("left operand is a float; integer 0 assumed"));
+ resultP->X_op = O_constant;
+ resultP->X_add_number = 0;
+ resultP->X_add_symbol = NULL;
+ resultP->X_op_symbol = NULL;
+ }
+ if (right.X_op == O_big)
+ {
+ if (right.X_add_number > 0)
+ as_warn (_("right operand is a bignum; integer 0 assumed"));
+ else
+ as_warn (_("right operand is a float; integer 0 assumed"));
+ right.X_op = O_constant;
+ right.X_add_number = 0;
+ right.X_add_symbol = NULL;
+ right.X_op_symbol = NULL;
+ }
+
+ /* Optimize common cases. */
+#ifdef md_optimize_expr
+ if (md_optimize_expr (resultP, op_left, &right))
+ {
+ /* Skip. */
+ ;
+ }
+ else
+#endif
+ if (op_left == O_add && right.X_op == O_constant)
+ {
+ /* X + constant. */
+ resultP->X_add_number += right.X_add_number;
+ }
+ /* This case comes up in PIC code. */
+ 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))
+ && (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)
+ - S_GET_VALUE (right.X_add_symbol));
+ resultP->X_op = O_constant;
+ resultP->X_add_symbol = 0;
+ }
+ else if (op_left == O_subtract && right.X_op == O_constant)
+ {
+ /* X - constant. */
+ resultP->X_add_number -= right.X_add_number;
+ }
+ else if (op_left == O_add && resultP->X_op == O_constant)
+ {
+ /* Constant + X. */
+ resultP->X_op = right.X_op;
+ resultP->X_add_symbol = right.X_add_symbol;
+ resultP->X_op_symbol = right.X_op_symbol;
+ resultP->X_add_number += right.X_add_number;
+ retval = rightseg;
+ }
+ else if (resultP->X_op == O_constant && right.X_op == O_constant)
+ {
+ /* Constant OP constant. */
+ offsetT v = right.X_add_number;
+ if (v == 0 && (op_left == O_divide || op_left == O_modulus))
+ {
+ as_warn (_("division by zero"));
+ v = 1;
+ }
+ switch (op_left)
+ {
+ default: abort ();
+ case O_multiply: resultP->X_add_number *= v; break;
+ 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:
+ /* 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;
+ case O_bit_and: resultP->X_add_number &= v; break;
+ case O_add: resultP->X_add_number += v; break;
+ case O_subtract: resultP->X_add_number -= v; break;
+ case O_eq:
+ resultP->X_add_number =
+ resultP->X_add_number == v ? ~ (offsetT) 0 : 0;
+ break;
+ case O_ne:
+ resultP->X_add_number =
+ resultP->X_add_number != v ? ~ (offsetT) 0 : 0;
+ break;
+ case O_lt:
+ resultP->X_add_number =
+ resultP->X_add_number < v ? ~ (offsetT) 0 : 0;
+ break;
+ case O_le:
+ resultP->X_add_number =
+ resultP->X_add_number <= v ? ~ (offsetT) 0 : 0;
+ break;
+ case O_ge:
+ resultP->X_add_number =
+ resultP->X_add_number >= v ? ~ (offsetT) 0 : 0;
+ break;
+ case O_gt:
+ 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
+ && right.X_op == O_symbol
+ && (op_left == O_add
+ || op_left == O_subtract
+ || (resultP->X_add_number == 0
+ && right.X_add_number == 0)))
+ {
+ /* Symbol OP symbol. */
+ resultP->X_op = op_left;
+ resultP->X_op_symbol = right.X_add_symbol;
+ 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;
+ if (retval == rightseg && SEG_NORMAL (retval))
+ {
+ retval = absolute_section;
+ rightseg = absolute_section;
+ }
+ }
+ }
+ else
+ {
+ /* The general case. */
+ resultP->X_add_symbol = make_expr_symbol (resultP);
+ resultP->X_op_symbol = make_expr_symbol (&right);
+ resultP->X_op = op_left;
+ resultP->X_add_number = 0;
+ 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. */
+
+ /* The PA port needs this information. */
+ if (resultP->X_add_symbol)
+ symbol_mark_used (resultP->X_add_symbol);
+
+ return resultP->X_op == O_constant ? absolute_section : retval;
+}
+\f
+/* This lives here because it belongs equally in expr.c & read.c.
+ expr.c is just a branch office read.c anyway, and putting it
+ here lessens the crowd at read.c.
+
+ Assume input_line_pointer is at start of symbol name.
+ Advance input_line_pointer past symbol name.
+ Turn that character into a '\0', returning its former value.
+ This allows a string compare (RMS wants symbol names to be strings)
+ of the symbol name.
+ There will always be a char following symbol name, because all good
+ lines end in end-of-line. */
+