+#define FB_LABEL_SPECIAL (10)
+
+static long fb_low_counter[FB_LABEL_SPECIAL];
+static long *fb_labels;
+static long *fb_label_instances;
+static long fb_label_count;
+static long fb_label_max;
+
+/* this must be more than FB_LABEL_SPECIAL */
+#define FB_LABEL_BUMP_BY (FB_LABEL_SPECIAL + 6)
+
+static void
+fb_label_init ()
+{
+ memset ((void *) fb_low_counter, '\0', sizeof (fb_low_counter));
+} /* fb_label_init() */
+
+/* add one to the instance number of this fb label */
+void
+fb_label_instance_inc (label)
+ long label;
+{
+ long *i;
+
+ if (label < FB_LABEL_SPECIAL)
+ {
+ ++fb_low_counter[label];
+ return;
+ }
+
+ if (fb_labels != NULL)
+ {
+ for (i = fb_labels + FB_LABEL_SPECIAL;
+ i < fb_labels + fb_label_count; ++i)
+ {
+ if (*i == label)
+ {
+ ++fb_label_instances[i - fb_labels];
+ return;
+ } /* if we find it */
+ } /* for each existing label */
+ }
+
+ /* if we get to here, we don't have label listed yet. */
+
+ if (fb_labels == NULL)
+ {
+ fb_labels = (long *) xmalloc (FB_LABEL_BUMP_BY * sizeof (long));
+ fb_label_instances = (long *) xmalloc (FB_LABEL_BUMP_BY * sizeof (long));
+ fb_label_max = FB_LABEL_BUMP_BY;
+ fb_label_count = FB_LABEL_SPECIAL;
+
+ }
+ else if (fb_label_count == fb_label_max)
+ {
+ fb_label_max += FB_LABEL_BUMP_BY;
+ fb_labels = (long *) xrealloc ((char *) fb_labels,
+ fb_label_max * sizeof (long));
+ fb_label_instances = (long *) xrealloc ((char *) fb_label_instances,
+ fb_label_max * sizeof (long));
+ } /* if we needed to grow */
+
+ fb_labels[fb_label_count] = label;
+ fb_label_instances[fb_label_count] = 1;
+ ++fb_label_count;
+}
+
+static long
+fb_label_instance (label)
+ long label;
+{
+ long *i;
+
+ if (label < FB_LABEL_SPECIAL)
+ {
+ return (fb_low_counter[label]);
+ }
+
+ if (fb_labels != NULL)
+ {
+ for (i = fb_labels + FB_LABEL_SPECIAL;
+ i < fb_labels + fb_label_count; ++i)
+ {
+ if (*i == label)
+ {
+ return (fb_label_instances[i - fb_labels]);
+ } /* if we find it */
+ } /* for each existing label */
+ }
+
+ /* We didn't find the label, so this must be a reference to the
+ first instance. */
+ return 0;
+}
+
+/*
+ * fb_label_name()
+ *
+ * Caller must copy returned name: we re-use the area for the next name.
+ *
+ * The mth occurence of label n: is turned into the symbol "Ln^Bm"
+ * where n is the label number and m is the instance number. "L" makes
+ * it a label discarded unless debugging and "^B"('\2') ensures no
+ * ordinary symbol SHOULD get the same name as a local label
+ * symbol. The first "4:" is "L4^B1" - the m numbers begin at 1.
+ *
+ * dollar labels get the same treatment, except that ^A is used in place of ^B. */
+
+char * /* Return local label name. */
+fb_label_name (n, augend)
+ long n; /* we just saw "n:", "nf" or "nb" : n a number */
+ long augend; /* 0 for nb, 1 for n:, nf */
+{
+ long i;
+ /* Returned to caller, then copied. used for created names ("4f") */
+ static char symbol_name_build[24];
+ register char *p;
+ register char *q;
+ char symbol_name_temporary[20]; /* build up a number, BACKWARDS */
+
+ know (n >= 0);
+ know (augend == 0 || augend == 1);
+ p = symbol_name_build;
+ *p++ = 'L';
+
+ /* Next code just does sprintf( {}, "%d", n); */
+ /* label number */
+ q = symbol_name_temporary;
+ for (*q++ = 0, i = n; i; ++q)
+ {
+ *q = i % 10 + '0';
+ i /= 10;
+ }
+ while ((*p = *--q) != '\0')
+ ++p;
+
+ *p++ = 2; /* ^B */
+
+ /* instance number */
+ q = symbol_name_temporary;
+ for (*q++ = 0, i = fb_label_instance (n) + augend; i; ++q)
+ {
+ *q = i % 10 + '0';
+ i /= 10;
+ }
+ while ((*p++ = *--q) != '\0');;
+
+ /* The label, as a '\0' ended string, starts at symbol_name_build. */
+ return (symbol_name_build);
+} /* fb_label_name() */
+
+/*
+ * decode name that may have been generated by foo_label_name() above. If
+ * the name wasn't generated by foo_label_name(), then return it unaltered.
+ * This is used for error messages.
+ */
+
+char *
+decode_local_label_name (s)
+ char *s;
+{
+ char *p;
+ char *symbol_decode;
+ int label_number;
+ int instance_number;
+ char *type;
+ const char *message_format = "\"%d\" (instance number %d of a %s label)";
+
+ if (s[0] != 'L')
+ return s;
+
+ for (label_number = 0, p = s + 1; isdigit (*p); ++p)
+ label_number = (10 * label_number) + *p - '0';
+
+ if (*p == 1)
+ type = "dollar";
+ else if (*p == 2)
+ type = "fb";
+ else
+ return s;
+
+ for (instance_number = 0, p++; isdigit (*p); ++p)
+ instance_number = (10 * instance_number) + *p - '0';
+
+ symbol_decode = obstack_alloc (¬es, strlen (message_format) + 30);
+ sprintf (symbol_decode, message_format, label_number, instance_number, type);
+
+ return symbol_decode;
+}
+
+/* Get the value of a symbol. */
+
+valueT
+S_GET_VALUE (s)
+ symbolS *s;
+{
+ if (!s->sy_resolved && !s->sy_resolving && s->sy_value.X_op != O_constant)
+ resolve_symbol_value (s);
+ if (s->sy_value.X_op != O_constant)
+ {
+ static symbolS *recur;
+
+ /* FIXME: In non BFD assemblers, S_IS_DEFINED and S_IS_COMMON
+ may call S_GET_VALUE. We use a static symbol to avoid the
+ immediate recursion. */
+ if (recur == s)
+ return (valueT) s->sy_value.X_add_number;
+ recur = s;
+ if (! s->sy_resolved
+ || s->sy_value.X_op != O_symbol
+ || (S_IS_DEFINED (s) && ! S_IS_COMMON (s)))
+ as_bad ("Attempt to get value of unresolved symbol %s",
+ S_GET_NAME (s));
+ recur = NULL;
+ }
+ return (valueT) s->sy_value.X_add_number;
+}
+
+/* Set the value of a symbol. */
+
+void
+S_SET_VALUE (s, val)
+ symbolS *s;
+ valueT val;
+{
+ s->sy_value.X_op = O_constant;
+ s->sy_value.X_add_number = (offsetT) val;
+ s->sy_value.X_unsigned = 0;
+}
+
+void
+copy_symbol_attributes (dest, src)
+ symbolS *dest, *src;
+{
+#ifdef BFD_ASSEMBLER
+ /* In an expression, transfer the settings of these flags.
+ The user can override later, of course. */
+#define COPIED_SYMFLAGS (BSF_FUNCTION)
+ dest->bsym->flags |= src->bsym->flags & COPIED_SYMFLAGS;
+#endif
+
+#ifdef OBJ_COPY_SYMBOL_ATTRIBUTES
+ OBJ_COPY_SYMBOL_ATTRIBUTES (dest, src);
+#endif
+}
+
+#ifdef BFD_ASSEMBLER
+
+int
+S_IS_EXTERNAL (s)
+ symbolS *s;
+{
+ flagword flags = s->bsym->flags;
+
+ /* sanity check */
+ if (flags & BSF_LOCAL && flags & BSF_GLOBAL)
+ abort ();
+
+ return (flags & BSF_GLOBAL) != 0;
+}
+
+int
+S_IS_WEAK (s)
+ symbolS *s;
+{
+ return (s->bsym->flags & BSF_WEAK) != 0;
+}
+
+int
+S_IS_COMMON (s)
+ symbolS *s;
+{
+ return bfd_is_com_section (s->bsym->section);
+}
+
+int
+S_IS_DEFINED (s)
+ symbolS *s;
+{
+ return s->bsym->section != undefined_section;
+}
+
+int
+S_IS_DEBUG (s)
+ symbolS *s;
+{
+ if (s->bsym->flags & BSF_DEBUGGING)
+ return 1;
+ return 0;
+}
+
+int
+S_IS_LOCAL (s)
+ symbolS *s;
+{
+ flagword flags = s->bsym->flags;
+ const char *name;
+
+ /* sanity check */
+ if (flags & BSF_LOCAL && flags & BSF_GLOBAL)
+ abort ();
+
+ if (bfd_get_section (s->bsym) == reg_section)
+ return 1;
+
+ name = S_GET_NAME (s);
+ return (name != NULL
+ && ! S_IS_DEBUG (s)
+ && (strchr (name, '\001')
+ || strchr (name, '\002')
+ || (! flag_keep_locals
+ && (bfd_is_local_label (stdoutput, s->bsym)
+ || (flag_mri
+ && name[0] == '?'
+ && name[1] == '?')))));
+}
+
+int
+S_IS_EXTERN (s)
+ symbolS *s;
+{
+ return S_IS_EXTERNAL (s);
+}
+
+int
+S_IS_STABD (s)
+ symbolS *s;
+{
+ return S_GET_NAME (s) == 0;
+}
+
+CONST char *
+S_GET_NAME (s)
+ symbolS *s;
+{
+ return s->bsym->name;
+}
+
+segT
+S_GET_SEGMENT (s)
+ symbolS *s;
+{
+ return s->bsym->section;
+}
+
+void
+S_SET_SEGMENT (s, seg)
+ symbolS *s;
+ segT seg;
+{
+ s->bsym->section = seg;
+}
+
+void
+S_SET_EXTERNAL (s)
+ symbolS *s;
+{
+ if ((s->bsym->flags & BSF_WEAK) != 0)
+ {
+ /* Let .weak override .global. */
+ return;
+ }
+ s->bsym->flags |= BSF_GLOBAL;
+ s->bsym->flags &= ~(BSF_LOCAL|BSF_WEAK);
+}
+
+void
+S_CLEAR_EXTERNAL (s)
+ symbolS *s;
+{
+ if ((s->bsym->flags & BSF_WEAK) != 0)
+ {
+ /* Let .weak override. */
+ return;
+ }
+ s->bsym->flags |= BSF_LOCAL;
+ s->bsym->flags &= ~(BSF_GLOBAL|BSF_WEAK);
+}
+
+void
+S_SET_WEAK (s)
+ symbolS *s;
+{
+ s->bsym->flags |= BSF_WEAK;
+ s->bsym->flags &= ~(BSF_GLOBAL|BSF_LOCAL);
+}
+
+void
+S_SET_NAME (s, name)
+ symbolS *s;
+ char *name;
+{
+ s->bsym->name = name;
+}
+#endif /* BFD_ASSEMBLER */
+
+void
+symbol_begin ()
+{
+ symbol_lastP = NULL;
+ symbol_rootP = NULL; /* In case we have 0 symbols (!!) */
+ sy_hash = hash_new ();
+
+ memset ((char *) (&abs_symbol), '\0', sizeof (abs_symbol));
+#ifdef BFD_ASSEMBLER
+#if defined (EMIT_SECTION_SYMBOLS) || !defined (RELOC_REQUIRES_SYMBOL)
+ abs_symbol.bsym = bfd_abs_section.symbol;
+#endif
+#else
+ /* Can't initialise a union. Sigh. */
+ S_SET_SEGMENT (&abs_symbol, absolute_section);
+#endif
+ abs_symbol.sy_value.X_op = O_constant;
+ abs_symbol.sy_frag = &zero_address_frag;
+
+ if (LOCAL_LABELS_FB)
+ fb_label_init ();
+}
+
+\f
+int indent_level;
+
+#if 0
+
+static void
+indent ()
+{
+ printf ("%*s", indent_level * 4, "");
+}
+
+#endif
+
+void
+print_symbol_value_1 (file, sym)
+ FILE *file;
+ symbolS *sym;
+{
+ const char *name = S_GET_NAME (sym);
+ if (!name || !name[0])
+ name = "(unnamed)";
+ fprintf (file, "sym %lx %s", (unsigned long) sym, name);
+ if (sym->sy_frag != &zero_address_frag)
+ fprintf (file, " frag %lx", (long) sym->sy_frag);
+ if (sym->written)
+ fprintf (file, " written");
+ if (sym->sy_resolved)
+ fprintf (file, " resolved");
+ else if (sym->sy_resolving)
+ fprintf (file, " resolving");
+ if (sym->sy_used_in_reloc)
+ fprintf (file, " used-in-reloc");
+ if (sym->sy_used)
+ fprintf (file, " used");
+ if (S_IS_LOCAL (sym))
+ fprintf (file, " local");
+ if (S_IS_EXTERN (sym))
+ fprintf (file, " extern");
+ if (S_IS_DEBUG (sym))
+ fprintf (file, " debug");
+ if (S_IS_DEFINED (sym))
+ fprintf (file, " defined");
+ fprintf (file, " %s", segment_name (S_GET_SEGMENT (sym)));
+ if (sym->sy_resolved)
+ {
+ segT s = S_GET_SEGMENT (sym);
+
+ if (s != undefined_section
+ && s != expr_section)
+ fprintf (file, " %lx", (long) S_GET_VALUE (sym));
+ }
+ else if (indent_level < 8 && S_GET_SEGMENT (sym) != undefined_section)
+ {
+ indent_level++;
+ fprintf (file, "\n%*s<", indent_level * 4, "");
+ print_expr_1 (file, &sym->sy_value);
+ fprintf (file, ">");
+ indent_level--;
+ }
+ fflush (file);
+}
+
+void
+print_symbol_value (sym)
+ symbolS *sym;
+{
+ indent_level = 0;
+ print_symbol_value_1 (stderr, sym);
+ fprintf (stderr, "\n");
+}
+
+void
+print_expr_1 (file, exp)
+ FILE *file;
+ expressionS *exp;
+{
+ fprintf (file, "expr %lx ", (long) exp);
+ switch (exp->X_op)
+ {
+ case O_illegal:
+ fprintf (file, "illegal");
+ break;
+ case O_absent:
+ fprintf (file, "absent");
+ break;
+ case O_constant:
+ fprintf (file, "constant %lx", (long) exp->X_add_number);
+ break;
+ case O_symbol:
+ indent_level++;
+ fprintf (file, "symbol\n%*s<", indent_level * 4, "");
+ print_symbol_value_1 (file, exp->X_add_symbol);
+ fprintf (file, ">");
+ maybe_print_addnum:
+ if (exp->X_add_number)
+ fprintf (file, "\n%*s%lx", indent_level * 4, "",
+ (long) exp->X_add_number);
+ indent_level--;
+ break;
+ case O_register:
+ fprintf (file, "register #%d", (int) exp->X_add_number);
+ break;
+ case O_big:
+ fprintf (file, "big");
+ break;
+ case O_uminus:
+ fprintf (file, "uminus -<");
+ indent_level++;
+ print_symbol_value_1 (file, exp->X_add_symbol);
+ fprintf (file, ">");
+ goto maybe_print_addnum;
+ case O_bit_not:
+ fprintf (file, "bit_not");
+ break;
+ case O_multiply:
+ fprintf (file, "multiply");
+ break;
+ case O_divide:
+ fprintf (file, "divide");
+ break;
+ case O_modulus:
+ fprintf (file, "modulus");
+ break;
+ case O_left_shift:
+ fprintf (file, "lshift");
+ break;
+ case O_right_shift:
+ fprintf (file, "rshift");
+ break;
+ case O_bit_inclusive_or:
+ fprintf (file, "bit_ior");
+ break;
+ case O_bit_exclusive_or:
+ fprintf (file, "bit_xor");
+ break;
+ case O_bit_and:
+ fprintf (file, "bit_and");
+ break;
+ case O_eq:
+ fprintf (file, "eq");
+ break;
+ case O_ne:
+ fprintf (file, "ne");
+ break;
+ case O_lt:
+ fprintf (file, "lt");
+ break;
+ case O_le:
+ fprintf (file, "le");
+ break;
+ case O_ge:
+ fprintf (file, "ge");
+ break;
+ case O_gt:
+ fprintf (file, "gt");
+ break;
+ case O_logical_and:
+ fprintf (file, "logical_and");
+ break;
+ case O_logical_or:
+ fprintf (file, "logical_or");
+ break;
+ case O_add:
+ indent_level++;
+ fprintf (file, "add\n%*s<", indent_level * 4, "");
+ print_symbol_value_1 (file, exp->X_add_symbol);
+ fprintf (file, ">\n%*s<", indent_level * 4, "");
+ print_symbol_value_1 (file, exp->X_op_symbol);
+ fprintf (file, ">");
+ goto maybe_print_addnum;
+ case O_subtract:
+ indent_level++;
+ fprintf (file, "subtract\n%*s<", indent_level * 4, "");
+ print_symbol_value_1 (file, exp->X_add_symbol);
+ fprintf (file, ">\n%*s<", indent_level * 4, "");
+ print_symbol_value_1 (file, exp->X_op_symbol);
+ fprintf (file, ">");
+ goto maybe_print_addnum;
+ default:
+ fprintf (file, "{unknown opcode %d}", (int) exp->X_op);
+ break;
+ }
+ fflush (stdout);
+}
+
+void
+print_expr (exp)
+ expressionS *exp;
+{
+ print_expr_1 (stderr, exp);
+ fprintf (stderr, "\n");
+}
+
+void
+symbol_print_statistics (file)
+ FILE *file;
+{
+ hash_print_statistics (file, "symbol table", sy_hash);
+}
+
+/* end of symbols.c */