X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gas%2Fexpr.c;h=16c89343a71b23ad3befd1d9ccb5c74765b286b7;hb=62e6599087efba193e0156d89ee65fb74fc99cb2;hp=2dae6bacce0b2779e1faa56dfb56b1b186b598f3;hpb=c14c7a8a619ce03a7c8f41d1cfac3af728df453b;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/expr.c b/gas/expr.c index 2dae6bacce..16c89343a7 100644 --- a/gas/expr.c +++ b/gas/expr.c @@ -1,5 +1,5 @@ /* expr.c -operands, expressions- - Copyright (C) 1987-2015 Free Software Foundation, Inc. + Copyright (C) 1987-2019 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -35,6 +35,8 @@ #define CHAR_BIT 8 #endif +bfd_boolean literal_prefix_dollar_hex = FALSE; + static void floating_constant (expressionS * expressionP); static valueT generic_bignum_to_int32 (void); #ifdef BFD64 @@ -46,15 +48,13 @@ static void clean_up_expression (expressionS * expressionP); static segT operand (expressionS *, enum expr_mode); static operatorT operatorf (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; + const char *file; unsigned int line; }; @@ -108,9 +108,9 @@ make_expr_symbol (expressionS *expressionP) if (expressionP->X_op == O_constant) resolve_symbol_value (symbolP); - n = (struct expr_symbol_line *) xmalloc (sizeof *n); + n = XNEW (struct expr_symbol_line); n->sym = symbolP; - as_where (&n->file, &n->line); + n->file = as_where (&n->line); n->next = expr_symbol_lines; expr_symbol_lines = n; @@ -122,7 +122,7 @@ make_expr_symbol (expressionS *expressionP) the symbol. */ int -expr_symbol_where (symbolS *sym, char **pfile, unsigned int *pline) +expr_symbol_where (symbolS *sym, const char **pfile, unsigned int *pline) { struct expr_symbol_line *l; @@ -510,6 +510,21 @@ integer_constant (int radix, expressionS *expressionP) && input_line_pointer - 1 == suffix) c = *input_line_pointer++; +#ifndef tc_allow_U_suffix +#define tc_allow_U_suffix 1 +#endif + /* PR 19910: Look for, and ignore, a U suffix to the number. */ + if (tc_allow_U_suffix && (c == 'U' || c == 'u')) + c = * input_line_pointer++; + +#ifndef tc_allow_L_suffix +#define tc_allow_L_suffix 1 +#endif + /* PR 20732: Look for, and ignore, a L or LL suffix to the number. */ + if (tc_allow_L_suffix) + while (c == 'L' || c == 'l') + c = * input_line_pointer++; + if (small) { /* Here with number, in correct radix. c is the next char. @@ -765,15 +780,6 @@ operand (expressionS *expressionP, enum expr_mode mode) expressionP); break; -#ifdef LITERAL_PREFIXDOLLAR_HEX - case '$': - /* $L is the start of a local label, not a hex constant. */ - if (* input_line_pointer == 'L') - goto isname; - integer_constant (16, expressionP); - break; -#endif - #ifdef LITERAL_PREFIXPERCENT_BIN case '%': integer_constant (2, expressionP); @@ -877,48 +883,35 @@ operand (expressionS *expressionP, enum expr_mode mode) case 'f': if (LOCAL_LABELS_FB) { + int is_label = 1; + /* 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. */ - ; + if (!is_end_of_line[(unsigned char) input_line_pointer[1]] + && strchr (FLT_CHARS, 'f') != NULL) + { + char *cp = input_line_pointer + 1; + + atof_generic (&cp, ".", EXP_CHARS, + &generic_floating_point_number); + + /* Was nothing parsed, or does it look like an + expression? */ + is_label = (cp == input_line_pointer + 1 + || (cp == input_line_pointer + 2 + && (cp[-1] == '-' || cp[-1] == '+')) + || *cp == 'f' + || *cp == 'b'); + } + if (is_label) + { + input_line_pointer--; + integer_constant (10, expressionP); + break; + } } + /* Fall through. */ case 'd': case 'D': @@ -957,15 +950,21 @@ operand (expressionS *expressionP, enum expr_mode mode) if (md_need_index_operator()) goto de_fault; # endif - /* FALLTHROUGH */ #endif + /* Fall through. */ case '(': /* Didn't begin with digit & not a name. */ segment = expr (0, expressionP, mode); /* expression () will pass trailing whitespace. */ if ((c == '(' && *input_line_pointer != ')') || (c == '[' && *input_line_pointer != ']')) - as_bad (_("missing '%c'"), c == '(' ? ')' : ']'); + { + if (* input_line_pointer) + as_bad (_("found '%c', expected: '%c'"), + * input_line_pointer, c == '(' ? ')' : ']'); + else + as_bad (_("missing '%c'"), c == '(' ? ')' : ']'); + } else input_line_pointer++; SKIP_WHITESPACE (); @@ -982,8 +981,8 @@ operand (expressionS *expressionP, enum expr_mode mode) if (! flag_m68k_mri || *input_line_pointer != '\'') goto de_fault; ++input_line_pointer; - /* Fall through. */ #endif + /* Fall through. */ case '\'': if (! flag_m68k_mri) { @@ -1004,12 +1003,13 @@ operand (expressionS *expressionP, enum expr_mode mode) /* Double quote is the bitwise not operator in MRI mode. */ if (! flag_m68k_mri) goto de_fault; - /* Fall through. */ #endif + /* Fall through. */ case '~': /* '~' is permitted to start a label on the Delta. */ if (is_name_beginner (c)) goto isname; + /* Fall through. */ case '!': case '-': case '+': @@ -1107,7 +1107,21 @@ operand (expressionS *expressionP, enum expr_mode mode) } break; -#if defined (DOLLAR_DOT) || defined (TC_M68K) +#if !defined (DOLLAR_DOT) && !defined (TC_M68K) + case '$': + if (literal_prefix_dollar_hex) + { + /* $L is the start of a local label, not a hex constant. */ + if (* input_line_pointer == 'L') + goto isname; + integer_constant (16, expressionP); + } + else + { + goto isname; + } + break; +#else case '$': /* '$' is the program counter when in MRI mode, or when DOLLAR_DOT is defined. */ @@ -1147,6 +1161,10 @@ operand (expressionS *expressionP, enum expr_mode mode) || input_line_pointer[1] == 'T'); input_line_pointer += start ? 8 : 7; SKIP_WHITESPACE (); + + /* Cover for the as_bad () invocations below. */ + expressionP->X_op = O_absent; + if (*input_line_pointer != '(') as_bad (_("syntax error in .startof. or .sizeof.")); else @@ -1155,14 +1173,20 @@ operand (expressionS *expressionP, enum expr_mode mode) ++input_line_pointer; SKIP_WHITESPACE (); - name = input_line_pointer; - c = get_symbol_end (); + c = get_symbol_name (& name); + if (! *name) + { + as_bad (_("expected symbol name")); + (void) restore_line_pointer (c); + if (c != ')') + ignore_rest_of_line (); + else + ++input_line_pointer; + break; + } - buf = (char *) xmalloc (strlen (name) + 10); - if (start) - sprintf (buf, ".startof.%s", name); - else - sprintf (buf, ".sizeof.%s", name); + buf = concat (start ? ".startof." : ".sizeof.", name, + (char *) NULL); symbolP = symbol_make (buf); free (buf); @@ -1171,7 +1195,7 @@ operand (expressionS *expressionP, enum expr_mode mode) expressionP->X_add_number = 0; *input_line_pointer = c; - SKIP_WHITESPACE (); + SKIP_WHITESPACE_AFTER_NAME (); if (*input_line_pointer != ')') as_bad (_("syntax error in .startof. or .sizeof.")); else @@ -1227,13 +1251,13 @@ operand (expressionS *expressionP, enum expr_mode mode) #if defined(md_need_index_operator) || defined(TC_M68K) de_fault: #endif - if (is_name_beginner (c)) /* Here if did not begin with a digit. */ + if (is_name_beginner (c) || 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 (); + -- input_line_pointer; + c = get_symbol_name (&name); #ifdef md_operator { @@ -1242,15 +1266,15 @@ operand (expressionS *expressionP, enum expr_mode mode) switch (op) { case O_uminus: - *input_line_pointer = c; + restore_line_pointer (c); c = '-'; goto unary; case O_bit_not: - *input_line_pointer = c; + restore_line_pointer (c); c = '~'; goto unary; case O_logical_not: - *input_line_pointer = c; + restore_line_pointer (c); c = '!'; goto unary; case O_illegal: @@ -1259,9 +1283,10 @@ operand (expressionS *expressionP, enum expr_mode mode) default: break; } + if (op != O_absent && op != O_illegal) { - *input_line_pointer = c; + restore_line_pointer (c); expr (9, expressionP, mode); expressionP->X_add_symbol = make_expr_symbol (expressionP); expressionP->X_op_symbol = NULL; @@ -1279,46 +1304,7 @@ operand (expressionS *expressionP, enum expr_mode mode) entering it in the symbol table. */ if (md_parse_name (name, expressionP, mode, &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 (); - + restore_line_pointer (c); break; } #endif @@ -1346,7 +1332,8 @@ operand (expressionS *expressionP, enum expr_mode mode) expressionP->X_add_symbol = symbolP; expressionP->X_add_number = 0; } - *input_line_pointer = c; + + restore_line_pointer (c); } else { @@ -1371,7 +1358,7 @@ operand (expressionS *expressionP, enum expr_mode mode) /* 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. */ + SKIP_ALL_WHITESPACE (); /* -> 1st char after operand. */ know (*input_line_pointer != ' '); /* The PA port needs this information. */ @@ -1602,8 +1589,8 @@ operatorf (int *num_chars) #ifdef md_operator if (is_name_beginner (c)) { - char *name = input_line_pointer; - char ec = get_symbol_end (); + char *name; + char ec = get_symbol_name (& name); ret = md_operator (name, 2, &ec); switch (ret) @@ -1858,6 +1845,13 @@ expr (int rankarg, /* Larger # is higher rank. */ right.X_op_symbol = NULL; } + if (mode == expr_defer + && ((resultP->X_add_symbol != NULL + && S_IS_FORWARD_REF (resultP->X_add_symbol)) + || (right.X_add_symbol != NULL + && S_IS_FORWARD_REF (right.X_add_symbol)))) + goto general; + /* Optimize common cases. */ #ifdef md_optimize_expr if (md_optimize_expr (resultP, op_left, &right)) @@ -2192,7 +2186,10 @@ resolve_expression (expressionS *expressionP) || op == O_lt || op == O_le || op == O_ge || op == O_gt) && seg_left == seg_right && (finalize_syms - || frag_offset_fixed_p (frag_left, frag_right, &frag_off)) + || frag_offset_fixed_p (frag_left, frag_right, &frag_off) + || (op == O_gt + && frag_gtoffset_p (left, frag_left, + right, frag_right, &frag_off))) && (seg_left != reg_section || left == right) && (seg_left != undefined_section || add_symbol == op_symbol))) { @@ -2331,31 +2328,63 @@ resolve_expression (expressionS *expressionP) 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. + Assume input_line_pointer is at start of symbol name, or the + start of a double quote enclosed symbol name. Advance input_line_pointer past symbol name. - Turn that character into a '\0', returning its former value. + Turn that character into a '\0', returning its former value, + which may be the closing double quote. This allows a string compare (RMS wants symbol names to be strings) - of the symbol name. + 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 (void) +get_symbol_name (char ** ilp_return) { char c; - /* We accept \001 in a name in case this is being called with a + * ilp_return = input_line_pointer; + /* We accept FAKE_LABEL_CHAR in a name in case this is being called with a constructed string. */ - if (is_name_beginner (c = *input_line_pointer++) || c == '\001') + if (is_name_beginner (c = *input_line_pointer++) + || (input_from_string && c == FAKE_LABEL_CHAR)) { while (is_part_of_name (c = *input_line_pointer++) - || c == '\001') + || (input_from_string && c == FAKE_LABEL_CHAR)) ; if (is_name_ender (c)) c = *input_line_pointer++; } + else if (c == '"') + { + bfd_boolean backslash_seen; + + * ilp_return = input_line_pointer; + do + { + backslash_seen = c == '\\'; + c = * input_line_pointer ++; + } + while (c != 0 && (c != '"' || backslash_seen)); + + if (c == 0) + as_warn (_("missing closing '\"'")); + } *--input_line_pointer = 0; - return (c); + return c; +} + +/* Replace the NUL character pointed to by input_line_pointer + with C. If C is \" then advance past it. Return the character + now pointed to by input_line_pointer. */ + +char +restore_line_pointer (char c) +{ + * input_line_pointer = c; + if (c == '"') + c = * ++ input_line_pointer; + return c; } unsigned int