/* expr.c -operands, expressions-
- Copyright (C) 1987-2014 Free Software Foundation, Inc.
+ Copyright (C) 1987-2019 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
#include "as.h"
#include "safe-ctype.h"
-#include "obstack.h"
#ifdef HAVE_LIMITS_H
#include <limits.h>
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;
};
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;
the symbol. */
int
-expr_symbol_where (symbolS *sym, char **pfile, unsigned int *pline)
+expr_symbol_where (symbolS *sym, const char **pfile, unsigned int *pline)
{
- register struct expr_symbol_line *l;
+ struct expr_symbol_line *l;
for (l = expr_symbol_lines; l != NULL; l = l->next)
{
#define valuesize 32
#endif
+ if (is_end_of_line[(unsigned char) *input_line_pointer])
+ {
+ expressionP->X_op = O_absent;
+ return;
+ }
+
if ((NUMBERS_WITH_SUFFIX || flag_m68k_mri) && radix == 0)
{
int flt = 0;
&& 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.
break;
case 'b':
- if (LOCAL_LABELS_FB && ! (flag_m68k_mri || NUMBERS_WITH_SUFFIX))
+ if (LOCAL_LABELS_FB && !flag_m68k_mri
+ && input_line_pointer[1] != '0'
+ && input_line_pointer[1] != '1')
{
- /* This code used to check for '+' and '-' here, and, in
- some conditions, fall through to call
- integer_constant. However, that didn't make sense,
- as integer_constant only accepts digits. */
- /* Some of our code elsewhere does permit digits greater
- than the expected base; for consistency, do the same
- here. */
- if (input_line_pointer[1] < '0'
- || input_line_pointer[1] > '9')
- {
- /* Parse this as a back reference to label 0. */
- input_line_pointer--;
- integer_constant (10, expressionP);
- break;
- }
- /* Otherwise, parse this as a binary number. */
+ /* 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 (input_line_pointer[1] == '0'
+ || input_line_pointer[1] == '1')
+ {
+ input_line_pointer++;
+ integer_constant (2, expressionP);
+ break;
+ }
if (flag_m68k_mri || NUMBERS_WITH_SUFFIX)
- goto default_case;
- integer_constant (2, expressionP);
- break;
+ input_line_pointer++;
+ goto default_case;
case '0':
case '1':
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':
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 ();
if (! flag_m68k_mri || *input_line_pointer != '\'')
goto de_fault;
++input_line_pointer;
- /* Fall through. */
#endif
+ /* Fall through. */
case '\'':
if (! flag_m68k_mri)
{
/* 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 '+':
/* input_line_pointer -> char after operand. */
if (c == '-')
{
- expressionP->X_add_number = - expressionP->X_add_number;
+ expressionP->X_add_number
+ = - (addressT) expressionP->X_add_number;
/* Notice: '-' may overflow: no warning is given.
This is compatible with other people's
assemblers. Sigh. */
|| 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
++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);
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
#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
{
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:
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;
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
expressionP->X_add_symbol = symbolP;
expressionP->X_add_number = 0;
}
- *input_line_pointer = c;
+
+ restore_line_pointer (c);
}
else
{
/* 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. */
#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)
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))
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