#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 (expressionS * expressionP);
static valueT generic_bignum_to_int32 (void);
#ifdef BFD64
static valueT generic_bignum_to_int64 (void);
#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 *);
static operatorT operator (int *);
extern const char EXP_CHARS[], FLT_CHARS[];
struct expr_symbol_line {
struct expr_symbol_line *next;
symbolS *sym;
char *file;
unsigned int line;
};
static struct expr_symbol_line *expr_symbol_lines;
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)
{
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;
clean_up_expression (&zero);
expressionP = &zero;
}
symbolP = symbol_create (FAKE_LABEL_NAME,
(expressionP->X_op == O_constant
? absolute_section
: expr_section),
0, &zero_address_frag);
symbol_set_value_expression (symbolP, expressionP);
if (expressionP->X_op == O_constant)
resolve_symbol_value (symbolP);
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;
}
int
expr_symbol_where (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;
}
symbolS *
expr_build_uconstant (offsetT value)
{
expressionS e;
e.X_op = O_constant;
e.X_add_number = value;
e.X_unsigned = 1;
return make_expr_symbol (&e);
}
symbolS *
expr_build_unary (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);
}
symbolS *
expr_build_binary (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);
}
symbolS *
expr_build_dot (void)
{
expressionS e;
current_location (&e);
return make_expr_symbol (&e);
}
LITTLENUM_TYPE generic_bignum[SIZE_OF_LARGE_NUMBER + 6];
FLONUM_TYPE generic_floating_point_number = {
&generic_bignum[6],
&generic_bignum[SIZE_OF_LARGE_NUMBER + 6 - 1],
0,
0,
0
};
int generic_floating_point_magic;
static void
floating_constant (expressionS *expressionP)
{
int error_code;
error_code = atof_generic (&input_line_pointer, ".", EXP_CHARS,
&generic_floating_point_number);
if (error_code)
{
if (error_code == ERROR_EXPONENT_OVERFLOW)
{
as_bad (_("bad floating-point constant: exponent overflow"));
}
else
{
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 (void)
{
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 (void)
{
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 (int radix, expressionS *expressionP)
{
char *start;
char *suffix = NULL;
char c;
valueT number;
short int digit;
short int maxdig = 0;
int too_many_digits = 0;
char *name;
symbolS *symbolP;
int small;
#ifdef BFD64
#define valuesize 64
#else
#define valuesize 32
#endif
if ((NUMBERS_WITH_SUFFIX || flag_m68k_mri) && radix == 0)
{
int flt = 0;
for (suffix = input_line_pointer; ISALNUM (*suffix); suffix++)
{
if (*suffix == 'e' || *suffix == 'E')
flt = 1;
}
if (suffix == input_line_pointer)
{
radix = 10;
suffix = NULL;
}
else
{
c = *--suffix;
c = TOUPPER (c);
if (c == 'B')
radix = 2;
else if (c == 'D')
radix = 10;
else if (c == 'O' || c == 'Q')
radix = 8;
else if (c == 'H')
radix = 16;
else if (suffix[1] == '.' || c == 'E' || flt)
{
floating_constant (expressionP);
return;
}
else
{
radix = 10;
suffix = NULL;
}
}
}
switch (radix)
{
case 2:
maxdig = 2;
too_many_digits = valuesize + 1;
break;
case 8:
maxdig = radix = 8;
too_many_digits = (valuesize + 2) / 3 + 1;
break;
case 16:
maxdig = radix = 16;
too_many_digits = (valuesize + 3) / 4 + 1;
break;
case 10:
maxdig = radix = 10;
too_many_digits = (valuesize + 11) / 4;
}
#undef valuesize
start = input_line_pointer;
c = *input_line_pointer++;
for (number = 0;
(digit = hex_value (c)) < maxdig;
c = *input_line_pointer++)
{
number = number * radix + digit;
}
small = (input_line_pointer - start - 1) < too_many_digits;
if (radix == 16 && c == '_')
{
int num_little_digits = 0;
int i;
input_line_pointer = start;
know (LITTLENUM_NUMBER_OF_BITS == 16);
for (c = '_'; c == '_'; num_little_digits += 2)
{
int ndigit = 0;
number = 0;
for (c = *input_line_pointer++;
(digit = hex_value (c)) < maxdig;
c = *(input_line_pointer++))
{
number = number * radix + digit;
ndigit++;
}
if (ndigit > 8)
as_bad (_("a bignum with underscores may not have more than 8 hex digits in any word"));
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];
generic_bignum[0] = number & 0xffffffff;
generic_bignum[1] = number >> 16;
}
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"));
while (generic_bignum[num_little_digits - 1] == 0
&& num_little_digits > 1)
num_little_digits--;
if (num_little_digits <= 2)
{
number = generic_bignum_to_int32 ();
small = 1;
}
#ifdef BFD64
else if (num_little_digits <= 4)
{
number = generic_bignum_to_int64 ();
small = 1;
}
#endif
else
{
small = 0;
number = num_little_digits;
}
}
else if (!small)
{
LITTLENUM_TYPE *leader;
LITTLENUM_TYPE *pointer;
long carry;
leader = generic_bignum;
generic_bignum[0] = 0;
generic_bignum[1] = 0;
generic_bignum[2] = 0;
generic_bignum[3] = 0;
input_line_pointer = start;
c = *input_line_pointer++;
for (; (carry = hex_value (c)) < maxdig; c = *input_line_pointer++)
{
for (pointer = generic_bignum; pointer <= leader; pointer++)
{
long work;
work = carry + radix * *pointer;
*pointer = work & LITTLENUM_MASK;
carry = work >> LITTLENUM_NUMBER_OF_BITS;
}
if (carry)
{
if (leader < generic_bignum + SIZE_OF_LARGE_NUMBER - 1)
{
*++leader = carry;
}
}
}
know (LITTLENUM_NUMBER_OF_BITS == 16);
if (leader < generic_bignum + 2)
{
number = generic_bignum_to_int32 ();
small = 1;
}
#ifdef BFD64
else if (leader < generic_bignum + 4)
{
number = generic_bignum_to_int64 ();
small = 1;
}
#endif
else
{
number = leader - generic_bignum + 1;
}
}
if ((NUMBERS_WITH_SUFFIX || flag_m68k_mri)
&& suffix != NULL
&& input_line_pointer - 1 == suffix)
c = *input_line_pointer++;
if (small)
{
if (LOCAL_LABELS_FB && c == 'b')
{
name = fb_label_name ((int) number, 0);
symbolP = symbol_find (name);
if ((symbolP != NULL) && (S_IS_DEFINED (symbolP)))
{
know (SEG_NORMAL (S_GET_SEGMENT (symbolP)));
expressionP->X_op = O_symbol;
expressionP->X_add_symbol = symbolP;
}
else
{
as_bad (_("backward ref to unknown label \"%d:\""),
(int) number);
expressionP->X_op = O_constant;
}
expressionP->X_add_number = 0;
}
else if (LOCAL_LABELS_FB && c == 'f')
{
name = fb_label_name ((int) number, 1);
symbolP = symbol_find_or_make (name);
#ifndef many_segments
know (S_GET_SEGMENT (symbolP) == undefined_section || S_GET_SEGMENT (symbolP) == text_section || S_GET_SEGMENT (symbolP) == data_section);
#endif
expressionP->X_op = O_symbol;
expressionP->X_add_symbol = symbolP;
expressionP->X_add_number = 0;
}
else if (LOCAL_LABELS_DOLLAR && c == '$')
{
if (dollar_label_defined ((long) number))
{
name = dollar_label_name ((long) number, 0);
symbolP = symbol_find (name);
know (symbolP != NULL);
}
else
{
name = dollar_label_name ((long) number, 1);
symbolP = symbol_find_or_make (name);
}
expressionP->X_op = O_symbol;
expressionP->X_add_symbol = symbolP;
expressionP->X_add_number = 0;
}
else
{
expressionP->X_op = O_constant;
#ifdef TARGET_WORD_SIZE
number |= (-(number >> (TARGET_WORD_SIZE - 1))) << (TARGET_WORD_SIZE - 1);
#endif
expressionP->X_add_number = number;
input_line_pointer--;
}
}
else
{
expressionP->X_op = O_big;
expressionP->X_add_number = number;
input_line_pointer--;
}
}
static void
mri_char_constant (expressionS *expressionP)
{
int i;
if (*input_line_pointer == '\''
&& input_line_pointer[1] != '\'')
{
expressionP->X_op = O_constant;
expressionP->X_add_number = 0;
return;
}
for (i = SIZE_OF_LARGE_NUMBER - 1; i >= 0; i--)
{
int j;
generic_bignum[i] = 0;
for (j = 0; j < CHARS_PER_LITTLENUM; j++)
{
if (*input_line_pointer == '\'')
{
if (input_line_pointer[1] != '\'')
break;
++input_line_pointer;
}
generic_bignum[i] <<= 8;
generic_bignum[i] += *input_line_pointer;
++input_line_pointer;
}
if (i < SIZE_OF_LARGE_NUMBER - 1)
{
for (; j < CHARS_PER_LITTLENUM; j++)
generic_bignum[i] <<= 8;
}
if (*input_line_pointer == '\''
&& input_line_pointer[1] != '\'')
break;
}
if (i < 0)
{
as_bad (_("character constant too large"));
i = 0;
}
if (i > 0)
{
int c;
int j;
c = SIZE_OF_LARGE_NUMBER - i;
for (j = 0; j < c; j++)
generic_bignum[j] = generic_bignum[i + j];
i = c;
}
know (LITTLENUM_NUMBER_OF_BITS == 16);
if (i > 2)
{
expressionP->X_op = O_big;
expressionP->X_add_number = i;
}
else
{
expressionP->X_op = O_constant;
if (i < 2)
expressionP->X_add_number = generic_bignum[0] & LITTLENUM_MASK;
else
expressionP->X_add_number =
(((generic_bignum[1] & LITTLENUM_MASK)
<< LITTLENUM_NUMBER_OF_BITS)
| (generic_bignum[0] & LITTLENUM_MASK));
}
++input_line_pointer;
}
static void
current_location (expressionS *expressionp)
{
if (now_seg == absolute_section)
{
expressionp->X_op = O_constant;
expressionp->X_add_number = abs_section_offset;
}
else
{
expressionp->X_op = O_symbol;
expressionp->X_add_symbol = symbol_temp_new_now ();
expressionp->X_add_number = 0;
}
}
static segT
operand (expressionS *expressionP)
{
char c;
symbolS *symbolP;
char *name;
segT segment;
expressionP->X_unsigned = 1;
SKIP_WHITESPACE ();
c = *input_line_pointer++;
if (is_end_of_line[(unsigned char) c])
goto eol;
switch (c)
{
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
input_line_pointer--;
integer_constant ((NUMBERS_WITH_SUFFIX || flag_m68k_mri)
? 0 : 10,
expressionP);
break;
#ifdef LITERAL_PREFIXDOLLAR_HEX
case '$':
if (* input_line_pointer == 'L')
goto isname;
integer_constant (16, expressionP);
break;
#endif
#ifdef LITERAL_PREFIXPERCENT_BIN
case '%':
integer_constant (2, expressionP);
break;
#endif
case '0':
if (NUMBERS_WITH_SUFFIX || flag_m68k_mri)
{
char *s;
for (s = input_line_pointer; hex_p (*s); s++)
;
if (*s == 'h' || *s == 'H' || *input_line_pointer == '.')
{
--input_line_pointer;
integer_constant (0, expressionP);
break;
}
}
c = *input_line_pointer;
switch (c)
{
case 'o':
case 'O':
case 'q':
case 'Q':
case '8':
case '9':
if (NUMBERS_WITH_SUFFIX || flag_m68k_mri)
{
integer_constant (0, expressionP);
break;
}
default:
default_case:
if (c && strchr (FLT_CHARS, c))
{
input_line_pointer++;
floating_constant (expressionP);
expressionP->X_add_number = - TOLOWER (c);
}
else
{
expressionP->X_op = O_constant;
expressionP->X_add_number = 0;
}
break;
case 'x':
case 'X':
if (flag_m68k_mri)
goto default_case;
input_line_pointer++;
integer_constant (16, expressionP);
break;
case 'b':
if (LOCAL_LABELS_FB && ! (flag_m68k_mri || NUMBERS_WITH_SUFFIX))
{
if (input_line_pointer[1] < '0'
|| input_line_pointer[1] > '9')
{
input_line_pointer--;
integer_constant (10, expressionP);
break;
}
}
case 'B':
input_line_pointer++;
if (flag_m68k_mri || NUMBERS_WITH_SUFFIX)
goto default_case;
integer_constant (2, expressionP);
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
integer_constant ((flag_m68k_mri || NUMBERS_WITH_SUFFIX)
? 0 : 8,
expressionP);
break;
case 'f':
if (LOCAL_LABELS_FB)
{
if (!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;
int r = atof_generic (&cp, ".", EXP_CHARS,
&generic_floating_point_number);
switch (r)
{
case 0:
case ERROR_EXPONENT_OVERFLOW:
if (*cp == 'f' || *cp == 'b')
goto is_0f_label;
else if (cp == input_line_pointer + 1)
goto is_0f_label;
else
goto is_0f_float;
default:
as_fatal (_("expr.c(operand): bad atof_generic return val %d"),
r);
}
}
is_0f_label:
input_line_pointer--;
integer_constant (10, expressionP);
break;
is_0f_float:
;
}
case 'd':
case 'D':
if (flag_m68k_mri || NUMBERS_WITH_SUFFIX)
{
integer_constant (0, expressionP);
break;
}
case 'F':
case 'r':
case 'e':
case 'E':
case 'g':
case 'G':
input_line_pointer++;
floating_constant (expressionP);
expressionP->X_add_number = - TOLOWER (c);
break;
case '$':
if (LOCAL_LABELS_DOLLAR)
{
integer_constant (10, expressionP);
break;
}
else
goto default_case;
}
break;
case '(':
#ifndef NEED_INDEX_OPERATOR
case '[':
#endif
segment = expression (expressionP);
if ((c == '(' && *input_line_pointer != ')')
|| (c == '[' && *input_line_pointer != ']'))
{
#ifdef RELAX_PAREN_GROUPING
if (c != '(')
#endif
as_bad (_("missing '%c'"), c == '(' ? ')' : ']');
}
else
input_line_pointer++;
SKIP_WHITESPACE ();
return segment;
#ifdef TC_M68K
case 'E':
if (! flag_m68k_mri || *input_line_pointer != '\'')
goto de_fault;
as_bad (_("EBCDIC constants are not supported"));
case 'A':
if (! flag_m68k_mri || *input_line_pointer != '\'')
goto de_fault;
++input_line_pointer;
#endif
case '\'':
if (! flag_m68k_mri)
{
expressionP->X_op = O_constant;
expressionP->X_add_number = *input_line_pointer++;
break;
}
mri_char_constant (expressionP);
break;
case '+':
if (0 && *input_line_pointer == '+')
goto target_op;
(void) operand (expressionP);
break;
#ifdef TC_M68K
case '"':
if (! flag_m68k_mri)
goto de_fault;
#endif
case '~':
if (is_name_beginner (c))
goto isname;
case '!':
case '-':
{
if (0 && c == '-' && *input_line_pointer == '-')
goto target_op;
operand (expressionP);
if (expressionP->X_op == O_constant)
{
if (c == '-')
{
expressionP->X_add_number = - expressionP->X_add_number;
expressionP->X_unsigned = 0;
}
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_big
&& expressionP->X_add_number <= 0
&& c == '-'
&& (generic_floating_point_number.sign == '+'
|| generic_floating_point_number.sign == 'P'))
{
if (generic_floating_point_number.sign == '+')
generic_floating_point_number.sign = '-';
else
generic_floating_point_number.sign = 'N';
}
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 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"),
c);
}
break;
#if defined (DOLLAR_DOT) || defined (TC_M68K)
case '$':
#ifndef DOLLAR_DOT
if (! flag_m68k_mri)
goto de_fault;
#endif
if (flag_m68k_mri && hex_p (*input_line_pointer))
{
integer_constant (16, expressionP);
break;
}
if (is_part_of_name (*input_line_pointer))
goto isname;
current_location (expressionP);
break;
#endif
case '.':
if (!is_part_of_name (*input_line_pointer))
{
current_location (expressionP);
break;
}
else if ((strncasecmp (input_line_pointer, "startof.", 8) == 0
&& ! is_part_of_name (input_line_pointer[8]))
|| (strncasecmp (input_line_pointer, "sizeof.", 7) == 0
&& ! is_part_of_name (input_line_pointer[7])))
{
int start;
start = (input_line_pointer[1] == 't'
|| input_line_pointer[1] == 'T');
input_line_pointer += start ? 8 : 7;
SKIP_WHITESPACE ();
if (*input_line_pointer != '(')
as_bad (_("syntax error in .startof. or .sizeof."));
else
{
char *buf;
++input_line_pointer;
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 ();
if (*input_line_pointer != ')')
as_bad (_("syntax error in .startof. or .sizeof."));
else
++input_line_pointer;
}
break;
}
else
{
goto isname;
}
case ',':
eol:
expressionP->X_op = O_absent;
input_line_pointer--;
break;
#ifdef TC_M68K
case '%':
if (! flag_m68k_mri)
goto de_fault;
integer_constant (2, expressionP);
break;
case '@':
if (! flag_m68k_mri)
goto de_fault;
integer_constant (8, expressionP);
break;
case ':':
if (! flag_m68k_mri)
goto de_fault;
++input_line_pointer;
integer_constant (16, expressionP);
break;
case '*':
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_name_beginner (c))
{
isname:
name = --input_line_pointer;
c = get_symbol_end ();
#ifdef md_parse_name
if (md_parse_name (name, expressionP, &c))
{
*input_line_pointer = c;
break;
}
#endif
#ifdef TC_I960
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);
segment = S_GET_SEGMENT (symbolP);
if (segment == absolute_section)
{
expressionP->X_op = O_constant;
expressionP->X_add_number = S_GET_VALUE (symbolP);
}
else if (segment == reg_section)
{
expressionP->X_op = O_register;
expressionP->X_add_number = S_GET_VALUE (symbolP);
}
else
{
expressionP->X_op = O_symbol;
expressionP->X_add_symbol = symbolP;
expressionP->X_add_number = 0;
}
*input_line_pointer = c;
}
else
{
target_op:
expressionP->X_op = O_absent;
--input_line_pointer;
md_operand (expressionP);
if (expressionP->X_op == O_absent)
{
++input_line_pointer;
as_bad (_("bad expression"));
expressionP->X_op = O_constant;
expressionP->X_add_number = 0;
}
}
break;
}
clean_up_expression (expressionP);
SKIP_WHITESPACE ();
know (*input_line_pointer != ' ');
if (expressionP->X_add_symbol)
symbol_mark_used (expressionP->X_add_symbol);
switch (expressionP->X_op)
{
default:
return absolute_section;
case O_symbol:
return S_GET_SEGMENT (expressionP->X_add_symbol);
case O_register:
return reg_section;
}
}
static void
clean_up_expression (expressionS *expressionP)
{
switch (expressionP->X_op)
{
case O_illegal:
case O_absent:
expressionP->X_add_number = 0;
case O_big:
case O_constant:
case O_register:
expressionP->X_add_symbol = NULL;
case O_symbol:
case O_uminus:
case O_bit_not:
expressionP->X_op_symbol = NULL;
break;
default:
break;
}
}
#undef __
#define __ O_illegal
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, __, __, __,
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __
};
static operator_rankT op_rank[] = {
0,
0,
0,
0,
0,
0,
0,
9,
9,
9,
8,
8,
8,
8,
8,
7,
7,
7,
7,
5,
5,
4,
4,
4,
4,
4,
4,
3,
2,
1,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
};
#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;
}
}
void
expr_begin (void)
{
expr_set_precedence ();
{
expressionS e;
e.X_op = O_max;
assert (e.X_op == O_max);
}
}
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 '-':
if (1 || 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 '!':
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;
}
}
segT
expr (int rankarg,
expressionS *resultP )
{
operator_rankT rank = (operator_rankT) rankarg;
segT retval;
expressionS right;
operatorT op_left;
operatorT op_right;
int op_chars;
know (rank >= 0);
if (rank == 0)
dot_value = frag_now_fix ();
retval = operand (resultP);
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;
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);
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;
}
#ifdef md_optimize_expr
if (md_optimize_expr (resultP, op_left, &right))
{
;
}
else
#endif
if (op_left == O_add && right.X_op == O_constant)
{
resultP->X_add_number += right.X_add_number;
}
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)
{
resultP->X_add_number -= right.X_add_number;
}
else if (op_left == O_add && resultP->X_op == O_constant)
{
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)
{
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:
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)))
{
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
{
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;
}
if (resultP->X_add_symbol)
symbol_mark_used (resultP->X_add_symbol);
return resultP->X_op == O_constant ? absolute_section : retval;
}
char
get_symbol_end (void)
{
char c;
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);
}
unsigned int
get_single_number (void)
{
expressionS exp;
operand (&exp);
return exp.X_add_number;
}