/* expr.c -operands, expressions-
- Copyright (C) 1987, 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+ Copyright (C) 1987, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 2000
+ Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with GAS; see the file COPYING. If not, write to
- the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+ along with GAS; see the file COPYING. If not, write to the Free
+ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA. */
/*
* This is really a branch office of as-read.c. I split it out to clearly
#include <ctype.h>
#include <string.h>
+#define min(a, b) ((a) < (b) ? (a) : (b))
#include "as.h"
-#include "libiberty.h"
#include "obstack.h"
static void floating_constant PARAMS ((expressionS * expressionP));
+static valueT generic_bignum_to_int32 PARAMS ((void));
+#ifdef BFD64
+static valueT generic_bignum_to_int64 PARAMS ((void));
+#endif
static void integer_constant PARAMS ((int radix, expressionS * expressionP));
static void mri_char_constant PARAMS ((expressionS *));
static void current_location PARAMS ((expressionS *));
static void clean_up_expression PARAMS ((expressionS * expressionP));
+static segT operand PARAMS ((expressionS *));
+static operatorT operator PARAMS ((void));
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 *next;
+ symbolS *sym;
+ 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
make_expr_symbol (expressionP)
expressionS *expressionP;
{
+ expressionS zero;
const char *fake;
symbolS *symbolP;
+ struct expr_symbol_line *n;
if (expressionP->X_op == O_symbol
&& expressionP->X_add_number == 0)
return expressionP->X_add_symbol;
- /* FIXME: This should be something which decode_local_label_name
- will handle. */
+ 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; zero assumed"));
+ else
+ as_bad (_("floating point number invalid; zero assumed"));
+ zero.X_op = O_constant;
+ zero.X_add_number = 0;
+ zero.X_unsigned = 0;
+ clean_up_expression (&zero);
+ expressionP = &zero;
+ }
+
fake = FAKE_LABEL_NAME;
/* Putting constant symbols in absolute_section rather than
? absolute_section
: expr_section),
0, &zero_address_frag);
- symbolP->sy_value = *expressionP;
+ symbol_set_value_expression (symbolP, expressionP);
if (expressionP->X_op == O_constant)
- resolve_symbol_value (symbolP);
+ resolve_symbol_value (symbolP, 1);
+
+ n = (struct expr_symbol_line *) xmalloc (sizeof *n);
+ n->sym = symbolP;
+ as_where (&n->file, &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 (sym, pfile, pline)
+ symbolS *sym;
+ char **pfile;
+ unsigned int *pline;
+{
+ register 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 (value)
+ offsetT value;
+{
+ expressionS e;
+
+ e.X_op = O_constant;
+ e.X_add_number = value;
+ e.X_unsigned = 1;
+ return make_expr_symbol (&e);
+}
+
+/* Build an expression for OP s1. */
+
+symbolS *
+expr_build_unary (op, s1)
+ operatorT op;
+ symbolS *s1;
+{
+ expressionS e;
+
+ e.X_op = op;
+ e.X_add_symbol = s1;
+ e.X_add_number = 0;
+ return make_expr_symbol (&e);
+}
+
+/* Build an expression for s1 OP s2. */
+
+symbolS *
+expr_build_binary (op, s1, s2)
+ operatorT op;
+ symbolS *s1;
+ symbolS *s2;
+{
+ expressionS e;
+
+ e.X_op = op;
+ e.X_add_symbol = s1;
+ e.X_op_symbol = s2;
+ e.X_add_number = 0;
+ return make_expr_symbol (&e);
+}
+
+/* Build an expression for the current location ('.'). */
+
+symbolS *
+expr_build_dot ()
+{
+ expressionS e;
+
+ current_location (&e);
+ return make_expr_symbol (&e);
+}
\f
/*
* Build any floating-point literal here.
{
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, probably assembling junk"));
}
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;
expressionP->X_add_number = -1;
}
+static valueT
+generic_bignum_to_int32 ()
+{
+ valueT number =
+ ((generic_bignum[1] & LITTLENUM_MASK) << LITTLENUM_NUMBER_OF_BITS)
+ | (generic_bignum[0] & LITTLENUM_MASK);
+ number &= 0xffffffff;
+ return number;
+}
+
+#ifdef BFD64
+static valueT
+generic_bignum_to_int64 ()
+{
+ valueT number =
+ ((((((((valueT) generic_bignum[3] & LITTLENUM_MASK)
+ << LITTLENUM_NUMBER_OF_BITS)
+ | ((valueT) generic_bignum[2] & LITTLENUM_MASK))
+ << LITTLENUM_NUMBER_OF_BITS)
+ | ((valueT) generic_bignum[1] & LITTLENUM_MASK))
+ << LITTLENUM_NUMBER_OF_BITS)
+ | ((valueT) generic_bignum[0] & LITTLENUM_MASK));
+ return number;
+}
+#endif
+
static void
integer_constant (radix, expressionP)
int radix;
#define valuesize 32
#endif
- if (flag_mri && radix == 0)
+ if ((NUMBERS_WITH_SUFFIX || flag_m68k_mri) && radix == 0)
{
int flt = 0;
/* 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 (*suffix); suffix++)
+ for (suffix = input_line_pointer;
+ isalnum ((unsigned char) *suffix);
+ suffix++)
{
if (*suffix == 'e' || *suffix == 'E')
flt = 1;
else
{
c = *--suffix;
- if (islower (c))
+ if (islower ((unsigned char) c))
c = toupper (c);
if (c == 'B')
radix = 2;
break;
case 10:
maxdig = radix = 10;
- too_many_digits = (valuesize + 12) / 4; /* very rough */
+ too_many_digits = (valuesize + 11) / 4; /* very rough */
}
#undef valuesize
start = input_line_pointer;
/* c contains character after number. */
/* input_line_pointer->char after c. */
small = (input_line_pointer - start - 1) < too_many_digits;
- if (!small)
+
+ if (radix == 16 && c == '_')
+ {
+ /* This is literal of the form 0x333_0_12345678_1.
+ This example is equivalent to 0x00000333000000001234567800000001. */
+
+ int num_little_digits = 0;
+ int i;
+ input_line_pointer = start; /*->1st digit. */
+
+ know (LITTLENUM_NUMBER_OF_BITS == 16);
+
+ for (c = '_'; c == '_'; num_little_digits+=2)
+ {
+
+ /* Convert one 64-bit word. */
+ int ndigit = 0;
+ number = 0;
+ for (c = *input_line_pointer++;
+ (digit = hex_value (c)) < maxdig;
+ c = *(input_line_pointer++))
+ {
+ number = number * radix + digit;
+ ndigit++;
+ }
+
+ /* 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."));
+
+ /* Add this chunk to the bignum. Shift things down 2 little digits.*/
+ know (LITTLENUM_NUMBER_OF_BITS == 16);
+ for (i = min (num_little_digits + 1, SIZE_OF_LARGE_NUMBER - 1); i >= 2; i--)
+ generic_bignum[i] = generic_bignum[i-2];
+
+ /* Add the new digits as the least significant new ones. */
+ generic_bignum[0] = number & 0xffffffff;
+ generic_bignum[1] = number >> 16;
+ }
+
+ /* Again, c is char after number, input_line_pointer->after c. */
+
+ if (num_little_digits > SIZE_OF_LARGE_NUMBER - 1)
+ num_little_digits = SIZE_OF_LARGE_NUMBER - 1;
+
+ assert (num_little_digits >= 4);
+
+ if (num_little_digits != 8)
+ 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.
+ */
+ while (generic_bignum[num_little_digits-1] == 0 && num_little_digits > 1)
+ num_little_digits--;
+
+ if (num_little_digits <= 2)
+ {
+ /* will fit into 32 bits. */
+ number = generic_bignum_to_int32 ();
+ small = 1;
+ }
+#ifdef BFD64
+ else if (num_little_digits <= 4)
+ {
+ /* Will fit into 64 bits. */
+ number = generic_bignum_to_int64 ();
+ small = 1;
+ }
+#endif
+ else
+ {
+ small = 0;
+ number = num_little_digits; /* number of littlenums in the bignum. */
+ }
+ }
+ else if (!small)
{
/*
* we saw a lot of digits. manufacture a bignum the hard way.
leader = generic_bignum;
generic_bignum[0] = 0;
generic_bignum[1] = 0;
+ generic_bignum[2] = 0;
+ generic_bignum[3] = 0;
input_line_pointer = start; /*->1st digit. */
c = *input_line_pointer++;
for (;
if (leader < generic_bignum + 2)
{
/* will fit into 32 bits. */
- number =
- ((generic_bignum[1] & LITTLENUM_MASK) << LITTLENUM_NUMBER_OF_BITS)
- | (generic_bignum[0] & LITTLENUM_MASK);
+ number = generic_bignum_to_int32 ();
small = 1;
}
+#ifdef BFD64
+ else if (leader < generic_bignum + 4)
+ {
+ /* Will fit into 64 bits. */
+ number = generic_bignum_to_int64 ();
+ small = 1;
+ }
+#endif
else
{
number = leader - generic_bignum + 1; /* number of littlenums in the bignum. */
}
}
- if (flag_mri && suffix != NULL && input_line_pointer - 1 == suffix)
+ if ((NUMBERS_WITH_SUFFIX || flag_m68k_mri)
+ && suffix != NULL
+ && input_line_pointer - 1 == suffix)
c = *input_line_pointer++;
if (small)
/* 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 (_("backw. ref to unknown label \"%d:\", 0 assumed."),
(int) number);
expressionP->X_op = O_constant;
}
if (i < 0)
{
- as_bad ("Character constant too large");
+ as_bad (_("Character constant too large"));
i = 0;
}
case '9':
input_line_pointer--;
- integer_constant (flag_mri ? 0 : 10, expressionP);
+ integer_constant ((NUMBERS_WITH_SUFFIX || flag_m68k_mri)
+ ? 0 : 10,
+ expressionP);
break;
case '0':
/* non-decimal radix */
- if (flag_mri)
+ if (NUMBERS_WITH_SUFFIX || flag_m68k_mri)
{
char *s;
integer_constant (0, expressionP);
break;
}
- }
-
+ }
c = *input_line_pointer;
switch (c)
{
+ case 'o':
+ case 'O':
+ case 'q':
+ case 'Q':
case '8':
case '9':
- if (flag_mri)
+ if (NUMBERS_WITH_SUFFIX || flag_m68k_mri)
{
integer_constant (0, expressionP);
break;
{
input_line_pointer++;
floating_constant (expressionP);
- expressionP->X_add_number = -(isupper (c) ? tolower (c) : c);
+ expressionP->X_add_number =
+ - (isupper ((unsigned char) c) ? tolower (c) : c);
}
else
{
case 'x':
case 'X':
- if (flag_mri)
+ if (flag_m68k_mri)
goto default_case;
input_line_pointer++;
integer_constant (16, expressionP);
break;
case 'b':
- if (LOCAL_LABELS_FB)
+ if (LOCAL_LABELS_FB && ! (flag_m68k_mri || NUMBERS_WITH_SUFFIX))
{
- switch (input_line_pointer[1])
+ /* This code used to check for '+' and '-' here, and, in
+ some conditions, fall through to call
+ integer_constant. However, that didn't make sense,
+ as integer_constant only accepts digits. */
+ /* Some of our code elsewhere does permit digits greater
+ than the expected base; for consistency, do the same
+ here. */
+ if (input_line_pointer[1] < '0'
+ || input_line_pointer[1] > '9')
{
- case '+':
- case '-':
- /* If unambiguously a difference expression, treat
- it as one by indicating a label; otherwise, it's
- always a binary number. */
- {
- char *cp = input_line_pointer + 1;
- while (strchr ("0123456789", *++cp))
- ;
- if (*cp == 'b' || *cp == 'f')
- goto is_0b_label;
- }
- goto is_0b_binary;
- case '0': case '1':
- /* Some of our code elsewhere does permit digits
- greater than the expected base; for consistency,
- do the same here. */
- case '2': case '3': case '4': case '5':
- case '6': case '7': case '8': case '9':
- goto is_0b_binary;
- case 0:
- goto is_0b_label;
- default:
- goto is_0b_label;
+ /* Parse this as a back reference to label 0. */
+ input_line_pointer--;
+ integer_constant (10, expressionP);
+ break;
}
- is_0b_label:
- input_line_pointer--;
- integer_constant (10, expressionP);
- break;
- is_0b_binary:
- ;
+ /* Otherwise, parse this as a binary number. */
}
+ /* Fall through. */
case 'B':
input_line_pointer++;
- if (flag_mri)
+ if (flag_m68k_mri || NUMBERS_WITH_SUFFIX)
goto default_case;
integer_constant (2, expressionP);
break;
case '5':
case '6':
case '7':
- integer_constant (flag_mri ? 0 : 8, expressionP);
+ integer_constant ((flag_m68k_mri || NUMBERS_WITH_SUFFIX)
+ ? 0 : 8,
+ expressionP);
break;
case 'f':
number, make it one. Otherwise, make it a local label,
and try to deal with parsing the rest later. */
if (!input_line_pointer[1]
- || (is_end_of_line[0xff & input_line_pointer[1]]))
+ || (is_end_of_line[0xff & input_line_pointer[1]])
+ || strchr (FLT_CHARS, 'f') == NULL)
goto is_0f_label;
{
char *cp = input_line_pointer + 1;
if (*cp == 'f' || *cp == 'b')
/* looks like a difference expression */
goto is_0f_label;
+ else if (cp == input_line_pointer + 1)
+ /* No characters has been accepted -- looks like
+ end of operand. */
+ goto is_0f_label;
else
goto is_0f_float;
default:
- as_fatal ("expr.c(operand): bad atof_generic return val %d",
+ as_fatal (_("expr.c(operand): bad atof_generic return val %d"),
r);
}
}
case 'd':
case 'D':
+ if (flag_m68k_mri || NUMBERS_WITH_SUFFIX)
+ {
+ integer_constant (0, expressionP);
+ break;
+ }
+ /* Fall through. */
case 'F':
case 'r':
case 'e':
case 'G':
input_line_pointer++;
floating_constant (expressionP);
- expressionP->X_add_number = -(isupper (c) ? tolower (c) : c);
+ expressionP->X_add_number =
+ - (isupper ((unsigned char) c) ? tolower (c) : c);
break;
case '$':
break;
case '(':
+#ifndef NEED_INDEX_OPERATOR
case '[':
+#endif
/* didn't begin with digit & not a name */
segment = expression (expressionP);
/* Expression() will pass trailing whitespace */
if ((c == '(' && *input_line_pointer++ != ')')
|| (c == '[' && *input_line_pointer++ != ']'))
{
- as_bad ("Missing ')' assumed");
+ as_bad (_("Missing ')' assumed"));
input_line_pointer--;
}
+ SKIP_WHITESPACE ();
/* here with input_line_pointer->char after "(...)" */
return segment;
+#ifdef TC_M68K
case 'E':
- if (! flag_mri || *input_line_pointer != '\'')
+ if (! flag_m68k_mri || *input_line_pointer != '\'')
goto de_fault;
- as_bad ("EBCDIC constants are not supported");
+ as_bad (_("EBCDIC constants are not supported"));
/* Fall through. */
case 'A':
- if (! flag_mri || *input_line_pointer != '\'')
+ if (! flag_m68k_mri || *input_line_pointer != '\'')
goto de_fault;
++input_line_pointer;
/* Fall through. */
+#endif
case '\'':
- if (! flag_mri)
+ if (! flag_m68k_mri)
{
/* Warning: to conform to other people's assemblers NO
ESCAPEMENT is permitted for a single quote. The next
(void) operand (expressionP);
break;
+#ifdef TC_M68K
case '"':
- /* Double quote is the logical not operator in MRI mode. */
- if (! flag_mri)
+ /* Double quote is the bitwise not operator in MRI mode. */
+ if (! flag_m68k_mri)
goto de_fault;
/* Fall through. */
+#endif
case '~':
+ /* ~ is permitted to start a label on the Delta. */
+ if (is_name_beginner (c))
+ goto isname;
+ case '!':
case '-':
{
operand (expressionP);
compatible with other people's assemblers. Sigh. */
expressionP->X_unsigned = 0;
}
- else
+ else if (c == '~' || c == '"')
expressionP->X_add_number = ~ expressionP->X_add_number;
+ else
+ expressionP->X_add_number = ! expressionP->X_add_number;
}
else if (expressionP->X_op != O_illegal
&& expressionP->X_op != O_absent)
expressionP->X_add_symbol = make_expr_symbol (expressionP);
if (c == '-')
expressionP->X_op = O_uminus;
- else
+ else if (c == '~' || c == '"')
expressionP->X_op = O_bit_not;
+ else
+ expressionP->X_op = O_logical_not;
expressionP->X_add_number = 0;
}
else
- as_warn ("Unary operator %c ignored because bad operand follows",
+ as_warn (_("Unary operator %c ignored because bad operand follows"),
c);
}
break;
+#if defined (DOLLAR_DOT) || defined (TC_M68K)
case '$':
/* $ is the program counter when in MRI mode, or when DOLLAR_DOT
is defined. */
#ifndef DOLLAR_DOT
- if (! flag_mri)
+ if (! flag_m68k_mri)
goto de_fault;
#endif
- if (flag_mri && hex_p (*input_line_pointer))
+ if (flag_m68k_mri && hex_p (*input_line_pointer))
{
/* In MRI mode, $ is also used as the prefix for a
hexadecimal constant. */
current_location (expressionP);
break;
+#endif
case '.':
if (!is_part_of_name (*input_line_pointer))
input_line_pointer += start ? 8 : 7;
SKIP_WHITESPACE ();
if (*input_line_pointer != '(')
- as_bad ("syntax error in .startof. or .sizeof.");
+ as_bad (_("syntax error in .startof. or .sizeof."));
else
{
char *buf;
*input_line_pointer = c;
SKIP_WHITESPACE ();
if (*input_line_pointer != ')')
- as_bad ("syntax error in .startof. or .sizeof.");
+ as_bad (_("syntax error in .startof. or .sizeof."));
else
++input_line_pointer;
}
input_line_pointer--;
break;
+#ifdef TC_M68K
case '%':
- if (! flag_mri)
+ if (! flag_m68k_mri)
goto de_fault;
integer_constant (2, expressionP);
break;
case '@':
- if (! flag_mri)
+ if (! flag_m68k_mri)
goto de_fault;
integer_constant (8, expressionP);
break;
case ':':
- if (! flag_mri)
+ if (! flag_m68k_mri)
goto de_fault;
/* In MRI mode, this is a floating point constant represented
break;
case '*':
- if (! flag_mri || is_part_of_name (*input_line_pointer))
+ if (! flag_m68k_mri || is_part_of_name (*input_line_pointer))
goto de_fault;
current_location (expressionP);
break;
+#endif
default:
+#ifdef TC_M68K
de_fault:
+#endif
if (is_end_of_line[(unsigned char) c])
goto eol;
if (is_name_beginner (c)) /* here if did not begin with a digit */
isname:
name = --input_line_pointer;
c = get_symbol_end ();
+
+#ifdef md_parse_name
+ /* This is a hook for the backend to parse certain names
+ 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))
+ {
+ *input_line_pointer = c;
+ break;
+ }
+#endif
+
+#ifdef TC_I960
+ /* The MRI i960 assembler permits
+ lda sizeof code,g13
+ FIXME: This should use md_parse_name. */
+ if (flag_mri
+ && (strcasecmp (name, "sizeof") == 0
+ || strcasecmp (name, "startof") == 0))
+ {
+ int start;
+ char *buf;
+
+ start = (name[1] == 't'
+ || name[1] == 'T');
+
+ *input_line_pointer = c;
+ SKIP_WHITESPACE ();
+
+ name = input_line_pointer;
+ c = get_symbol_end ();
+
+ buf = (char *) xmalloc (strlen (name) + 10);
+ if (start)
+ sprintf (buf, ".startof.%s", name);
+ else
+ sprintf (buf, ".sizeof.%s", name);
+ symbolP = symbol_make (buf);
+ free (buf);
+
+ expressionP->X_op = O_symbol;
+ expressionP->X_add_symbol = symbolP;
+ expressionP->X_add_number = 0;
+
+ *input_line_pointer = c;
+ SKIP_WHITESPACE ();
+
+ break;
+ }
+#endif
+
symbolP = symbol_find_or_make (name);
/* If we have an absolute symbol or a reg, then we know its
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;
}
/* The PA port needs this information. */
if (expressionP->X_add_symbol)
- expressionP->X_add_symbol->sy_used = 1;
+ symbol_mark_used (expressionP->X_add_symbol);
switch (expressionP->X_op)
{
break;
case O_subtract:
if (expressionP->X_op_symbol == expressionP->X_add_symbol
- || ((expressionP->X_op_symbol->sy_frag
- == expressionP->X_add_symbol->sy_frag)
+ || ((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))))
#undef __
#define __ O_illegal
-static operatorT op_encoding[256] =
+static const operatorT op_encoding[256] =
{ /* maps ASCII->operators */
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
__, __, __, __, __, __, __, __,
__, __, __, __, __, __, __, __,
__, __, __, __, __, __, __, __,
- __, __, __, __, __, __, O_bit_exclusive_or, __,
+ __, __, __,
+#ifdef NEED_INDEX_OPERATOR
+ O_index,
+#else
+ __,
+#endif
+ __, __, O_bit_exclusive_or, __,
__, __, __, __, __, __, __, __,
__, __, __, __, __, __, __, __,
__, __, __, __, __, __, __, __,
/*
* Rank Examples
* 0 operand, (expression)
- * 1 = <> < <= >= >
- * 2 + -
- * 3 used for * / % in MRI mode
- * 4 & ^ ! |
- * 5 * / % << >>
- * 6 unary - unary ~
+ * 1 ||
+ * 2 &&
+ * 3 = <> < <= >= >
+ * 4 + -
+ * 5 used for * / % in MRI mode
+ * 6 & ^ ! |
+ * 7 * / % << >>
+ * 8 unary - unary ~
*/
static operator_rankT op_rank[] =
{
0, /* O_absent */
0, /* O_constant */
0, /* O_symbol */
+ 0, /* O_symbol_rva */
0, /* O_register */
0, /* O_bit */
- 6, /* O_uminus */
- 6, /* O_bit_not */
- 5, /* O_multiply */
- 5, /* O_divide */
- 5, /* O_modulus */
- 5, /* O_left_shift */
- 5, /* O_right_shift */
- 4, /* O_bit_inclusive_or */
- 4, /* O_bit_or_not */
- 4, /* O_bit_exclusive_or */
- 4, /* O_bit_and */
- 2, /* O_add */
- 2, /* O_subtract */
- 1, /* O_eq */
- 1, /* O_ne */
- 1, /* O_lt */
- 1, /* O_le */
- 1, /* O_ge */
- 1 /* O_gt */
+ 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 */
};
-/* Initialize the expression parser. */
+/* 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 (7)
+#define MRI_MUL_PRECEDENCE (5)
void
-expr_begin ()
+expr_set_precedence ()
{
- /* In MRI mode, multiplication and division have lower precedence
- than the bit wise operators. */
- if (flag_mri)
+ 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] = 3;
- op_rank[O_divide] = 3;
- op_rank[O_modulus] = 3;
- op_encoding['"'] = O_bit_not;
+ 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 ()
+{
+ 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.
Advance INPUT_LINE_POINTER to the last character in the operator
int c;
operatorT ret;
- c = *input_line_pointer;
+ c = *input_line_pointer & 0xff;
switch (c)
{
++input_line_pointer;
return ret;
+ case '=':
+ if (input_line_pointer[1] != '=')
+ return op_encoding[c];
+
+ ++input_line_pointer;
+ return O_eq;
+
case '>':
switch (input_line_pointer[1])
{
/* We accept !! as equivalent to ^ for MRI compatibility. */
if (input_line_pointer[1] != '!')
{
- if (flag_mri)
+ if (flag_m68k_mri)
return O_bit_inclusive_or;
return op_encoding[c];
}
++input_line_pointer;
return O_bit_exclusive_or;
+
+ case '|':
+ if (input_line_pointer[1] != '|')
+ return op_encoding[c];
+
+ ++input_line_pointer;
+ return O_logical_or;
+
+ case '&':
+ if (input_line_pointer[1] != '&')
+ return op_encoding[c];
+
+ ++input_line_pointer;
+ return O_logical_and;
}
/*NOTREACHED*/
-}
+}
/* Parse an expression. */
segT
-expr (rank, resultP)
- operator_rankT rank; /* Larger # is higher rank. */
+expr (rankarg, resultP)
+ int rankarg; /* Larger # is higher rank. */
expressionS *resultP; /* Deliver result here. */
{
+ operator_rankT rank = (operator_rankT) rankarg;
segT retval;
expressionS right;
operatorT op_left;
rightseg = expr (op_rank[(int) op_left], &right);
if (right.X_op == O_absent)
{
- as_warn ("missing operand; zero assumed");
+ as_warn (_("missing operand; zero assumed"));
right.X_op = O_constant;
right.X_add_number = 0;
right.X_add_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 ();
+ }
+ }
+
if (retval == undefined_section)
{
if (SEG_NORMAL (rightseg))
&& op_left != O_subtract
#endif
)
- as_bad ("operation combines symbols in different segments");
+ as_bad (_("operation combines symbols in different segments"));
op_right = operator ();
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_gt);
+ 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 */
if (resultP->X_op == O_big)
{
- as_warn ("left operand is a %s; integer 0 assumed",
- resultP->X_add_number > 0 ? "bignum" : "float");
+ 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;
}
if (right.X_op == O_big)
{
- as_warn ("right operand is a %s; integer 0 assumed",
- right.X_add_number > 0 ? "bignum" : "float");
+ 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;
}
/* 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. */
else if (op_left == O_subtract
&& right.X_op == O_symbol
&& resultP->X_op == O_symbol
- && (right.X_add_symbol->sy_frag
- == resultP->X_add_symbol->sy_frag)
+ && (symbol_get_frag (right.X_add_symbol)
+ == symbol_get_frag (resultP->X_add_symbol))
&& SEG_NORMAL (S_GET_SEGMENT (right.X_add_symbol)))
{
- resultP->X_add_number += right.X_add_number;
+ 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;
offsetT v = right.X_add_number;
if (v == 0 && (op_left == O_divide || op_left == O_modulus))
{
- as_warn ("division by zero");
+ as_warn (_("division by zero"));
v = 1;
}
switch (op_left)
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: 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;
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
/* The PA port needs this information. */
if (resultP->X_add_symbol)
- resultP->X_add_symbol->sy_used = 1;
+ symbol_mark_used (resultP->X_add_symbol);
return resultP->X_op == O_constant ? absolute_section : retval;
}
/* We accept \001 in a name in case this is being called with a
constructed string. */
- while (is_part_of_name (c = *input_line_pointer++)
- || c == '\001')
- ;
+ if (is_name_beginner (c = *input_line_pointer++) || c == '\001')
+ {
+ while (is_part_of_name (c = *input_line_pointer++)
+ || c == '\001')
+ ;
+ if (is_name_ender (c))
+ c = *input_line_pointer++;
+ }
*--input_line_pointer = 0;
return (c);
}