根据ANTLR4中的行号和列号获取最可能的令牌类型

时间:2013-09-16 18:57:39

标签: c#-4.0 antlr antlr4

我想获取文本中给定位置的最可能的令牌列表(行号和列号),以确定为自动代码完成填充的内容。使用ANTLR 4 API可以轻松实现这一目标。

我想获得给定位置的可能的令牌列表,因为用户可能正在文本中间的某处写入/编辑,这仍然保证了可能的令牌列表。

请给我一些指导,因为我无法找到有关此主题的在线资源。

1 个答案:

答案 0 :(得分:1)

按行号获取令牌的一种方法是为您的语法创建ParseTreeListener,使用它来遍历给定的ParseTree并按行号索引TerminalNodes。我不了解C#,但这是我在Java中的表现。逻辑应该是相似的。

public class MyLineIndexer extends MyGrammarParserBaseListener {

protected MultiMap<Integer, TerminalNode> filelineTokenIndex;

@Override
public void visitTerminal(@NotNull TerminalNode node) {
    // map every token to its file line for searching later...

    if ( node.getSymbol() != null ) {
        List<TerminalNode> tokens;
        Integer line = node.getSymbol().getLine();
        if (!filelineTokenIndex.containsKey(line)) {
            tokens = new ArrayList<>();
            filelineTokenIndex.put(line, tokens);
        } else {
            tokens = filelineTokenIndex.get(line);
        }
        tokens.add(node);
    }
    super.visitTerminal(node);
}
}

然后以通常的方式走解析树......

ParseTree parseTree = ... ; // parse it how you want to
MyLineIndexer indexer = new MyLineIndexer();
ParseTreeWalker walker = new ParseTreeWalker();
walker.walk(indexer, parseTree);

如果您在一条线上拥有合理数量的令牌,那么在线和范围内获取令牌现在相当简单有效。例如,您可以向Listener添加另一个方法,如下所示:

public TerminalNode findTerminalNodeAtCaret(int caretPos, int caretLine) {
    if (caretPos <= 0) return null;

    if (this.filelineTokenIndex.containsKey(caretLine)) {
        List<TerminalNode> nodes = filelineTokenIndex.get(caretLine);

        if (nodes.size() == 0) return null;

        int tokenEndPos, tokenStartPos;

        for (TerminalNode n : nodes) {
            if (n.getSymbol() != null) {
                tokenEndPos = n.getSymbol().getCharPositionInLine() + n.getText().length();
                tokenStartPos = n.getSymbol().getCharPositionInLine();
                // If the caret is within this token, return this token
                if (caretPos >= tokenStartPos && caretPos <= tokenEndPos) {
                    return n;
                }
            }
        }
    }
    return null;
}

您还需要确保您的解析器允许“松散”&#39;解析。在输入语言结构时,它很可能无效。您的解析器规则应允许这样做。