aboutsummaryrefslogtreecommitdiff
path: root/gdb/linespec.c
diff options
context:
space:
mode:
authorKeith Seitz <keiths@redhat.com>2015-03-23 12:59:18 -0700
committerKeith Seitz <keiths@redhat.com>2015-03-23 13:16:39 -0700
commit0578b14e990e76f3c2dd9010c4cb9201bc9fa4b4 (patch)
treef1d3015cb60449da8288124ca8634ac7aa13a584 /gdb/linespec.c
parent7e993ebf2343a5b39d6d1df29fdebc2818064ae5 (diff)
downloadgdb-0578b14e990e76f3c2dd9010c4cb9201bc9fa4b4.zip
gdb-0578b14e990e76f3c2dd9010c4cb9201bc9fa4b4.tar.gz
gdb-0578b14e990e76f3c2dd9010c4cb9201bc9fa4b4.tar.bz2
Expand keyword lexing intelligence in the linespec parser.
This patch changes the heuristic the linespec lexer uses to detect a keyword in the input stream. Currently, the heuristic is: a word is a keyword if it 1) points to a string that is a keyword 2) is followed by a non-identifier character This is strictly more correct than using whitespace. For example, it allows constructs such as "break foo if(i == 1)". However, find_condition_and_thread in breakpoint.c does not support this expanded usage. It requires whitespace to follow the keyword. The proposed new heuristic is: a word is a keyword if it 1) points to a string that is a keyword 2) is followed by whitespace 3) is not followed by another keyword string followed by whitespace This additional complexity allows constructs such as "break thread thread 3" and "break thread 3". In the former case, the actual location is a symbol named "thread" to be set on thread #3. In the later case, the location is NULL, i.e., the default location, to be set on thread #3. In order to pass all the new tests added here, I've also had to add a new feature to parse_breakpoint_sals, which expands recognition of the default location to keywords other than "if", which is the only keyword currently permitted with the default (NULL) location, but there is no reason to exclude other keywords. Consequently, it will be possible to use "break thread 1" or "break task 1". In addition to all of this, it is now possible to remove the keyword_ok state from the linespec parser. gdb/ChangeLog * breakpoint.c (parse_breakpoint_sals): Use linespec_lexer_lex_keyword to ascertain if the user specified a NULL location. * linespec.c [IF_KEYWORD_INDEX]: Define. (linespec_lexer_lex_keyword): Export. (struct ls_parser) <keyword_ok>: Remove. A keyword is only a keyword if not followed by another keyword. (linespec_lexer_lex_one): Remove keyword_ok handling. Add comment explaining why the parsing stream is not advanced when a keyword is seen. (parse_linespec): Remove parser->keyword_ok. * linespec.h (linespec_lexer_lex_keyword): Add declaration. gdb/testsuite/ChangeLog * gdb.linespec/keywords.c: New file. * gdb.linespec/keywords.exp: New file.
Diffstat (limited to 'gdb/linespec.c')
-rw-r--r--gdb/linespec.c55
1 files changed, 35 insertions, 20 deletions
diff --git a/gdb/linespec.c b/gdb/linespec.c
index 9ec4a5e..90c07a2 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -246,6 +246,7 @@ typedef enum ls_token_type linespec_token_type;
/* List of keywords */
static const char * const linespec_keywords[] = { "if", "thread", "task" };
+#define IF_KEYWORD_INDEX 0
/* A token of the linespec lexer */
@@ -290,11 +291,6 @@ struct ls_parser
/* Is the entire linespec quote-enclosed? */
int is_quote_enclosed;
- /* Is a keyword syntactically valid at this point?
- In, e.g., "break thread thread 1", the leading "keyword" must not
- be interpreted as such. */
- int keyword_ok;
-
/* The state of the parse. */
struct linespec_state state;
#define PARSER_STATE(PPTR) (&(PPTR)->state)
@@ -421,7 +417,7 @@ linespec_lexer_lex_number (linespec_parser *parser, linespec_token *tokenp)
/* Does P represent one of the keywords? If so, return
the keyword. If not, return NULL. */
-static const char *
+const char *
linespec_lexer_lex_keyword (const char *p)
{
int i;
@@ -433,11 +429,34 @@ linespec_lexer_lex_keyword (const char *p)
int len = strlen (linespec_keywords[i]);
/* If P begins with one of the keywords and the next
- character is not a valid identifier character,
- we have found a keyword. */
+ character is whitespace, we may have found a keyword.
+ It is only a keyword if it is not followed by another
+ keyword. */
if (strncmp (p, linespec_keywords[i], len) == 0
- && !(isalnum (p[len]) || p[len] == '_'))
- return linespec_keywords[i];
+ && isspace (p[len]))
+ {
+ int j;
+
+ /* Special case: "if" ALWAYS stops the lexer, since it
+ is not possible to predict what is going to appear in
+ the condition, which can only be parsed after SaLs have
+ been found. */
+ if (i != IF_KEYWORD_INDEX)
+ {
+ p += len;
+ p = skip_spaces_const (p);
+ for (j = 0; j < ARRAY_SIZE (linespec_keywords); ++j)
+ {
+ int nextlen = strlen (linespec_keywords[j]);
+
+ if (strncmp (p, linespec_keywords[j], nextlen) == 0
+ && isspace (p[nextlen]))
+ return NULL;
+ }
+ }
+
+ return linespec_keywords[i];
+ }
}
}
@@ -734,13 +753,16 @@ linespec_lexer_lex_one (linespec_parser *parser)
PARSER_STREAM (parser) = skip_spaces_const (PARSER_STREAM (parser));
/* Check for a keyword, they end the linespec. */
- keyword = NULL;
- if (parser->keyword_ok)
- keyword = linespec_lexer_lex_keyword (PARSER_STREAM (parser));
+ keyword = linespec_lexer_lex_keyword (PARSER_STREAM (parser));
if (keyword != NULL)
{
parser->lexer.current.type = LSTOKEN_KEYWORD;
LS_TOKEN_KEYWORD (parser->lexer.current) = keyword;
+ /* We do not advance the stream here intentionally:
+ we would like lexing to stop when a keyword is seen.
+
+ PARSER_STREAM (parser) += strlen (keyword); */
+
return parser->lexer.current;
}
@@ -2175,10 +2197,6 @@ parse_linespec (linespec_parser *parser, const char **argptr)
}
}
- /* A keyword at the start cannot be interpreted as such.
- Consider "b thread thread 42". */
- parser->keyword_ok = 0;
-
parser->lexer.saved_arg = *argptr;
parser->lexer.stream = argptr;
@@ -2250,9 +2268,6 @@ parse_linespec (linespec_parser *parser, const char **argptr)
else if (token.type != LSTOKEN_STRING && token.type != LSTOKEN_NUMBER)
unexpected_linespec_error (parser);
- /* Now we can recognize keywords. */
- parser->keyword_ok = 1;
-
/* Shortcut: If the next token is not LSTOKEN_COLON, we know that
this token cannot represent a filename. */
token = linespec_lexer_peek_token (parser);