+#define VISIBILITY_PRIVATE '0' /* Stabs character for private field */
+#define VISIBILITY_PROTECTED '1' /* Stabs character for protected fld */
+#define VISIBILITY_PUBLIC '2' /* Stabs character for public field */
+#define VISIBILITY_IGNORE '9' /* Optimized out or zero length */
+
+#define CFRONT_VISIBILITY_PRIVATE '2' /* Stabs character for private field */
+#define CFRONT_VISIBILITY_PUBLIC '1' /* Stabs character for public field */
+
+/* This code added to support parsing of ARM/Cfront stabs strings */
+
+/* Get substring from string up to char c, advance string pointer past
+ suibstring. */
+
+static char *
+get_substring (p, c)
+ char ** p;
+ int c;
+{
+ char *str;
+ str = *p;
+ *p = strchr (*p, c);
+ if (*p)
+ {
+ **p = 0;
+ (*p)++;
+ }
+ else
+ str = 0;
+ return str;
+}
+
+/* Physname gets strcat'd onto sname in order to recreate the mangled
+ name (see funtion gdb_mangle_name in gdbtypes.c). For cfront, make
+ the physname look like that of g++ - take out the initial mangling
+ eg: for sname="a" and fname="foo__1aFPFs_i" return "FPFs_i" */
+
+static char *
+get_cfront_method_physname (fname)
+ char *fname;
+{
+ int len = 0;
+ /* FIXME would like to make this generic for g++ too, but
+ that is already handled in read_member_funcctions */
+ char * p = fname;
+
+ /* search ahead to find the start of the mangled suffix */
+ if (*p == '_' && *(p+1)=='_') /* compiler generated; probably a ctor/dtor */
+ p += 2;
+ while (p && (unsigned) ((p+1) - fname) < strlen (fname) && *(p+1) != '_')
+ p = strchr (p, '_');
+ if (!(p && *p == '_' && *(p+1) == '_'))
+ error ("Invalid mangled function name %s",fname);
+ p += 2; /* advance past '__' */
+
+ /* struct name length and name of type should come next; advance past it */
+ while (isdigit (*p))
+ {
+ len = len * 10 + (*p - '0');
+ p++;
+ }
+ p += len;
+
+ return p;
+}
+
+/* Read base classes within cfront class definition.
+ eg: A:ZcA;1@Bpub v2@Bvirpri;__ct__1AFv func__1AFv *sfunc__1AFv ;as__1A ;;
+ ^^^^^^^^^^^^^^^^^^
+
+ A:ZcA;;foopri__1AFv foopro__1AFv __ct__1AFv __ct__1AFRC1A foopub__1AFv ;;;
+ ^
+ */
+
+static int
+read_cfront_baseclasses (fip, pp, type, objfile)
+ struct field_info *fip;
+ struct objfile *objfile;
+ char ** pp;
+ struct type *type;
+{
+ static struct complaint msg_unknown = {"\
+ Unsupported token in stabs string %s.\n",
+ 0, 0};
+ static struct complaint msg_notfound = {"\
+ Unable to find base type for %s.\n",
+ 0, 0};
+ int bnum = 0;
+ char * p;
+ int i;
+ struct nextfield *new;
+
+ if (**pp == ';') /* no base classes; return */
+ {
+ ++(*pp);
+ return 1;
+ }
+
+ /* first count base classes so we can allocate space before parsing */
+ for (p = *pp; p && *p && *p != ';'; p++)
+ {
+ if (*p == ' ')
+ bnum++;
+ }
+ bnum++; /* add one more for last one */
+
+ /* now parse the base classes until we get to the start of the methods
+ (code extracted and munged from read_baseclasses) */
+ ALLOCATE_CPLUS_STRUCT_TYPE (type);
+ TYPE_N_BASECLASSES(type) = bnum;
+
+ /* allocate space */
+ {
+ int num_bytes = B_BYTES (TYPE_N_BASECLASSES (type));
+ char *pointer;
+
+ pointer = (char *) TYPE_ALLOC (type, num_bytes);
+ TYPE_FIELD_VIRTUAL_BITS (type) = (B_TYPE *) pointer;
+ }
+ B_CLRALL (TYPE_FIELD_VIRTUAL_BITS (type), TYPE_N_BASECLASSES (type));
+
+ for (i = 0; i < TYPE_N_BASECLASSES (type); i++)
+ {
+ new = (struct nextfield *) xmalloc (sizeof (struct nextfield));
+ make_cleanup (free, new);
+ memset (new, 0, sizeof (struct nextfield));
+ new -> next = fip -> list;
+ fip -> list = new;
+ FIELD_BITSIZE (new->field) = 0; /* this should be an unpacked field! */
+
+ STABS_CONTINUE (pp, objfile);
+
+ /* virtual? eg: v2@Bvir */
+ if (**pp=='v')
+ {
+ SET_TYPE_FIELD_VIRTUAL (type, i);
+ ++(*pp);
+ }
+
+ /* access? eg: 2@Bvir */
+ /* Note: protected inheritance not supported in cfront */
+ switch (*(*pp)++)
+ {
+ case CFRONT_VISIBILITY_PRIVATE:
+ new -> visibility = VISIBILITY_PRIVATE;
+ break;
+ case CFRONT_VISIBILITY_PUBLIC:
+ new -> visibility = VISIBILITY_PUBLIC;
+ break;
+ default:
+ /* Bad visibility format. Complain and treat it as
+ public. */
+ {
+ static struct complaint msg = {
+ "Unknown visibility `%c' for baseclass", 0, 0};
+ complain (&msg, new -> visibility);
+ new -> visibility = VISIBILITY_PUBLIC;
+ }
+ }
+
+ /* "@" comes next - eg: @Bvir */
+ if (**pp!='@')
+ {
+ complain (&msg_unknown, *pp);
+ return 1;
+ }
+ ++(*pp);
+
+
+ /* Set the bit offset of the portion of the object corresponding
+ to this baseclass. Always zero in the absence of
+ multiple inheritance. */
+ /* Unable to read bit position from stabs;
+ Assuming no multiple inheritance for now FIXME! */
+ /* We may have read this in the structure definition;
+ now we should fixup the members to be the actual base classes */
+ FIELD_BITPOS (new->field) = 0;
+
+ /* Get the base class name and type */
+ {
+ char * bname; /* base class name */
+ struct symbol * bsym; /* base class */
+ char * p1, * p2;
+ p1 = strchr (*pp,' ');
+ p2 = strchr (*pp,';');
+ if (p1<p2)
+ bname = get_substring (pp,' ');
+ else
+ bname = get_substring (pp,';');
+ if (!bname || !*bname)
+ {
+ complain (&msg_unknown, *pp);
+ return 1;
+ }
+ /* FIXME! attach base info to type */
+ bsym = lookup_symbol (bname, 0, STRUCT_NAMESPACE, 0, 0); /*demangled_name*/
+ if (bsym)
+ {
+ new -> field.type = SYMBOL_TYPE(bsym);
+ new -> field.name = type_name_no_tag (new -> field.type);
+ }
+ else
+ {
+ complain (&msg_notfound, *pp);
+ return 1;
+ }
+ }
+
+ /* If more base classes to parse, loop again.
+ We ate the last ' ' or ';' in get_substring,
+ so on exit we will have skipped the trailing ';' */
+ /* if invalid, return 0; add code to detect - FIXME! */
+ }
+ return 1;
+}
+
+/* read cfront member functions.
+ pp points to string starting with list of functions
+ eg: A:ZcA;1@Bpub v2@Bvirpri;__ct__1AFv func__1AFv *sfunc__1AFv ;as__1A ;;
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ A:ZcA;;foopri__1AFv foopro__1AFv __ct__1AFv __ct__1AFRC1A foopub__1AFv ;;;
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+*/
+
+static int
+read_cfront_member_functions (fip, pp, type, objfile)
+ struct field_info *fip;
+ char **pp;
+ struct type *type;
+ struct objfile *objfile;
+{
+ /* This code extracted from read_member_functions
+ so as to do the similar thing for our funcs */
+
+ int nfn_fields = 0;
+ int length = 0;
+ /* Total number of member functions defined in this class. If the class
+ defines two `f' functions, and one `g' function, then this will have
+ the value 3. */
+ int total_length = 0;
+ int i;
+ struct next_fnfield
+ {
+ struct next_fnfield *next;
+ struct fn_field fn_field;
+ } *sublist;
+ struct type *look_ahead_type;
+ struct next_fnfieldlist *new_fnlist;
+ struct next_fnfield *new_sublist;
+ char *main_fn_name;
+ char * fname;
+ struct symbol * ref_func = 0;
+
+ /* Process each list until we find the end of the member functions.
+ eg: p = "__ct__1AFv foo__1AFv ;;;" */
+
+ STABS_CONTINUE (pp, objfile); /* handle \\ */
+
+ while (**pp != ';' && (fname = get_substring (pp, ' '), fname))
+ {
+ int is_static = 0;
+ int sublist_count = 0;
+ char * pname;
+ if (fname[0] == '*') /* static member */
+ {
+ is_static=1;
+ sublist_count++;
+ fname++;
+ }
+ ref_func = lookup_symbol (fname, 0, VAR_NAMESPACE, 0, 0); /* demangled name */
+ if (!ref_func)
+ {
+ static struct complaint msg = {"\
+ Unable to find function symbol for %s\n",
+ 0, 0};
+ complain (&msg, fname);
+ continue;
+ }
+ sublist = NULL;
+ look_ahead_type = NULL;
+ length = 0;
+
+ new_fnlist = (struct next_fnfieldlist *)
+ xmalloc (sizeof (struct next_fnfieldlist));
+ make_cleanup (free, new_fnlist);
+ memset (new_fnlist, 0, sizeof (struct next_fnfieldlist));
+
+ /* The following is code to work around cfront generated stabs.
+ The stabs contains full mangled name for each field.
+ We try to demangle the name and extract the field name out of it. */
+ {
+ char *dem, *dem_p, *dem_args;
+ int dem_len;
+ dem = cplus_demangle (fname, DMGL_ANSI | DMGL_PARAMS);
+ if (dem != NULL)
+ {
+ dem_p = strrchr (dem, ':');
+ if (dem_p != 0 && *(dem_p-1) == ':')
+ dem_p++;
+ /* get rid of args */
+ dem_args = strchr (dem_p, '(');
+ if (dem_args == NULL)
+ dem_len = strlen (dem_p);
+ else
+ dem_len = dem_args - dem_p;
+ main_fn_name =
+ obsavestring (dem_p, dem_len, &objfile -> type_obstack);
+ }
+ else
+ {
+ main_fn_name =
+ obsavestring (fname, strlen (fname), &objfile -> type_obstack);
+ }
+ } /* end of code for cfront work around */
+
+ new_fnlist -> fn_fieldlist.name = main_fn_name;
+
+ /*-------------------------------------------------*/
+ /* Set up the sublists
+ Sublists are stuff like args, static, visibility, etc.
+ so in ARM, we have to set that info some other way.
+ Multiple sublists happen if overloading
+ eg: foo::26=##1;:;2A.;
+ In g++, we'd loop here thru all the sublists... */
+
+ new_sublist =
+ (struct next_fnfield *) xmalloc (sizeof (struct next_fnfield));
+ make_cleanup (free, new_sublist);
+ memset (new_sublist, 0, sizeof (struct next_fnfield));
+
+ /* eat 1; from :;2A.; */
+ new_sublist -> fn_field.type = SYMBOL_TYPE(ref_func); /* normally takes a read_type */
+ /* Make this type look like a method stub for gdb */
+ TYPE_FLAGS (new_sublist -> fn_field.type) |= TYPE_FLAG_STUB;
+ TYPE_CODE (new_sublist -> fn_field.type) = TYPE_CODE_METHOD;
+
+ /* If this is just a stub, then we don't have the real name here. */
+ if (TYPE_FLAGS (new_sublist -> fn_field.type) & TYPE_FLAG_STUB)
+ {
+ if (!TYPE_DOMAIN_TYPE (new_sublist -> fn_field.type))
+ TYPE_DOMAIN_TYPE (new_sublist -> fn_field.type) = type;
+ new_sublist -> fn_field.is_stub = 1;
+ }
+
+ /* physname used later in mangling; eg PFs_i,5 for foo__1aFPFs_i
+ physname gets strcat'd in order to recreate the onto mangled name */
+ pname = get_cfront_method_physname (fname);
+ new_sublist -> fn_field.physname = savestring (pname, strlen (pname));
+
+
+ /* Set this member function's visibility fields.
+ Unable to distinguish access from stabs definition!
+ Assuming public for now. FIXME!
+ (for private, set new_sublist->fn_field.is_private = 1,
+ for public, set new_sublist->fn_field.is_protected = 1) */
+
+ /* Unable to distinguish const/volatile from stabs definition!
+ Assuming normal for now. FIXME! */
+
+ new_sublist -> fn_field.is_const = 0;
+ new_sublist -> fn_field.is_volatile = 0; /* volatile not implemented in cfront */
+
+ /* Set virtual/static function info
+ How to get vtable offsets ?
+ Assuming normal for now FIXME!!
+ For vtables, figure out from whence this virtual function came.
+ It may belong to virtual function table of
+ one of its baseclasses.
+ set:
+ new_sublist -> fn_field.voffset = vtable offset,
+ new_sublist -> fn_field.fcontext = look_ahead_type;
+ where look_ahead_type is type of baseclass */
+ if (is_static)
+ new_sublist -> fn_field.voffset = VOFFSET_STATIC;
+ else /* normal member function. */
+ new_sublist -> fn_field.voffset = 0;
+ new_sublist -> fn_field.fcontext = 0;
+
+
+ /* Prepare new sublist */
+ new_sublist -> next = sublist;
+ sublist = new_sublist;
+ length++;
+
+ /* In g++, we loop thu sublists - now we set from functions. */
+ new_fnlist -> fn_fieldlist.fn_fields = (struct fn_field *)
+ obstack_alloc (&objfile -> type_obstack,
+ sizeof (struct fn_field) * length);
+ memset (new_fnlist -> fn_fieldlist.fn_fields, 0,
+ sizeof (struct fn_field) * length);
+ for (i = length; (i--, sublist); sublist = sublist -> next)
+ {
+ new_fnlist -> fn_fieldlist.fn_fields[i] = sublist -> fn_field;
+ }
+
+ new_fnlist -> fn_fieldlist.length = length;
+ new_fnlist -> next = fip -> fnlist;
+ fip -> fnlist = new_fnlist;
+ nfn_fields++;
+ total_length += length;
+ STABS_CONTINUE (pp, objfile); /* handle \\ */
+ } /* end of loop */
+
+ if (nfn_fields)
+ {
+ /* type should already have space */
+ TYPE_FN_FIELDLISTS (type) = (struct fn_fieldlist *)
+ TYPE_ALLOC (type, sizeof (struct fn_fieldlist) * nfn_fields);
+ memset (TYPE_FN_FIELDLISTS (type), 0,
+ sizeof (struct fn_fieldlist) * nfn_fields);
+ TYPE_NFN_FIELDS (type) = nfn_fields;
+ TYPE_NFN_FIELDS_TOTAL (type) = total_length;
+ }
+
+ /* end of scope for reading member func */
+
+ /* eg: ";;" */
+
+ /* Skip trailing ';' and bump count of number of fields seen */
+ if (**pp == ';')
+ (*pp)++;
+ else
+ return 0;
+ return 1;
+}
+
+/* This routine fixes up partial cfront types that were created
+ while parsing the stabs. The main need for this function is
+ to add information such as methods to classes.
+ Examples of "p": "sA;;__ct__1AFv foo__1AFv ;;;" */
+int
+resolve_cfront_continuation (objfile, sym, p)
+ struct objfile * objfile;
+ struct symbol * sym;
+ char * p;
+{
+ struct symbol * ref_sym=0;
+ char * sname;
+ /* snarfed from read_struct_type */
+ struct field_info fi;
+ struct type *type;
+ struct cleanup *back_to;
+
+ /* Need to make sure that fi isn't gunna conflict with struct
+ in case struct already had some fnfs */
+ fi.list = NULL;
+ fi.fnlist = NULL;
+ back_to = make_cleanup (null_cleanup, 0);
+
+ /* We only accept structs, classes and unions at the moment.
+ Other continuation types include t (typedef), r (long dbl), ...
+ We may want to add support for them as well;
+ right now they are handled by duplicating the symbol information
+ into the type information (see define_symbol) */
+ if (*p != 's' /* structs */
+ && *p != 'c' /* class */
+ && *p != 'u') /* union */
+ return 0; /* only handle C++ types */
+ p++;
+
+ /* Get symbol typs name and validate
+ eg: p = "A;;__ct__1AFv foo__1AFv ;;;" */
+ sname = get_substring (&p, ';');
+ if (!sname || strcmp (sname, SYMBOL_NAME(sym)))
+ error ("Internal error: base symbol type name does not match\n");
+
+ /* Find symbol's internal gdb reference using demangled_name.
+ This is the real sym that we want;
+ sym was a temp hack to make debugger happy */
+ ref_sym = lookup_symbol (SYMBOL_NAME(sym), 0, STRUCT_NAMESPACE, 0, 0);
+ type = SYMBOL_TYPE(ref_sym);
+
+
+ /* Now read the baseclasses, if any, read the regular C struct or C++
+ class member fields, attach the fields to the type, read the C++
+ member functions, attach them to the type, and then read any tilde
+ field (baseclass specifier for the class holding the main vtable). */
+
+ if (!read_cfront_baseclasses (&fi, &p, type, objfile)
+ /* g++ does this next, but cfront already did this:
+ || !read_struct_fields (&fi, &p, type, objfile) */
+ || !copy_cfront_struct_fields (&fi, type, objfile)
+ || !read_cfront_member_functions (&fi, &p, type, objfile)
+ || !read_cfront_static_fields (&fi, &p, type, objfile)
+ || !attach_fields_to_type (&fi, type, objfile)
+ || !attach_fn_fields_to_type (&fi, type)
+ /* g++ does this next, but cfront doesn't seem to have this:
+ || !read_tilde_fields (&fi, &p, type, objfile) */
+ )
+ {
+ type = error_type (&p, objfile);
+ }
+
+ do_cleanups (back_to);
+ return 0;
+}
+/* End of code added to support parsing of ARM/Cfront stabs strings */
+
+
+/* This routine fixes up symbol references/aliases to point to the original
+ symbol definition. */
+
+static int
+resolve_symbol_reference (objfile, sym, p)
+ struct objfile *objfile;
+ struct symbol *sym;
+ char *p;
+{
+ int refnum;
+ struct symbol *ref_sym=0;
+ struct alias_list *alias;
+
+ /* If this is not a symbol reference return now. */
+ if (*p != '#')
+ return 0;
+
+ /* Use "#<num>" as the name; we'll fix the name later.
+ We stored the original symbol name as "#<id>=<name>"
+ so we can now search for "#<id>" to resolving the reference.
+ We'll fix the names later by removing the "#<id>" or "#<id>=" */
+
+ /*---------------------------------------------------------*/
+ /* Get the reference id number, and
+ advance p past the names so we can parse the rest.
+ eg: id=2 for p : "2=", "2=z:r(0,1)" "2:r(0,1);l(#5,#6),l(#7,#4)" */
+ /*---------------------------------------------------------*/
+
+ /* This gets reference name from string. sym may not have a name. */
+
+ /* Get the reference number associated with the reference id in the
+ gdb stab string. From that reference number, get the main/primary
+ symbol for this alias. */
+ refnum = process_reference (&p);
+ ref_sym = ref_search (refnum);
+ if (!ref_sym)
+ error ("error: symbol for reference not found.\n");
+
+
+ /* Parse the stab of the referencing symbol
+ now that we have the referenced symbol.
+ Add it as a new symbol and a link back to the referenced symbol.
+ eg: p : "=", "=z:r(0,1)" ":r(0,1);l(#5,#6),l(#7,#4)" */
+
+
+ /* If the stab symbol table and string contain:
+ RSYM 0 5 00000000 868 #15=z:r(0,1)
+ LBRAC 0 0 00000000 899 #5=
+ SLINE 0 16 00000003 923 #6=
+ Then the same symbols can be later referenced by:
+ RSYM 0 5 00000000 927 #15:r(0,1);l(#5,#6)
+ This is used in live range splitting to:
+ 1) specify that a symbol (#15) is actually just a new storage
+ class for a symbol (#15=z) which was previously defined.
+ 2) specify that the beginning and ending ranges for a symbol
+ (#15) are the values of the beginning (#5) and ending (#6)
+ symbols. */
+
+ /* Read number as reference id.
+ eg: p : "=", "=z:r(0,1)" ":r(0,1);l(#5,#6),l(#7,#4)" */
+ /* FIXME! Might I want to use SYMBOL_CLASS (sym) = LOC_OPTIMIZED_OUT;
+ in case of "l(0,0)"? */
+
+ /*--------------------------------------------------*/
+ /* Add this symbol to the reference list. */
+ /*--------------------------------------------------*/
+
+ alias = (struct alias_list *) obstack_alloc (&objfile->type_obstack,
+ sizeof (struct alias_list));
+ if (!alias)
+ error ("Unable to allocate alias list memory");
+
+ alias->next = 0;
+ alias->sym = sym;
+
+ if (!SYMBOL_ALIASES (ref_sym))
+ {
+ SYMBOL_ALIASES (ref_sym) = alias;
+ }
+ else
+ {
+ struct alias_list *temp;
+
+ /* Get to the end of the list. */
+ for (temp = SYMBOL_ALIASES (ref_sym);
+ temp->next;
+ temp = temp->next);
+ ;
+ temp->next = alias;
+ }
+
+ /* Want to fix up name so that other functions (eg. valops)
+ will correctly print the name.
+ Don't add_symbol_to_list so that lookup_symbol won't find it.
+ nope... needed for fixups. */
+ SYMBOL_NAME (sym) = SYMBOL_NAME (ref_sym);
+
+ /* Done! */
+ return 0;
+}
+
+#define MAX_CHUNK_REFS 100
+#define REF_CHUNK_SIZE \
+ MAX_CHUNK_REFS * sizeof (struct ref_map_s)
+#define REF_MAP_SIZE(ref_chunk) \
+ ref_chunk * REF_CHUNK_SIZE
+
+/* Structure for storing pointers to reference definitions for fast lookup
+ during "process_later". */
+static struct ref_map_s
+{
+ char *stabs;
+ CORE_ADDR value;
+ struct symbol *sym;
+} *ref_map;
+
+/* Ptr to free cell in chunk's linked list. */
+static int ref_count = 0;
+
+/* Number of chunks malloced. */
+static int ref_chunk = 0;
+
+/* Initialize our list of references.
+ This should be called before any symbol table is read. */
+
+static void
+ref_init ()
+{
+ ref_count = 0;
+ ref_chunk = 0;
+}
+
+/* Create array of pointers mapping refids to symbols and stab strings.
+ Add pointers to reference definition symbols and/or their values as we
+ find them, using their reference numbers as our index.
+ These will be used later when we resolve references. */
+void
+ref_add (refnum, sym, stabs, value)
+ int refnum;
+ struct symbol *sym;
+ char *stabs;
+ CORE_ADDR value;
+{
+ if (ref_count == 0)
+ ref_init ();
+ if (refnum >= ref_count)
+ ref_count = refnum + 1;
+ if (ref_count > ref_chunk * MAX_CHUNK_REFS)
+ {
+ int new_slots = ref_count - ref_chunk * MAX_CHUNK_REFS;
+ int new_chunks = new_slots / MAX_CHUNK_REFS + 1;
+ ref_map = xrealloc (ref_map, REF_MAP_SIZE(ref_chunk + new_chunks));
+ if (!ref_map)
+ error ("no more free slots in chain\n");
+ memset (ref_map + REF_MAP_SIZE(ref_chunk), 0, new_chunks * REF_CHUNK_SIZE);
+ ref_chunk += new_chunks;
+ }
+ ref_map[refnum].stabs = stabs;
+ ref_map[refnum].sym = sym;
+ ref_map[refnum].value = value;
+}
+
+/* Return defined sym for the reference REFNUM. */
+struct symbol *
+ref_search (refnum)
+ int refnum;
+{
+ if (refnum < 0 || refnum > ref_count)
+ return 0;
+ return ref_map[refnum].sym;
+}
+
+/* Return value for the reference REFNUM. */
+
+static CORE_ADDR
+ref_search_value (refnum)
+ int refnum;
+{
+ if (refnum < 0 || refnum > ref_count)
+ return 0;
+ return ref_map[refnum].value;
+}
+
+/* Parse a reference id in STRING and return the resulting
+ reference number. Move STRING beyond the reference id. */
+
+static int
+process_reference (string)
+ char **string;
+{
+ char *p;
+ int refnum = 0;
+
+ if (**string != '#')
+ return 0;
+
+ /* Advance beyond the initial '#'. */
+ p = *string + 1;
+
+ /* Read number as reference id. */
+ while (*p && isdigit (*p))
+ {
+ refnum = refnum * 10 + *p - '0';
+ p++;
+ }
+ *string = p;
+ return refnum;
+}
+
+/* If STRING defines a reference, store away a pointer to the reference
+ definition for later use. Return the reference number. */
+
+int
+symbol_reference_defined (string)
+ char **string;
+{
+ char *p = *string;
+ int refnum = 0;
+
+ refnum = process_reference (&p);
+
+ /* Defining symbols end in '=' */
+ if (*p == '=')
+ {
+ /* Symbol is being defined here. */
+ *string = p + 1;
+ return refnum;
+ }
+ else
+ {
+ /* Must be a reference. Either the symbol has already been defined,
+ or this is a forward reference to it. */
+ *string = p;
+ return -1;
+ }
+}
+