2013-10-15 56 views
14

如何在通用遍歷分析樹時訪問ANTLR4中的替代標籤?或者,是否有任何方法可以複製ANTLR3運算符的功能,因爲這樣做會有所斬獲。如何在一般遍歷分析樹時訪問ANTLR4中的替代標籤?

我正在努力爲任何ANTLR4語法寫一個AST漂亮的打印機,以堅持一種簡單的方法(如使用替代標籤命名製作)。我希望能夠漂亮打印像3 + 5(int_expression (plus (int_literal 3) (int_literal 5))),或類似的術語,給出類似下面的語法:

int_expression 
    : int_expression '+' int_expression # plus 
    | int_expression '-' int_expression # minus 
    | raw_int       # int_literal 
    ; 
raw_int 
    : Int 
    ; 
Int : [0-9]+ ; 

我無法有效地給名字的plusminus製作,因爲將它們拉出到自己的生產中會導致該工具抱怨規則是相互左移遞歸的。如果我不能把它們拉出來,我怎麼能給這些產品的名稱?

注1:我是能夠方法論通過把「好」終端(例如,上面Int)在特別生產(生產開始於一個特殊的前綴,像raw_)擺脫+說法。然後,我只能打印其父製作命名爲「raw_ ...」的終端,並將所有其他終端刪除。這對於擺脫+非常有用,同時在輸出中保留35。這可以通過ANTLR3中的!完成。注2:我知道我可以編寫一個專門的漂亮的打印機,或者爲給定語言的每個生成使用動作,但是我想使用ANTLR4來解析和生成各種語言的AST,並且它似乎就像我應該能夠寫出這樣一個簡單漂亮的打印機一般。換一種說法,我只關心獲取AST,而我寧願不必爲了獲得AST而用定製的漂亮打印機來填充每個語法。也許我應該回到ANTLR3?

回答

1

我建議使用嵌套訪問者類來實現漂亮打印機作爲偵聽器實現,以獲取各種上下文對象的名稱。

private MyParser parser; // you'll have to assign this field 
private StringBuilder builder = new StringBuilder(); 

@Override 
public void enterEveryRule(@NotNull ParserRuleContext ctx) { 
    if (!builder.isEmpty()) { 
     builder.append(' '); 
    } 

    builder.append('('); 
} 

@Override 
public void visitTerminalNode(@NotNull TerminalNode node) { 
    // TODO: print node text to builder 
} 

@Override 
public void visitErrorNode(@NotNull TerminalNode node) { 
    // TODO: print node text to builder 
} 

@Override 
public void exitEveryRule(@NotNull ParserRuleContext ctx) { 
    builder.append(')'); 
} 

protected String getContextName(@NotNull ParserRuleContext ctx) { 
    return new ContextNameVisitor().visit(ctx); 
} 

protected class ContextNameVisitor extends MyParserBaseVisitor<String> { 
    @Override 
    public String visitChildren() { 
     return parser.getRuleNames()[ctx.getRuleIndex()]; 
    } 

    @Override 
    public String visitPlus(@NotNull PlusContext ctx) { 
     return "plus"; 
    } 

    @Override 
    public String visitMinus(@NotNull MinusContext ctx) { 
     return "minus"; 
    } 

    @Override 
    public String visitInt_literal(@NotNull MinusContext ctx) { 
     return "int_literal"; 
    } 
} 
+0

我正在尋找一種通用的方法來做到這一點,而無需爲每種語言編寫專門的漂亮打印機。有沒有辦法做到這一點?從用戶的角度來看,我不明白爲什麼沒有,因爲替代標籤就在那裏。 –