2013-10-13 14 views
8

Tôi đang cố gắng viết một đoạn mã sẽ lấy một trình phân tích cú pháp ANTLR4 và sử dụng nó để tạo các AST cho các đầu vào tương tự với các mã được đưa ra bởi tùy chọn -tree trên grun (misc.TestRig). Tuy nhiên, tôi cũng muốn cho đầu ra bao gồm tất cả thông tin về số/bù đắp dòng.Làm cách nào để in ấn và in số dòng sản phẩm bằng cách sử dụng ANTLR4?

Ví dụ, thay vì in

(add (int 5) '+' (int 6)) 

Tôi muốn để có được

(add (int 5 [line 3, offset 6:7]) '+' (int 6 [line 3, offset 8:9]) [line 3, offset 5:10]) 

Hoặc một cái gì đó tương tự.

Không có số lượng lớn ví dụ về khách truy cập cho ANTLR4, nhưng tôi khá chắc chắn tôi có thể thực hiện hầu hết việc này bằng cách sao chép triển khai mặc định cho toStringTree (được sử dụng bởi grun). Tuy nhiên, tôi không thấy bất kỳ thông tin nào về số dòng hoặc bù trừ.

tôi mong đợi để có thể viết mã siêu đơn giản như thế này:

String visit(ParseTree t) { 
    return "(" + t.productionName + t.visitChildren() + t.lineNumber + ")"; 
} 

nhưng nó dường như không thể đơn giản này. Tôi đoán tôi sẽ có thể nhận được thông tin số dòng từ trình phân tích cú pháp, nhưng tôi đã không tìm ra cách làm như vậy. Làm thế nào tôi có thể lấy số dòng/bù đắp thông tin trong quá trình truyền tải của mình?


Để điền vào vài chỗ trống trong các giải pháp dưới đây, tôi sử dụng:

List<String> ruleNames = Arrays.asList(parser.getRuleNames()); 
parser.setBuildParseTree(true); 
ParserRuleContext prc = parser.program(); 
ParseTree tree = prc; 

để có được những treeruleNames. program là tên cho sản xuất hàng đầu trong ngữ pháp của tôi.

+0

Có 2 ' phương thức toStringTree'. Người ta lấy một cá thể 'Parser', nhưng cái kia chỉ lấy một' List 'của các tên quy tắc. –

+0

@ 280Z28: Bạn nêu rõ sự thật. Gọi 'toStringTree' với một đối số phân tích cú pháp làm cho việc triển khai thực hiện lấy danh sách các quy tắc (' recog.getRuleNames() ') và chuyển nó vào' toStringTree' lấy một 'List'. Ở mức nào, điều này vẫn không giải thích làm thế nào để có được số dòng/bù đắp thông tin trong khi viết một khách truy cập. –

Trả lời

11

Phương pháp Trees.toStringTree có thể được triển khai bằng cách sử dụng ParseTreeListener. Trình nghe sau đây tạo ra chính xác cùng một đầu ra là Trees.toStringTree.

public class TreePrinterListener implements ParseTreeListener { 
    private final List<String> ruleNames; 
    private final StringBuilder builder = new StringBuilder(); 

    public TreePrinterListener(Parser parser) { 
     this.ruleNames = Arrays.asList(parser.getRuleNames()); 
    } 

    public TreePrinterListener(List<String> ruleNames) { 
     this.ruleNames = ruleNames; 
    } 

    @Override 
    public void visitTerminal(TerminalNode node) { 
     if (builder.length() > 0) { 
      builder.append(' '); 
     } 

     builder.append(Utils.escapeWhitespace(Trees.getNodeText(node, ruleNames), false)); 
    } 

    @Override 
    public void visitErrorNode(ErrorNode node) { 
     if (builder.length() > 0) { 
      builder.append(' '); 
     } 

     builder.append(Utils.escapeWhitespace(Trees.getNodeText(node, ruleNames), false)); 
    } 

    @Override 
    public void enterEveryRule(ParserRuleContext ctx) { 
     if (builder.length() > 0) { 
      builder.append(' '); 
     } 

     if (ctx.getChildCount() > 0) { 
      builder.append('('); 
     } 

     int ruleIndex = ctx.getRuleIndex(); 
     String ruleName; 
     if (ruleIndex >= 0 && ruleIndex < ruleNames.size()) { 
      ruleName = ruleNames.get(ruleIndex); 
     } 
     else { 
      ruleName = Integer.toString(ruleIndex); 
     } 

     builder.append(ruleName); 
    } 

    @Override 
    public void exitEveryRule(ParserRuleContext ctx) { 
     if (ctx.getChildCount() > 0) { 
      builder.append(')'); 
     } 
    } 

    @Override 
    public String toString() { 
     return builder.toString(); 
    } 
} 

Lớp có thể được sử dụng như sau:

List<String> ruleNames = ...; 
ParseTree tree = ...; 

TreePrinterListener listener = new TreePrinterListener(ruleNames); 
ParseTreeWalker.DEFAULT.walk(listener, tree); 
String formatted = listener.toString(); 

Các lớp có thể được sửa đổi để tạo ra thông tin về sản lượng của bạn bằng cách cập nhật exitEveryRule phương pháp:

@Override 
public void exitEveryRule(ParserRuleContext ctx) { 
    if (ctx.getChildCount() > 0) { 
     Token positionToken = ctx.getStart(); 
     if (positionToken != null) { 
      builder.append(" [line "); 
      builder.append(positionToken.getLine()); 
      builder.append(", offset "); 
      builder.append(positionToken.getStartIndex()); 
      builder.append(':'); 
      builder.append(positionToken.getStopIndex()); 
      builder.append("])"); 
     } 
     else { 
      builder.append(')'); 
     } 
    } 
} 
+0

Điều này làm việc tuyệt vời. Tôi đang cập nhật câu hỏi để điền vào một vài chỗ trống. –

Các vấn đề liên quan