+static segT operand (expressionS *, enum expr_mode);
+static operatorT operatorf (int *);
+
+/* 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;
+ const char *file;
+ unsigned int line;
+};
+
+static struct expr_symbol_line *expr_symbol_lines;
+\f
+/* Build a dummy symbol to hold a complex expression. This is how we
+ build expressions up out of other expressions. The symbol is put
+ into the fake section expr_section. */
+
+symbolS *
+make_expr_symbol (expressionS *expressionP)
+{
+ expressionS zero;
+ symbolS *symbolP;
+ struct expr_symbol_line *n;
+
+ if (expressionP->X_op == O_symbol
+ && expressionP->X_add_number == 0)
+ return expressionP->X_add_symbol;
+
+ 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. */
+ if (expressionP->X_add_number > 0)
+ as_bad (_("bignum invalid"));
+ else
+ as_bad (_("floating point number invalid"));
+ zero.X_op = O_constant;
+ zero.X_add_number = 0;
+ zero.X_unsigned = 0;
+ zero.X_extrabit = 0;
+ clean_up_expression (&zero);
+ expressionP = &zero;
+ }
+
+ /* 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_LABEL_NAME,
+ (expressionP->X_op == O_constant
+ ? absolute_section
+ : expressionP->X_op == O_register
+ ? reg_section
+ : expr_section),
+ 0, &zero_address_frag);
+ symbol_set_value_expression (symbolP, expressionP);
+
+ if (expressionP->X_op == O_constant)
+ resolve_symbol_value (symbolP);
+
+ n = XNEW (struct expr_symbol_line);
+ n->sym = symbolP;
+ n->file = as_where (&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 (symbolS *sym, const char **pfile, unsigned int *pline)
+{
+ 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;
+}
+\f
+/* 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 (offsetT value)
+{
+ expressionS e;
+
+ e.X_op = O_constant;
+ e.X_add_number = value;
+ e.X_unsigned = 1;
+ e.X_extrabit = 0;
+ return make_expr_symbol (&e);
+}
+
+/* Build an expression for the current location ('.'). */
+
+symbolS *
+expr_build_dot (void)
+{
+ expressionS e;
+
+ current_location (&e);
+ return symbol_clone_if_forward_ref (make_expr_symbol (&e));
+}
+\f
+/* Build any floating-point literal here.
+ Also build any bignum literal here. */
+