Tue Jul 7 13:00:37 1998 Alan Modra <alan@spri.levels.unisa.edu.au>

* config/tc-i386.c (space_chars): Remove. The scrubber converts
	sequences of whitespace to a single space.
	(is_space_chars): Just compare with space.
	(md_begin): Don't initialize space_chars.
	(md_assemble): Just skip a single whitespace character.
	(i386_operand): Rewrite base-index parsing to use new
	parse_register, and to skip white space.  Skip white space in a
	number of other places too.  Don't give error message if
	parse_register fails.
	(parse_register): Change reg_string parameter to be non-const.
	Add end_op parameter.  Skip white space after the `%', and return
	end of register string.  Give error message here rather than
	caller.
This commit is contained in:
Ian Lance Taylor
1998-07-07 17:09:55 +00:00
parent 89f015d750
commit 4edc93e913
2 changed files with 226 additions and 154 deletions

@ -1,3 +1,19 @@
Tue Jul 7 13:00:37 1998 Alan Modra <alan@spri.levels.unisa.edu.au>
* config/tc-i386.c (space_chars): Remove. The scrubber converts
sequences of whitespace to a single space.
(is_space_chars): Just compare with space.
(md_begin): Don't initialize space_chars.
(md_assemble): Just skip a single whitespace character.
(i386_operand): Rewrite base-index parsing to use new
parse_register, and to skip white space. Skip white space in a
number of other places too. Don't give error message if
parse_register fails.
(parse_register): Change reg_string parameter to be non-const.
Add end_op parameter. Skip white space after the `%', and return
end of register string. Give error message here rather than
caller.
Fri Jul 3 15:34:34 1998 Ian Lance Taylor <ian@cygnus.com> Fri Jul 3 15:34:34 1998 Ian Lance Taylor <ian@cygnus.com>
Based on patch from Matt Semersky <matts@scd.hp.com>: Based on patch from Matt Semersky <matts@scd.hp.com>:

@ -127,9 +127,19 @@ struct _i386_insn
typedef struct _i386_insn i386_insn; typedef struct _i386_insn i386_insn;
/* List of chars besides those in app.c:symbol_chars that can start an
operand. Used to prevent the scrubber eating vital white-space. */
#ifdef LEX_AT
const char extra_symbol_chars[] = "*%-(@";
#else
const char extra_symbol_chars[] = "*%-(";
#endif
/* This array holds the chars that always start a comment. If the /* This array holds the chars that always start a comment. If the
pre-processor is disabled, these aren't very useful */ pre-processor is disabled, these aren't very useful */
#if defined (TE_I386AIX) || defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) #if defined (TE_I386AIX) || ((defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) && ! defined (TE_LINUX))
/* Putting '/' here makes it impossible to use the divide operator.
However, we need it for compatibility with SVR4 systems. */
const char comment_chars[] = "#/"; const char comment_chars[] = "#/";
#define PREFIX_SEPARATOR '\\' #define PREFIX_SEPARATOR '\\'
#else #else
@ -145,7 +155,7 @@ const char comment_chars[] = "#";
#NO_APP at the beginning of its output. */ #NO_APP at the beginning of its output. */
/* Also note that comments started like this one will always work if /* Also note that comments started like this one will always work if
'/' isn't otherwise defined. */ '/' isn't otherwise defined. */
#if defined (TE_I386AIX) || defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) #if defined (TE_I386AIX) || ((defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) && ! defined (TE_LINUX))
const char line_comment_chars[] = ""; const char line_comment_chars[] = "";
#else #else
const char line_comment_chars[] = "/"; const char line_comment_chars[] = "/";
@ -165,7 +175,6 @@ const char FLT_CHARS[] = "fFdDxX";
static char opcode_chars[256]; static char opcode_chars[256];
static char register_chars[256]; static char register_chars[256];
static char operand_chars[256]; static char operand_chars[256];
static char space_chars[256];
static char identifier_chars[256]; static char identifier_chars[256];
static char digit_chars[256]; static char digit_chars[256];
@ -173,7 +182,7 @@ static char digit_chars[256];
#define is_opcode_char(x) (opcode_chars[(unsigned char) x]) #define is_opcode_char(x) (opcode_chars[(unsigned char) x])
#define is_operand_char(x) (operand_chars[(unsigned char) x]) #define is_operand_char(x) (operand_chars[(unsigned char) x])
#define is_register_char(x) (register_chars[(unsigned char) x]) #define is_register_char(x) (register_chars[(unsigned char) x])
#define is_space_char(x) (space_chars[(unsigned char) x]) #define is_space_char(x) ((x) == ' ')
#define is_identifier_char(x) (identifier_chars[(unsigned char) x]) #define is_identifier_char(x) (identifier_chars[(unsigned char) x])
#define is_digit_char(x) (digit_chars[(unsigned char) x]) #define is_digit_char(x) (digit_chars[(unsigned char) x])
@ -365,7 +374,8 @@ i386_align_code (fragP, count)
static char *output_invalid PARAMS ((int c)); static char *output_invalid PARAMS ((int c));
static int i386_operand PARAMS ((char *operand_string)); static int i386_operand PARAMS ((char *operand_string));
static const reg_entry *parse_register PARAMS ((const char *reg_string)); static const reg_entry *parse_register PARAMS ((char *reg_string,
char **end_op));
#ifndef I386COFF #ifndef I386COFF
static void s_bss PARAMS ((int)); static void s_bss PARAMS ((int));
#endif #endif
@ -581,7 +591,7 @@ md_begin ()
} }
} }
/* fill in lexical tables: opcode_chars, operand_chars, space_chars */ /* fill in lexical tables: opcode_chars, operand_chars. */
{ {
register int c; register int c;
register char *p; register char *p;
@ -620,8 +630,6 @@ md_begin ()
digit_chars['-'] = '-'; digit_chars['-'] = '-';
identifier_chars['_'] = '_'; identifier_chars['_'] = '_';
identifier_chars['.'] = '.'; identifier_chars['.'] = '.';
space_chars[' '] = ' ';
space_chars['\t'] = '\t';
for (p = operand_special_chars; *p != '\0'; p++) for (p = operand_special_chars; *p != '\0'; p++)
operand_chars[(unsigned char) *p] = *p; operand_chars[(unsigned char) *p] = *p;
@ -1009,17 +1017,15 @@ md_assemble (line)
do do
{ {
/* skip optional white space before operand */ /* skip optional white space before operand */
while (!is_operand_char (*l) && *l != END_OF_INSN) if (is_space_char (*l))
{ ++l;
if (!is_space_char (*l)) if (!is_operand_char (*l) && *l != END_OF_INSN)
{ {
as_bad (_("invalid character %s before operand %d"), as_bad (_("invalid character %s before operand %d"),
output_invalid (*l), output_invalid (*l),
i.operands + 1); i.operands + 1);
return; return;
} }
l++;
}
token_start = l; /* after white space */ token_start = l; /* after white space */
paren_not_balanced = 0; paren_not_balanced = 0;
while (paren_not_balanced || *l != ',') while (paren_not_balanced || *l != ',')
@ -2231,7 +2237,9 @@ i386_operand (operand_string)
for example, 'jmp pc_relative_label' from 'jmp *absolute_label'. */ for example, 'jmp pc_relative_label' from 'jmp *absolute_label'. */
if (*op_string == ABSOLUTE_PREFIX) if (*op_string == ABSOLUTE_PREFIX)
{ {
op_string++; ++op_string;
if (is_space_char (*op_string))
++op_string;
i.types[this_operand] |= JumpAbsolute; i.types[this_operand] |= JumpAbsolute;
} }
@ -2239,14 +2247,17 @@ i386_operand (operand_string)
if (*op_string == REGISTER_PREFIX) if (*op_string == REGISTER_PREFIX)
{ {
register const reg_entry *r; register const reg_entry *r;
if (!(r = parse_register (op_string))) char *end_op;
{
as_bad (_("bad register name `%s'"), op_string); r = parse_register (op_string, &end_op);
if (r == NULL)
return 0; return 0;
} /* Check for a segment override by searching for ':' after a
/* Check for segment override, rather than segment register by segment register. */
searching for ':' after %<x>s where <x> = s, c, d, e, f, g. */ op_string = end_op;
if ((r->reg_type & (SReg2 | SReg3)) && op_string[3] == ':') if (is_space_char (*op_string))
++op_string;
if ((r->reg_type & (SReg2 | SReg3)) && *op_string == ':')
{ {
switch (r->reg_num) switch (r->reg_num)
{ {
@ -2269,7 +2280,12 @@ i386_operand (operand_string)
i.seg[i.mem_operands] = &gs; i.seg[i.mem_operands] = &gs;
break; break;
} }
op_string += 4; /* skip % <x> s : */
/* Skip the ':' and whitespace. */
++op_string;
if (is_space_char (*op_string))
++op_string;
operand_string = op_string; /* Pretend given string starts here. */ operand_string = op_string; /* Pretend given string starts here. */
if (!is_digit_char (*op_string) && !is_identifier_char (*op_string) if (!is_digit_char (*op_string) && !is_identifier_char (*op_string)
&& *op_string != '(' && *op_string != ABSOLUTE_PREFIX) && *op_string != '(' && *op_string != ABSOLUTE_PREFIX)
@ -2280,7 +2296,9 @@ i386_operand (operand_string)
/* Handle case of %es:*foo. */ /* Handle case of %es:*foo. */
if (*op_string == ABSOLUTE_PREFIX) if (*op_string == ABSOLUTE_PREFIX)
{ {
op_string++; ++op_string;
if (is_space_char (*op_string))
++op_string;
i.types[this_operand] |= JumpAbsolute; i.types[this_operand] |= JumpAbsolute;
} }
goto do_memory_reference; goto do_memory_reference;
@ -2303,9 +2321,13 @@ i386_operand (operand_string)
exp = &im_expressions[i.imm_operands++]; exp = &im_expressions[i.imm_operands++];
i.imms[this_operand] = exp; i.imms[this_operand] = exp;
++op_string;
if (is_space_char (*op_string))
++op_string;
save_input_line_pointer = input_line_pointer; save_input_line_pointer = input_line_pointer;
input_line_pointer = ++op_string; /* must advance op_string! */ input_line_pointer = op_string;
SKIP_WHITESPACE ();
exp_seg = expression (exp); exp_seg = expression (exp);
if (*input_line_pointer != '\0') if (*input_line_pointer != '\0')
{ {
@ -2396,10 +2418,15 @@ i386_operand (operand_string)
/* Check for base index form. We detect the base index form by /* Check for base index form. We detect the base index form by
looking for an ')' at the end of the operand, searching looking for an ')' at the end of the operand, searching
for the '(' matching it, and finding a REGISTER_PREFIX or ',' for the '(' matching it, and finding a REGISTER_PREFIX or ','
after it. */ after the '('. */
found_base_index_form = 0; found_base_index_form = 0;
end_of_operand_string = op_string + strlen (op_string); end_of_operand_string = op_string + strlen (op_string);
base_string = end_of_operand_string - 1;
--end_of_operand_string;
if (is_space_char (*end_of_operand_string))
--end_of_operand_string;
base_string = end_of_operand_string;
if (*base_string == ')') if (*base_string == ')')
{ {
unsigned int parens_balanced = 1; unsigned int parens_balanced = 1;
@ -2414,7 +2441,16 @@ i386_operand (operand_string)
parens_balanced--; parens_balanced--;
} }
while (parens_balanced); while (parens_balanced);
base_string++; /* Skip past '('. */
/* If there is a displacement set-up for it to be parsed later. */
displacement_string_start = op_string;
displacement_string_end = base_string;
/* Skip past '(' and whitespace. */
++base_string;
if (is_space_char (*base_string))
++base_string;
if (*base_string == REGISTER_PREFIX || *base_string == ',') if (*base_string == REGISTER_PREFIX || *base_string == ',')
found_base_index_form = 1; found_base_index_form = 1;
} }
@ -2425,133 +2461,130 @@ i386_operand (operand_string)
if (!found_base_index_form) if (!found_base_index_form)
{ {
displacement_string_start = op_string; displacement_string_start = op_string;
displacement_string_end = end_of_operand_string; displacement_string_end = end_of_operand_string + 1;
} }
else else
{ {
char *base_reg_name, *index_reg_name, *num_string;
int num;
i.types[this_operand] |= BaseIndex; i.types[this_operand] |= BaseIndex;
/* If there is a displacement set-up for it to be parsed later. */
displacement_string_start = NULL;
if (base_string != op_string + 1)
{
displacement_string_start = op_string;
displacement_string_end = base_string - 1;
}
/* Find base register (if any). */ /* Find base register (if any). */
if (*base_string != ',') if (*base_string != ',')
{ {
base_reg_name = base_string++; char *end_op;
/* skip past register name & parse it */
while (isalpha (*base_string)) /* Trim off the closing ')' so that parse_register won't
base_string++; see it. */
if (base_string == base_reg_name + 1) END_STRING_AND_SAVE (end_of_operand_string);
i.base_reg = parse_register (base_string, &end_op);
if (i.base_reg == NULL)
{ {
as_bad (_("can't find base register name after `(%c'"), RESTORE_END_STRING (end_of_operand_string);
REGISTER_PREFIX);
return 0; return 0;
} }
END_STRING_AND_SAVE (base_string); RESTORE_END_STRING (end_of_operand_string);
if (!(i.base_reg = parse_register (base_reg_name))) base_string = end_op;
{ if (is_space_char (*base_string))
as_bad (_("bad base register name `%s'"), base_reg_name); ++base_string;
RESTORE_END_STRING (base_string);
return 0;
}
RESTORE_END_STRING (base_string);
} }
/* Now check seperator; must be ',' ==> index reg /* There may be an index reg or scale factor here. */
OR num ==> no index reg. just scale factor if (*base_string == ',')
OR ')' ==> end. (scale factor = 1) */
if (*base_string != ',' && *base_string != ')')
{ {
as_bad (_("expecting `,' or `)' after base register in `%s'"), ++base_string;
if (is_space_char (*base_string))
++base_string;
if (*base_string == REGISTER_PREFIX)
{
char *end_op;
END_STRING_AND_SAVE (end_of_operand_string);
i.index_reg = parse_register (base_string, &end_op);
RESTORE_END_STRING (end_of_operand_string);
if (i.index_reg == NULL)
return 0;
base_string = end_op;
if (is_space_char (*base_string))
++base_string;
if (*base_string == ',')
{
++base_string;
if (is_space_char (*base_string))
++base_string;
}
else if (*base_string != ')')
{
as_bad (_("expecting `,' or `)' after index register in `%s'"),
operand_string); operand_string);
return 0; return 0;
} }
/* There may index reg here; and there may be a scale factor. */
if (*base_string == ',' && *(base_string + 1) == REGISTER_PREFIX)
{
index_reg_name = ++base_string;
while (isalpha (*++base_string));
END_STRING_AND_SAVE (base_string);
if (!(i.index_reg = parse_register (index_reg_name)))
{
as_bad (_("bad index register name `%s'"), index_reg_name);
RESTORE_END_STRING (base_string);
return 0;
}
RESTORE_END_STRING (base_string);
} }
/* Check for scale factor. */ /* Check for scale factor. */
if (*base_string == ',' && isdigit (*(base_string + 1))) if (isdigit ((unsigned char) *base_string))
{ {
num_string = ++base_string; if (isdigit ((unsigned char) base_string[1]))
while (is_digit_char (*base_string)) goto bad_scale; /* must be 1 digit scale */
base_string++; switch (*base_string)
if (base_string == num_string)
{ {
as_bad (_("can't find a scale factor after `,'")); case '1':
return 0;
}
END_STRING_AND_SAVE (base_string);
/* We've got a scale factor. */
if (!sscanf (num_string, "%d", &num))
{
as_bad (_("can't parse scale factor from `%s'"), num_string);
RESTORE_END_STRING (base_string);
return 0;
}
RESTORE_END_STRING (base_string);
switch (num)
{ /* must be 1 digit scale */
case 1:
i.log2_scale_factor = 0; i.log2_scale_factor = 0;
break; break;
case 2: case '2':
i.log2_scale_factor = 1; i.log2_scale_factor = 1;
break; break;
case 4: case '4':
i.log2_scale_factor = 2; i.log2_scale_factor = 2;
break; break;
case 8: case '8':
i.log2_scale_factor = 3; i.log2_scale_factor = 3;
break; break;
default: default:
as_bad (_("expecting scale factor of 1, 2, 4, 8; got %d"), num); bad_scale:
as_bad (_("expecting scale factor of 1, 2, 4 or 8; got `%s'"),
base_string);
return 0; return 0;
} }
if (num != 1 && ! i.index_reg)
++base_string;
if (is_space_char (*base_string))
++base_string;
if (*base_string != ')')
{
as_bad (_("expecting `)' after scale factor in `%s'"),
operand_string);
return 0;
}
if (i.log2_scale_factor != 0 && ! i.index_reg)
{ {
as_warn (_("scale factor of %d without an index register"), as_warn (_("scale factor of %d without an index register"),
num); 1 << i.log2_scale_factor);
#if SCALE1_WHEN_NO_INDEX #if SCALE1_WHEN_NO_INDEX
i.log2_scale_factor = 0; i.log2_scale_factor = 0;
#endif #endif
} }
} }
else else if (!i.index_reg)
{
if (!i.index_reg && *base_string == ',')
{ {
as_bad (_("expecting index register or scale factor after `,'; got '%c'"), as_bad (_("expecting index register or scale factor after `,'; got '%c'"),
*(base_string + 1)); *base_string);
return 0; return 0;
} }
} }
else if (*base_string != ')')
{
as_bad (_("expecting `,' or `)' after base register in `%s'"),
operand_string);
return 0;
}
} }
/* If there's an expression begining the operand, parse it, /* If there's an expression begining the operand, parse it,
assuming displacement_string_start and displacement_string_end assuming displacement_string_start and
are meaningful. */ displacement_string_end are meaningful. */
if (displacement_string_start) if (displacement_string_start != displacement_string_end)
{ {
register expressionS *exp; register expressionS *exp;
segT exp_seg = 0; segT exp_seg = 0;
@ -3199,23 +3232,45 @@ output_invalid (c)
return output_invalid_buf; return output_invalid_buf;
} }
/* reg_string starts *before* REGISTER_PREFIX */ /* REG_STRING starts *before* REGISTER_PREFIX. */
static const reg_entry *
parse_register (reg_string) static const reg_entry *
const char *reg_string; parse_register (reg_string, end_op)
{ char *reg_string;
register const char *s = reg_string; char **end_op;
register char *p; {
char reg_name_given[MAX_REG_NAME_SIZE]; register char *s = reg_string;
register char *p;
char reg_name_given[MAX_REG_NAME_SIZE + 1];
const reg_entry *r;
/* Skip REGISTER_PREFIX and possible whitespace. */
++s;
if (is_space_char (*s))
++s;
s++; /* skip REGISTER_PREFIX */
p = reg_name_given; p = reg_name_given;
while ((*p++ = register_chars[(unsigned char) *s++]) != '\0') while ((*p++ = register_chars[(unsigned char) *s++]) != '\0')
{ {
if (p >= reg_name_given + MAX_REG_NAME_SIZE) if (p >= reg_name_given + MAX_REG_NAME_SIZE)
{
*p = '\0';
as_bad (_("bad register name `%s'"), reg_name_given);
return (const reg_entry *) NULL; return (const reg_entry *) NULL;
} }
return (const reg_entry *) hash_find (reg_hash, reg_name_given); }
*end_op = s - 1;
r = (const reg_entry *) hash_find (reg_hash, reg_name_given);
if (r == NULL)
{
as_bad (_("bad register name `%s'"), reg_name_given);
return (const reg_entry *) NULL;
}
return r;
} }
#ifdef OBJ_ELF #ifdef OBJ_ELF
@ -3337,9 +3392,10 @@ md_section_align (segment, size)
return size; return size;
} }
/* Exactly what point is a PC-relative offset relative TO? On the /* On the i386, PC-relative offsets are relative to the start of the
i386, they're relative to the address of the offset, plus its next instruction. That is, the address of the offset, plus its
size. (??? Is this right? FIXME-SOON!) */ size, since the offset is always the last part of the insn. */
long long
md_pcrel_from (fixP) md_pcrel_from (fixP)
fixS *fixP; fixS *fixP;