gdb-2.5.2
[binutils-gdb.git] / gdb / expread.y
index 468d409a7d8848e217724f55057e42e29f1bb230..996ca219fcf4b77d648fc9e1ac8258c911f6856a 100644 (file)
@@ -93,10 +93,14 @@ struct stoken
     struct block *bval;
     enum exp_opcode opcode;
     struct internalvar *ivar;
+
+    struct type **tvec;
+    int *ivec;
   }
 
 %type <voidval> exp exp1 start variable
 %type <tval> type typebase
+%type <tvec> nonempty_typelist
 %type <bval> block
 
 %token <lval> INT CHAR
@@ -122,6 +126,9 @@ struct stoken
 
 %token <opcode> ASSIGN_MODIFY
 
+/* C++ */
+%token THIS
+
 %left ','
 %left ABOVE_COMMA
 %right '=' ASSIGN_MODIFY
@@ -196,12 +203,20 @@ exp       :       exp ARROW name
                          write_exp_elt (STRUCTOP_PTR); }
        ;
 
+exp    :       exp ARROW '*' exp
+                       { write_exp_elt (STRUCTOP_MPTR); }
+       ;
+
 exp    :       exp '.' name
                        { write_exp_elt (STRUCTOP_STRUCT);
                          write_exp_string ($3);
                          write_exp_elt (STRUCTOP_STRUCT); }
        ;
 
+exp    :       exp '.' '*' exp
+                       { write_exp_elt (STRUCTOP_MEMBER); }
+       ;
+
 exp    :       exp '[' exp1 ']'
                        { write_exp_elt (BINOP_SUBSCRIPT); }
        ;
@@ -390,8 +405,17 @@ exp        :       STRING
                          write_exp_elt (OP_STRING); }
        ;
 
+/* C++.  */
+exp    :       THIS
+                       { write_exp_elt (OP_THIS);
+                         write_exp_elt (OP_THIS); }
+       ;
+
+/* end of C++.  */
+
 block  :       name
-                       { struct symtab *tem = lookup_symtab (copy_name ($1));
+                       {
+                         struct symtab *tem = lookup_symtab (copy_name ($1));
                          struct symbol *sym;
                          
                          if (tem)
@@ -406,34 +430,88 @@ block     :       name
                              else
                                error ("No file or function \"%s\".",
                                       copy_name ($1));
-                           }}
+                           }
+                       }
        ;
 
 block  :       block COLONCOLON name
-                       { struct symbol *tem
+                       {
+                         struct symbol *tem
                            = lookup_symbol (copy_name ($3), $1, VAR_NAMESPACE);
                          if (!tem || SYMBOL_CLASS (tem) != LOC_BLOCK)
                            error ("No function \"%s\" in specified context.",
-                                  copy_name ($3));
-                         $$ = SYMBOL_BLOCK_VALUE (tem); }
+                                  copy_name ($1));
+                         $$ = SYMBOL_BLOCK_VALUE (tem);
+                       }
        ;
 
 variable:      block COLONCOLON name
-                       { struct symbol *sym;
-                         sym = lookup_symbol ($3, copy_name ($1), VAR_NAMESPACE);
+                       {
+                         struct symbol *sym;
+                         sym = lookup_symbol (copy_name ($3), $1, VAR_NAMESPACE);
                          if (sym == 0)
                            error ("No symbol \"%s\" in specified context.",
                                   copy_name ($3));
                          write_exp_elt (OP_VAR_VALUE);
                          write_exp_elt (sym);
-                         write_exp_elt (OP_VAR_VALUE); }
+                         write_exp_elt (OP_VAR_VALUE);
+                       }
+       ;
+
+variable:      typebase COLONCOLON name
+                       {
+                         struct type *type = $1;
+                         if (TYPE_CODE (type) != TYPE_CODE_STRUCT
+                             && TYPE_CODE (type) != TYPE_CODE_UNION)
+                           error ("`%s' is not defined as an aggregate type.",
+                                  TYPE_NAME (type));
+
+                         write_exp_elt (OP_SCOPE);
+                         write_exp_elt (type);
+                         write_exp_string ($3);
+                         write_exp_elt (OP_SCOPE);
+                       }
+       |       COLONCOLON name
+                       {
+                         char *name = copy_name ($2);
+                         struct symbol *sym;
+                         int i;
+
+                         sym = lookup_symbol_2 (name, 0, VAR_NAMESPACE);
+                         if (sym)
+                           {
+                             write_exp_elt (OP_VAR_VALUE);
+                             write_exp_elt (sym);
+                             write_exp_elt (OP_VAR_VALUE);
+                             break;
+                           }
+                         for (i = 0; i < misc_function_count; i++)
+                           if (!strcmp (misc_function_vector[i].name, name))
+                             break;
+
+                         if (i < misc_function_count)
+                           {
+                             write_exp_elt (OP_LONG);
+                             write_exp_elt (builtin_type_int);
+                             write_exp_elt (misc_function_vector[i].address);
+                             write_exp_elt (OP_LONG);
+                             write_exp_elt (UNOP_MEMVAL);
+                             write_exp_elt (builtin_type_char);
+                             write_exp_elt (UNOP_MEMVAL);
+                           }
+                         else
+                           if (symtab_list == 0)
+                             error ("No symbol table is loaded.  Use the \"symbol-file\" command.");
+                           else
+                             error ("No symbol \"%s\" in current context.", name);
+                       }
        ;
 
 variable:      NAME
                        { struct symbol *sym;
-                         sym = lookup_symbol (copy_name ($1),
-                                             expression_context_block,
-                                             VAR_NAMESPACE);
+                         sym = lookup_symbol_1 (copy_name ($1),
+                                                expression_context_block,
+                                                VAR_NAMESPACE);
                          if (sym)
                            {
                              write_exp_elt (OP_VAR_VALUE);
@@ -444,6 +522,32 @@ variable:  NAME
                            {
                              register char *arg = copy_name ($1);
                              register int i;
+                             int v, val;
+                             /* C++: see if it hangs off of `this'.  Must
+                                not inadvertently convert from a method call
+                                to data ref.  */
+                             v = (int)value_of_this (0);
+                             if (v)
+                               {
+                                 val = check_field (v, arg);
+                                 if (val)
+                                   {
+                                     write_exp_elt (OP_THIS);
+                                     write_exp_elt (OP_THIS);
+                                     write_exp_elt (STRUCTOP_PTR);
+                                     write_exp_string ($1);
+                                     write_exp_elt (STRUCTOP_PTR);
+                                     break;
+                                   }
+                               }
+                             sym = lookup_symbol_2 (arg, 0, VAR_NAMESPACE);
+                             if (sym)
+                               {
+                                 write_exp_elt (OP_VAR_VALUE);
+                                 write_exp_elt (sym);
+                                 write_exp_elt (OP_VAR_VALUE);
+                                 break; /* YACC-dependent */
+                               }
                              for (i = 0; i < misc_function_count; i++)
                                if (!strcmp (misc_function_vector[i].name, arg))
                                  break;
@@ -471,6 +575,17 @@ variable:  NAME
 type   :       typebase
        |       type '*'
                        { $$ = lookup_pointer_type ($1); }
+       |       type '&'
+                       { $$ = lookup_reference_type ($1); }
+       |       typebase COLONCOLON '*'
+                       { $$ = lookup_member_type (builtin_type_int, $1); }
+       |       type '(' typebase COLONCOLON '*' ')'
+                       { $$ = lookup_member_type ($1, $3); }
+       |       type '(' typebase COLONCOLON '*' ')' '(' ')'
+                       { $$ = lookup_member_type (lookup_function_type ($1, 0), $3); }
+       |       type '(' typebase COLONCOLON '*' ')' '(' nonempty_typelist ')'
+                       { $$ = lookup_member_type (lookup_function_type ($1, $8), $3);
+                         free ($8); }
        ;
 
 typebase
@@ -490,6 +605,19 @@ typebase
                        { $$ = lookup_unsigned_typename (copy_name ($2)); }
        ;
 
+nonempty_typelist
+       :       type
+               { $$ = (struct type **)xmalloc (sizeof (struct type *) * 2);
+                 $$[0] = (struct type *)0;
+                 $$[1] = $1;
+               }
+       |       nonempty_typelist ',' type
+               { int len = sizeof (struct type *) * ++($<ivec>1[0]);
+                 $$ = (struct type **)xrealloc ($1, len);
+                 $$[$<ivec>$[0]] = $3;
+               }
+       ;
+
 name   :       NAME
        |       TYPENAME
        ;
@@ -598,6 +726,14 @@ static char *lexptr;
 
 static char *namecopy;
 
+/* Current depth in parentheses within the expression.  */
+
+static int paren_depth;
+
+/* Nonzero means stop parsing on first comma (if not within parentheses).  */
+
+static int comma_terminates;
+
 /* Take care of parsing a number (anything that starts with a digit).
    Set yylval and return the token type; update lexptr.
    LEN is the number of characters in it.  */
@@ -753,6 +889,24 @@ yylex ()
        error ("Invalid character constant.");
       return CHAR;
 
+    case '(':
+      paren_depth++;
+      lexptr++;
+      return c;
+
+    case ')':
+      if (paren_depth == 0)
+       return 0;
+      paren_depth--;
+      lexptr++;
+      return c;
+
+    case ',':
+      if (comma_terminates && paren_depth == 0)
+       return 0;
+      lexptr++;
+      return c;
+
     case '+':
     case '-':
     case '*':
@@ -766,8 +920,6 @@ yylex ()
     case '@':
     case '<':
     case '>':
-    case '(':
-    case ')':
     case '[':
     case ']':
     case '.':
@@ -776,7 +928,6 @@ yylex ()
     case '=':
     case '{':
     case '}':
-    case ',':
       lexptr++;
       return c;
 
@@ -881,13 +1032,23 @@ yylex ()
     {
       return STRUCT;
     }
-  if (namelen == 5 && !strncmp (tokstart, "union", 5))
+  if (namelen == 5)
     {
-      return UNION;
+      if (!strncmp (tokstart, "union", 5))
+       {
+         return UNION;
+       }
     }
-  if (namelen == 4 && !strncmp (tokstart, "enum", 4))
+  if (namelen == 4)
     {
-      return ENUM;
+      if (!strncmp (tokstart, "enum", 4))
+       {
+         return ENUM;
+       }
+      if (!strncmp (tokstart, "this", 4))
+       {
+         return THIS;
+       }
     }
   if (namelen == 6 && !strncmp (tokstart, "sizeof", 6))
     {
@@ -968,10 +1129,20 @@ length_of_subexp (expr, endpos)
   register int args = 0;
   register int i;
 
+  if (endpos < 0)
+    error ("?error in length_of_subexp");
+
   i = (int) expr->elts[endpos - 1].opcode;
 
   switch (i)
     {
+      /* C++  */
+    case OP_SCOPE:
+      oplen = 4 + ((expr->elts[endpos - 2].longconst
+                   + sizeof (union exp_element))
+                  / sizeof (union exp_element));
+      break;
+
     case OP_LONG:
     case OP_DOUBLE:
       oplen = 4;
@@ -1002,7 +1173,6 @@ length_of_subexp (expr, endpos)
       oplen = 3 + ((expr->elts[endpos - 2].longconst
                    + sizeof (union exp_element))
                   / sizeof (union exp_element));
-                  
       break;
 
     case TERNOP_COND:
@@ -1014,6 +1184,11 @@ length_of_subexp (expr, endpos)
       args = 2;
       break;
 
+      /* C++ */
+    case OP_THIS:
+      oplen = 2;
+      break;
+
     default:
       args = 1 + (i < (int) BINOP_END);
     }
@@ -1051,6 +1226,13 @@ prefixify_subexp (inexpr, outexpr, inend, outbeg)
   opcode = inexpr->elts[inend - 1].opcode;
   switch (opcode)
     {
+      /* C++  */
+    case OP_SCOPE:
+      oplen = 4 + ((inexpr->elts[inend - 2].longconst
+                   + sizeof (union exp_element))
+                  / sizeof (union exp_element));
+      break;
+
     case OP_LONG:
     case OP_DOUBLE:
       oplen = 4;
@@ -1093,6 +1275,11 @@ prefixify_subexp (inexpr, outexpr, inend, outbeg)
       args = 2;
       break;
 
+      /* C++ */
+    case OP_THIS:
+      oplen = 2;
+      break;
+
     default:
       args = 1 + ((int) opcode < (int) BINOP_END);
     }
@@ -1136,10 +1323,12 @@ prefixify_subexp (inexpr, outexpr, inend, outbeg)
    if BLOCK is zero, use the block of the selected stack frame.
    Meanwhile, advance *STRINGPTR to point after the expression,
    at the first nonwhite character that is not part of the expression
-   (possibly a null character).  */
+   (possibly a null character).
+
+   If COMMA is nonzero, stop if a comma is reached.  */
 
 struct expression *
-parse_c_1 (stringptr, block)
+parse_c_1 (stringptr, block, comma)
      char **stringptr;
      struct block *block;
 {
@@ -1147,6 +1336,8 @@ parse_c_1 (stringptr, block)
 
   lexptr = *stringptr;
 
+  comma_terminates = comma;
+
   if (lexptr == 0 || *lexptr == 0)
     error_no_arg ("expression to compute");
 
@@ -1182,7 +1373,7 @@ parse_c_expression (string)
      char *string;
 {
   register struct expression *exp;
-  exp = parse_c_1 (&string, 0);
+  exp = parse_c_1 (&string, 0, 0);
   if (*string)
     error ("Junk after end of expression.");
   return exp;