/* expr.c -operands, expressions-
- Copyright (C) 1987, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 2000
+ Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+ 1999, 2000, 2001, 2002
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
(It also gives smaller files to re-compile.)
Here, "operand"s are of expressions, not instructions. */
-#include <ctype.h>
#include <string.h>
#define min(a, b) ((a) < (b) ? (a) : (b))
#include "as.h"
+#include "safe-ctype.h"
#include "obstack.h"
static void floating_constant PARAMS ((expressionS * expressionP));
static void current_location PARAMS ((expressionS *));
static void clean_up_expression PARAMS ((expressionS * expressionP));
static segT operand PARAMS ((expressionS *));
-static operatorT operator PARAMS ((void));
+static operatorT operator PARAMS ((int *));
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 {
struct expr_symbol_line *next;
symbolS *sym;
char *file;
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; zero assumed"));
+ as_bad (_("bignum invalid"));
else
- as_bad (_("floating point number invalid; zero assumed"));
+ as_bad (_("floating point number invalid"));
zero.X_op = O_constant;
zero.X_add_number = 0;
zero.X_unsigned = 0;
symbol_set_value_expression (symbolP, expressionP);
if (expressionP->X_op == O_constant)
- resolve_symbol_value (symbolP, 1);
+ resolve_symbol_value (symbolP);
n = (struct expr_symbol_line *) xmalloc (sizeof *n);
n->sym = symbolP;
and never write into the early words, thus they'll always be zero.
I hate Dean's floating-point code. Bleh. */
LITTLENUM_TYPE generic_bignum[SIZE_OF_LARGE_NUMBER + 6];
-FLONUM_TYPE generic_floating_point_number =
-{
- &generic_bignum[6], /* Low. (JF: Was 0) */
- &generic_bignum[SIZE_OF_LARGE_NUMBER + 6 - 1], /* High. JF: (added +6) */
- 0, /* Leader. */
- 0, /* Exponent. */
- 0 /* Sign. */
+
+FLONUM_TYPE generic_floating_point_number = {
+ &generic_bignum[6], /* low. (JF: Was 0) */
+ &generic_bignum[SIZE_OF_LARGE_NUMBER + 6 - 1], /* high. JF: (added +6) */
+ 0, /* leader. */
+ 0, /* exponent. */
+ 0 /* sign. */
};
/* If nonzero, we've been asked to assemble nan, +inf or -inf. */
{
if (error_code == ERROR_EXPONENT_OVERFLOW)
{
- as_bad (_("bad floating-point constant: exponent overflow, probably assembling junk"));
+ as_bad (_("bad floating-point constant: exponent overflow"));
}
else
{
- as_bad (_("bad floating-point constant: unknown error code=%d."), error_code);
+ as_bad (_("bad floating-point constant: unknown error code=%d"),
+ error_code);
}
}
expressionP->X_op = O_big;
/* 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 ((unsigned char) *suffix);
- suffix++)
+ for (suffix = input_line_pointer; ISALNUM (*suffix); suffix++)
{
if (*suffix == 'e' || *suffix == 'E')
flt = 1;
else
{
c = *--suffix;
- if (islower ((unsigned char) c))
- c = toupper (c);
+ c = TOUPPER (c);
if (c == 'B')
radix = 2;
else if (c == 'D')
/* Check for 8 digit per word max. */
if (ndigit > 8)
- as_bad (_("A bignum with underscores may not have more than 8 hex digits in any word."));
+ as_bad (_("a 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. */
assert (num_little_digits >= 4);
if (num_little_digits != 8)
- as_bad (_("A bignum with underscores must have exactly 4 words."));
+ 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. */
/* Either not seen or not defined. */
/* @@ Should print out the original string instead of
the parsed number. */
- as_bad (_("backw. ref to unknown label \"%d:\", 0 assumed."),
+ as_bad (_("backward ref to unknown label \"%d:\""),
(int) number);
expressionP->X_op = O_constant;
}
number |= (-(number >> (TARGET_WORD_SIZE - 1))) << (TARGET_WORD_SIZE - 1);
#endif
expressionP->X_add_number = number;
- input_line_pointer--; /* Rstore following character. */
+ input_line_pointer--; /* Restore following character. */
} /* Really just a number. */
}
else
{
- /* not a small number */
+ /* Not a small number. */
expressionP->X_op = O_big;
expressionP->X_add_number = number; /* Number of littlenums. */
input_line_pointer--; /* -> char following number. */
if (i < 0)
{
- as_bad (_("Character constant too large"));
+ as_bad (_("character constant too large"));
i = 0;
}
/* In: Input_line_pointer points to 1st char of operand, which may
be a space.
- Out: A expressionS.
+ Out: An expressionS.
The operand may have been empty: in this case X_op == O_absent.
Input_line_pointer->(next non-blank) char after operand. */
/* Digits, assume it is a bignum. */
SKIP_WHITESPACE (); /* Leading whitespace is part of operand. */
- c = *input_line_pointer++; /* input_line_pointer->past char in c. */
+ c = *input_line_pointer++; /* input_line_pointer -> past char in c. */
if (is_end_of_line[(unsigned char) c])
goto eol;
integer_constant ((NUMBERS_WITH_SUFFIX || flag_m68k_mri)
? 0 : 10,
- expressionP);
+ expressionP);
break;
#ifdef LITERAL_PREFIXDOLLAR_HEX
case '$':
+ /* $L is the start of a local label, not a hex constant. */
+ if (* input_line_pointer == 'L')
+ goto isname;
integer_constant (16, expressionP);
break;
#endif
{
input_line_pointer++;
floating_constant (expressionP);
- expressionP->X_add_number =
- -(isupper ((unsigned char) c) ? tolower (c) : c);
+ expressionP->X_add_number = - TOLOWER (c);
}
else
{
case 'G':
input_line_pointer++;
floating_constant (expressionP);
- expressionP->X_add_number =
- -(isupper ((unsigned char) c) ? tolower (c) : c);
+ expressionP->X_add_number = - TOLOWER (c);
break;
case '$':
#ifdef RELAX_PAREN_GROUPING
if (c != '(')
#endif
- as_bad (_("Missing '%c' assumed"), c == '(' ? ')' : ']');
+ as_bad (_("missing '%c'"), c == '(' ? ')' : ']');
}
else
input_line_pointer++;
/* input_line_pointer -> char after operand. */
if (c == '-')
{
- expressionP->X_add_number = -expressionP->X_add_number;
+ expressionP->X_add_number = - expressionP->X_add_number;
/* Notice: '-' may overflow: no warning is given.
This is compatible with other people's
assemblers. Sigh. */
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))
+ if (md_parse_name (name, expressionP, &c))
{
*input_line_pointer = c;
break;
{
/* 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 passed the expression. If it can't parse the
+ input_line_pointer past the expression. If it can't parse the
expression, X_op and input_line_pointer should be unchanged. */
expressionP->X_op = O_absent;
--input_line_pointer;
if (expressionP->X_op == O_absent)
{
++input_line_pointer;
- as_bad (_("Bad expression"));
+ as_bad (_("bad expression"));
expressionP->X_op = O_constant;
expressionP->X_add_number = 0;
}
\f
/* Internal. Simplify a struct expression for use by expr (). */
-/* In: address of a expressionS.
+/* In: address of an expressionS.
The X_op field of the expressionS may only take certain values.
Elsewise we waste time special-case testing. Sigh. Ditto SEG_ABSENT.
if (expressionP->X_op_symbol == expressionP->X_add_symbol
|| ((symbol_get_frag (expressionP->X_op_symbol)
== symbol_get_frag (expressionP->X_add_symbol))
- && SEG_NORMAL (S_GET_SEGMENT (expressionP->X_add_symbol))
- && (S_GET_VALUE (expressionP->X_op_symbol)
- == S_GET_VALUE (expressionP->X_add_symbol))))
+ && SEG_NORMAL (S_GET_SEGMENT (expressionP->X_add_symbol))))
{
addressT diff = (S_GET_VALUE (expressionP->X_add_symbol)
- S_GET_VALUE (expressionP->X_op_symbol));
Unary operators and parenthetical expressions are treated as operands.
As usual, Q==quantity==operand, O==operator, X==expression mnemonics.
- We used to do a aho/ullman shift-reduce parser, but the logic got so
+ 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)
#undef __
#define __ O_illegal
-static const operatorT op_encoding[256] =
-{ /* Maps ASCII -> operators. */
-
+/* Maps ASCII -> operators. */
+static const operatorT op_encoding[256] = {
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
0 operand, (expression)
1 ||
2 &&
- 3 = <> < <= >= >
+ 3 == <> < <= >= >
4 + -
5 used for * / % in MRI mode
6 & ^ ! |
7 * / % << >>
8 unary - unary ~
*/
-static operator_rankT op_rank[] =
-{
+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_bit */
+ 0, /* O_big */
9, /* O_uminus */
9, /* O_bit_not */
9, /* O_logical_not */
mode. Also, MRI uses a different bit_not operator, and this fixes
that as well. */
-#define STANDARD_MUL_PRECEDENCE (7)
-#define MRI_MUL_PRECEDENCE (5)
+#define STANDARD_MUL_PRECEDENCE 8
+#define MRI_MUL_PRECEDENCE 6
void
expr_set_precedence ()
}
}
\f
-/* Return the encoding for the operator at INPUT_LINE_POINTER.
- Advance INPUT_LINE_POINTER to the last character in the operator
- (i.e., don't change it for a single character operator). */
+/* 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 ()
+operator (num_chars)
+ int *num_chars;
{
int c;
operatorT ret;
c = *input_line_pointer & 0xff;
+ *num_chars = 1;
if (is_end_of_line[c])
return O_illegal;
ret = O_le;
break;
}
- ++input_line_pointer;
+ *num_chars = 2;
return ret;
case '=':
if (input_line_pointer[1] != '=')
return op_encoding[c];
- ++input_line_pointer;
+ *num_chars = 2;
return O_eq;
case '>':
ret = O_ge;
break;
}
- ++input_line_pointer;
+ *num_chars = 2;
return ret;
case '!':
return O_bit_inclusive_or;
return op_encoding[c];
}
- ++input_line_pointer;
+ *num_chars = 2;
return O_bit_exclusive_or;
case '|':
if (input_line_pointer[1] != '|')
return op_encoding[c];
- ++input_line_pointer;
+ *num_chars = 2;
return O_logical_or;
case '&':
if (input_line_pointer[1] != '&')
return op_encoding[c];
- ++input_line_pointer;
+ *num_chars = 2;
return O_logical_and;
}
expressionS right;
operatorT op_left;
operatorT op_right;
+ int op_chars;
know (rank >= 0);
/* operand () gobbles spaces. */
know (*input_line_pointer != ' ');
- op_left = operator ();
+ op_left = operator (&op_chars);
while (op_left != O_illegal && op_rank[(int) op_left] > rank)
{
segT rightseg;
- input_line_pointer++; /* -> after 1st character of operator. */
+ input_line_pointer += op_chars; /* -> after operator. */
rightseg = expr (op_rank[(int) op_left], &right);
if (right.X_op == O_absent)
}
}
- if (retval == undefined_section)
- {
- if (SEG_NORMAL (rightseg))
- retval = rightseg;
- }
- else if (! SEG_NORMAL (retval))
- retval = rightseg;
- else if (SEG_NORMAL (rightseg)
- && retval != rightseg
-#ifdef DIFF_EXPR_OK
- && op_left != O_subtract
-#endif
- )
- as_bad (_("operation combines symbols in different segments"));
-
- op_right = operator ();
+ op_right = operator (&op_chars);
know (op_right == O_illegal
|| op_rank[(int) op_right] <= op_rank[(int) op_left]);
&& resultP->X_op == O_symbol
&& (symbol_get_frag (right.X_add_symbol)
== symbol_get_frag (resultP->X_add_symbol))
- && SEG_NORMAL (S_GET_SEGMENT (right.X_add_symbol)))
-
+ && SEG_NORMAL (rightseg))
{
resultP->X_add_number -= right.X_add_number;
resultP->X_add_number += (S_GET_VALUE (resultP->X_add_symbol)
case O_subtract: resultP->X_add_number -= v; break;
case O_eq:
resultP->X_add_number =
- resultP->X_add_number == v ? ~(offsetT) 0 : 0;
+ resultP->X_add_number == v ? ~ (offsetT) 0 : 0;
break;
case O_ne:
resultP->X_add_number =
- resultP->X_add_number != v ? ~(offsetT) 0 : 0;
+ resultP->X_add_number != v ? ~ (offsetT) 0 : 0;
break;
case O_lt:
resultP->X_add_number =
- resultP->X_add_number < v ? ~(offsetT) 0 : 0;
+ resultP->X_add_number < v ? ~ (offsetT) 0 : 0;
break;
case O_le:
resultP->X_add_number =
- resultP->X_add_number <= v ? ~(offsetT) 0 : 0;
+ resultP->X_add_number <= v ? ~ (offsetT) 0 : 0;
break;
case O_ge:
resultP->X_add_number =
- resultP->X_add_number >= v ? ~(offsetT) 0 : 0;
+ resultP->X_add_number >= v ? ~ (offsetT) 0 : 0;
break;
case O_gt:
resultP->X_add_number =
- resultP->X_add_number > v ? ~(offsetT) 0 : 0;
+ resultP->X_add_number > v ? ~ (offsetT) 0 : 0;
break;
case O_logical_and:
resultP->X_add_number = resultP->X_add_number && v;
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;
+ {
+ resultP->X_add_number -= right.X_add_number;
+ if (retval == rightseg && SEG_NORMAL (retval))
+ {
+ retval = absolute_section;
+ rightseg = absolute_section;
+ }
+ }
}
else
{
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. */