This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
RFC: Allow field completion for pascal language
- From: "Pierre Muller" <pierre dot muller at ics-cnrs dot unistra dot fr>
- To: <gdb-patches at sourceware dot org>
- Date: Wed, 12 Jan 2011 15:58:59 +0100
- Subject: RFC: Allow field completion for pascal language
I wrote this patch to get correct field completion
for pascal language.
As pascal maintainer, I could have simply
committed that change (I verified that it introduced
no testsuite regression), but as
I am not that familiar with the parser and completion
code in general, I wanted to submit it for review first.
I tried to adapt c-exp.y specific code using the
COMPLETE token to p-exp.y.
The things are in fact a little easier in pascal
as only '.' can be found before a union/struct field
(named records, objects or classes in pascal language).
If nobody has any remarks on that code,
I plan to commit it in a few days, but I would
of course welcome any comment.
This modification is probably also doable in other language
parsers... But I will not do that.
Pierre Muller
GDB pascal language maintainer
2011-01-12 Pierre Muller <muller@ics.u-strasbg.fr>
* p-exp.y (intvar): New static variable, used to set CURRENT_TYPE
for internal variables.
(last_was_structop): New static variable.
(COMPLETE): New token.
(field_exp): New rule to group all '.' suffix handling.
Add mark_struct_expression calls when approriate to be able
to correctly find fields for completion.
(yylex): Adapt to handle field completion and set INTVAR when
required.
Index: src/gdb/p-exp.y
===================================================================
RCS file: /cvs/src/src/gdb/p-exp.y,v
retrieving revision 1.53
diff -u -p -r1.53 p-exp.y
--- src/gdb/p-exp.y 10 Jan 2011 20:38:49 -0000 1.53
+++ src/gdb/p-exp.y 12 Jan 2011 14:33:45 -0000
@@ -158,10 +158,12 @@ static int
parse_number (char *, int, int, YYSTYPE *);
static struct type *current_type;
+static struct internalvar *intvar;
static int leftdiv_is_integer;
static void push_current_type (void);
static void pop_current_type (void);
static int search_field;
+
%}
%type <voidval> exp exp1 type_exp start normal_start variable
qualified_name
@@ -184,6 +186,7 @@ static int search_field;
%token <sval> STRING
%token <sval> FIELDNAME
+%token <voidval> COMPLETE
%token <ssym> NAME /* BLOCKNAME defined below to give it higher precedence.
*/
%token <tsym> TYPENAME
%type <sval> name
@@ -233,6 +236,7 @@ static int search_field;
%%
start : { current_type = NULL;
+ intvar = NULL;
search_field = 0;
leftdiv_is_integer = 0;
}
@@ -285,19 +289,56 @@ exp : DECREMENT '(' exp ')' %prec UNA
{ write_exp_elt_opcode (UNOP_PREDECREMENT); }
;
-exp : exp '.' { search_field = 1; }
- FIELDNAME
- /* name */
+
+field_exp : exp '.' %prec UNARY
+ { search_field = 1; }
+ ;
+
+exp : field_exp FIELDNAME
{ write_exp_elt_opcode (STRUCTOP_STRUCT);
- write_exp_string ($4);
+ write_exp_string ($2);
write_exp_elt_opcode (STRUCTOP_STRUCT);
search_field = 0;
if (current_type)
- { while (TYPE_CODE (current_type) ==
TYPE_CODE_PTR)
- current_type = TYPE_TARGET_TYPE
(current_type);
+ {
+ while (TYPE_CODE (current_type)
+ == TYPE_CODE_PTR)
+ current_type =
+ TYPE_TARGET_TYPE (current_type);
current_type = lookup_struct_elt_type (
- current_type, $4.ptr, 0); };
- } ;
+ current_type, $2.ptr, 0);
+ }
+ }
+ ;
+
+exp : field_exp name
+ { mark_struct_expression ();
+ write_exp_elt_opcode (STRUCTOP_STRUCT);
+ write_exp_string ($2);
+ write_exp_elt_opcode (STRUCTOP_STRUCT);
+ search_field = 0;
+ if (current_type)
+ {
+ while (TYPE_CODE (current_type)
+ == TYPE_CODE_PTR)
+ current_type =
+ TYPE_TARGET_TYPE (current_type);
+ current_type = lookup_struct_elt_type (
+ current_type, $2.ptr, 0);
+ }
+ }
+ ;
+
+exp : field_exp COMPLETE
+ { struct stoken s;
+ mark_struct_expression ();
+ write_exp_elt_opcode (STRUCTOP_STRUCT);
+ s.ptr = "";
+ s.length = 0;
+ write_exp_string (s);
+ write_exp_elt_opcode (STRUCTOP_STRUCT); }
+ ;
+
exp : exp '['
/* We need to save the current_type value. */
{ char *arrayname;
@@ -516,8 +557,19 @@ exp : variable
;
exp : VARIABLE
- /* Already written by write_dollar_variable. */
- ;
+ /* Already written by write_dollar_variable.
+ Handle current_type. */
+ { if (intvar) {
+ struct value * val, * mark;
+
+ mark = value_mark ();
+ val = value_of_internalvar (parse_gdbarch,
+ intvar);
+ current_type = value_type (val);
+ value_release_to_mark (mark);
+ }
+ }
+ ;
exp : SIZEOF '(' type ')' %prec UNARY
{ write_exp_elt_opcode (OP_LONG);
@@ -1060,8 +1112,13 @@ static char * uptok (tokstart, namelen)
uptokstart[namelen]='\0';
return uptokstart;
}
-/* Read one token, getting characters through lexptr. */
+/* This is set if the previously-returned token was a structure
+ operator '.'. This is used only when parsing to
+ do field name completion. */
+static int last_was_structop;
+
+/* Read one token, getting characters through lexptr. */
static int
yylex ()
@@ -1075,7 +1132,9 @@ yylex ()
int explen, tempbufindex;
static char *tempbuf;
static int tempbufsize;
-
+ int saw_structop = last_was_structop;
+
+ last_was_structop = 0;
retry:
prev_lexptr = lexptr;
@@ -1111,7 +1170,10 @@ yylex ()
switch (c = *tokstart)
{
case 0:
- return 0;
+ if (saw_structop && search_field)
+ return COMPLETE;
+ else
+ return 0;
case ' ':
case '\t':
@@ -1172,7 +1234,12 @@ yylex ()
case '.':
/* Might be a floating point number. */
if (lexptr[1] < '0' || lexptr[1] > '9')
- goto symbol; /* Nope, must be a symbol. */
+ {
+ if (in_parse_field)
+ last_was_structop = 1;
+ goto symbol; /* Nope, must be a symbol. */
+ }
+
/* FALL THRU into number case. */
case '0':
@@ -1430,11 +1497,17 @@ yylex ()
if (*tokstart == '$')
{
+ char c;
/* $ is the normal prefix for pascal hexadecimal values
but this conflicts with the GDB use for debugger variables
so in expression to enter hexadecimal values
we still need to use C syntax with 0xff */
write_dollar_variable (yylval.sval);
+ c = tokstart[namelen];
+ tokstart[namelen] = 0;
+ intvar = lookup_only_internalvar (++tokstart);
+ --tokstart;
+ tokstart[namelen] = c;
free (uptokstart);
return VARIABLE;
}
@@ -1454,7 +1527,7 @@ yylex ()
if (search_field && current_type)
is_a_field = (lookup_struct_elt_type (current_type, tmp, 1) != NULL);
- if (is_a_field)
+ if (is_a_field || in_parse_field)
sym = NULL;
else
sym = lookup_symbol (tmp, expression_context_block,
@@ -1469,7 +1542,7 @@ yylex ()
}
if (search_field && current_type)
is_a_field = (lookup_struct_elt_type (current_type, tmp, 1) !=
NULL);
- if (is_a_field)
+ if (is_a_field || in_parse_field)
sym = NULL;
else
sym = lookup_symbol (tmp, expression_context_block,
@@ -1497,7 +1570,7 @@ yylex ()
}
if (search_field && current_type)
is_a_field = (lookup_struct_elt_type (current_type, tmp, 1) !=
NULL);
- if (is_a_field)
+ if (is_a_field || in_parse_field)
sym = NULL;
else
sym = lookup_symbol (tmp, expression_context_block,