2013-09-16 76 views
2

我想獲得文本中給定位置的最可能令牌列表(行和列號)以確定必須填充的內容用於完成自動代碼。這可以通過使用ANTLR 4 API輕鬆實現。根據ANTLR4中的行號和列號獲取最可能的令牌類型

我想獲得給定位置的令牌的可能列表,因爲用戶可能正在寫入/編輯文本中間的某個位置,這仍然保證了可能的令牌列表。

請給我一些指導,因爲我無法找到關於此主題的在線資源。

回答

0

通過行號獲取令牌的一種方法是爲您的語法創建一個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; 
} 

您還需要確保你的解析器允許「寬鬆」的解析。在輸入語言結構時,它可能不是有效的。你的解析器規則應該允許這個。