static int local_label_id;
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
symbol table. The other assembler only does 32 levels, so there! */
#define MAX_SUBSYM_HASH 100
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
since macros use their own 'namespace' for local labels, use a separate hash
We use our own macro nesting counter, since GAS overloads it when expanding
other things (like conditionals and repeat loops). */
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. */
static htab_t stag_hash;
static htab_t op_hash;
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);
}
else
{
+ size_t len;
str = input_line_pointer;
while ((c = *input_line_pointer) != ',')
{
break;
++input_line_pointer;
}
- *input_line_pointer = 0;
+ len = input_line_pointer - str;
+ str = notes_memdup (str, len, len + 1);
}
if (c != ',')
{
as_bad (_("Comma and symbol expected for '.asg STRING, SYMBOL'"));
+ notes_free (str);
ignore_rest_of_line ();
return;
}
++input_line_pointer;
c = get_symbol_name (&name); /* Get terminator. */
+ name = notes_strdup (name);
+ (void) restore_line_pointer (c);
if (!ISALPHA (*name))
{
as_bad (_("symbols assigned with .asg must begin with a letter"));
+ notes_free (str);
ignore_rest_of_line ();
return;
}
- str = xstrdup (str);
- name = xstrdup (name);
subsym_create_or_replace (name, str);
- (void) restore_line_pointer (c);
demand_empty_rest_of_line ();
}
return;
}
c = get_symbol_name (&name); /* Get terminator. */
- name = xstrdup (name);
- (void) restore_line_pointer (c);
if (!ISALPHA (*name))
{
as_bad (_("symbols assigned with .eval must begin with a letter"));
+ (void) restore_line_pointer (c);
ignore_rest_of_line ();
return;
}
+ name = notes_strdup (name);
+ (void) restore_line_pointer (c);
+
symbolP = symbol_new (name, absolute_section, &zero_address_frag, value);
SF_SET_LOCAL (symbolP);
symbol_table_insert (symbolP);
But since there's not written rule as to when, don't even bother trying
to match their behavior. */
sprintf (valuestr, "%d", value);
- tmp = xstrdup (valuestr);
+ tmp = notes_strdup (valuestr);
subsym_create_or_replace (name, tmp);
demand_empty_rest_of_line ();
}
else
{
- char *replacement;
-
- replacement = concat (S_GET_NAME (rootsym), "+", root_stag_name,
- name + strlen (S_GET_NAME (rootsym)), NULL);
- str_hash_insert (subsym_hash[0], name, replacement, 0);
+ subsym_ent_t *ent = xmalloc (sizeof (*ent));
+ ent->u.s = concat (S_GET_NAME (rootsym), "+", root_stag_name,
+ name + strlen (S_GET_NAME (rootsym)), NULL);
+ ent->freekey = 1;
+ ent->freeval = 1;
+ ent->isproc = 0;
+ ent->ismath = 0;
+ str_hash_insert (subsym_hash[0], name, ent, 0);
freename = NULL;
}
demand_empty_rest_of_line ();
}
-/* Remove the symbol from the local label hash lookup. */
+static void
+free_subsym_ent (void *ent)
+{
+ string_tuple_t *tuple = (string_tuple_t *) ent;
+ subsym_ent_t *val = (void *) tuple->value;
+ if (val->freekey)
+ free ((void *) tuple->key);
+ if (val->freeval)
+ free (val->u.s);
+ free (val);
+ free (ent);
+}
-static int
-tic54x_remove_local_label (void **slot, void *arg ATTRIBUTE_UNUSED)
+static htab_t
+subsym_htab_create (void)
{
- string_tuple_t *tuple = *((string_tuple_t **) slot);
- void *elem = str_hash_find (local_label_hash[macro_level], tuple->key);
- str_hash_delete (local_label_hash[macro_level], tuple->key);
- free (elem);
- return 0;
+ 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. */
static void
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
static void
tic54x_var (int ignore ATTRIBUTE_UNUSED)
{
- static char empty[] = "";
char *name;
int c;
return;
}
c = get_symbol_name (&name);
- /* .var symbols start out with a null string. */
name = xstrdup (name);
- str_hash_insert (subsym_hash[macro_level], name, empty, 0);
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 == ',')
{
++input_line_pointer;
{
if (++macro_level >= MAX_SUBSYM_HASH)
{
+ --macro_level;
as_fatal (_("Macro nesting is too deep"));
return;
}
- subsym_hash[macro_level] = str_htab_create ();
- local_label_hash[macro_level] = str_htab_create ();
+ subsym_hash[macro_level] = subsym_htab_create ();
+ local_label_hash[macro_level] = local_label_htab_create ();
}
void
for (entry = macro->formals; entry; entry = entry->next)
{
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';
- value[entry->actual.len] = '\0';
- str_hash_insert (subsym_hash[macro_level], name, value, 0);
+ ent->u.s = xstrndup (entry->actual.ptr, entry->actual.len);
+ ent->freekey = 1;
+ ent->freeval = 1;
+ ent->isproc = 0;
+ ent->ismath = 0;
+ str_hash_insert (subsym_hash[macro_level], name, ent, 0);
}
}
static int
subsym_ismember (char *sym, char *list)
{
- char *elem, *ptr, *listv;
+ char *elem, *ptr;
+ subsym_ent_t *listv;
if (!list)
return 0;
listv = subsym_lookup (list, macro_level);
- if (!listv)
+ if (!listv || listv->isproc)
{
as_bad (_("Undefined substitution symbol '%s'"), list);
ignore_rest_of_line ();
return 0;
}
- ptr = elem = xstrdup (listv);
+ ptr = elem = notes_strdup (listv->u.s);
while (*ptr && *ptr != ',')
++ptr;
*ptr++ = 0;
return (float) ceil (arg1);
}
-static float
+static int
math_cvi (float arg1, float ignore ATTRIBUTE_UNUSED)
{
return (int) arg1;
return (int) arg1 % (int) arg2;
}
-static float
+static int
math_int (float arg1, float ignore ATTRIBUTE_UNUSED)
{
- return ((float) ((int) arg1)) == arg1;
+ return arg1 == (float) (int) arg1;
}
static float
return arg1 > 0 ? (int) (arg1 + 0.5) : (int) (arg1 - 0.5);
}
-static float
+static int
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
}
/* 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[] =
{
/* Assembler built-in string substitution functions. */
- { "$symlen", subsym_symlen, 1, },
- { "$symcmp", subsym_symcmp, 2, },
- { "$firstch", subsym_firstch, 2, },
- { "$lastch", subsym_lastch, 2, },
- { "$isdefed", subsym_isdefed, 1, },
- { "$ismember", subsym_ismember, 2, },
- { "$iscons", subsym_iscons, 1, },
- { "$isname", subsym_isname, 1, },
- { "$isreg", subsym_isreg, 1, },
- { "$structsz", subsym_structsz, 1, },
- { "$structacc", subsym_structacc, 1, },
- { NULL, NULL, 0 },
-};
-
-typedef struct
-{
- const char *name;
- float (*proc) (float, float);
- int nargs;
- int int_return;
-} math_proc_entry;
+ { "$symlen", { .s = subsym_symlen }, 1, 0 },
+ { "$symcmp", { .s = subsym_symcmp }, 2, 0 },
+ { "$firstch", { .s = subsym_firstch }, 2, 0 },
+ { "$lastch", { .s = subsym_lastch }, 2, 0 },
+ { "$isdefed", { .s = subsym_isdefed }, 1, 0 },
+ { "$ismember", { .s = subsym_ismember }, 2, 0 },
+ { "$iscons", { .s = subsym_iscons }, 1, 0 },
+ { "$isname", { .s = subsym_isname }, 1, 0 },
+ { "$isreg", { .s = subsym_isreg }, 1, 0 },
+ { "$structsz", { .s = subsym_structsz }, 1, 0 },
+ { "$structacc", { .s = subsym_structacc }, 1, 0 },
-static const math_proc_entry math_procs[] =
-{
/* Integer-returning built-in math functions. */
- { "$cvi", math_cvi, 1, 1 },
- { "$int", math_int, 1, 1 },
- { "$sgn", math_sgn, 1, 1 },
+ { "$cvi", { .i = math_cvi }, 1, 2 },
+ { "$int", { .i = math_int }, 1, 2 },
+ { "$sgn", { .i = math_sgn }, 1, 2 },
/* Float-returning built-in math functions. */
- { "$acos", math_acos, 1, 0 },
- { "$asin", math_asin, 1, 0 },
- { "$atan", math_atan, 1, 0 },
- { "$atan2", math_atan2, 2, 0 },
- { "$ceil", math_ceil, 1, 0 },
- { "$cosh", math_cosh, 1, 0 },
- { "$cos", math_cos, 1, 0 },
- { "$cvf", math_cvf, 1, 0 },
- { "$exp", math_exp, 1, 0 },
- { "$fabs", math_fabs, 1, 0 },
- { "$floor", math_floor, 1, 0 },
- { "$fmod", math_fmod, 2, 0 },
- { "$ldexp", math_ldexp, 2, 0 },
- { "$log10", math_log10, 1, 0 },
- { "$log", math_log, 1, 0 },
- { "$max", math_max, 2, 0 },
- { "$min", math_min, 2, 0 },
- { "$pow", math_pow, 2, 0 },
- { "$round", math_round, 1, 0 },
- { "$sin", math_sin, 1, 0 },
- { "$sinh", math_sinh, 1, 0 },
- { "$sqrt", math_sqrt, 1, 0 },
- { "$tan", math_tan, 1, 0 },
- { "$tanh", math_tanh, 1, 0 },
- { "$trunc", math_trunc, 1, 0 },
- { NULL, NULL, 0, 0 },
+ { "$acos", { .f = math_acos }, 1, 1 },
+ { "$asin", { .f = math_asin }, 1, 1 },
+ { "$atan", { .f = math_atan }, 1, 1 },
+ { "$atan2", { .f = math_atan2 }, 2, 1 },
+ { "$ceil", { .f = math_ceil }, 1, 1 },
+ { "$cosh", { .f = math_cosh }, 1, 1 },
+ { "$cos", { .f = math_cos }, 1, 1 },
+ { "$cvf", { .f = math_cvf }, 1, 1 },
+ { "$exp", { .f = math_exp }, 1, 1 },
+ { "$fabs", { .f = math_fabs }, 1, 1 },
+ { "$floor", { .f = math_floor }, 1, 1 },
+ { "$fmod", { .f = math_fmod }, 2, 1 },
+ { "$ldexp", { .f = math_ldexp }, 2, 1 },
+ { "$log10", { .f = math_log10 }, 1, 1 },
+ { "$log", { .f = math_log }, 1, 1 },
+ { "$max", { .f = math_max }, 2, 1 },
+ { "$min", { .f = math_min }, 2, 1 },
+ { "$pow", { .f = math_pow }, 2, 1 },
+ { "$round", { .f = math_round }, 1, 1 },
+ { "$sin", { .f = math_sin }, 1, 1 },
+ { "$sinh", { .f = math_sinh }, 1, 1 },
+ { "$sqrt", { .f = math_sqrt }, 1, 1 },
+ { "$tan", { .f = math_tan }, 1, 1 },
+ { "$tanh", { .f = math_tanh }, 1, 1 },
+ { "$trunc", { .f = math_trunc }, 1, 1 },
+ { NULL, { NULL }, 0, 0 },
};
void
insn_template *tm;
const tic54x_symbol *sym;
const subsym_proc_entry *subsym_proc;
- const math_proc_entry *math_proc;
const char **symname;
char *TIC54X_DIR = getenv ("TIC54X_DIR");
char *A_DIR = TIC54X_DIR ? TIC54X_DIR : getenv ("A_DIR");
/* Only the base substitution table and local label table are initialized;
the others (for local macro substitution) get instantiated as needed. */
- local_label_hash[0] = str_htab_create ();
- subsym_hash[0] = str_htab_create ();
+ local_label_hash[0] = local_label_htab_create ();
+ subsym_hash[0] = subsym_htab_create ();
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
- the math hash to actually store information. */
- str_hash_insert (subsym_hash[0], math_proc->name, math_proc, 0);
- str_hash_insert (math_hash, math_proc->name, math_proc, 0);
+ subsym_ent_t *ent = xmalloc (sizeof (*ent));
+ ent->u.p = subsym_proc;
+ ent->freekey = 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 ();
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
is_accumulator (struct opstruct *operand)
{
else
{
const char *term = terminators;
- char *value = NULL;
while (*ptr && *ptr != *term)
{
endp = ptr;
*str = xmemdup0 (line, ptr - line);
/* Do simple substitution, if available. */
- if (!nosub && (value = subsym_lookup (*str, macro_level)) != NULL)
- *str = value;
+ if (!nosub)
+ {
+ subsym_ent_t *ent = subsym_lookup (*str, macro_level);
+ if (ent && !ent->isproc)
+ *str = ent->u.s;
+ }
}
return endp;
subsym_create_or_replace (char *name, char *value)
{
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--)
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;
}
- 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.
Start with the innermost macro substitution table given and work
outwards. */
-static char *
+static subsym_ent_t *
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)
return value;
int recurse = 1;
int line_conditional = 0;
char *tmp;
-
- /* Work with a copy of the input line. */
- replacement = xstrdup (line);
-
- ptr = head = replacement;
+ unsigned char current_char;
/* Flag lines where we might need to replace a single '=' with two;
GAS uses single '=' to assign macro args values, and possibly other
if (strstr (line, ".macro"))
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)])
{
/* Need to update this since LINE may have been modified. */
char *name; /* Symbol to be replaced. */
char *savedp = input_line_pointer;
int c;
+ subsym_ent_t *ent = NULL;
char *value = NULL;
char *tail; /* Rest of line after symbol. */
/* Avoid infinite recursion; if a symbol shows up a second time for
substitution, leave it as is. */
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
as_warn (_("%s symbol recursion stopped at "
"second appearance of '%s'"),
ptr = tail;
}
/* 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;
- math_proc_entry *math_entry = str_hash_find (math_hash, name);
+ const subsym_proc_entry *entry = ent->u.p;
char *arg1, *arg2 = NULL;
*ptr = c;
- if (entry == NULL)
+ if (!ent->isproc)
{
as_bad (_("Unrecognized substitution symbol function"));
break;
break;
}
++ptr;
- if (math_entry != NULL)
+ if (ent->ismath)
{
float farg1, farg2 = 0;
- volatile float fresult;
farg1 = (float) strtod (ptr, &ptr);
- if (math_entry->nargs == 2)
+ if (entry->nargs == 2)
{
if (*ptr++ != ',')
{
}
farg2 = (float) strtod (ptr, &ptr);
}
- fresult = (*math_entry->proc) (farg1, farg2);
value = XNEWVEC (char, 128);
- if (math_entry->int_return)
- sprintf (value, "%d", (int) fresult);
+ if (entry->type == 2)
+ {
+ int result = (*entry->proc.i) (farg1, farg2);
+ sprintf (value, "%d", result);
+ }
else
- sprintf (value, "%f", fresult);
+ {
+ float result = (*entry->proc.f) (farg1, farg2);
+ sprintf (value, "%f", result);
+ }
if (*ptr++ != ')')
{
as_bad (_("Extra junk in function call, expecting ')'"));
as_bad (_("Extra junk in function call, expecting ')'"));
break;
}
- val = (*entry->proc) (arg1, arg2);
+ val = (*entry->proc.s) (arg1, arg2);
value = XNEWVEC (char, 64);
sprintf (value, "%d", val);
}
if (changed)
return replacement;
- else
- return line;
+
+ free (replacement);
+ return line;
}
/* We use this to handle substitution symbols