Yes, that easy to accomplish. The generated parse tree contains a node for every found symbol which comes with the character position in the input stream and line/column informations. Do a simple iteration over the tree to find a context or terminal at a given position, which you then can use the check for certain types you wanna handle (like variables etc.). That depends on your grammar. Here’s a C++ snippet for getting a tree from a specific character index in the input. It can easily be changed to use row/column pairs instead.
static bool treeContainsPosition(ParseTree *node, size_t position) {
auto terminal = dynamic_cast<TerminalNode *>(node);
if (terminal != nullptr) {
return terminal->getSymbol()->getStartIndex() <= position && position <= terminal->getSymbol()->getStopIndex();
}
auto context = dynamic_cast<ParserRuleContext *>(node);
if (context == nullptr)
return false;
return context->start->getStartIndex() <= position && position <= context->stop->getStopIndex();
}
//----------------------------------------------------------------------------------------------------------------------
/**
* Returns the parse tree at the given character index position or nullptr if there's none.
*/
ParseTree* MySQLRecognizerCommon::contextFromPosition(ParseTree *root, size_t position) {
if (!treeContainsPosition(root, position))
return nullptr;
for (auto child : root->children) {
auto result = contextFromPosition(child, position);
if (result != nullptr)
return result;
}
// No child contains the given position, so it must be in whitespaces between them. Return the root for that case.
return root;
}
Mike