summaryrefslogtreecommitdiff
path: root/gdb/f-exp.y
diff options
context:
space:
mode:
authorAndrew Burgess <andrew.burgess@embecosm.com>2020-11-13 18:27:42 +0000
committerAndrew Burgess <andrew.burgess@embecosm.com>2020-11-14 21:19:27 +0000
commit9dd02fc063284f59994c095ce525e1b8934b0dc1 (patch)
tree54b999286c860db72841595efeeb35f80dd85724 /gdb/f-exp.y
parent758cb81029440efad398f1aba4789a18e59daee2 (diff)
downloadbinutils-gdb-9dd02fc063284f59994c095ce525e1b8934b0dc1.tar.gz
gdb: add tab completion of type field names for Fortran
Add support for tab-completion on Fortran field names. Consider this test case: program test type my_type integer :: field_a integer :: other_field integer :: last_field end type my_type type(my_type) :: var print *, var end program test And the GDB session before this patch: (gdb) start ... (gdb) p var% <- Trigger TAB completion here. Display all 200 possibilities? (y or n) n (gdb) p var% And the GDB session with this patch: (gdb) start ... (gdb) p var% <- Trigger TAB completion here. field_a last_field other_field (gdb) p var% The implementation for this is basically copied from c-exp.y, I tweaked the parser patterns to be appropriate for Fortran, and it "just worked". gdb/ChangeLog: PR cli/26879 * f-exp.y (COMPLETE): New token. (exp): Two new rules for tab-completion. (saw_name_at_eof): New static global. (last_was_structop): Likewise. (yylex): Set new variables, and return COMPLETE token at the end of the input stream in some cases. gdb/testsuite/ChangeLog: PR cli/26879 * gdb.fortran/completion.exp: New file. * gdb.fortran/completion.f90: New file.
Diffstat (limited to 'gdb/f-exp.y')
-rw-r--r--gdb/f-exp.y51
1 files changed, 47 insertions, 4 deletions
diff --git a/gdb/f-exp.y b/gdb/f-exp.y
index 5e16678886b..edfbe0cd220 100644
--- a/gdb/f-exp.y
+++ b/gdb/f-exp.y
@@ -149,6 +149,7 @@ static int parse_number (struct parser_state *, const char *, int,
%token <lval> BOOLEAN_LITERAL
%token <ssym> NAME
%token <tsym> TYPENAME
+%token <voidval> COMPLETE
%type <sval> name
%type <ssym> name_not_typename
@@ -374,6 +375,22 @@ exp : exp '%' name
write_exp_elt_opcode (pstate, STRUCTOP_STRUCT); }
;
+exp : exp '%' name COMPLETE
+ { pstate->mark_struct_expression ();
+ write_exp_elt_opcode (pstate, STRUCTOP_STRUCT);
+ write_exp_string (pstate, $3);
+ write_exp_elt_opcode (pstate, STRUCTOP_STRUCT); }
+ ;
+
+exp : exp '%' COMPLETE
+ { struct stoken s;
+ pstate->mark_struct_expression ();
+ write_exp_elt_opcode (pstate, STRUCTOP_PTR);
+ s.ptr = "";
+ s.length = 0;
+ write_exp_string (pstate, s);
+ write_exp_elt_opcode (pstate, STRUCTOP_PTR); }
+
/* Binary operators in order of decreasing precedence. */
exp : exp '@' exp
@@ -1100,6 +1117,15 @@ match_string_literal (void)
}
}
+/* This is set if a NAME token appeared at the very end of the input
+ string, with no whitespace separating the name from the EOF. This
+ is used only when parsing to do field name completion. */
+static bool saw_name_at_eof;
+
+/* This is set if the previously-returned token was a structure
+ operator '%'. */
+static bool last_was_structop;
+
/* Read one token, getting characters through lexptr. */
static int
@@ -1109,7 +1135,10 @@ yylex (void)
int namelen;
unsigned int token;
const char *tokstart;
-
+ bool saw_structop = last_was_structop;
+
+ last_was_structop = false;
+
retry:
pstate->prev_lexptr = pstate->lexptr;
@@ -1156,6 +1185,13 @@ yylex (void)
switch (c = *tokstart)
{
case 0:
+ if (saw_name_at_eof)
+ {
+ saw_name_at_eof = false;
+ return COMPLETE;
+ }
+ else if (pstate->parse_completion && saw_structop)
+ return COMPLETE;
return 0;
case ' ':
@@ -1257,12 +1293,14 @@ yylex (void)
pstate->lexptr = p;
return toktype;
}
-
+
+ case '%':
+ last_was_structop = true;
+ /* Fall through. */
case '+':
case '-':
case '*':
case '/':
- case '%':
case '|':
case '&':
case '^':
@@ -1374,7 +1412,10 @@ yylex (void)
return NAME_OR_INT;
}
}
-
+
+ if (pstate->parse_completion && *pstate->lexptr == '\0')
+ saw_name_at_eof = true;
+
/* Any other kind of symbol */
yylval.ssym.sym = result;
yylval.ssym.is_a_field_of_this = false;
@@ -1391,6 +1432,8 @@ f_language::parser (struct parser_state *par_state) const
parser_debug);
gdb_assert (par_state != NULL);
pstate = par_state;
+ last_was_structop = false;
+ saw_name_at_eof = false;
paren_depth = 0;
struct type_stack stack;