1999-01-19 Fernando Nasser <fnasser@totem.to.cygnus.com>
[deliverable/binutils-gdb.git] / gdb / parse.c
index f7f5d1d71b7d3dc6d564ec46448d1cb30d21bf4d..480b41bbab39aa8a677558ac65c31a7c6b073a33 100644 (file)
@@ -1,5 +1,5 @@
 /* Parse expressions for GDB.
-   Copyright (C) 1986, 1989, 1990, 1991, 1994 Free Software Foundation, Inc.
+   Copyright (C) 1986, 89, 90, 91, 94, 1998 Free Software Foundation, Inc.
    Modified from expread.y by the Department of Computer Science at the
    State University of New York at Buffalo, 1991.
 
@@ -38,6 +38,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include "command.h"
 #include "language.h"
 #include "parser-defs.h"
+#include "gdbcmd.h"
+#include "symfile.h"   /* for overlay functions */
 \f
 /* Global variables declared in parser-defs.h (and commented there).  */
 struct expression *expout;
@@ -53,6 +55,12 @@ char *namecopy;
 int paren_depth;
 int comma_terminates;
 \f
+#ifdef MAINTENANCE_CMDS
+static int expressiondebug = 0;
+#endif
+
+extern int hp_som_som_object_present;
+
 static void
 free_funcalls PARAMS ((void));
 
@@ -101,9 +109,9 @@ unsigned num_std_regs = (sizeof std_regs / sizeof std_regs[0]);
 
 #endif
 
-/* The generic method for targets to specify how their registers are named.
-   The mapping can be derived from three sources: reg_names; std_regs; or
-   a target specific alias hook. */
+/* The generic method for targets to specify how their registers are
+   named.  The mapping can be derived from three sources:
+   REGISTER_NAME; std_regs; or a target specific alias hook. */
 
 int
 target_map_name_to_register (str, len)
@@ -112,10 +120,19 @@ target_map_name_to_register (str, len)
 {
   int i;
 
-  /* First search architectural register name space. */
+  /* First try target specific aliases. We try these first because on some 
+     systems standard names can be context dependent (eg. $pc on a 
+     multiprocessor can be could be any of several PCs).  */
+#ifdef REGISTER_NAME_ALIAS_HOOK
+  i =  REGISTER_NAME_ALIAS_HOOK (str, len);
+  if (i >= 0)
+    return i;
+#endif
+
+  /* Search architectural register name space. */
   for (i = 0; i < NUM_REGS; i++)
-    if (reg_names[i] && len == strlen (reg_names[i])
-       && STREQN (str, reg_names[i], len))
+    if (REGISTER_NAME (i) && len == strlen (REGISTER_NAME (i))
+       && STREQN (str, REGISTER_NAME (i), len))
       {
        return i;
       }
@@ -128,11 +145,6 @@ target_map_name_to_register (str, len)
        return std_regs[i].regnum;
       }
 
-  /* Try target specific aliases */
-#ifdef REGISTER_NAME_ALIAS_HOOK
-  return REGISTER_NAME_ALIAS_HOOK (str, len);
-#endif
-
   return -1;
 }
 
@@ -402,9 +414,16 @@ write_exp_msymbol (msymbol, text_symbol_type, data_symbol_type)
      struct type *text_symbol_type;
      struct type *data_symbol_type;
 {
+  CORE_ADDR addr;
+
   write_exp_elt_opcode (OP_LONG);
   write_exp_elt_type (lookup_pointer_type (builtin_type_void));
-  write_exp_elt_longcst ((LONGEST) SYMBOL_VALUE_ADDRESS (msymbol));
+
+  addr = SYMBOL_VALUE_ADDRESS (msymbol);
+  if (overlay_debugging)
+    addr = symbol_overlayed_address (addr, SYMBOL_BFD_SECTION (msymbol));
+  write_exp_elt_longcst ((LONGEST) addr);
+                                               
   write_exp_elt_opcode (OP_LONG);
 
   write_exp_elt_opcode (UNOP_MEMVAL);
@@ -460,6 +479,9 @@ write_dollar_variable (str)
   /* Handle the tokens $digits; also $ (short for $0) and $$ (short for $$1)
      and $$digits (equivalent to $<-digits> if you could type that). */
 
+  struct symbol * sym = NULL;
+  struct minimal_symbol * msym = NULL;
+
   int negate = 0;
   int i = 1;
   /* Double dollar means negate the number and add -1 as well.
@@ -493,6 +515,29 @@ write_dollar_variable (str)
   if( i >= 0 )
     goto handle_register;
 
+  /* On HP-UX, certain system routines (millicode) have names beginning
+     with $ or $$, e.g. $$dyncall, which handles inter-space procedure
+     calls on PA-RISC. Check for those, first. */
+
+  sym = lookup_symbol (copy_name (str), (struct block *) NULL,
+                       VAR_NAMESPACE, (int *) NULL, (struct symtab **) NULL);
+  if (sym)
+    {
+      write_exp_elt_opcode (OP_VAR_VALUE);
+      write_exp_elt_block (block_found); /* set by lookup_symbol */
+      write_exp_elt_sym (sym);
+      write_exp_elt_opcode (OP_VAR_VALUE);
+      return;
+    }
+  msym = lookup_minimal_symbol (copy_name (str), NULL, NULL);
+  if (msym)
+    {
+      write_exp_msymbol (msym,
+                         lookup_function_type (builtin_type_int),
+                         builtin_type_int);
+      return;
+    }
+  
   /* Any other names starting in $ are debugger internal variables.  */
 
   write_exp_elt_opcode (OP_INTERNALVAR);
@@ -510,6 +555,257 @@ write_dollar_variable (str)
   write_exp_elt_opcode (OP_REGISTER); 
   return;
 }
+
+
+/* Parse a string that is possibly a namespace / nested class
+   specification, i.e., something of the form A::B::C::x.  Input
+   (NAME) is the entire string; LEN is the current valid length; the
+   output is a string, TOKEN, which points to the largest recognized
+   prefix which is a series of namespaces or classes.  CLASS_PREFIX is
+   another output, which records whether a nested class spec was
+   recognized (= 1) or a fully qualified variable name was found (=
+   0).  ARGPTR is side-effected (if non-NULL) to point to beyond the
+   string recognized and consumed by this routine.
+
+   The return value is a pointer to the symbol for the base class or
+   variable if found, or NULL if not found.  Callers must check this
+   first -- if NULL, the outputs may not be correct. 
+
+   This function is used c-exp.y.  This is used specifically to get
+   around HP aCC (and possibly other compilers), which insists on
+   generating names with embedded colons for namespace or nested class
+   members.
+
+   (Argument LEN is currently unused. 1997-08-27)
+
+   Callers must free memory allocated for the output string TOKEN.  */
+
+static const char coloncolon[2] = {':',':'};
+
+struct symbol *
+parse_nested_classes_for_hpacc (name, len, token, class_prefix, argptr)
+  char * name;
+  int len;
+  char ** token;
+  int * class_prefix;
+  char ** argptr;
+{
+   /* Comment below comes from decode_line_1 which has very similar
+      code, which is called for "break" command parsing. */
+  
+   /* We have what looks like a class or namespace
+     scope specification (A::B), possibly with many
+     levels of namespaces or classes (A::B::C::D).
+
+     Some versions of the HP ANSI C++ compiler (as also possibly
+     other compilers) generate class/function/member names with
+     embedded double-colons if they are inside namespaces. To
+     handle this, we loop a few times, considering larger and
+     larger prefixes of the string as though they were single
+     symbols.  So, if the initially supplied string is
+     A::B::C::D::foo, we have to look up "A", then "A::B",
+     then "A::B::C", then "A::B::C::D", and finally
+     "A::B::C::D::foo" as single, monolithic symbols, because
+     A, B, C or D may be namespaces.
+
+     Note that namespaces can nest only inside other
+     namespaces, and not inside classes.  So we need only
+     consider *prefixes* of the string; there is no need to look up
+     "B::C" separately as a symbol in the previous example. */
+
+  register char * p;
+  char * start, * end;
+  char * prefix = NULL;
+  char * tmp;
+  struct symbol * sym_class = NULL;
+  struct symbol * sym_var = NULL;
+  struct type * t;
+  register int i;
+  int colons_found = 0;
+  int prefix_len = 0;
+  int done = 0;
+  char * q; 
+
+  /* Check for HP-compiled executable -- in other cases
+     return NULL, and caller must default to standard GDB
+     behaviour. */
+
+  if (!hp_som_som_object_present)
+    return (struct symbol *) NULL;
+
+  p = name;
+
+  /* Skip over whitespace and possible global "::" */ 
+  while (*p && (*p == ' ' || *p == '\t')) p++;
+  if (p[0] == ':' && p[1] == ':')
+    p += 2;
+  while (*p && (*p == ' ' || *p == '\t')) p++;
+  
+  while (1)
+    {
+      /* Get to the end of the next namespace or class spec. */
+      /* If we're looking at some non-token, fail immediately */
+      start = p;
+      if (!(isalpha (*p) || *p == '$' || *p == '_'))
+        return (struct symbol *) NULL;
+      p++;
+      while (*p && (isalnum (*p) || *p == '$' || *p == '_')) p++;
+
+      if (*p == '<') 
+        {
+          /* If we have the start of a template specification,
+             scan right ahead to its end */ 
+          q = find_template_name_end (p);
+          if (q)
+            p = q;
+        }
+        
+      end = p;
+
+      /* Skip over "::" and whitespace for next time around */ 
+      while (*p && (*p == ' ' || *p == '\t')) p++;
+      if (p[0] == ':' && p[1] == ':')
+        p += 2;
+      while (*p && (*p == ' ' || *p == '\t')) p++;
+
+      /* Done with tokens? */ 
+      if (!*p || !(isalpha (*p) || *p == '$' || *p == '_'))
+        done = 1;
+
+      tmp = (char *) alloca (prefix_len + end - start + 3);
+      if (prefix)
+        {
+          memcpy (tmp, prefix, prefix_len);
+          memcpy (tmp + prefix_len, coloncolon, 2);
+          memcpy (tmp + prefix_len + 2, start, end - start);
+          tmp[prefix_len + 2 + end - start] = '\000';
+        }
+      else
+        {
+          memcpy (tmp, start, end - start);
+          tmp[end - start] = '\000';
+        }
+      
+      prefix = tmp;
+      prefix_len = strlen (prefix);
+      
+#if 0 /* DEBUGGING */ 
+      printf ("Searching for nested class spec: Prefix is %s\n", prefix);
+#endif      
+
+      /* See if the prefix we have now is something we know about */
+
+      if (!done) 
+        {
+          /* More tokens to process, so this must be a class/namespace */
+          sym_class = lookup_symbol (prefix, 0, STRUCT_NAMESPACE,
+                                     0, (struct symtab **) NULL);
+        }
+      else
+        {
+          /* No more tokens, so try as a variable first */ 
+          sym_var = lookup_symbol (prefix, 0, VAR_NAMESPACE,
+                               0, (struct symtab **) NULL);
+          /* If failed, try as class/namespace */ 
+          if (!sym_var)
+            sym_class = lookup_symbol (prefix, 0, STRUCT_NAMESPACE,
+                                       0, (struct symtab **) NULL);
+        }
+
+      if (sym_var ||
+          (sym_class &&
+           (t = check_typedef (SYMBOL_TYPE (sym_class)),
+            (TYPE_CODE (t) == TYPE_CODE_STRUCT
+             || TYPE_CODE (t) == TYPE_CODE_UNION))))
+        {
+          /* We found a valid token */
+          *token = (char *) xmalloc (prefix_len + 1 );
+          memcpy (*token, prefix, prefix_len);
+          (*token)[prefix_len] = '\000';
+          break;
+        }
+
+      /* No variable or class/namespace found, no more tokens */ 
+      if (done)
+        return (struct symbol *) NULL;
+    }
+
+  /* Out of loop, so we must have found a valid token */
+  if (sym_var)
+    *class_prefix = 0;
+  else
+    *class_prefix = 1;
+
+  if (argptr)
+    *argptr = done ? p : end;
+
+#if 0 /* DEBUGGING */ 
+  printf ("Searching for nested class spec: Token is %s, class_prefix %d\n", *token, *class_prefix);
+#endif
+
+  return sym_var ? sym_var : sym_class; /* found */ 
+}
+
+char *
+find_template_name_end (p)
+  char * p;
+{
+  int depth = 1;
+  int just_seen_right = 0;
+  int just_seen_colon = 0;
+  int just_seen_space = 0;
+  
+  if (!p || (*p != '<'))
+    return 0;
+
+  while (*++p)
+    {
+      switch (*p)
+        {
+          case '\'': case '\"':
+          case '{': case '}':
+            /* In future, may want to allow these?? */ 
+            return 0;
+          case '<':
+            depth++;                /* start nested template */ 
+            if (just_seen_colon || just_seen_right || just_seen_space)    
+              return 0;             /* but not after : or :: or > or space */ 
+            break;
+          case '>': 
+            if (just_seen_colon || just_seen_right)
+              return 0;             /* end a (nested?) template */
+            just_seen_right = 1;    /* but not after : or :: */ 
+            if (--depth == 0)       /* also disallow >>, insist on > > */ 
+              return ++p;           /* if outermost ended, return */ 
+            break;
+          case ':':
+            if (just_seen_space || (just_seen_colon > 1))
+              return 0;             /* nested class spec coming up */ 
+            just_seen_colon++;      /* we allow :: but not :::: */ 
+            break;
+          case ' ':
+            break;
+          default:
+            if (!((*p >= 'a' && *p <= 'z') ||   /* allow token chars */ 
+                  (*p >= 'A' && *p <= 'Z') ||
+                  (*p >= '0' && *p <= '9') ||
+                  (*p == '_') || (*p == ',') || /* commas for template args */
+                  (*p == '&') || (*p == '*') || /* pointer and ref types */
+                  (*p == '(') || (*p == ')') || /* function types */ 
+                  (*p == '[') || (*p == ']') )) /* array types */  
+              return 0;
+        }
+      if (*p != ' ')
+        just_seen_space = 0;
+      if (*p != ':')
+        just_seen_colon = 0;
+      if (*p != '>')
+        just_seen_right = 0;
+    }
+  return 0;
+}
+
+
 \f
 /* Return a null-terminated temporary copy of the name
    of a string token.  */
@@ -869,7 +1165,7 @@ parse_exp_1 (stringptr, block, comma)
   if (lexptr == 0 || *lexptr == 0)
     error_no_arg ("expression to compute");
 
-  old_chain = make_cleanup (free_funcalls, 0);
+  old_chain = make_cleanup ((make_cleanup_func) free_funcalls, 0);
   funcall_chain = 0;
 
   expression_context_block = block ? block : get_selected_block ();
@@ -880,7 +1176,7 @@ parse_exp_1 (stringptr, block, comma)
   expout = (struct expression *)
     xmalloc (sizeof (struct expression) + EXP_ELEM_TO_BYTES (expout_size));
   expout->language_defn = current_language;
-  make_cleanup (free_current_contents, &expout);
+  make_cleanup ((make_cleanup_func) free_current_contents, &expout);
 
   if (current_language->la_parser ())
     current_language->la_error (NULL);
@@ -899,9 +1195,19 @@ parse_exp_1 (stringptr, block, comma)
   /* Convert expression from postfix form as generated by yacc
      parser, to a prefix form. */
 
-  DUMP_EXPRESSION (expout, gdb_stdout, "before conversion to prefix form");
+#ifdef MAINTENANCE_CMDS
+  if (expressiondebug)
+    dump_prefix_expression (expout, gdb_stdout,
+                           "before conversion to prefix form");
+#endif /* MAINTENANCE_CMDS */
+
   prefixify_expression (expout);
-  DUMP_EXPRESSION (expout, gdb_stdout, "after conversion to prefix form");
+
+#ifdef MAINTENANCE_CMDS
+  if (expressiondebug)
+    dump_postfix_expression (expout, gdb_stdout,
+                            "after conversion to prefix form");
+#endif /* MAINTENANCE_CMDS */
 
   *stringptr = lexptr;
   return expout;
@@ -1031,4 +1337,14 @@ _initialize_parse ()
     init_type (TYPE_CODE_INT, 1, 0,
               "<variable (not text or data), no debug info>",
               NULL);
+
+#ifdef MAINTENANCE_CMDS
+  add_show_from_set (
+     add_set_cmd ("expressiondebug", class_maintenance, var_zinteger,
+                 (char *)&expressiondebug,
+                "Set expression debugging.\n\
+When non-zero, the internal representation of expressions will be printed.",
+                 &setlist),
+     &showlist);
+#endif
 }
This page took 0.027921 seconds and 4 git commands to generate.