gas: tc-tic54x.c hash tables

Cleaning up the subsym_hash memory is a real pain.  Keys and values
entered into the table are quite diverse.  In some cases the key is
allocated and thus needs to be freed, in others the key is a const
string.  Values are similar, and in some cases not even a string.
Tidy this by inserting a new subsym_ent_t that describes key/value
type.  This meant the math_hash table was no longer needed.  The patch
also tidies how math functions are called, those that are supposed to
return int now no longer return their value in a float.

	* config/tc-tic54x.c (math_hash): Delete.
	(subsym_proc_entry): Move earlier, make proc a union, merge with..
	(math_proc_entry): ..this.  Delete type.
	(math_procs): Merge into subsym_procs.
	(subsym_ent_t): New.  Use this type in subsym_hash..
	(stag_add_field_symbols, tic54x_var, tic54x_macro_info): ..here..
	(md_begin, subsym_create_or_replace, subsym_lookup): ..and here..
	(subsym_substitute): ..and here.  Adjust subsym_proc_entry
	function calls.  Free replacement when not returned.
	(subsym_get_arg): Adjust subsym_lookup.
	(free_subsym_ent, subsym_htab_create ): New functions, use when
	creating subsym_hash.
	(free_local_label_ent, local_label_htab_create): Similarly.
	(tic54x_remove_local_label): Delete.
	(tic54x_clear_local_labels): Simplify.
	(tic54x_asg): Use notes obstack to dup strings.
	(tic54x_eval): Likewise.
	(subsym_ismember): Likewise.
	(math_cvi, math_int, math_sgn): Return int.
	(tic54x_macro_start): Decrement macro_level before calling as_fatal.
	(tic54x_md_end): New function.
	* config/tc-tic54h.c (tic54x_md_end): Declare.
	(md_end): Define.
This commit is contained in:
Alan Modra
2022-07-08 17:37:07 +09:30
parent 0edfd2985b
commit eb6dce11fc
2 changed files with 224 additions and 140 deletions

View File

@ -182,12 +182,35 @@ static symbolS *last_label_seen = NULL;
static int local_label_id; static int local_label_id;
static htab_t subsym_recurse_hash; /* Prevent infinite recurse. */ static htab_t subsym_recurse_hash; /* Prevent infinite recurse. */
static htab_t math_hash; /* Built-in math functions. */
/* Allow maximum levels of macro nesting; level 0 is the main substitution /* Allow maximum levels of macro nesting; level 0 is the main substitution
symbol table. The other assembler only does 32 levels, so there! */ symbol table. The other assembler only does 32 levels, so there! */
#define MAX_SUBSYM_HASH 100 #define MAX_SUBSYM_HASH 100
static htab_t subsym_hash[MAX_SUBSYM_HASH]; static htab_t subsym_hash[MAX_SUBSYM_HASH];
typedef struct
{
const char *name;
union {
int (*s) (char *, char *);
float (*f) (float, float);
int (*i) (float, float);
} proc;
int nargs;
int type;
} subsym_proc_entry;
typedef struct {
union {
char *s;
const subsym_proc_entry *p;
} u;
unsigned int freekey : 1;
unsigned int freeval : 1;
unsigned int isproc : 1;
unsigned int ismath : 1;
} subsym_ent_t;
/* Keep track of local labels so we can substitute them before GAS sees them /* Keep track of local labels so we can substitute them before GAS sees them
since macros use their own 'namespace' for local labels, use a separate hash since macros use their own 'namespace' for local labels, use a separate hash
@ -197,7 +220,7 @@ static htab_t subsym_hash[MAX_SUBSYM_HASH];
We use our own macro nesting counter, since GAS overloads it when expanding We use our own macro nesting counter, since GAS overloads it when expanding
other things (like conditionals and repeat loops). */ other things (like conditionals and repeat loops). */
static int macro_level = 0; static int macro_level = 0;
static htab_t local_label_hash[100]; static htab_t local_label_hash[MAX_SUBSYM_HASH];
/* Keep track of struct/union tags. */ /* Keep track of struct/union tags. */
static htab_t stag_hash; static htab_t stag_hash;
static htab_t op_hash; static htab_t op_hash;
@ -223,7 +246,7 @@ static htab_t misc_symbol_hash;
static void subsym_create_or_replace (char *, char *); static void subsym_create_or_replace (char *, char *);
static char *subsym_lookup (char *, int); static subsym_ent_t *subsym_lookup (char *, int);
static char *subsym_substitute (char *, int); static char *subsym_substitute (char *, int);
@ -334,6 +357,7 @@ tic54x_asg (int x ATTRIBUTE_UNUSED)
} }
else else
{ {
size_t len;
str = input_line_pointer; str = input_line_pointer;
while ((c = *input_line_pointer) != ',') while ((c = *input_line_pointer) != ',')
{ {
@ -341,28 +365,30 @@ tic54x_asg (int x ATTRIBUTE_UNUSED)
break; break;
++input_line_pointer; ++input_line_pointer;
} }
*input_line_pointer = 0; len = input_line_pointer - str;
str = notes_memdup (str, len, len + 1);
} }
if (c != ',') if (c != ',')
{ {
as_bad (_("Comma and symbol expected for '.asg STRING, SYMBOL'")); as_bad (_("Comma and symbol expected for '.asg STRING, SYMBOL'"));
notes_free (str);
ignore_rest_of_line (); ignore_rest_of_line ();
return; return;
} }
++input_line_pointer; ++input_line_pointer;
c = get_symbol_name (&name); /* Get terminator. */ c = get_symbol_name (&name); /* Get terminator. */
name = notes_strdup (name);
(void) restore_line_pointer (c);
if (!ISALPHA (*name)) if (!ISALPHA (*name))
{ {
as_bad (_("symbols assigned with .asg must begin with a letter")); as_bad (_("symbols assigned with .asg must begin with a letter"));
notes_free (str);
ignore_rest_of_line (); ignore_rest_of_line ();
return; return;
} }
str = xstrdup (str);
name = xstrdup (name);
subsym_create_or_replace (name, str); subsym_create_or_replace (name, str);
(void) restore_line_pointer (c);
demand_empty_rest_of_line (); demand_empty_rest_of_line ();
} }
@ -407,15 +433,17 @@ tic54x_eval (int x ATTRIBUTE_UNUSED)
return; return;
} }
c = get_symbol_name (&name); /* Get terminator. */ c = get_symbol_name (&name); /* Get terminator. */
name = xstrdup (name);
(void) restore_line_pointer (c);
if (!ISALPHA (*name)) if (!ISALPHA (*name))
{ {
as_bad (_("symbols assigned with .eval must begin with a letter")); as_bad (_("symbols assigned with .eval must begin with a letter"));
(void) restore_line_pointer (c);
ignore_rest_of_line (); ignore_rest_of_line ();
return; return;
} }
name = notes_strdup (name);
(void) restore_line_pointer (c);
symbolP = symbol_new (name, absolute_section, &zero_address_frag, value); symbolP = symbol_new (name, absolute_section, &zero_address_frag, value);
SF_SET_LOCAL (symbolP); SF_SET_LOCAL (symbolP);
symbol_table_insert (symbolP); symbol_table_insert (symbolP);
@ -424,7 +452,7 @@ tic54x_eval (int x ATTRIBUTE_UNUSED)
But since there's not written rule as to when, don't even bother trying But since there's not written rule as to when, don't even bother trying
to match their behavior. */ to match their behavior. */
sprintf (valuestr, "%d", value); sprintf (valuestr, "%d", value);
tmp = xstrdup (valuestr); tmp = notes_strdup (valuestr);
subsym_create_or_replace (name, tmp); subsym_create_or_replace (name, tmp);
demand_empty_rest_of_line (); demand_empty_rest_of_line ();
@ -564,11 +592,14 @@ stag_add_field_symbols (struct stag *stag,
} }
else else
{ {
char *replacement; subsym_ent_t *ent = xmalloc (sizeof (*ent));
ent->u.s = concat (S_GET_NAME (rootsym), "+", root_stag_name,
replacement = concat (S_GET_NAME (rootsym), "+", root_stag_name, name + strlen (S_GET_NAME (rootsym)), NULL);
name + strlen (S_GET_NAME (rootsym)), NULL); ent->freekey = 1;
str_hash_insert (subsym_hash[0], name, replacement, 0); ent->freeval = 1;
ent->isproc = 0;
ent->ismath = 0;
str_hash_insert (subsym_hash[0], name, ent, 0);
freename = NULL; freename = NULL;
} }
@ -1115,16 +1146,40 @@ tic54x_global (int type)
demand_empty_rest_of_line (); demand_empty_rest_of_line ();
} }
/* Remove the symbol from the local label hash lookup. */ static void
free_subsym_ent (void *ent)
static int
tic54x_remove_local_label (void **slot, void *arg ATTRIBUTE_UNUSED)
{ {
string_tuple_t *tuple = *((string_tuple_t **) slot); string_tuple_t *tuple = (string_tuple_t *) ent;
void *elem = str_hash_find (local_label_hash[macro_level], tuple->key); subsym_ent_t *val = (void *) tuple->value;
str_hash_delete (local_label_hash[macro_level], tuple->key); if (val->freekey)
free (elem); free ((void *) tuple->key);
return 0; if (val->freeval)
free (val->u.s);
free (val);
free (ent);
}
static htab_t
subsym_htab_create (void)
{
return htab_create_alloc (16, hash_string_tuple, eq_string_tuple,
free_subsym_ent, xcalloc, free);
}
static void
free_local_label_ent (void *ent)
{
string_tuple_t *tuple = (string_tuple_t *) ent;
free ((void *) tuple->key);
free ((void *) tuple->value);
free (ent);
}
static htab_t
local_label_htab_create (void)
{
return htab_create_alloc (16, hash_string_tuple, eq_string_tuple,
free_local_label_ent, xcalloc, free);
} }
/* Reset all local labels. */ /* Reset all local labels. */
@ -1132,7 +1187,7 @@ tic54x_remove_local_label (void **slot, void *arg ATTRIBUTE_UNUSED)
static void static void
tic54x_clear_local_labels (int ignored ATTRIBUTE_UNUSED) tic54x_clear_local_labels (int ignored ATTRIBUTE_UNUSED)
{ {
htab_traverse (local_label_hash[macro_level], tic54x_remove_local_label, NULL); htab_empty (local_label_hash[macro_level]);
} }
/* .text /* .text
@ -2215,7 +2270,6 @@ tic54x_sslist (int show)
static void static void
tic54x_var (int ignore ATTRIBUTE_UNUSED) tic54x_var (int ignore ATTRIBUTE_UNUSED)
{ {
static char empty[] = "";
char *name; char *name;
int c; int c;
@ -2236,10 +2290,17 @@ tic54x_var (int ignore ATTRIBUTE_UNUSED)
return; return;
} }
c = get_symbol_name (&name); c = get_symbol_name (&name);
/* .var symbols start out with a null string. */
name = xstrdup (name); name = xstrdup (name);
str_hash_insert (subsym_hash[macro_level], name, empty, 0);
c = restore_line_pointer (c); c = restore_line_pointer (c);
/* .var symbols start out with a null string. */
subsym_ent_t *ent = xmalloc (sizeof (*ent));
ent->u.s = (char *) "";
ent->freekey = 1;
ent->freeval = 0;
ent->isproc = 0;
ent->ismath = 0;
str_hash_insert (subsym_hash[macro_level], name, ent, 0);
if (c == ',') if (c == ',')
{ {
++input_line_pointer; ++input_line_pointer;
@ -2503,11 +2564,12 @@ tic54x_macro_start (void)
{ {
if (++macro_level >= MAX_SUBSYM_HASH) if (++macro_level >= MAX_SUBSYM_HASH)
{ {
--macro_level;
as_fatal (_("Macro nesting is too deep")); as_fatal (_("Macro nesting is too deep"));
return; return;
} }
subsym_hash[macro_level] = str_htab_create (); subsym_hash[macro_level] = subsym_htab_create ();
local_label_hash[macro_level] = str_htab_create (); local_label_hash[macro_level] = local_label_htab_create ();
} }
void void
@ -2519,11 +2581,14 @@ tic54x_macro_info (const macro_entry *macro)
for (entry = macro->formals; entry; entry = entry->next) for (entry = macro->formals; entry; entry = entry->next)
{ {
char *name = xstrndup (entry->name.ptr, entry->name.len); char *name = xstrndup (entry->name.ptr, entry->name.len);
char *value = xstrndup (entry->actual.ptr, entry->actual.len); subsym_ent_t *ent = xmalloc (sizeof (*ent));
name[entry->name.len] = '\0'; ent->u.s = xstrndup (entry->actual.ptr, entry->actual.len);
value[entry->actual.len] = '\0'; ent->freekey = 1;
str_hash_insert (subsym_hash[macro_level], name, value, 0); ent->freeval = 1;
ent->isproc = 0;
ent->ismath = 0;
str_hash_insert (subsym_hash[macro_level], name, ent, 0);
} }
} }
@ -2594,20 +2659,21 @@ subsym_isdefed (char *a, char *ignore ATTRIBUTE_UNUSED)
static int static int
subsym_ismember (char *sym, char *list) subsym_ismember (char *sym, char *list)
{ {
char *elem, *ptr, *listv; char *elem, *ptr;
subsym_ent_t *listv;
if (!list) if (!list)
return 0; return 0;
listv = subsym_lookup (list, macro_level); listv = subsym_lookup (list, macro_level);
if (!listv) if (!listv || listv->isproc)
{ {
as_bad (_("Undefined substitution symbol '%s'"), list); as_bad (_("Undefined substitution symbol '%s'"), list);
ignore_rest_of_line (); ignore_rest_of_line ();
return 0; return 0;
} }
ptr = elem = xstrdup (listv); ptr = elem = notes_strdup (listv->u.s);
while (*ptr && *ptr != ',') while (*ptr && *ptr != ',')
++ptr; ++ptr;
*ptr++ = 0; *ptr++ = 0;
@ -2728,7 +2794,7 @@ math_ceil (float arg1, float ignore ATTRIBUTE_UNUSED)
return (float) ceil (arg1); return (float) ceil (arg1);
} }
static float static int
math_cvi (float arg1, float ignore ATTRIBUTE_UNUSED) math_cvi (float arg1, float ignore ATTRIBUTE_UNUSED)
{ {
return (int) arg1; return (int) arg1;
@ -2746,10 +2812,10 @@ math_fmod (float arg1, float arg2)
return (int) arg1 % (int) arg2; return (int) arg1 % (int) arg2;
} }
static float static int
math_int (float arg1, float ignore ATTRIBUTE_UNUSED) math_int (float arg1, float ignore ATTRIBUTE_UNUSED)
{ {
return ((float) ((int) arg1)) == arg1; return arg1 == (float) (int) arg1;
} }
static float static float
@ -2758,10 +2824,10 @@ math_round (float arg1, float ignore ATTRIBUTE_UNUSED)
return arg1 > 0 ? (int) (arg1 + 0.5) : (int) (arg1 - 0.5); return arg1 > 0 ? (int) (arg1 + 0.5) : (int) (arg1 - 0.5);
} }
static float static int
math_sgn (float arg1, float ignore ATTRIBUTE_UNUSED) math_sgn (float arg1, float ignore ATTRIBUTE_UNUSED)
{ {
return (arg1 < 0) ? -1 : (arg1 ? 1 : 0); return arg1 < 0.0f ? -1 : arg1 != 0.0f ? 1 : 0;
} }
static float static float
@ -2893,72 +2959,53 @@ math_tanh (float arg1, float ignore ATTRIBUTE_UNUSED)
} }
/* Built-in substitution symbol functions and math functions. */ /* Built-in substitution symbol functions and math functions. */
typedef struct
{
const char *name;
int (*proc) (char *, char *);
int nargs;
} subsym_proc_entry;
static const subsym_proc_entry subsym_procs[] = static const subsym_proc_entry subsym_procs[] =
{ {
/* Assembler built-in string substitution functions. */ /* Assembler built-in string substitution functions. */
{ "$symlen", subsym_symlen, 1, }, { "$symlen", { .s = subsym_symlen }, 1, 0 },
{ "$symcmp", subsym_symcmp, 2, }, { "$symcmp", { .s = subsym_symcmp }, 2, 0 },
{ "$firstch", subsym_firstch, 2, }, { "$firstch", { .s = subsym_firstch }, 2, 0 },
{ "$lastch", subsym_lastch, 2, }, { "$lastch", { .s = subsym_lastch }, 2, 0 },
{ "$isdefed", subsym_isdefed, 1, }, { "$isdefed", { .s = subsym_isdefed }, 1, 0 },
{ "$ismember", subsym_ismember, 2, }, { "$ismember", { .s = subsym_ismember }, 2, 0 },
{ "$iscons", subsym_iscons, 1, }, { "$iscons", { .s = subsym_iscons }, 1, 0 },
{ "$isname", subsym_isname, 1, }, { "$isname", { .s = subsym_isname }, 1, 0 },
{ "$isreg", subsym_isreg, 1, }, { "$isreg", { .s = subsym_isreg }, 1, 0 },
{ "$structsz", subsym_structsz, 1, }, { "$structsz", { .s = subsym_structsz }, 1, 0 },
{ "$structacc", subsym_structacc, 1, }, { "$structacc", { .s = subsym_structacc }, 1, 0 },
{ NULL, NULL, 0 },
};
typedef struct
{
const char *name;
float (*proc) (float, float);
int nargs;
int int_return;
} math_proc_entry;
static const math_proc_entry math_procs[] =
{
/* Integer-returning built-in math functions. */ /* Integer-returning built-in math functions. */
{ "$cvi", math_cvi, 1, 1 }, { "$cvi", { .i = math_cvi }, 1, 2 },
{ "$int", math_int, 1, 1 }, { "$int", { .i = math_int }, 1, 2 },
{ "$sgn", math_sgn, 1, 1 }, { "$sgn", { .i = math_sgn }, 1, 2 },
/* Float-returning built-in math functions. */ /* Float-returning built-in math functions. */
{ "$acos", math_acos, 1, 0 }, { "$acos", { .f = math_acos }, 1, 1 },
{ "$asin", math_asin, 1, 0 }, { "$asin", { .f = math_asin }, 1, 1 },
{ "$atan", math_atan, 1, 0 }, { "$atan", { .f = math_atan }, 1, 1 },
{ "$atan2", math_atan2, 2, 0 }, { "$atan2", { .f = math_atan2 }, 2, 1 },
{ "$ceil", math_ceil, 1, 0 }, { "$ceil", { .f = math_ceil }, 1, 1 },
{ "$cosh", math_cosh, 1, 0 }, { "$cosh", { .f = math_cosh }, 1, 1 },
{ "$cos", math_cos, 1, 0 }, { "$cos", { .f = math_cos }, 1, 1 },
{ "$cvf", math_cvf, 1, 0 }, { "$cvf", { .f = math_cvf }, 1, 1 },
{ "$exp", math_exp, 1, 0 }, { "$exp", { .f = math_exp }, 1, 1 },
{ "$fabs", math_fabs, 1, 0 }, { "$fabs", { .f = math_fabs }, 1, 1 },
{ "$floor", math_floor, 1, 0 }, { "$floor", { .f = math_floor }, 1, 1 },
{ "$fmod", math_fmod, 2, 0 }, { "$fmod", { .f = math_fmod }, 2, 1 },
{ "$ldexp", math_ldexp, 2, 0 }, { "$ldexp", { .f = math_ldexp }, 2, 1 },
{ "$log10", math_log10, 1, 0 }, { "$log10", { .f = math_log10 }, 1, 1 },
{ "$log", math_log, 1, 0 }, { "$log", { .f = math_log }, 1, 1 },
{ "$max", math_max, 2, 0 }, { "$max", { .f = math_max }, 2, 1 },
{ "$min", math_min, 2, 0 }, { "$min", { .f = math_min }, 2, 1 },
{ "$pow", math_pow, 2, 0 }, { "$pow", { .f = math_pow }, 2, 1 },
{ "$round", math_round, 1, 0 }, { "$round", { .f = math_round }, 1, 1 },
{ "$sin", math_sin, 1, 0 }, { "$sin", { .f = math_sin }, 1, 1 },
{ "$sinh", math_sinh, 1, 0 }, { "$sinh", { .f = math_sinh }, 1, 1 },
{ "$sqrt", math_sqrt, 1, 0 }, { "$sqrt", { .f = math_sqrt }, 1, 1 },
{ "$tan", math_tan, 1, 0 }, { "$tan", { .f = math_tan }, 1, 1 },
{ "$tanh", math_tanh, 1, 0 }, { "$tanh", { .f = math_tanh }, 1, 1 },
{ "$trunc", math_trunc, 1, 0 }, { "$trunc", { .f = math_trunc }, 1, 1 },
{ NULL, NULL, 0, 0 }, { NULL, { NULL }, 0, 0 },
}; };
void void
@ -2967,7 +3014,6 @@ md_begin (void)
insn_template *tm; insn_template *tm;
const tic54x_symbol *sym; const tic54x_symbol *sym;
const subsym_proc_entry *subsym_proc; const subsym_proc_entry *subsym_proc;
const math_proc_entry *math_proc;
const char **symname; const char **symname;
char *TIC54X_DIR = getenv ("TIC54X_DIR"); char *TIC54X_DIR = getenv ("TIC54X_DIR");
char *A_DIR = TIC54X_DIR ? TIC54X_DIR : getenv ("A_DIR"); char *A_DIR = TIC54X_DIR ? TIC54X_DIR : getenv ("A_DIR");
@ -3037,23 +3083,41 @@ md_begin (void)
/* Only the base substitution table and local label table are initialized; /* Only the base substitution table and local label table are initialized;
the others (for local macro substitution) get instantiated as needed. */ the others (for local macro substitution) get instantiated as needed. */
local_label_hash[0] = str_htab_create (); local_label_hash[0] = local_label_htab_create ();
subsym_hash[0] = str_htab_create (); subsym_hash[0] = subsym_htab_create ();
for (subsym_proc = subsym_procs; subsym_proc->name; subsym_proc++) for (subsym_proc = subsym_procs; subsym_proc->name; subsym_proc++)
str_hash_insert (subsym_hash[0], subsym_proc->name, subsym_proc, 0);
math_hash = str_htab_create ();
for (math_proc = math_procs; math_proc->name; math_proc++)
{ {
/* Insert into the main subsym hash for recognition; insert into subsym_ent_t *ent = xmalloc (sizeof (*ent));
the math hash to actually store information. */ ent->u.p = subsym_proc;
str_hash_insert (subsym_hash[0], math_proc->name, math_proc, 0); ent->freekey = 0;
str_hash_insert (math_hash, math_proc->name, math_proc, 0); ent->freeval = 0;
ent->isproc = 1;
ent->ismath = subsym_proc->type != 0;
str_hash_insert (subsym_hash[0], subsym_proc->name, ent, 0);
} }
subsym_recurse_hash = str_htab_create (); subsym_recurse_hash = str_htab_create ();
stag_hash = str_htab_create (); stag_hash = str_htab_create ();
} }
void
tic54x_md_end (void)
{
htab_delete (stag_hash);
htab_delete (subsym_recurse_hash);
while (macro_level != -1)
tic54x_macro_end ();
macro_level = 0;
htab_delete (misc_symbol_hash);
htab_delete (sbit_hash);
htab_delete (cc3_hash);
htab_delete (cc2_hash);
htab_delete (cc_hash);
htab_delete (mmreg_hash);
htab_delete (reg_hash);
htab_delete (parop_hash);
htab_delete (op_hash);
}
static int static int
is_accumulator (struct opstruct *operand) is_accumulator (struct opstruct *operand)
{ {
@ -4295,7 +4359,6 @@ subsym_get_arg (char *line, const char *terminators, char **str, int nosub)
else else
{ {
const char *term = terminators; const char *term = terminators;
char *value = NULL;
while (*ptr && *ptr != *term) while (*ptr && *ptr != *term)
{ {
@ -4310,8 +4373,12 @@ subsym_get_arg (char *line, const char *terminators, char **str, int nosub)
endp = ptr; endp = ptr;
*str = xmemdup0 (line, ptr - line); *str = xmemdup0 (line, ptr - line);
/* Do simple substitution, if available. */ /* Do simple substitution, if available. */
if (!nosub && (value = subsym_lookup (*str, macro_level)) != NULL) if (!nosub)
*str = value; {
subsym_ent_t *ent = subsym_lookup (*str, macro_level);
if (ent && !ent->isproc)
*str = ent->u.s;
}
} }
return endp; return endp;
@ -4326,24 +4393,30 @@ static void
subsym_create_or_replace (char *name, char *value) subsym_create_or_replace (char *name, char *value)
{ {
int i; int i;
subsym_ent_t *ent = xmalloc (sizeof (*ent));
ent->u.s = value;
ent->freekey = 0;
ent->freeval = 0;
ent->isproc = 0;
ent->ismath = 0;
for (i = macro_level; i > 0; i--) for (i = macro_level; i > 0; i--)
if (str_hash_find (subsym_hash[i], name)) if (str_hash_find (subsym_hash[i], name))
{ {
str_hash_insert (subsym_hash[i], name, value, 1); str_hash_insert (subsym_hash[i], name, ent, 1);
return; return;
} }
str_hash_insert (subsym_hash[0], name, value, 1); str_hash_insert (subsym_hash[0], name, ent, 1);
} }
/* Look up the substitution string replacement for the given symbol. /* Look up the substitution string replacement for the given symbol.
Start with the innermost macro substitution table given and work Start with the innermost macro substitution table given and work
outwards. */ outwards. */
static char * static subsym_ent_t *
subsym_lookup (char *name, int nest_level) subsym_lookup (char *name, int nest_level)
{ {
char *value = str_hash_find (subsym_hash[nest_level], name); void *value = str_hash_find (subsym_hash[nest_level], name);
if (value || nest_level == 0) if (value || nest_level == 0)
return value; return value;
@ -4374,11 +4447,7 @@ subsym_substitute (char *line, int forced)
int recurse = 1; int recurse = 1;
int line_conditional = 0; int line_conditional = 0;
char *tmp; char *tmp;
unsigned char current_char;
/* Work with a copy of the input line. */
replacement = xstrdup (line);
ptr = head = replacement;
/* Flag lines where we might need to replace a single '=' with two; /* Flag lines where we might need to replace a single '=' with two;
GAS uses single '=' to assign macro args values, and possibly other GAS uses single '=' to assign macro args values, and possibly other
@ -4398,7 +4467,10 @@ subsym_substitute (char *line, int forced)
if (strstr (line, ".macro")) if (strstr (line, ".macro"))
return line; return line;
unsigned char current_char; /* Work with a copy of the input line. */
replacement = xstrdup (line);
ptr = head = replacement;
while (!is_end_of_line[(current_char = * (unsigned char *) ptr)]) while (!is_end_of_line[(current_char = * (unsigned char *) ptr)])
{ {
/* Need to update this since LINE may have been modified. */ /* Need to update this since LINE may have been modified. */
@ -4445,6 +4517,7 @@ subsym_substitute (char *line, int forced)
char *name; /* Symbol to be replaced. */ char *name; /* Symbol to be replaced. */
char *savedp = input_line_pointer; char *savedp = input_line_pointer;
int c; int c;
subsym_ent_t *ent = NULL;
char *value = NULL; char *value = NULL;
char *tail; /* Rest of line after symbol. */ char *tail; /* Rest of line after symbol. */
@ -4465,7 +4538,11 @@ subsym_substitute (char *line, int forced)
/* Avoid infinite recursion; if a symbol shows up a second time for /* Avoid infinite recursion; if a symbol shows up a second time for
substitution, leave it as is. */ substitution, leave it as is. */
if (str_hash_find (subsym_recurse_hash, name) == NULL) if (str_hash_find (subsym_recurse_hash, name) == NULL)
value = subsym_lookup (name, macro_level); {
ent = subsym_lookup (name, macro_level);
if (ent && !ent->isproc)
value = ent->u.s;
}
else else
as_warn (_("%s symbol recursion stopped at " as_warn (_("%s symbol recursion stopped at "
"second appearance of '%s'"), "second appearance of '%s'"),
@ -4499,14 +4576,13 @@ subsym_substitute (char *line, int forced)
ptr = tail; ptr = tail;
} }
/* Check for built-in subsym and math functions. */ /* Check for built-in subsym and math functions. */
else if (value != NULL && *name == '$') else if (ent != NULL && *name == '$')
{ {
subsym_proc_entry *entry = (subsym_proc_entry *) value; const subsym_proc_entry *entry = ent->u.p;
math_proc_entry *math_entry = str_hash_find (math_hash, name);
char *arg1, *arg2 = NULL; char *arg1, *arg2 = NULL;
*ptr = c; *ptr = c;
if (entry == NULL) if (!ent->isproc)
{ {
as_bad (_("Unrecognized substitution symbol function")); as_bad (_("Unrecognized substitution symbol function"));
break; break;
@ -4517,13 +4593,12 @@ subsym_substitute (char *line, int forced)
break; break;
} }
++ptr; ++ptr;
if (math_entry != NULL) if (ent->ismath)
{ {
float farg1, farg2 = 0; float farg1, farg2 = 0;
volatile float fresult;
farg1 = (float) strtod (ptr, &ptr); farg1 = (float) strtod (ptr, &ptr);
if (math_entry->nargs == 2) if (entry->nargs == 2)
{ {
if (*ptr++ != ',') if (*ptr++ != ',')
{ {
@ -4532,12 +4607,17 @@ subsym_substitute (char *line, int forced)
} }
farg2 = (float) strtod (ptr, &ptr); farg2 = (float) strtod (ptr, &ptr);
} }
fresult = (*math_entry->proc) (farg1, farg2);
value = XNEWVEC (char, 128); value = XNEWVEC (char, 128);
if (math_entry->int_return) if (entry->type == 2)
sprintf (value, "%d", (int) fresult); {
int result = (*entry->proc.i) (farg1, farg2);
sprintf (value, "%d", result);
}
else else
sprintf (value, "%f", fresult); {
float result = (*entry->proc.f) (farg1, farg2);
sprintf (value, "%f", result);
}
if (*ptr++ != ')') if (*ptr++ != ')')
{ {
as_bad (_("Extra junk in function call, expecting ')'")); as_bad (_("Extra junk in function call, expecting ')'"));
@ -4593,7 +4673,7 @@ subsym_substitute (char *line, int forced)
as_bad (_("Extra junk in function call, expecting ')'")); as_bad (_("Extra junk in function call, expecting ')'"));
break; break;
} }
val = (*entry->proc) (arg1, arg2); val = (*entry->proc.s) (arg1, arg2);
value = XNEWVEC (char, 64); value = XNEWVEC (char, 64);
sprintf (value, "%d", val); sprintf (value, "%d", val);
} }
@ -4703,8 +4783,9 @@ subsym_substitute (char *line, int forced)
if (changed) if (changed)
return replacement; return replacement;
else
return line; free (replacement);
return line;
} }
/* We use this to handle substitution symbols /* We use this to handle substitution symbols

View File

@ -131,4 +131,7 @@ extern void tic54x_convert_frag(bfd *, segT, fragS *);
extern void tic54x_global (int); extern void tic54x_global (int);
extern void tic54x_md_end (void);
#define md_end tic54x_md_end
#endif #endif