diff options
author | Paul N. Hilfinger <hilfinger@adacore.com> | 2006-01-02 09:46:34 +0000 |
---|---|---|
committer | Paul N. Hilfinger <hilfinger@adacore.com> | 2006-01-02 09:46:34 +0000 |
commit | 52ce64369c7d39c1e901f946c6128c8439f7392c (patch) | |
tree | 437feb1b53fcad99ceded7d91107bd842facb04d /gdb/ada-exp.y | |
parent | 529cad9c5b74f4a079b07107e736fe9857a5dc84 (diff) | |
download | gdb-52ce64369c7d39c1e901f946c6128c8439f7392c.zip gdb-52ce64369c7d39c1e901f946c6128c8439f7392c.tar.gz gdb-52ce64369c7d39c1e901f946c6128c8439f7392c.tar.bz2 |
* ada-exp.y: Considerable reorganization to move functionality
from ada-lex.l to here, where it is logically more appropriate.
The original reason, however, was to prevent premature name
lookups for selector names in record aggregates.
(BLOCKNAME, TYPENAME, OBJECT_RENAMING): Remove; lexer now returns
NAME for all of these.
(VAR): New artificial token to clarify precedence rules.
(OTHERS): New lexeme.
(empty_stoken): New symbol.
(%union): Remove ssym, voidval.
(%type): Remove <voidval> type declarations.
(syntax definitions): Add aggregates.
Remove distinction between NAME, TYPENAME, BLOCKNAME, OBJECT_RENAMING.
Rename some non-terminals to be closer to reference manual usage.
Tighten up expression syntax to disallow certain non-Ada
constructions such as X and then Y or else Z.
(ada_parse): Remove initialization of left_block_context.
(write_var_from_name): Remove.
(write_var_or_type): New function, containing previous code from
defunct write_var_from_name and name_lookup.
(block_lookup): New function, moved from ada-lex.l
(select_possible_type_sym): New function, factored out of
name_lookup, which used to be in ada-lex.l.
(find_primitive_type): Ditto.
(chop_selector): Ditto.
(write_ambiguous_var): New function, factored out of defunct
write_var_from_name.
(write_selectors): New function.
(write_name_assoc): New function.
(write_exp_op_with_string): New function.
* ada-lex.l (processId): Change interface to return stoken.
(tempbuf, resize_tempbuf, tempbuf_size, tempbuf_len): Remove.
(block_lookup, name_lookup): Remove. Functionality moved to
ada-exp.y.
(state IN_STRING): Remove.
(rules): Handle string escapes in processString.
Add 'others' token.
Return all NAMEs, BLOCKNAMEs, OBJECT_RENAMINGs, TYPENAMEs in
yylval.sval (as simple strings).
All name look-ups now handled in ada-exp.y.
Introduce "::" (COLONCOLON) token and return as separate token.
(processId): Change return convention. Comment.
Leave leading "'" in place.
(processString): New function.
(find_dot_all): Add note to comment.
Fix problem that allowed match only at the end.
* ada-lang.c: Introduce aggregates.
(find_struct_field): Add new parameter to count fields skipped, and
allow other output parameters to be NULL.
(value_tag_from_contents_and_address, ada_value_struct_elt): Use
new find_struct_field.
(ada_index_struct_field, assign_aggregate, ada_is_array_type)
(num_visible_fields, ada_index_struct_field_1, ada_index_struct_field)
(num_component_specs, assign_component, assign_aggregate):
(aggregate_assign_from_choices,aggregate_assign_positional)
(aggregate_assign_others,add_component_interval):
New functions.
(ada_evaluate_subexp): Declare.
Add aggregate-related operators.
(ada_forward_operator_length): Declare.
(resolve_subexp): Add cases for new aggregate operators and OP_NAME.
Consolidate Ada operators, using ada_forward_operator_length.
(ada_search_struct_field): Search in forward order.
(ADA_OPERATORS): Add new aggregate operators.
(ada_operator_length, ada_op_name, ada_forward_operator_length)
(ada_dump_subexp_body, ada_print_subexp): Handle new aggregate
operators and OP_NAME.
(ada_type_of_array): Use longest_to_int.
(value_assign_to_component): New function.
(ada_forward_operator_length, ada_op_name, ada_dump_subexp_body):
Add OP_NAME case.
(ada_forward_operator_length, ada_dump_subexp_body):
Add OP_STRING case.
* ada-lang.h (enum ada_operator): Add OP_AGGREGATE, OP_OTHERS,
OP_CHOICES, OP_DISCRETE_RANGE, OP_POSITIONAL.
Diffstat (limited to 'gdb/ada-exp.y')
-rw-r--r-- | gdb/ada-exp.y | 819 |
1 files changed, 637 insertions, 182 deletions
diff --git a/gdb/ada-exp.y b/gdb/ada-exp.y index 4253eb8..c22083e 100644 --- a/gdb/ada-exp.y +++ b/gdb/ada-exp.y @@ -108,6 +108,8 @@ struct name_info { struct stoken stoken; }; +static struct stoken empty_stoken = { "", 0 }; + /* If expression is in the context of TYPE'(...), then TYPE, else * NULL. */ static struct type *type_qualifier; @@ -124,10 +126,18 @@ static void write_int (LONGEST, struct type *); static void write_object_renaming (struct block *, struct symbol *, int); -static void write_var_from_name (struct block *, struct name_info); +static struct type* write_var_or_type (struct block *, struct stoken); + +static void write_name_assoc (struct stoken); + +static void write_exp_op_with_string (enum exp_opcode, struct stoken); + +static struct block *block_lookup (struct block *, char *); static LONGEST convert_char_literal (struct type *, LONGEST); +static void write_ambiguous_var (struct block *, char *, int); + static struct type *type_int (void); static struct type *type_long (void); @@ -143,6 +153,7 @@ static struct type *type_long_double (void); static struct type *type_char (void); static struct type *type_system_address (void); + %} %union @@ -158,31 +169,18 @@ static struct type *type_system_address (void); } typed_val_float; struct type *tval; struct stoken sval; - struct name_info ssym; - int voidval; struct block *bval; struct internalvar *ivar; - } -%type <voidval> exp exp1 simple_exp start variable -%type <tval> type +%type <lval> positional_list component_groups component_associations +%type <lval> aggregate_component_list +%type <tval> var_or_type %token <typed_val> INT NULL_PTR CHARLIT %token <typed_val_float> FLOAT -%token <tval> TYPENAME -%token <bval> BLOCKNAME - -/* Both NAME and TYPENAME tokens represent symbols in the input, - and both convey their data as strings. - But a TYPENAME is a string that happens to be defined as a typedef - or builtin type name (such as int or char) - and a NAME is any other symbol. - Contexts where this distinction is not important can use the - nonterminal "name", which matches either NAME or TYPENAME. */ - -%token <sval> STRING -%token <ssym> NAME DOT_ID OBJECT_RENAMING +%token COLONCOLON +%token <sval> STRING NAME DOT_ID %type <bval> block %type <lval> arglist tick_arglist @@ -202,61 +200,77 @@ static struct type *type_system_address (void); %left UNARY %left '*' '/' MOD REM %right STARSTAR ABS NOT - /* The following are right-associative only so that reductions at this - precedence have lower precedence than '.' and '('. The syntax still - forces a.b.c, e.g., to be LEFT-associated. */ + +/* Artificial token to give NAME => ... and NAME | priority over reducing + NAME to <primary> and to give <primary>' priority over reducing <primary> + to <simple_exp>. */ +%nonassoc VAR + +%nonassoc ARROW '|' + %right TICK_ACCESS TICK_ADDRESS TICK_FIRST TICK_LAST TICK_LENGTH %right TICK_MAX TICK_MIN TICK_MODULUS %right TICK_POS TICK_RANGE TICK_SIZE TICK_TAG TICK_VAL + /* The following are right-associative only so that reductions at this + precedence have lower precedence than '.' and '('. The syntax still + forces a.b.c, e.g., to be LEFT-associated. */ %right '.' '(' '[' DOT_ID DOT_ALL -%token ARROW NEW +%token NEW OTHERS %% start : exp1 - | type { write_exp_elt_opcode (OP_TYPE); - write_exp_elt_type ($1); - write_exp_elt_opcode (OP_TYPE); } ; /* Expressions, including the sequencing operator. */ exp1 : exp | exp1 ';' exp { write_exp_elt_opcode (BINOP_COMMA); } + | primary ASSIGN exp /* Extension for convenience */ + { write_exp_elt_opcode (BINOP_ASSIGN); } ; /* Expressions, not including the sequencing operator. */ -simple_exp : simple_exp DOT_ALL +primary : primary DOT_ALL { write_exp_elt_opcode (UNOP_IND); } ; -simple_exp : simple_exp DOT_ID - { write_exp_elt_opcode (STRUCTOP_STRUCT); - write_exp_string ($2.stoken); - write_exp_elt_opcode (STRUCTOP_STRUCT); - } +primary : primary DOT_ID + { write_exp_op_with_string (STRUCTOP_STRUCT, $2); } ; -simple_exp : simple_exp '(' arglist ')' +primary : primary '(' arglist ')' { write_exp_elt_opcode (OP_FUNCALL); write_exp_elt_longcst ($3); write_exp_elt_opcode (OP_FUNCALL); } - ; - -simple_exp : type '(' exp ')' + | var_or_type '(' arglist ')' { - write_exp_elt_opcode (UNOP_CAST); - write_exp_elt_type ($1); - write_exp_elt_opcode (UNOP_CAST); + if ($1 != NULL) + { + if ($3 != 1) + error ("Illegal conversion"); + write_exp_elt_opcode (UNOP_CAST); + write_exp_elt_type ($1); + write_exp_elt_opcode (UNOP_CAST); + } + else + { + write_exp_elt_opcode (OP_FUNCALL); + write_exp_elt_longcst ($3); + write_exp_elt_opcode (OP_FUNCALL); + } } ; -simple_exp : type '\'' save_qualifier { type_qualifier = $1; } '(' exp ')' +primary : var_or_type '\'' save_qualifier { type_qualifier = $1; } + '(' exp ')' { + if ($1 == NULL) + error ("Type required for qualification"); write_exp_elt_opcode (UNOP_QUAL); write_exp_elt_type ($1); write_exp_elt_opcode (UNOP_QUAL); @@ -267,41 +281,61 @@ simple_exp : type '\'' save_qualifier { type_qualifier = $1; } '(' exp ')' save_qualifier : { $$ = type_qualifier; } ; -simple_exp : - simple_exp '(' exp DOTDOT exp ')' +primary : + primary '(' simple_exp DOTDOT simple_exp ')' { write_exp_elt_opcode (TERNOP_SLICE); } + | var_or_type '(' simple_exp DOTDOT simple_exp ')' + { if ($1 == NULL) + write_exp_elt_opcode (TERNOP_SLICE); + else + error ("Cannot slice a type"); + } ; -simple_exp : '(' exp1 ')' { } +primary : '(' exp1 ')' { } ; -simple_exp : variable +/* The following rule causes a conflict with the type conversion + var_or_type (exp) + To get around it, we give '(' higher priority and add bridge rules for + var_or_type (exp, exp, ...) + var_or_type (exp .. exp) + We also have the action for var_or_type(exp) generate a function call + when the first symbol does not denote a type. */ + +primary : var_or_type %prec VAR + { if ($1 != NULL) + { + write_exp_elt_opcode (OP_TYPE); + write_exp_elt_type ($1); + write_exp_elt_opcode (OP_TYPE); + } + } ; -simple_exp: SPECIAL_VARIABLE /* Various GDB extensions */ +primary : SPECIAL_VARIABLE /* Various GDB extensions */ { write_dollar_variable ($1); } ; -exp : simple_exp - ; +primary : aggregate + ; -exp : exp ASSIGN exp /* Extension for convenience */ - { write_exp_elt_opcode (BINOP_ASSIGN); } +simple_exp : primary ; -exp : '-' exp %prec UNARY +simple_exp : '-' simple_exp %prec UNARY { write_exp_elt_opcode (UNOP_NEG); } ; -exp : '+' exp %prec UNARY +simple_exp : '+' simple_exp %prec UNARY { write_exp_elt_opcode (UNOP_PLUS); } ; -exp : NOT exp %prec UNARY +simple_exp : NOT simple_exp %prec UNARY { write_exp_elt_opcode (UNOP_LOGICAL_NOT); } ; -exp : ABS exp %prec UNARY +simple_exp : ABS simple_exp %prec UNARY { write_exp_elt_opcode (UNOP_ABS); } ; @@ -310,17 +344,20 @@ arglist : { $$ = 0; } arglist : exp { $$ = 1; } - | any_name ARROW exp + | NAME ARROW exp { $$ = 1; } | arglist ',' exp { $$ = $1 + 1; } - | arglist ',' any_name ARROW exp + | arglist ',' NAME ARROW exp { $$ = $1 + 1; } ; -exp : '{' type '}' exp %prec '.' +simple_exp : '{' var_or_type '}' simple_exp %prec '.' /* GDB extension */ - { write_exp_elt_opcode (UNOP_MEMVAL); + { + if ($2 == NULL) + error ("Type required within braces in coercion"); + write_exp_elt_opcode (UNOP_MEMVAL); write_exp_elt_type ($2); write_exp_elt_opcode (UNOP_MEMVAL); } @@ -328,136 +365,175 @@ exp : '{' type '}' exp %prec '.' /* Binary operators in order of decreasing precedence. */ -exp : exp STARSTAR exp +simple_exp : simple_exp STARSTAR simple_exp { write_exp_elt_opcode (BINOP_EXP); } ; -exp : exp '*' exp +simple_exp : simple_exp '*' simple_exp { write_exp_elt_opcode (BINOP_MUL); } ; -exp : exp '/' exp +simple_exp : simple_exp '/' simple_exp { write_exp_elt_opcode (BINOP_DIV); } ; -exp : exp REM exp /* May need to be fixed to give correct Ada REM */ +simple_exp : simple_exp REM simple_exp /* May need to be fixed to give correct Ada REM */ { write_exp_elt_opcode (BINOP_REM); } ; -exp : exp MOD exp +simple_exp : simple_exp MOD simple_exp { write_exp_elt_opcode (BINOP_MOD); } ; -exp : exp '@' exp /* GDB extension */ +simple_exp : simple_exp '@' simple_exp /* GDB extension */ { write_exp_elt_opcode (BINOP_REPEAT); } ; -exp : exp '+' exp +simple_exp : simple_exp '+' simple_exp { write_exp_elt_opcode (BINOP_ADD); } ; -exp : exp '&' exp +simple_exp : simple_exp '&' simple_exp { write_exp_elt_opcode (BINOP_CONCAT); } ; -exp : exp '-' exp +simple_exp : simple_exp '-' simple_exp { write_exp_elt_opcode (BINOP_SUB); } ; -exp : exp '=' exp +relation : simple_exp + ; + +relation : simple_exp '=' simple_exp { write_exp_elt_opcode (BINOP_EQUAL); } ; -exp : exp NOTEQUAL exp +relation : simple_exp NOTEQUAL simple_exp { write_exp_elt_opcode (BINOP_NOTEQUAL); } ; -exp : exp LEQ exp +relation : simple_exp LEQ simple_exp { write_exp_elt_opcode (BINOP_LEQ); } ; -exp : exp IN exp DOTDOT exp +relation : simple_exp IN simple_exp DOTDOT simple_exp { write_exp_elt_opcode (TERNOP_IN_RANGE); } - | exp IN exp TICK_RANGE tick_arglist + | simple_exp IN primary TICK_RANGE tick_arglist { write_exp_elt_opcode (BINOP_IN_BOUNDS); write_exp_elt_longcst ((LONGEST) $5); write_exp_elt_opcode (BINOP_IN_BOUNDS); } - | exp IN TYPENAME %prec TICK_ACCESS - { write_exp_elt_opcode (UNOP_IN_RANGE); + | simple_exp IN var_or_type %prec TICK_ACCESS + { + if ($3 == NULL) + error ("Right operand of 'in' must be type"); + write_exp_elt_opcode (UNOP_IN_RANGE); write_exp_elt_type ($3); write_exp_elt_opcode (UNOP_IN_RANGE); } - | exp NOT IN exp DOTDOT exp + | simple_exp NOT IN simple_exp DOTDOT simple_exp { write_exp_elt_opcode (TERNOP_IN_RANGE); write_exp_elt_opcode (UNOP_LOGICAL_NOT); } - | exp NOT IN exp TICK_RANGE tick_arglist + | simple_exp NOT IN primary TICK_RANGE tick_arglist { write_exp_elt_opcode (BINOP_IN_BOUNDS); write_exp_elt_longcst ((LONGEST) $6); write_exp_elt_opcode (BINOP_IN_BOUNDS); write_exp_elt_opcode (UNOP_LOGICAL_NOT); } - | exp NOT IN TYPENAME %prec TICK_ACCESS - { write_exp_elt_opcode (UNOP_IN_RANGE); + | simple_exp NOT IN var_or_type %prec TICK_ACCESS + { + if ($4 == NULL) + error ("Right operand of 'in' must be type"); + write_exp_elt_opcode (UNOP_IN_RANGE); write_exp_elt_type ($4); write_exp_elt_opcode (UNOP_IN_RANGE); write_exp_elt_opcode (UNOP_LOGICAL_NOT); } ; -exp : exp GEQ exp +relation : simple_exp GEQ simple_exp { write_exp_elt_opcode (BINOP_GEQ); } ; -exp : exp '<' exp +relation : simple_exp '<' simple_exp { write_exp_elt_opcode (BINOP_LESS); } ; -exp : exp '>' exp +relation : simple_exp '>' simple_exp { write_exp_elt_opcode (BINOP_GTR); } ; -exp : exp _AND_ exp /* Fix for Ada elementwise AND. */ +exp : relation + | and_exp + | and_then_exp + | or_exp + | or_else_exp + | xor_exp + ; + +and_exp : + relation _AND_ relation { write_exp_elt_opcode (BINOP_BITWISE_AND); } - ; + | and_exp _AND_ relation + { write_exp_elt_opcode (BINOP_BITWISE_AND); } + ; -exp : exp _AND_ THEN exp %prec _AND_ +and_then_exp : + relation _AND_ THEN relation + { write_exp_elt_opcode (BINOP_LOGICAL_AND); } + | and_then_exp _AND_ THEN relation { write_exp_elt_opcode (BINOP_LOGICAL_AND); } ; -exp : exp OR exp /* Fix for Ada elementwise OR */ +or_exp : + relation OR relation { write_exp_elt_opcode (BINOP_BITWISE_IOR); } - ; + | or_exp OR relation + { write_exp_elt_opcode (BINOP_BITWISE_IOR); } + ; -exp : exp OR ELSE exp +or_else_exp : + relation OR ELSE relation + { write_exp_elt_opcode (BINOP_LOGICAL_OR); } + | or_else_exp OR ELSE relation { write_exp_elt_opcode (BINOP_LOGICAL_OR); } ; -exp : exp XOR exp /* Fix for Ada elementwise XOR */ +xor_exp : relation XOR relation + { write_exp_elt_opcode (BINOP_BITWISE_XOR); } + | xor_exp XOR relation { write_exp_elt_opcode (BINOP_BITWISE_XOR); } ; -simple_exp : simple_exp TICK_ACCESS +/* Primaries can denote types (OP_TYPE). In cases such as + primary TICK_ADDRESS, where a type would be illegal, it will be + caught when evaluate_subexp in ada-lang.c tries to evaluate the + primary, expecting a value. Precedence rules resolve the ambiguity + in NAME TICK_ACCESS in favor of shifting to form a var_or_type. A + construct such as aType'access'access will again cause an error when + aType'access evaluates to a type that evaluate_subexp attempts to + evaluate. */ +primary : primary TICK_ACCESS { write_exp_elt_opcode (UNOP_ADDR); } - | simple_exp TICK_ADDRESS + | primary TICK_ADDRESS { write_exp_elt_opcode (UNOP_ADDR); write_exp_elt_opcode (UNOP_CAST); write_exp_elt_type (type_system_address ()); write_exp_elt_opcode (UNOP_CAST); } - | simple_exp TICK_FIRST tick_arglist + | primary TICK_FIRST tick_arglist { write_int ($3, type_int ()); write_exp_elt_opcode (OP_ATR_FIRST); } - | simple_exp TICK_LAST tick_arglist + | primary TICK_LAST tick_arglist { write_int ($3, type_int ()); write_exp_elt_opcode (OP_ATR_LAST); } - | simple_exp TICK_LENGTH tick_arglist + | primary TICK_LENGTH tick_arglist { write_int ($3, type_int ()); write_exp_elt_opcode (OP_ATR_LENGTH); } - | simple_exp TICK_SIZE + | primary TICK_SIZE { write_exp_elt_opcode (OP_ATR_SIZE); } - | simple_exp TICK_TAG + | primary TICK_TAG { write_exp_elt_opcode (OP_ATR_TAG); } | opt_type_prefix TICK_MIN '(' exp ',' exp ')' { write_exp_elt_opcode (OP_ATR_MIN); } @@ -465,15 +541,6 @@ simple_exp : simple_exp TICK_ACCESS { write_exp_elt_opcode (OP_ATR_MAX); } | opt_type_prefix TICK_POS '(' exp ')' { write_exp_elt_opcode (OP_ATR_POS); } - | type_prefix TICK_FIRST tick_arglist - { write_int ($3, type_int ()); - write_exp_elt_opcode (OP_ATR_FIRST); } - | type_prefix TICK_LAST tick_arglist - { write_int ($3, type_int ()); - write_exp_elt_opcode (OP_ATR_LAST); } - | type_prefix TICK_LENGTH tick_arglist - { write_int ($3, type_int ()); - write_exp_elt_opcode (OP_ATR_LENGTH); } | type_prefix TICK_VAL '(' exp ')' { write_exp_elt_opcode (OP_ATR_VAL); } | type_prefix TICK_MODULUS @@ -487,8 +554,11 @@ tick_arglist : %prec '(' ; type_prefix : - TYPENAME - { write_exp_elt_opcode (OP_TYPE); + var_or_type + { + if ($1 == NULL) + error ("Prefix must be type"); + write_exp_elt_opcode (OP_TYPE); write_exp_elt_type ($1); write_exp_elt_opcode (OP_TYPE); } ; @@ -502,18 +572,18 @@ opt_type_prefix : ; -exp : INT +primary : INT { write_int ((LONGEST) $1.val, $1.type); } ; -exp : CHARLIT +primary : CHARLIT { write_int (convert_char_literal (type_qualifier, $1.val), (type_qualifier == NULL) ? $1.type : type_qualifier); } ; -exp : FLOAT +primary : FLOAT { write_exp_elt_opcode (OP_DOUBLE); write_exp_elt_type ($1.type); write_exp_elt_dblcst ($1.dval); @@ -521,61 +591,139 @@ exp : FLOAT } ; -exp : NULL_PTR +primary : NULL_PTR { write_int (0, type_int ()); } ; -exp : STRING +primary : STRING { - write_exp_elt_opcode (OP_STRING); - write_exp_string ($1); - write_exp_elt_opcode (OP_STRING); + write_exp_op_with_string (OP_STRING, $1); } ; -exp : NEW TYPENAME +primary : NEW NAME { error ("NEW not implemented."); } ; -variable: NAME { write_var_from_name (NULL, $1); } - | block NAME /* GDB extension */ - { write_var_from_name ($1, $2); } - | OBJECT_RENAMING - { write_object_renaming (NULL, $1.sym, - MAX_RENAMING_CHAIN_LENGTH); } - | block OBJECT_RENAMING - { write_object_renaming ($1, $2.sym, - MAX_RENAMING_CHAIN_LENGTH); } +var_or_type: NAME %prec VAR + { $$ = write_var_or_type (NULL, $1); } + | block NAME %prec VAR + { $$ = write_var_or_type ($1, $2); } + | NAME TICK_ACCESS + { + $$ = write_var_or_type (NULL, $1); + if ($$ == NULL) + write_exp_elt_opcode (UNOP_ADDR); + else + $$ = lookup_pointer_type ($$); + } + | block NAME TICK_ACCESS + { + $$ = write_var_or_type ($1, $2); + if ($$ == NULL) + write_exp_elt_opcode (UNOP_ADDR); + else + $$ = lookup_pointer_type ($$); + } ; -any_name : NAME { } - | TYPENAME { } - | OBJECT_RENAMING { } - ; +/* GDB extension */ +block : NAME COLONCOLON + { $$ = block_lookup (NULL, $1.ptr); } + | block NAME COLONCOLON + { $$ = block_lookup ($1, $2.ptr); } + ; -block : BLOCKNAME /* GDB extension */ - { $$ = $1; } - | block BLOCKNAME /* GDB extension */ - { $$ = $2; } +aggregate : + '(' aggregate_component_list ')' + { + write_exp_elt_opcode (OP_AGGREGATE); + write_exp_elt_longcst ($2); + write_exp_elt_opcode (OP_AGGREGATE); + } ; +aggregate_component_list : + component_groups { $$ = $1; } + | positional_list exp + { write_exp_elt_opcode (OP_POSITIONAL); + write_exp_elt_longcst ($1); + write_exp_elt_opcode (OP_POSITIONAL); + $$ = $1 + 1; + } + | positional_list component_groups + { $$ = $1 + $2; } + ; -type : TYPENAME { $$ = $1; } - | block TYPENAME { $$ = $2; } - | TYPENAME TICK_ACCESS - { $$ = lookup_pointer_type ($1); } - | block TYPENAME TICK_ACCESS - { $$ = lookup_pointer_type ($2); } - ; +positional_list : + exp ',' + { write_exp_elt_opcode (OP_POSITIONAL); + write_exp_elt_longcst (0); + write_exp_elt_opcode (OP_POSITIONAL); + $$ = 1; + } + | positional_list exp ',' + { write_exp_elt_opcode (OP_POSITIONAL); + write_exp_elt_longcst ($1); + write_exp_elt_opcode (OP_POSITIONAL); + $$ = $1 + 1; + } + ; + +component_groups: + others { $$ = 1; } + | component_group { $$ = 1; } + | component_group ',' component_groups + { $$ = $3 + 1; } + ; + +others : OTHERS ARROW exp + { write_exp_elt_opcode (OP_OTHERS); } + ; + +component_group : + component_associations + { + write_exp_elt_opcode (OP_CHOICES); + write_exp_elt_longcst ($1); + write_exp_elt_opcode (OP_CHOICES); + } + ; + +/* We use this somewhat obscure definition in order to handle NAME => and + NAME | differently from exp => and exp |. ARROW and '|' have a precedence + above that of the reduction of NAME to var_or_type. By delaying + decisions until after the => or '|', we convert the ambiguity to a + resolved shift/reduce conflict. */ +component_associations : + NAME ARROW + { write_name_assoc ($1); } + exp { $$ = 1; } + | simple_exp ARROW exp + { $$ = 1; } + | simple_exp DOTDOT simple_exp ARROW + { write_exp_elt_opcode (OP_DISCRETE_RANGE); + write_exp_op_with_string (OP_NAME, empty_stoken); + } + exp { $$ = 1; } + | NAME '|' + { write_name_assoc ($1); } + component_associations { $$ = $4 + 1; } + | simple_exp '|' + component_associations { $$ = $3 + 1; } + | simple_exp DOTDOT simple_exp '|' + { write_exp_elt_opcode (OP_DISCRETE_RANGE); } + component_associations { $$ = $6 + 1; } + ; /* Some extensions borrowed from C, for the benefit of those who find they can't get used to Ada notation in GDB. */ -exp : '*' exp %prec '.' +primary : '*' primary %prec '.' { write_exp_elt_opcode (UNOP_IND); } - | '&' exp %prec '.' + | '&' primary %prec '.' { write_exp_elt_opcode (UNOP_ADDR); } - | exp '[' exp ']' + | primary '[' exp ']' { write_exp_elt_opcode (BINOP_SUBSCRIPT); } ; @@ -610,7 +758,6 @@ int ada_parse (void) { lexer_init (yyin); /* (Re-)initialize lexer. */ - left_block_context = NULL; type_qualifier = NULL; obstack_free (&temp_parse_space, NULL); obstack_init (&temp_parse_space); @@ -672,42 +819,6 @@ write_var_from_sym (struct block *orig_left_context, write_exp_elt_opcode (OP_VAR_VALUE); } -/* Emit expression to access an instance of NAME in :: context - * ORIG_LEFT_CONTEXT. If no unique symbol for NAME has been found, - * output a dummy symbol (good to the next call of ada_parse) for NAME - * in the UNDEF_DOMAIN, for later resolution by ada_resolve. */ -static void -write_var_from_name (struct block *orig_left_context, - struct name_info name) -{ - if (name.msym != NULL) - { - write_exp_msymbol (name.msym, - lookup_function_type (type_int ()), - type_int ()); - } - else if (name.sym == NULL) - { - /* Multiple matches: record name and starting block for later - resolution by ada_resolve. */ - char *encoded_name = ada_encode (name.stoken.ptr); - struct symbol *sym = - obstack_alloc (&temp_parse_space, sizeof (struct symbol)); - memset (sym, 0, sizeof (struct symbol)); - SYMBOL_DOMAIN (sym) = UNDEF_DOMAIN; - SYMBOL_LINKAGE_NAME (sym) - = obsavestring (encoded_name, strlen (encoded_name), &temp_parse_space); - SYMBOL_LANGUAGE (sym) = language_ada; - - write_exp_elt_opcode (OP_VAR_VALUE); - write_exp_elt_block (name.block); - write_exp_elt_sym (sym); - write_exp_elt_opcode (OP_VAR_VALUE); - } - else - write_var_from_sym (orig_left_context, name.block, name.sym); -} - /* Write integer constant ARG of type TYPE. */ static void @@ -719,6 +830,15 @@ write_int (LONGEST arg, struct type *type) write_exp_elt_opcode (OP_LONG); } +/* Write an OPCODE, string, OPCODE sequence to the current expression. */ +static void +write_exp_op_with_string (enum exp_opcode opcode, struct stoken token) +{ + write_exp_elt_opcode (opcode); + write_exp_string (token); + write_exp_elt_opcode (opcode); +} + /* Emit expression corresponding to the renamed object designated by * the type RENAMING, which must be the referent of an object renaming * type, in the context of ORIG_LEFT_CONTEXT. MAX_DEPTH is the maximum @@ -857,9 +977,7 @@ write_object_renaming (struct block *orig_left_context, strncpy (field_name.ptr, suffix, end - suffix); field_name.ptr[end - suffix] = '\000'; suffix = end; - write_exp_elt_opcode (STRUCTOP_STRUCT); - write_exp_string (field_name); - write_exp_elt_opcode (STRUCTOP_STRUCT); + write_exp_op_with_string (STRUCTOP_STRUCT, field_name); break; } @@ -875,10 +993,348 @@ write_object_renaming (struct block *orig_left_context, SYMBOL_LINKAGE_NAME (renaming)); } +static struct block* +block_lookup (struct block *context, char *raw_name) +{ + char *name; + struct ada_symbol_info *syms; + int nsyms; + struct symtab *symtab; + + if (raw_name[0] == '\'') + { + raw_name += 1; + name = raw_name; + } + else + name = ada_encode (raw_name); + + nsyms = ada_lookup_symbol_list (name, context, VAR_DOMAIN, &syms); + if (context == NULL && + (nsyms == 0 || SYMBOL_CLASS (syms[0].sym) != LOC_BLOCK)) + symtab = lookup_symtab (name); + else + symtab = NULL; + + if (symtab != NULL) + return BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK); + else if (nsyms == 0 || SYMBOL_CLASS (syms[0].sym) != LOC_BLOCK) + { + if (context == NULL) + error ("No file or function \"%s\".", raw_name); + else + error ("No function \"%s\" in specified context.", raw_name); + } + else + { + if (nsyms > 1) + warning ("Function name \"%s\" ambiguous here", raw_name); + return SYMBOL_BLOCK_VALUE (syms[0].sym); + } +} + +static struct symbol* +select_possible_type_sym (struct ada_symbol_info *syms, int nsyms) +{ + int i; + int preferred_index; + struct type *preferred_type; + + preferred_index = -1; preferred_type = NULL; + for (i = 0; i < nsyms; i += 1) + switch (SYMBOL_CLASS (syms[i].sym)) + { + case LOC_TYPEDEF: + if (ada_prefer_type (SYMBOL_TYPE (syms[i].sym), preferred_type)) + { + preferred_index = i; + preferred_type = SYMBOL_TYPE (syms[i].sym); + } + break; + case LOC_REGISTER: + case LOC_ARG: + case LOC_REF_ARG: + case LOC_REGPARM: + case LOC_REGPARM_ADDR: + case LOC_LOCAL: + case LOC_LOCAL_ARG: + case LOC_BASEREG: + case LOC_BASEREG_ARG: + case LOC_COMPUTED: + case LOC_COMPUTED_ARG: + return NULL; + default: + break; + } + if (preferred_type == NULL) + return NULL; + return syms[preferred_index].sym; +} + +static struct type* +find_primitive_type (char *name) +{ + struct type *type; + type = language_lookup_primitive_type_by_name (current_language, + current_gdbarch, + name); + if (type == NULL && strcmp ("system__address", name) == 0) + type = type_system_address (); + + if (type != NULL) + { + /* Check to see if we have a regular definition of this + type that just didn't happen to have been read yet. */ + int ntypes; + struct symbol *sym; + char *expanded_name = + (char *) alloca (strlen (name) + sizeof ("standard__")); + strcpy (expanded_name, "standard__"); + strcat (expanded_name, name); + sym = ada_lookup_symbol (expanded_name, NULL, VAR_DOMAIN, NULL, NULL); + if (sym != NULL && SYMBOL_CLASS (sym) == LOC_TYPEDEF) + type = SYMBOL_TYPE (sym); + } + + return type; +} + +static int +chop_selector (char *name, int end) +{ + int i; + for (i = end - 1; i > 0; i -= 1) + if (name[i] == '.' || (name[i] == '_' && name[i+1] == '_')) + return i; + return -1; +} + +/* Given that SELS is a string of the form (<sep><identifier>)*, where + <sep> is '__' or '.', write the indicated sequence of + STRUCTOP_STRUCT expression operators. */ +static void +write_selectors (char *sels) +{ + while (*sels != '\0') + { + struct stoken field_name; + char *p; + while (*sels == '_' || *sels == '.') + sels += 1; + p = sels; + while (*sels != '\0' && *sels != '.' + && (sels[0] != '_' || sels[1] != '_')) + sels += 1; + field_name.length = sels - p; + field_name.ptr = p; + write_exp_op_with_string (STRUCTOP_STRUCT, field_name); + } +} + +/* Write a variable access (OP_VAR_VALUE) to ambiguous encoded name + NAME[0..LEN-1], in block context BLOCK, to be resolved later. Writes + a temporary symbol that is valid until the next call to ada_parse. + */ +static void +write_ambiguous_var (struct block *block, char *name, int len) +{ + struct symbol *sym = + obstack_alloc (&temp_parse_space, sizeof (struct symbol)); + memset (sym, 0, sizeof (struct symbol)); + SYMBOL_DOMAIN (sym) = UNDEF_DOMAIN; + SYMBOL_LINKAGE_NAME (sym) = obsavestring (name, len, &temp_parse_space); + SYMBOL_LANGUAGE (sym) = language_ada; + + write_exp_elt_opcode (OP_VAR_VALUE); + write_exp_elt_block (block); + write_exp_elt_sym (sym); + write_exp_elt_opcode (OP_VAR_VALUE); +} + + +/* Look up NAME0 (an unencoded identifier or dotted name) in BLOCK (or + expression_block_context if NULL). If it denotes a type, return + that type. Otherwise, write expression code to evaluate it as an + object and return NULL. In this second case, NAME0 will, in general, + have the form <name>(.<selector_name>)*, where <name> is an object + or renaming encoded in the debugging data. Calls error if no + prefix <name> matches a name in the debugging data (i.e., matches + either a complete name or, as a wild-card match, the final + identifier). */ + +static struct type* +write_var_or_type (struct block *block, struct stoken name0) +{ + int depth; + char *encoded_name; + int name_len; + + if (block == NULL) + block = expression_context_block; + + encoded_name = ada_encode (name0.ptr); + name_len = strlen (encoded_name); + encoded_name = obsavestring (encoded_name, name_len, &temp_parse_space); + for (depth = 0; depth < MAX_RENAMING_CHAIN_LENGTH; depth += 1) + { + int tail_index; + + tail_index = name_len; + while (tail_index > 0) + { + int nsyms; + struct ada_symbol_info *syms; + struct symbol *type_sym; + int terminator = encoded_name[tail_index]; + + encoded_name[tail_index] = '\0'; + nsyms = ada_lookup_symbol_list (encoded_name, block, + VAR_DOMAIN, &syms); + encoded_name[tail_index] = terminator; + + /* A single symbol may rename a package or object. */ + + if (nsyms == 1 && !ada_is_object_renaming (syms[0].sym)) + { + struct symbol *renaming_sym = + ada_find_renaming_symbol (SYMBOL_LINKAGE_NAME (syms[0].sym), + syms[0].block); + + if (renaming_sym != NULL) + syms[0].sym = renaming_sym; + } + + type_sym = select_possible_type_sym (syms, nsyms); + 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 (ada_is_object_renaming (type_sym)) + { + write_object_renaming (block, type_sym, + MAX_RENAMING_CHAIN_LENGTH); + write_selectors (encoded_name + tail_index); + return NULL; + } + else if (ada_renaming_type (SYMBOL_TYPE (type_sym)) != NULL) + { + int result; + char *renaming = ada_simple_renamed_entity (type_sym); + int renaming_len = strlen (renaming); + + char *new_name + = obstack_alloc (&temp_parse_space, + renaming_len + name_len - tail_index + + 1); + strcpy (new_name, renaming); + xfree (renaming); + strcpy (new_name + renaming_len, encoded_name + tail_index); + encoded_name = new_name; + name_len = renaming_len + name_len - tail_index; + goto TryAfterRenaming; + } + else if (tail_index == name_len) + return type; + else + error ("Illegal attempt to select from type: \"%s\".", name0.ptr); + } + else if (tail_index == name_len && nsyms == 0) + { + struct type *type = find_primitive_type (encoded_name); + + if (type != NULL) + return type; + } + + if (nsyms == 1) + { + write_var_from_sym (block, syms[0].block, syms[0].sym); + write_selectors (encoded_name + tail_index); + return NULL; + } + else if (nsyms == 0) + { + int i; + struct minimal_symbol *msym + = ada_lookup_simple_minsym (encoded_name); + if (msym != NULL) + { + write_exp_msymbol (msym, lookup_function_type (type_int ()), + type_int ()); + /* Maybe cause error here rather than later? FIXME? */ + write_selectors (encoded_name + tail_index); + return NULL; + } + + if (tail_index == name_len + && strncmp (encoded_name, "standard__", + sizeof ("standard__") - 1) == 0) + error ("No definition of \"%s\" found.", name0.ptr); + + tail_index = chop_selector (encoded_name, tail_index); + } + else + { + write_ambiguous_var (block, encoded_name, tail_index); + write_selectors (encoded_name + tail_index); + return NULL; + } + } + + if (!have_full_symbols () && !have_partial_symbols () && block == NULL) + error ("No symbol table is loaded. Use the \"file\" command."); + if (block == expression_context_block) + error ("No definition of \"%s\" in current context.", name0.ptr); + else + error ("No definition of \"%s\" in specified context.", name0.ptr); + + TryAfterRenaming: ; + } + + error ("Could not find renamed symbol \"%s\"", name0.ptr); + +} + +/* Write a left side of a component association (e.g., NAME in NAME => + exp). If NAME has the form of a selected component, write it as an + ordinary expression. If it is a simple variable that unambiguously + corresponds to exactly one symbol that does not denote a type or an + object renaming, also write it normally as an OP_VAR_VALUE. + Otherwise, write it as an OP_NAME. + + Unfortunately, we don't know at this point whether NAME is supposed + to denote a record component name or the value of an array index. + Therefore, it is not appropriate to disambiguate an ambiguous name + as we normally would, nor to replace a renaming with its referent. + As a result, in the (one hopes) rare case that one writes an + aggregate such as (R => 42) where R renames an object or is an + ambiguous name, one must write instead ((R) => 42). */ + +static void +write_name_assoc (struct stoken name) +{ + if (strchr (name.ptr, '.') == NULL) + { + struct ada_symbol_info *syms; + int nsyms = ada_lookup_symbol_list (name.ptr, expression_context_block, + VAR_DOMAIN, &syms); + if (nsyms != 1 || SYMBOL_CLASS (syms[0].sym) == LOC_TYPEDEF) + write_exp_op_with_string (OP_NAME, name); + else + write_var_from_sym (NULL, syms[0].block, syms[0].sym); + } + else + if (write_var_or_type (NULL, name) != NULL) + error ("Illegal use of type."); +} + /* Convert the character literal whose ASCII value would be VAL to the appropriate value of type TYPE, if there is a translation. Otherwise return VAL. Hence, in an enumeration type ('A', 'B'), the literal 'A' (VAL == 65), returns 0. */ + static LONGEST convert_char_literal (struct type *type, LONGEST val) { @@ -962,4 +1418,3 @@ _initialize_ada_exp (void) struct stoken (*dummy_string_to_ada_operator) (struct stoken) = string_to_operator; - |