diff options
Diffstat (limited to 'gas/expr.c')
-rw-r--r-- | gas/expr.c | 1923 |
1 files changed, 0 insertions, 1923 deletions
diff --git a/gas/expr.c b/gas/expr.c deleted file mode 100644 index 633854c37bf..00000000000 --- a/gas/expr.c +++ /dev/null @@ -1,1923 +0,0 @@ -/* expr.c -operands, expressions- - Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001 - Free Software Foundation, Inc. - - This file is part of GAS, the GNU Assembler. - - GAS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - GAS is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - 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. */ - -/* This is really a branch office of as-read.c. I split it out to clearly - distinguish the world of expressions from the world of statements. - (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 "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 ((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 *next; - symbolS *sym; - char *file; - unsigned int line; -}; - -static struct expr_symbol_line *expr_symbol_lines; - -/* 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 (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; - - 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 - 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, - (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; -} - -/* 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; -} - -/* 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); -} - -/* Build any floating-point literal here. - Also build any bignum literal here. */ - -/* Seems atof_machine can backscan through generic_bignum and hit whatever - happens to be loaded before it in memory. And its way too complicated - for me to fix right. Thus a hack. JF: Just make generic_bignum bigger, - 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. */ -}; - -/* If nonzero, we've been asked to assemble nan, +inf or -inf. */ -int generic_floating_point_magic; - -static void -floating_constant (expressionP) - expressionS *expressionP; -{ - /* input_line_pointer -> floating-point constant. */ - 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, probably assembling junk")); - } - else - { - as_bad (_("bad floating-point constant: unknown error code=%d."), error_code); - } - } - expressionP->X_op = O_big; - /* input_line_pointer -> just after constant, which may point to - whitespace. */ - 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; - expressionS *expressionP; -{ - char *start; /* Start of number. */ - char *suffix = NULL; - char c; - valueT number; /* Offset or (absolute) value. */ - short int digit; /* Value of next digit in current radix. */ - short int maxdig = 0; /* Highest permitted digit value. */ - int too_many_digits = 0; /* If we see >= this number of. */ - char *name; /* Points to name of symbol. */ - symbolS *symbolP; /* Points to symbol. */ - - int small; /* True if fits in 32 bits. */ - - /* May be bignum, or may fit in 32 bits. */ - /* Most numbers fit into 32 bits, and we want this case to be fast. - so we pretend it will fit into 32 bits. If, after making up a 32 - bit number, we realise that we have scanned more digits than - comfortably fit into 32 bits, we re-scan the digits coding them - into a bignum. For decimal and octal numbers we are - conservative: Some numbers may be assumed bignums when in fact - they do fit into 32 bits. Numbers of any radix can have excess - leading zeros: We strive to recognise this and cast them back - into 32 bits. We must check that the bignum really is more than - 32 bits, and change it back to a 32-bit number if it fits. The - number we are looking for is expected to be positive, but if it - fits into 32 bits as an unsigned number, we let it be a 32-bit - number. The cavalier approach is for speed in ordinary cases. */ - /* This has been extended for 64 bits. We blindly assume that if - you're compiling in 64-bit mode, the target is a 64-bit machine. - This should be cleaned up. */ - -#ifdef BFD64 -#define valuesize 64 -#else /* includes non-bfd case, mostly */ -#define valuesize 32 -#endif - - 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 ((unsigned char) *suffix); - suffix++) - { - if (*suffix == 'e' || *suffix == 'E') - flt = 1; - } - - if (suffix == input_line_pointer) - { - radix = 10; - suffix = NULL; - } - else - { - c = *--suffix; - if (islower ((unsigned char) c)) - 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; /* Very rough. */ - } -#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; - } - /* c contains character after number. */ - /* input_line_pointer->char after c. */ - small = (input_line_pointer - start - 1) < too_many_digits; - - 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 of littlenums in the bignum. */ - number = num_little_digits; - } - } - else if (!small) - { - /* We saw a lot of digits. manufacture a bignum the hard way. */ - LITTLENUM_TYPE *leader; /* -> high order littlenum of the bignum. */ - LITTLENUM_TYPE *pointer; /* -> littlenum we are frobbing now. */ - 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; /* -> 1st digit. */ - 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) - { - /* Room to grow a longer bignum. */ - *++leader = carry; - } - } - } - /* Again, c is char after number. */ - /* input_line_pointer -> after c. */ - know (LITTLENUM_NUMBER_OF_BITS == 16); - if (leader < generic_bignum + 2) - { - /* Will fit into 32 bits. */ - 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 of littlenums in the bignum. */ - 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) - { - /* Here with number, in correct radix. c is the next char. - Note that unlike un*x, we allow "011f" "0x9f" to both mean - the same as the (conventional) "9f". - This is simply easier than checking for strict canonical - form. Syntax sux! */ - - if (LOCAL_LABELS_FB && c == 'b') - { - /* Backward ref to local label. - Because it is backward, expect it to be defined. */ - /* Construct a local label. */ - name = fb_label_name ((int) number, 0); - - /* Seen before, or symbol is defined: OK. */ - symbolP = symbol_find (name); - if ((symbolP != NULL) && (S_IS_DEFINED (symbolP))) - { - /* Local labels are never absolute. Don't waste time - checking absoluteness. */ - know (SEG_NORMAL (S_GET_SEGMENT (symbolP))); - - expressionP->X_op = O_symbol; - expressionP->X_add_symbol = symbolP; - } - else - { - /* 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."), - (int) number); - expressionP->X_op = O_constant; - } - - expressionP->X_add_number = 0; - } /* case 'b' */ - else if (LOCAL_LABELS_FB && c == 'f') - { - /* Forward reference. Expect symbol to be undefined or - unknown. undefined: seen it before. unknown: never seen - it before. - - Construct a local label name, then an undefined symbol. - Don't create a xseg frag for it: caller may do that. - Just return it as never seen before. */ - name = fb_label_name ((int) number, 1); - symbolP = symbol_find_or_make (name); - /* We have no need to check symbol properties. */ -#ifndef many_segments - /* Since "know" puts its arg into a "string", we - can't have newlines in the argument. */ - 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; - } /* case 'f' */ - else if (LOCAL_LABELS_DOLLAR && c == '$') - { - /* If the dollar label is *currently* defined, then this is just - another reference to it. If it is not *currently* defined, - then this is a fresh instantiation of that number, so create - it. */ - - 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; - } /* case '$' */ - else - { - expressionP->X_op = O_constant; -#ifdef TARGET_WORD_SIZE - /* Sign extend NUMBER. */ - number |= (-(number >> (TARGET_WORD_SIZE - 1))) << (TARGET_WORD_SIZE - 1); -#endif - expressionP->X_add_number = number; - input_line_pointer--; /* Restore following character. */ - } /* Really just a number. */ - } - else - { - /* Not a small number. */ - expressionP->X_op = O_big; - expressionP->X_add_number = number; /* Number of littlenums. */ - input_line_pointer--; /* -> char following number. */ - } -} - -/* Parse an MRI multi character constant. */ - -static void -mri_char_constant (expressionP) - expressionS *expressionP; -{ - int i; - - if (*input_line_pointer == '\'' - && input_line_pointer[1] != '\'') - { - expressionP->X_op = O_constant; - expressionP->X_add_number = 0; - return; - } - - /* In order to get the correct byte ordering, we must build the - number in reverse. */ - 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) - { - /* If there is more than one littlenum, left justify the - last one to make it match the earlier ones. If there is - only one, we can just use the value directly. */ - 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)); - } - - /* Skip the final closing quote. */ - ++input_line_pointer; -} - -/* Return an expression representing the current location. This - handles the magic symbol `.'. */ - -static void -current_location (expressionp) - expressionS *expressionp; -{ - if (now_seg == absolute_section) - { - expressionp->X_op = O_constant; - expressionp->X_add_number = abs_section_offset; - } - else - { - symbolS *symbolp; - - symbolp = symbol_new (FAKE_LABEL_NAME, now_seg, - (valueT) frag_now_fix (), - frag_now); - expressionp->X_op = O_symbol; - expressionp->X_add_symbol = symbolp; - expressionp->X_add_number = 0; - } -} - -/* In: Input_line_pointer points to 1st char of operand, which may - be a space. - - Out: A expressionS. - The operand may have been empty: in this case X_op == O_absent. - Input_line_pointer->(next non-blank) char after operand. */ - -static segT -operand (expressionP) - expressionS *expressionP; -{ - char c; - symbolS *symbolP; /* Points to symbol. */ - char *name; /* Points to name of symbol. */ - segT segment; - - /* All integers are regarded as unsigned unless they are negated. - This is because the only thing which cares whether a number is - unsigned is the code in emit_expr which extends constants into - bignums. It should only sign extend negative numbers, so that - something like ``.quad 0x80000000'' is not sign extended even - though it appears negative if valueT is 32 bits. */ - expressionP->X_unsigned = 1; - - /* 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. */ - - 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 '$': - integer_constant (16, expressionP); - break; -#endif - -#ifdef LITERAL_PREFIXPERCENT_BIN - case '%': - integer_constant (2, expressionP); - break; -#endif - - case '0': - /* Non-decimal radix. */ - - if (NUMBERS_WITH_SUFFIX || flag_m68k_mri) - { - char *s; - - /* Check for a hex constant. */ - for (s = input_line_pointer; hex_p (*s); s++) - ; - if (*s == 'h' || *s == 'H') - { - --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; - } - /* Fall through. */ - default: - default_case: - if (c && strchr (FLT_CHARS, c)) - { - input_line_pointer++; - floating_constant (expressionP); - expressionP->X_add_number = - - (isupper ((unsigned char) c) ? tolower (c) : c); - } - else - { - /* The string was only zero. */ - 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)) - { - /* 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') - { - /* Parse this as a back reference to label 0. */ - input_line_pointer--; - integer_constant (10, expressionP); - break; - } - /* Otherwise, parse this as a binary number. */ - } - /* Fall through. */ - 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 it says "0f" and it could possibly be a floating point - 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]]) - || 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') - /* 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"), - r); - } - } - - /* Okay, now we've sorted it out. We resume at one of these - two labels, depending on what we've decided we're probably - looking at. */ - is_0f_label: - input_line_pointer--; - integer_constant (10, expressionP); - break; - - is_0f_float: - /* Fall through. */ - ; - } - - 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 'E': - case 'g': - case 'G': - input_line_pointer++; - floating_constant (expressionP); - expressionP->X_add_number = - - (isupper ((unsigned char) c) ? tolower (c) : c); - break; - - case '$': - if (LOCAL_LABELS_DOLLAR) - { - integer_constant (10, expressionP); - break; - } - else - goto default_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 != ']')) - { -#ifdef RELAX_PAREN_GROUPING - if (c != '(') -#endif - as_bad (_("Missing '%c' assumed"), c == '(' ? ')' : ']'); - } - else - input_line_pointer++; - SKIP_WHITESPACE (); - /* Here with input_line_pointer -> char after "(...)". */ - return segment; - -#ifdef TC_M68K - case 'E': - if (! flag_m68k_mri || *input_line_pointer != '\'') - goto de_fault; - as_bad (_("EBCDIC constants are not supported")); - /* Fall through. */ - case 'A': - if (! flag_m68k_mri || *input_line_pointer != '\'') - goto de_fault; - ++input_line_pointer; - /* Fall through. */ -#endif - case '\'': - if (! flag_m68k_mri) - { - /* Warning: to conform to other people's assemblers NO - ESCAPEMENT is permitted for a single quote. The next - character, parity errors and all, is taken as the value - of the operand. VERY KINKY. */ - expressionP->X_op = O_constant; - expressionP->X_add_number = *input_line_pointer++; - break; - } - - mri_char_constant (expressionP); - break; - - case '+': - (void) operand (expressionP); - break; - -#ifdef TC_M68K - case '"': - /* 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); - if (expressionP->X_op == O_constant) - { - /* input_line_pointer -> char after operand. */ - if (c == '-') - { - expressionP->X_add_number = - expressionP->X_add_number; - /* Notice: '-' may overflow: no warning is given. - This is compatible with other people's - assemblers. Sigh. */ - 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_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 '$': - /* '$' is the program counter when in MRI mode, or when - DOLLAR_DOT is defined. */ -#ifndef DOLLAR_DOT - if (! flag_m68k_mri) - goto de_fault; -#endif - if (flag_m68k_mri && hex_p (*input_line_pointer)) - { - /* In MRI mode, '$' is also used as the prefix for a - hexadecimal constant. */ - 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: - /* Can't imagine any other kind of operand. */ - 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; - - /* In MRI mode, this is a floating point constant represented - using hexadecimal digits. */ - - ++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)) /* Here if did not begin with a digit. */ - { - /* Identifier begins here. - This is kludged for speed, so code is repeated. */ - 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, &c)) - { - *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 - value now. */ - 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 - { - /* 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 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; - 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; - } - - /* It is more 'efficient' to clean up the expressionS when they are - created. Doing it here saves lines of code. */ - clean_up_expression (expressionP); - SKIP_WHITESPACE (); /* -> 1st char after operand. */ - know (*input_line_pointer != ' '); - - /* The PA port needs this information. */ - 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; - } -} - -/* Internal. Simplify a struct expression for use by expr (). */ - -/* In: address of a expressionS. - The X_op field of the expressionS may only take certain values. - Elsewise we waste time special-case testing. Sigh. Ditto SEG_ABSENT. - - Out: expressionS may have been modified: - 'foo-foo' symbol references cancelled to 0, which changes X_op - from O_subtract to O_constant. - Unused fields zeroed to help expr (). */ - -static void -clean_up_expression (expressionP) - expressionS *expressionP; -{ - switch (expressionP->X_op) - { - case O_illegal: - case O_absent: - expressionP->X_add_number = 0; - /* Fall through. */ - case O_big: - case O_constant: - case O_register: - expressionP->X_add_symbol = NULL; - /* Fall through. */ - case O_symbol: - case O_uminus: - case O_bit_not: - expressionP->X_op_symbol = NULL; - break; - case O_subtract: - 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)))) - { - addressT diff = (S_GET_VALUE (expressionP->X_add_symbol) - - S_GET_VALUE (expressionP->X_op_symbol)); - - expressionP->X_op = O_constant; - expressionP->X_add_symbol = NULL; - expressionP->X_op_symbol = NULL; - expressionP->X_add_number += diff; - } - break; - default: - break; - } -} - -/* Expression parser. */ - -/* We allow an empty expression, and just assume (absolute,0) silently. - 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 - 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) - or 1 symbol. Then "symbol+constant" and "symbol-symbol" are common. - So I guess it doesn't really matter how inefficient more complex expressions - are parsed. - - After expr(RANK,resultP) input_line_pointer->operator of rank <= RANK. - Also, we have consumed any leading or trailing spaces (operand does that) - and done all intervening operators. - - This returns the segment of the result, which will be - absolute_section or the segment of a symbol. */ - -#undef __ -#define __ O_illegal - -/* Maps ASCII -> operators. */ -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, __, __, __, - - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, - __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __ -}; - -/* Rank Examples - 0 operand, (expression) - 1 || - 2 && - 3 == <> < <= >= > - 4 + - - 5 used for * / % in MRI mode - 6 & ^ ! | - 7 * / % << >> - 8 unary - unary ~ -*/ -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_big */ - 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 */ -}; - -/* 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 8 -#define MRI_MUL_PRECEDENCE 6 - -void -expr_set_precedence () -{ - 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; - } -} - -/* 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); - } -} - -/* 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 (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; - - switch (c) - { - default: - return op_encoding[c]; - - 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 '!': - /* We accept !! as equivalent to ^ for MRI compatibility. */ - 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; - } - - /* NOTREACHED */ -} - -/* Parse an expression. */ - -segT -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; - operatorT op_right; - int op_chars; - - know (rank >= 0); - - retval = operand (resultP); - - /* operand () gobbles spaces. */ - 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; /* -> after operator. */ - - 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 (); - } - } - - 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_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); - - /* input_line_pointer->after right-hand quantity. */ - /* left-hand quantity in resultP. */ - /* right-hand quantity in right. */ - /* operator in op_left. */ - - 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; - } - - /* 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. */ - resultP->X_add_number += right.X_add_number; - } - /* This case comes up in PIC code. */ - 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 (S_GET_SEGMENT (right.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) - { - /* X - constant. */ - resultP->X_add_number -= right.X_add_number; - } - else if (op_left == O_add && resultP->X_op == O_constant) - { - /* Constant + X. */ - 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) - { - /* Constant OP 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: - /* 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; - 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))) - { - /* Symbol OP symbol. */ - 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; - } - else - { - /* The general case. */ - 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; - } - - op_left = op_right; - } /* While next operator is >= this rank. */ - - /* The PA port needs this information. */ - if (resultP->X_add_symbol) - symbol_mark_used (resultP->X_add_symbol); - - return resultP->X_op == O_constant ? absolute_section : retval; -} - -/* This lives here because it belongs equally in expr.c & read.c. - expr.c is just a branch office read.c anyway, and putting it - here lessens the crowd at read.c. - - Assume input_line_pointer is at start of symbol name. - Advance input_line_pointer past symbol name. - Turn that character into a '\0', returning its former value. - This allows a string compare (RMS wants symbol names to be strings) - of the symbol name. - There will always be a char following symbol name, because all good - lines end in end-of-line. */ - -char -get_symbol_end () -{ - char c; - - /* We accept \001 in a name in case this is being called with a - constructed string. */ - 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 () -{ - expressionS exp; - operand (&exp); - return exp.X_add_number; -} |