3

自動コード補完のために何を入力する必要があるかを判断するために、テキスト内の特定の場所 (行番号と列番号) の最も可能性の高いトークンのリストを取得したいと考えています。これは、ANTLR 4 API を使用して簡単に実現できますか。

ユーザーがトークンの可能なリストを保証するテキストの途中で書き込み/編集している可能性があるため、特定の場所のトークンの可能なリストを取得したいと考えています。

このトピックに関するオンライン リソースが見つからなかったため、ガイドラインを教えてください。

4

1 に答える 1

1

行番号でトークンを取得する 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);

ラインと範囲でトークンを取得することは、ライン上に適切な数のトークンがあると仮定すると、合理的に簡単で効率的になりました。たとえば、次のようにリスナーに別のメソッドを追加できます。

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;
}

また、パーサーが「緩やかな」解析を許可していることを確認する必要があります。言語構造が型付けされている間は、有効ではない可能性があります。パーサー ルールでこれを許可する必要があります。

于 2015-02-05T02:46:08.457 に答える