/* expr.c -operands, expressions-
Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010, 2011
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
#endif
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 *, enum expr_mode);
-static operatorT operator (int *);
+static operatorT operatorf (int *);
extern const char EXP_CHARS[], FLT_CHARS[];
expressionS e;
current_location (&e);
- return make_expr_symbol (&e);
+ return symbol_clone_if_forward_ref (make_expr_symbol (&e));
}
\f
/* Build any floating-point literal here.
/* Return an expression representing the current location. This
handles the magic symbol `.'. */
-static void
+void
current_location (expressionS *expressionp)
{
if (now_seg == absolute_section)
else
{
expressionp->X_op = O_symbol;
- expressionp->X_add_symbol = symbol_temp_new_now ();
+ expressionp->X_add_symbol = &dot_symbol;
expressionp->X_add_number = 0;
}
}
#endif
case '(':
/* Didn't begin with digit & not a name. */
- if (mode != expr_defer)
- segment = expression (expressionP);
- else
- segment = deferred_expression (expressionP);
+ segment = expr (0, expressionP, mode);
/* expression () will pass trailing whitespace. */
if ((c == '(' && *input_line_pointer != ')')
|| (c == '[' && *input_line_pointer != ']'))
{
for (i = 0; i < expressionP->X_add_number; ++i)
generic_bignum[i] = ~generic_bignum[i];
+
+ /* Extend the bignum to at least the size of .octa. */
+ if (expressionP->X_add_number < SIZE_OF_LARGE_NUMBER)
+ {
+ expressionP->X_add_number = SIZE_OF_LARGE_NUMBER;
+ for (; i < expressionP->X_add_number; ++i)
+ generic_bignum[i] = ~(LITTLENUM_TYPE) 0;
+ }
+
if (c == '-')
for (i = 0; i < expressionP->X_add_number; ++i)
{
}
else if (c == '!')
{
- int nonzero = 0;
for (i = 0; i < expressionP->X_add_number; ++i)
- {
- if (generic_bignum[i])
- nonzero = 1;
- generic_bignum[i] = 0;
- }
- generic_bignum[0] = nonzero;
+ if (generic_bignum[i] != 0)
+ break;
+ expressionP->X_add_number = i >= expressionP->X_add_number;
+ expressionP->X_op = O_constant;
+ expressionP->X_unsigned = 1;
}
}
else if (expressionP->X_op != O_illegal
#ifdef md_operator
{
- operatorT operator = md_operator (name, 1, &c);
+ operatorT op = md_operator (name, 1, &c);
- switch (operator)
+ switch (op)
{
case O_uminus:
*input_line_pointer = c;
default:
break;
}
- if (operator != O_absent && operator != O_illegal)
+ if (op != O_absent && op != O_illegal)
{
*input_line_pointer = c;
expr (9, expressionP, mode);
expressionP->X_add_symbol = make_expr_symbol (expressionP);
expressionP->X_op_symbol = NULL;
expressionP->X_add_number = 0;
- expressionP->X_op = operator;
+ expressionP->X_op = op;
break;
}
}
/* If we have an absolute symbol or a reg, then we know its
value now. */
segment = S_GET_SEGMENT (symbolP);
- if (mode != expr_defer && segment == absolute_section)
+ if (mode != expr_defer
+ && segment == absolute_section
+ && !S_FORCE_RELOC (symbolP, 0))
{
expressionP->X_op = O_constant;
expressionP->X_add_number = S_GET_VALUE (symbolP);
if (expressionP->X_add_symbol)
symbol_mark_used (expressionP->X_add_symbol);
- expressionP->X_add_symbol = symbol_clone_if_forward_ref (expressionP->X_add_symbol);
- expressionP->X_op_symbol = symbol_clone_if_forward_ref (expressionP->X_op_symbol);
+ if (mode != expr_defer)
+ {
+ expressionP->X_add_symbol
+ = symbol_clone_if_forward_ref (expressionP->X_add_symbol);
+ expressionP->X_op_symbol
+ = symbol_clone_if_forward_ref (expressionP->X_op_symbol);
+ }
switch (expressionP->X_op)
{
}
void
-expr_set_rank (operatorT operator, operator_rankT rank)
+expr_set_rank (operatorT op, operator_rankT rank)
{
- gas_assert (operator >= O_md1 && operator < ARRAY_SIZE (op_rank));
- op_rank[operator] = rank;
+ gas_assert (op >= O_md1 && op < ARRAY_SIZE (op_rank));
+ op_rank[op] = rank;
}
/* Initialize the expression parser. */
Does not advance INPUT_LINE_POINTER. */
static inline operatorT
-operator (int *num_chars)
+operatorf (int *num_chars)
{
int c;
operatorT ret;
if (is_name_beginner (c))
{
char *name = input_line_pointer;
- char c = get_symbol_end ();
+ char ec = get_symbol_end ();
- ret = md_operator (name, 2, &c);
+ ret = md_operator (name, 2, &ec);
switch (ret)
{
case O_absent:
- *input_line_pointer = c;
+ *input_line_pointer = ec;
input_line_pointer = name;
break;
case O_uminus:
ret = O_illegal;
/* FALLTHROUGH */
default:
- *input_line_pointer = c;
+ *input_line_pointer = ec;
*num_chars = input_line_pointer - name;
input_line_pointer = name;
return ret;
/* operand () gobbles spaces. */
know (*input_line_pointer != ' ');
- op_left = operator (&op_chars);
+ op_left = operatorf (&op_chars);
while (op_left != O_illegal && op_rank[(int) op_left] > rank)
{
segT rightseg;
input_line_pointer += op_chars; /* -> after operator. */
+ right.X_md = 0;
rightseg = expr (op_rank[(int) op_left], &right, mode);
if (right.X_op == O_absent)
{
}
}
- op_right = operator (&op_chars);
+ op_right = operatorf (&op_chars);
know (op_right == O_illegal || op_left == O_index
|| op_rank[(int) op_right] <= op_rank[(int) op_left]);
#ifdef md_allow_local_subtract
&& md_allow_local_subtract (resultP, & right, rightseg)
#endif
- && (SEG_NORMAL (rightseg)
+ && ((SEG_NORMAL (rightseg)
+ && !S_FORCE_RELOC (resultP->X_add_symbol, 0)
+ && !S_FORCE_RELOC (right.X_add_symbol, 0))
|| 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),
else if (op_left == O_subtract)
{
resultP->X_add_number -= right.X_add_number;
- if (retval == rightseg && SEG_NORMAL (retval))
+ if (retval == rightseg
+ && SEG_NORMAL (retval)
+ && !S_FORCE_RELOC (resultP->X_add_symbol, 0)
+ && !S_FORCE_RELOC (right.X_add_symbol, 0))
{
retval = absolute_section;
rightseg = absolute_section;
if (retval != rightseg)
{
- if (! SEG_NORMAL (retval))
- {
- if (retval != undefined_section || SEG_NORMAL (rightseg))
- retval = rightseg;
- }
- else if (SEG_NORMAL (rightseg)
+ if (retval == undefined_section)
+ ;
+ else if (rightseg == undefined_section)
+ retval = rightseg;
+ else if (retval == expr_section)
+ ;
+ else if (rightseg == expr_section)
+ retval = rightseg;
+ else if (retval == reg_section)
+ ;
+ else if (rightseg == reg_section)
+ retval = rightseg;
+ else if (rightseg == absolute_section)
+ ;
+ else if (retval == absolute_section)
+ retval = rightseg;
#ifdef DIFF_EXPR_OK
- && op_left != O_subtract
+ else if (op_left == O_subtract)
+ ;
#endif
- )
+ else
as_bad (_("operation combines symbols in different segments"));
}
/* Help out with CSE. */
valueT final_val = expressionP->X_add_number;
symbolS *add_symbol = expressionP->X_add_symbol;
+ symbolS *orig_add_symbol = add_symbol;
symbolS *op_symbol = expressionP->X_op_symbol;
operatorT op = expressionP->X_op;
valueT left, right;
left = right;
seg_left = seg_right;
add_symbol = op_symbol;
+ orig_add_symbol = expressionP->X_op_symbol;
op = O_symbol;
break;
}
{
if (op == O_bit_exclusive_or || op == O_bit_inclusive_or)
{
- if (seg_right != absolute_section || right != 0)
+ if (!(seg_right == absolute_section && right == 0))
{
seg_left = seg_right;
left = right;
add_symbol = op_symbol;
+ orig_add_symbol = expressionP->X_op_symbol;
}
op = O_symbol;
break;
}
else if (op == O_left_shift || op == O_right_shift)
{
- if (seg_left != absolute_section || left != 0)
+ if (!(seg_left == absolute_section && left == 0))
{
op = O_symbol;
break;
seg_left = seg_right;
left = right;
add_symbol = op_symbol;
+ orig_add_symbol = expressionP->X_op_symbol;
op = O_symbol;
break;
}
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)))
+ 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_constant;
else if (seg_left == reg_section && final_val == 0)
op = O_register;
- else if (add_symbol != expressionP->X_add_symbol)
+ else if (!symbol_same_p (add_symbol, orig_add_symbol))
final_val += left;
expressionP->X_add_symbol = add_symbol;
}