diff options
author | Ian Lance Taylor <ian@airs.com> | 1995-08-01 22:01:01 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@airs.com> | 1995-08-01 22:01:01 +0000 |
commit | 219deb70ce2c2e92c12d476ec0cefa69fbf6c78b (patch) | |
tree | 64f71821b2328bc0b5c015c60518adc912bafa18 /gas/expr.c | |
parent | 2b57629364528ef2fd913154e58f626123d51f1c (diff) | |
download | gdb-219deb70ce2c2e92c12d476ec0cefa69fbf6c78b.zip gdb-219deb70ce2c2e92c12d476ec0cefa69fbf6c78b.tar.gz gdb-219deb70ce2c2e92c12d476ec0cefa69fbf6c78b.tar.bz2 |
Initial support for MRI style labels and expressions.
* as.h (flag_mri): Declare/define.
* as.c (show_usage): Mention -M and its synonym --mri.
(parse_args): Add 'M' to std_shortopts. Add "mri" to
std_longopts. Set flag_mri if -M is seen.
(main): Call parse_args before input_scrub_begin. Call
expr_begin.
* app.c (do_scrub_begin): Don't set lex for '"' or '\'' in MRI
mode. Do set lex for ';', '*', and '!' in MRI mode.
(do_scrub_next_char): Remove MRI ifdef in LEX_IS_WHITESPACE case.
In MRI mode, keep spaces between labels and colons. Remove MRI
ifndef around LEX_IS_ONECHAR_QUOTE case. In MRI mode, don't use
'!' or '*' as comment characters even if they are in
comment_chars.
* read.h (lex_type): No longer const.
* read.c: Include libiberty.h.
(lex_type): No longer const.
(read_begin): In MRI mode, set lex_type of '?' to 3.
(potable): Add dc, dc.b, dc.d, dc.l, dc.s, dc.w, dc.x, ds, ds.b,
ds.l, ds.w, and xdef.
(read_a_source_file): Change LABELS_WITHOUT_COLON ifdef to check
for MRI mode at runtime rather than compile time. Handle the EQU
pseudo-op in MRI mode. Remove bogus MRI ifdef around done_pseudo.
Change NO_PSEUDO_DOT ifdef to also take effect for MRI mode at
runtime.
(cons): In MRI mode, always call parse_mri_cons rather than
TC_PARSE_CONS_EXPRESSION.
(parse_mri_cons): Always compile, not just when MRI is defined.
Call TC_PARSE_CONS_EXPRESSION, not expression, when the input is
not a string constant. Handle A and E modifiers.
(float_cons): Accept :xxxx, where the x's are hex digits.
* expr.h (operatorT): Add O_eq, O_ne, O_lt, O_le, O_ge, O_gt.
(expr_begin): Declare.
* expr.c (integer_constant): In MRI mode, if the base was not
specified, look for a suffix on the number to set the base.
(mri_char_constant): New static function.
(operand): Remove MRI ifdef. In MRI mode, do various things: Pass
0 as the base when calling integer_constant if there was no
prefix. Check for a hex constant suffix if when a leading '0' is
seen. Don't accept 0x or 0b as a prefix. Check for E'chars' and
A'chars'. Handle MRI character constants. Treat '"' as the
unary bitwise not operator. Treat $ as the program counter, or as
the prefix for a hex constant. Treat % as the prefix for a binary
constant and @ as the prefix for an octal constant. Treat : as
the prefix for a hex constant.
(op_encoding): Set '"' to O_bit_not, '<' to O_lt, and '>' to O_gt.
(op_rank): No longer const. Change rank values.
(expr_begin): New function.
(operator): New static function.
(expr): Use operator. Don't bother to mention the operator in
warnings. Remove bogus #if 0 code. Handle new operatorT values.
* atof-generic.c (atof_generic): In MRI mode, accept underscores
around the exponent in floating point numbers.
* symbols.h (symbols_case_sensitive): Declare.
* symbols.c (symbols_case_sensitive): New global variable.
(symbol_create): Check symbols_case_sensitive.
(symbol_find_base): Likewise.
(resolve_symbol_value): Handle new operatorT values.
(print_expr_1): Likewise.
(S_IS_LOCAL): In MRI mode, names beginning with two '?' characters
are local.
Diffstat (limited to 'gas/expr.c')
-rw-r--r-- | gas/expr.c | 778 |
1 files changed, 535 insertions, 243 deletions
@@ -15,7 +15,7 @@ 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + 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 @@ -33,6 +33,7 @@ static void floating_constant PARAMS ((expressionS * expressionP)); static void integer_constant PARAMS ((int radix, expressionS * expressionP)); +static void mri_char_constant PARAMS ((expressionS *)); static void clean_up_expression PARAMS ((expressionS * expressionP)); extern const char EXP_CHARS[], FLT_CHARS[]; @@ -129,8 +130,8 @@ integer_constant (radix, expressionP) 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. */ @@ -164,6 +165,50 @@ integer_constant (radix, expressionP) #define valuesize 32 #endif + if (flag_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++) + { + if (*suffix == 'e' || *suffix == 'E') + flt = 1; + } + + if (suffix == input_line_pointer) + { + radix = 10; + suffix = NULL; + } + else + { + c = *--suffix; + if (islower (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: @@ -247,6 +292,10 @@ integer_constant (radix, expressionP) number = leader - generic_bignum + 1; /* number of littlenums in the bignum. */ } } + + if (flag_mri && suffix != NULL && input_line_pointer - 1 == suffix) + c = *input_line_pointer++; + if (small) { /* @@ -256,122 +305,191 @@ integer_constant (radix, expressionP) * than checking for strict canonical form. syntax sux! */ - switch (c) + 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); -#ifdef LOCAL_LABELS_FB - case '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; - } + /* 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_add_number = 0; - break; - } /* case 'b' */ + 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; + } - case '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. */ + 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); + /* 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; + 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. */ - break; - } /* case 'f' */ + 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); + } -#endif /* LOCAL_LABELS_FB */ + 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. */ + } +} -#ifdef LOCAL_LABELS_DOLLAR +/* Parse an MRI multi character constant. */ - case '$': - { +static void +mri_char_constant (expressionP) + expressionS *expressionP; +{ + int i; - /* 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 (*input_line_pointer == '\'' + && input_line_pointer[1] != '\'') + { + expressionP->X_op = O_constant; + expressionP->X_add_number = 0; + return; + } - 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); - } + /* 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; - expressionP->X_op = O_symbol; - expressionP->X_add_symbol = symbolP; - expressionP->X_add_number = 0; + 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; + } - break; - } /* case '$' */ + 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; + } -#endif /* LOCAL_LABELS_DOLLAR */ + if (*input_line_pointer == '\'' + && input_line_pointer[1] != '\'') + break; + } - default: - { - expressionP->X_op = O_constant; - expressionP->X_add_number = number; - input_line_pointer--; /* restore following character. */ - break; - } /* really just a number */ + if (i < 0) + { + as_bad ("Character constant too large"); + i = 0; + } - } /* switch on char following the number */ + 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; } - else + + know (LITTLENUM_NUMBER_OF_BITS == 16); + if (i > 2) { - /* not a small number */ expressionP->X_op = O_big; - expressionP->X_add_number = number; /* number of littlenums */ - input_line_pointer--; /*->char following number. */ + 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; +} /* * Summary of operand(). @@ -408,17 +526,6 @@ operand (expressionP) switch (c) { -#ifdef MRI - case '%': - integer_constant (2, expressionP); - break; - case '@': - integer_constant (8, expressionP); - break; - case '$': - integer_constant (16, expressionP); - break; -#endif case '1': case '2': case '3': @@ -430,17 +537,32 @@ operand (expressionP) case '9': input_line_pointer--; - integer_constant (10, expressionP); + integer_constant (flag_mri ? 0 : 10, expressionP); break; case '0': /* non-decimal radix */ + if (flag_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) { - default: + default_case: if (c && strchr (FLT_CHARS, c)) { input_line_pointer++; @@ -458,47 +580,53 @@ operand (expressionP) case 'x': case 'X': + if (flag_mri) + goto default_case; input_line_pointer++; integer_constant (16, expressionP); break; case 'b': -#ifdef LOCAL_LABELS_FB - switch (input_line_pointer[1]) + if (LOCAL_LABELS_FB) { - 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') + switch (input_line_pointer[1]) + { + 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; - } - 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; + default: + goto is_0b_label; + } + is_0b_label: + input_line_pointer--; + integer_constant (10, expressionP); + break; + is_0b_binary: + ; } - is_0b_label: - input_line_pointer--; - integer_constant (10, expressionP); - break; - is_0b_binary: -#endif case 'B': input_line_pointer++; + if (flag_mri) + goto default_case; integer_constant (2, expressionP); break; @@ -510,47 +638,49 @@ operand (expressionP) case '5': case '6': case '7': - integer_constant (8, expressionP); + integer_constant (flag_mri ? 0 : 8, expressionP); break; case 'f': -#ifdef 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]])) - goto is_0f_label; - { - char *cp = input_line_pointer + 1; - int r = atof_generic (&cp, ".", EXP_CHARS, - &generic_floating_point_number); - switch (r) + 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]])) + goto is_0f_label; { - case 0: - case ERROR_EXPONENT_OVERFLOW: - if (*cp == 'f' || *cp == 'b') - /* looks like a difference expression */ - goto is_0f_label; - else - goto is_0f_float; - default: - as_fatal ("expr.c(operand): bad atof_generic return val %d", - r); + 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 + 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 */ -#endif + /* 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': @@ -565,11 +695,14 @@ operand (expressionP) expressionP->X_add_number = -(isupper (c) ? tolower (c) : c); break; -#ifdef LOCAL_LABELS_DOLLAR case '$': - integer_constant (10, expressionP); - break; -#endif + if (LOCAL_LABELS_DOLLAR) + { + integer_constant (10, expressionP); + break; + } + else + goto default_case; } break; @@ -579,8 +712,8 @@ operand (expressionP) /* 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++ != ']') + if ((c == '(' && *input_line_pointer++ != ')') + || (c == '[' && *input_line_pointer++ != ']')) { as_bad ("Missing ')' assumed"); input_line_pointer--; @@ -588,18 +721,40 @@ operand (expressionP) /* here with input_line_pointer->char after "(...)" */ return segment; + case 'E': + if (! flag_mri || *input_line_pointer != '\'') + goto de_fault; + as_bad ("EBCDIC constants are not supported"); + /* Fall through. */ + case 'A': + if (! flag_mri || *input_line_pointer != '\'') + goto de_fault; + ++input_line_pointer; + /* Fall through. */ case '\'': - /* 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++; + if (! flag_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; + case '"': + /* Double quote is the logical not operator in MRI mode. */ + if (! flag_mri) + goto de_fault; + /* Fall through. */ case '~': case '-': { @@ -633,10 +788,22 @@ operand (expressionP) } break; - case '.': -#ifdef DOLLAR_DOT case '$': + /* $ is the program counter when in MRI mode, or when DOLLAR_DOT + is defined. */ +#ifndef DOLLAR_DOT + if (! flag_mri) + goto de_fault; #endif + if (flag_mri && hex_p (*input_line_pointer)) + { + /* In MRI mode, $ is also used as the prefix for a + hexadecimal constant. */ + integer_constant (16, expressionP); + break; + } + /* Fall through. */ + case '.': if (!is_part_of_name (*input_line_pointer)) { const char *fake; @@ -665,10 +832,33 @@ operand (expressionP) /* can't imagine any other kind of operand */ expressionP->X_op = O_absent; input_line_pointer--; - md_operand (expressionP); + break; + + case '%': + if (! flag_mri) + goto de_fault; + integer_constant (2, expressionP); + break; + + case '@': + if (! flag_mri) + goto de_fault; + integer_constant (8, expressionP); + break; + + case ':': + if (! flag_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; default: + de_fault: if (is_end_of_line[(unsigned char) c]) goto eol; if (is_name_beginner (c)) /* here if did not begin with a digit */ @@ -705,10 +895,22 @@ operand (expressionP) } else { - as_bad ("Bad expression"); - expressionP->X_op = O_constant; - expressionP->X_add_number = 0; + /* Let the target try to parse it. Success is indicated by changing + the X_op field to something other than O_absent and pointing + input_line_pointer passed the expression. If it can't parse the + 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; } /* @@ -820,10 +1022,10 @@ static const operatorT op_encoding[256] = __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, - __, O_bit_or_not, __, __, __, O_modulus, O_bit_and, __, + __, O_bit_or_not, O_bit_not, __, __, O_modulus, O_bit_and, __, __, __, O_multiply, O_add, __, O_subtract, __, O_divide, __, __, __, __, __, __, __, __, - __, __, __, __, O_left_shift, __, O_right_shift, __, + __, __, __, __, O_lt, __, O_gt, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, @@ -847,12 +1049,14 @@ static const operatorT op_encoding[256] = /* * Rank Examples * 0 operand, (expression) - * 1 + - - * 2 & ^ ! | - * 3 * / % << >> - * 4 unary - unary ~ + * 1 = <> < <= >= > + * 2 + - + * 3 used for * / % in MRI mode + * 4 & ^ ! | + * 5 * / % << >> + * 6 unary - unary ~ */ -static const operator_rankT op_rank[] = +static operator_rankT op_rank[] = { 0, /* O_illegal */ 0, /* O_absent */ @@ -860,21 +1064,109 @@ static const operator_rankT op_rank[] = 0, /* O_symbol */ 0, /* O_register */ 0, /* O_bit */ - 4, /* O_uminus */ - 4, /* O_bit_now */ - 3, /* O_multiply */ - 3, /* O_divide */ - 3, /* O_modulus */ - 3, /* O_left_shift */ - 3, /* O_right_shift */ - 2, /* O_bit_inclusive_or */ - 2, /* O_bit_or_not */ - 2, /* O_bit_exclusive_or */ - 2, /* O_bit_and */ - 1, /* O_add */ - 1, /* O_subtract */ + 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 */ }; + +/* Initialize the expression parser. */ + +void +expr_begin () +{ + /* In MRI mode, multiplication and division have lower precedence + than the bit wise operators. */ + if (flag_mri) + { + op_rank[O_multiply] = 3; + op_rank[O_divide] = 3; + op_rank[O_modulus] = 3; + } +} +/* Return the encoding for the operator at INPUT_LINE_POINTER. + Advance INPUT_LINE_POINTER to the last character in the operator + (i.e., don't change it for a single character operator). */ + +static inline operatorT +operator () +{ + int c; + operatorT ret; + + c = *input_line_pointer; + + 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; + } + ++input_line_pointer; + return ret; + + case '>': + switch (input_line_pointer[1]) + { + default: + return op_encoding[c]; + case '>': + ret = O_right_shift; + break; + case '=': + ret = O_ge; + break; + } + ++input_line_pointer; + return ret; + + case '!': + /* We accept !! as equivalent to ^ for MRI compatibility. */ + if (input_line_pointer[1] != '!') + { + if (flag_mri) + return O_bit_inclusive_or; + return op_encoding[c]; + } + ++input_line_pointer; + return O_bit_exclusive_or; + } + + /*NOTREACHED*/ +} + +/* Parse an expression. */ + segT expr (rank, resultP) operator_rankT rank; /* Larger # is higher rank. */ @@ -883,9 +1175,7 @@ expr (rank, resultP) segT retval; expressionS right; operatorT op_left; - char c_left; /* 1st operator character. */ operatorT op_right; - char c_right; know (rank >= 0); @@ -893,16 +1183,12 @@ expr (rank, resultP) know (*input_line_pointer != ' '); /* Operand() gobbles spaces. */ - c_left = *input_line_pointer; /* Potential operator character. */ - op_left = op_encoding[(unsigned char) c_left]; + op_left = operator (); while (op_left != O_illegal && op_rank[(int) op_left] > rank) { segT rightseg; input_line_pointer++; /*->after 1st character of operator. */ - /* Operators "<<" and ">>" have 2 characters. */ - if (*input_line_pointer == c_left && (c_left == '<' || c_left == '>')) - ++input_line_pointer; rightseg = expr (op_rank[(int) op_left], &right); if (right.X_op == O_absent) @@ -931,10 +1217,7 @@ expr (rank, resultP) ) as_bad ("operation combines symbols in different segments"); - c_right = *input_line_pointer; - op_right = op_encoding[(unsigned char) c_right]; - if (*input_line_pointer == c_right && (c_right == '<' || c_right == '>')) - ++input_line_pointer; + 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_subtract); @@ -946,8 +1229,8 @@ expr (rank, resultP) if (resultP->X_op == O_big) { - as_warn ("left operand of %c is a %s; integer 0 assumed", - c_left, resultP->X_add_number > 0 ? "bignum" : "float"); + as_warn ("left operand is a %s; integer 0 assumed", + resultP->X_add_number > 0 ? "bignum" : "float"); resultP->X_op = O_constant; resultP->X_add_number = 0; resultP->X_add_symbol = NULL; @@ -955,8 +1238,8 @@ expr (rank, resultP) } if (right.X_op == O_big) { - as_warn ("right operand of %c is a %s; integer 0 assumed", - c_left, right.X_add_number > 0 ? "bignum" : "float"); + as_warn ("right operand is a %s; integer 0 assumed", + right.X_add_number > 0 ? "bignum" : "float"); right.X_op = O_constant; right.X_add_number = 0; right.X_add_symbol = NULL; @@ -964,22 +1247,7 @@ expr (rank, resultP) } /* Optimize common cases. */ -#if 0 - if (op_left == O_add && resultP->X_got_symbol) - { - /* XXX - kludge here to accomodate "_GLOBAL_OFFSET_TABLE + (x - y)" - * expressions: this only works for this special case, the - * _GLOBAL_OFFSET_TABLE thing *must* be the left operand, the whole - * expression is given the segment of right expression (always a DIFFERENCE, - * which should get resolved by fixup_segment()) - */ - resultP->X_op = right.X_op; - resultP->X_add_symbol = right.X_add_symbol; - resultP->X_op_symbol = right.X_op_symbol; - } - else -#endif - if (op_left == O_add && right.X_op == O_constant) + if (op_left == O_add && right.X_op == O_constant) { /* X + constant. */ resultP->X_add_number += right.X_add_number; @@ -1024,6 +1292,7 @@ expr (rank, resultP) } 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; @@ -1035,7 +1304,30 @@ expr (rank, resultP) 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; - default: abort (); + 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; } } else if (resultP->X_op == O_symbol |