From: Joel Brobecker Date: Fri, 4 Jan 2008 15:04:10 +0000 (+0000) Subject: * ada-exp.y (chop_separator): New function. X-Git-Url: http://git.efficios.com/?a=commitdiff_plain;h=d3353bbdea34154d4134a818f1fd2ac16d68df00;p=deliverable%2Fbinutils-gdb.git * ada-exp.y (chop_separator): New function. (write_selectors): Rewrite to re-use chop_separator. (ada_nget_field_index, get_symbol_field_type): New functions. (write_var_or_type): Add support for "ptype TYPENAME.FIELD" expressions. --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 880ae7461b..6c6be45add 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,11 @@ +2008-01-04 Joel Brobecker + + * ada-exp.y (chop_separator): New function. + (write_selectors): Rewrite to re-use chop_separator. + (ada_nget_field_index, get_symbol_field_type): New functions. + (write_var_or_type): Add support for "ptype TYPENAME.FIELD" + expressions. + 2008-01-03 Thiago Jung Bauermann * symtab.c (find_pc_sect_line): Use SYMBOL_VALUE_ADDRESS instead diff --git a/gdb/ada-exp.y b/gdb/ada-exp.y index 6c93647ac8..3ba9f6c29f 100644 --- a/gdb/ada-exp.y +++ b/gdb/ada-exp.y @@ -1112,6 +1112,22 @@ chop_selector (char *name, int end) return -1; } +/* If NAME is a string beginning with a separator (either '__', or + '.'), chop this separator and return the result; else, return + NAME. */ + +static char * +chop_separator (char *name) +{ + if (*name == '.') + return name + 1; + + if (name[0] == '_' && name[1] == '_') + return name + 2; + + return name; +} + /* Given that SELS is a string of the form ()*, where is '__' or '.', write the indicated sequence of STRUCTOP_STRUCT expression operators. */ @@ -1121,10 +1137,8 @@ write_selectors (char *sels) while (*sels != '\0') { struct stoken field_name; - char *p; - while (*sels == '_' || *sels == '.') - sels += 1; - p = sels; + char *p = chop_separator (sels); + sels = p; while (*sels != '\0' && *sels != '.' && (sels[0] != '_' || sels[1] != '_')) sels += 1; @@ -1154,6 +1168,70 @@ write_ambiguous_var (struct block *block, char *name, int len) write_exp_elt_opcode (OP_VAR_VALUE); } +/* A convenient wrapper around ada_get_field_index that takes + a non NUL-terminated FIELD_NAME0 and a FIELD_NAME_LEN instead + of a NUL-terminated field name. */ + +static int +ada_nget_field_index (const struct type *type, const char *field_name0, + int field_name_len, int maybe_missing) +{ + char *field_name = alloca ((field_name_len + 1) * sizeof (char)); + + strncpy (field_name, field_name0, field_name_len); + field_name[field_name_len] = '\0'; + return ada_get_field_index (type, field_name, maybe_missing); +} + +/* If encoded_field_name is the name of a field inside symbol SYM, + then return the type of that field. Otherwise, return NULL. + + This function is actually recursive, so if ENCODED_FIELD_NAME + doesn't match one of the fields of our symbol, then try to see + if ENCODED_FIELD_NAME could not be a succession of field names + (in other words, the user entered an expression of the form + TYPE_NAME.FIELD1.FIELD2.FIELD3), in which case we evaluate + each field name sequentially to obtain the desired field type. + In case of failure, we return NULL. */ + +static struct type * +get_symbol_field_type (struct symbol *sym, char *encoded_field_name) +{ + char *field_name = encoded_field_name; + char *subfield_name; + struct type *type = SYMBOL_TYPE (sym); + int fieldno; + + if (type == NULL || field_name == NULL) + return NULL; + + while (field_name[0] != '\0') + { + field_name = chop_separator (field_name); + + fieldno = ada_get_field_index (type, field_name, 1); + if (fieldno >= 0) + return TYPE_FIELD_TYPE (type, fieldno); + + subfield_name = field_name; + while (*subfield_name != '\0' && *subfield_name != '.' + && (subfield_name[0] != '_' || subfield_name[1] != '_')) + subfield_name += 1; + + if (subfield_name[0] == '\0') + return NULL; + + fieldno = ada_nget_field_index (type, field_name, + subfield_name - field_name, 1); + if (fieldno < 0) + return NULL; + + type = TYPE_FIELD_TYPE (type, fieldno); + field_name = subfield_name; + } + + return NULL; +} /* Look up NAME0 (an unencoded identifier or dotted name) in BLOCK (or expression_block_context if NULL). If it denotes a type, return @@ -1252,14 +1330,21 @@ write_var_or_type (struct block *block, struct stoken name0) if (type_sym != NULL) { - struct type *type = SYMBOL_TYPE (type_sym); - - if (TYPE_CODE (type) == TYPE_CODE_VOID) - error (_("`%s' matches only void type name(s)"), name0.ptr); - else if (tail_index == name_len) - return type; + struct type *field_type; + + if (tail_index == name_len) + return SYMBOL_TYPE (type_sym); + + /* We have some extraneous characters after the type name. + If this is an expression "TYPE_NAME.FIELD0.[...].FIELDN", + then try to get the type of FIELDN. */ + field_type + = get_symbol_field_type (type_sym, encoded_name + tail_index); + if (field_type != NULL) + return field_type; else - error (_("Invalid attempt to select from type: \"%s\"."), name0.ptr); + error (_("Invalid attempt to select from type: \"%s\"."), + name0.ptr); } else if (tail_index == name_len && nsyms == 0) {