2013-02-02 41 views
10

我試圖使用帶有ANTLR4的AST,這個文件:ANTLR 4和AST遊客

Builder.java

import org.antlr.v4.runtime.ANTLRInputStream; 
import org.antlr.v4.runtime.CharStream; 
import org.antlr.v4.runtime.CommonTokenStream; 
import org.antlr.v4.runtime.TokenStream; 

public class Builder 
{ 

    public static void main(String[] args) 
    { 
     CharStream input = new ANTLRInputStream("ON M1==2 && M3 == 5 && (M2 > 1 || M5 <= 5.0) " 
               + "DO P5:42 P4:10"); 
     ExprLexer lexer = new ExprLexer(input); 
     TokenStream tokens = new CommonTokenStream(lexer); 
     ExprParser parser = new ExprParser(tokens); 
     parser.addParseListener(new ExprTestListener()); 
     ExprParser.ExpressionContext uu = parser.expression(); 
    } 

} 

ExprTestListener:

import org.antlr.v4.runtime.ParserRuleContext; 
import org.antlr.v4.runtime.Token; 
import org.antlr.v4.runtime.tree.TerminalNode; 
import org.antlr.v4.runtime.tree.ErrorNode; 

public class ExprTestListener extends ExprBaseListener { 
    @Override public void enterExpression(ExprParser.ExpressionContext ctx) 
    { 
     System.out.println(ctx); 
    } 
    @Override public void exitExpression(ExprParser.ExpressionContext ctx) 
    { 
     System.out.println(ctx); 
    } 

    @Override public void enterActionexpr(ExprParser.ActionexprContext ctx) 
    { 
     System.out.println(ctx); 
    } 
    @Override public void exitActionexpr(ExprParser.ActionexprContext ctx) 
    { 
     System.out.println(ctx); 
    } 

    @Override public void enterCondexpr(ExprParser.CondexprContext ctx) 
    { 
     System.out.println(ctx); 
    } 
    @Override public void exitCondexpr(ExprParser.CondexprContext ctx) 
    { 
     System.out.println(ctx); 
    } 

    @Override public void enterCond(ExprParser.CondContext ctx) 
    { 
     System.out.println(ctx); 
    } 
    @Override public void exitCond(ExprParser.CondContext ctx) 
    { 
     System.out.println(ctx); 
    } 

    @Override public void enterEveryRule(ParserRuleContext ctx) 
    { 
     System.out.println(ctx); 
    } 
    @Override public void exitEveryRule(ParserRuleContext ctx) 
    { 
     System.out.println(ctx); 
    } 
    @Override public void visitTerminal(TerminalNode node) 
    { 
    } 
    @Override public void visitErrorNode(ErrorNode node) 
    { 
    } 
} 

Expr.g:

grammar Expr; 
options 
{ 
    // antlr will generate java lexer and parser 
    language = Java; 

} 
WS  : [ \t\r\n]+ -> skip ; 
OP  : '&&' | '||'; 
COMP : '==' | '<' | '>' | '<=' | '>=' | '!='; 
fragment INT  : [0-9]+; 
REAL : INT '.' INT | INT; 

ACTION : 'P' INT ':' INT; 
MEASURE : 'M' INT; 

// ***************** parser rules: 
cond  : MEASURE COMP REAL; 
condexpr : '(' condexpr ')' | cond OP condexpr | cond; 
actionexpr : ACTION actionexpr | ACTION; 
expression : 'ON' condexpr 'DO' actionexpr; 

我有這樣的輸出:

[] 
[] 
[29] 
[29] 
[16 29] 
[16 29] 
[16 29] 
[16 29] 
[18 29] 
[18 29] 
[16 18 29] 
[16 18 29] 
[16 18 29] 
[16 18 29] 
[18 18 29] 
[18 18 29] 
[13 18 18 29] 
[13 18 18 29] 
[16 13 18 18 29] 
[16 13 18 18 29] 
[16 13 18 18 29] 
[16 13 18 18 29] 
[18 13 18 18 29] 
[18 13 18 18 29] 
[20 18 13 18 18 29] 
[20 18 13 18 18 29] 
[20 18 13 18 18 29] 
[20 18 13 18 18 29] 
[18 13 18 18 29] 
[18 13 18 18 29] 
[13 18 18 29] 
[13 18 18 29] 
[18 18 29] 
[18 18 29] 
[18 29] 
[18 29] 
[29] 
[29] 
[31] 
[31] 
[24 31] 
[24 31] 
[24 31] 
[24 31] 
[31] 
[31] 
[] 
[] 

我發現很難用ANTLR4瞭解訪問者。

我有樹的目標:

  • 獲取收集措施和行動的int(有兩種不同的套)
  • 更換一些有機磷農藥(例如=由<>!)
  • 獲取condexpr(頂部的項目)字符串的OP remplaced(SE我以前的點)
+0

明白嗎? '樹'的目標? :) –

回答

1

您可以使用樹標籤來設置解析的上下文,然後使用訪問者類瀏覽觀察圖形的葉子並觸發方法,以便從語言源代碼中的表達式創建動作。因此,在最初的訪問中,聽衆不會處理實際的訪客模式。實際的訪問者模式和通過訪問進行的處理是通過expressionbase偵聽器類擴展的方法完成的。

偵聽標識表達式:

@Override public void enterListener(ExprParser.EXPR_CONTEXTContext ctx) { 
    //some code to view the compilation process 
} 

表達規則得到一個名稱標籤:

'EXPR_CONTEXT' expression    # EXPR_CONTEXT //the tree label 

表達助行器被實現:

public class ExprWalker extends ExprBaseListener { 

    @Override 
    public void enterListener(ExprParser.EXPR_CONTEXTContext ctx) { 

    java.util.List<ExprParser.ExpressionContext> e = ctx.expression(); 

    System.out.println("EXPRESSION: " //print action 
    + e.get(0).getText() + ", " //first element 
    + e.get(1).getText() //second element 
    + ", " + ... + ", " //number of elements 
    + e.get(N).getText()); //last element 

} 

主文件然後用助行散步:

ParseTree tree = parser.parse(); //parse the tree 

間奏曲:將助行器探視圖案之一可想象樹段optimisation-或處理之前的模式。解析的樹可以在這裏作爲源代碼樹的單獨歸納來處理。這種方法可以實現更復雜的代碼和樹處理模式。

ParseTreeWalker walker = new ParseTreeWalker(); //get the walker 
walker.walk(new ExprWalker(), tree); //start visiting 
+1

沒有必要創建一個'新的ParseTreeWalker()'。只需使用'ParseTreeWalker.DEFAULT.walk(...)'。 –

11

首先,我將解釋你在上面觀察到的:

首先,請閱讀所調用方法的文檔。 Parser.addParseListener文檔包括以下說明:

這僅適用於高級用戶。請給ParseTreeListener一個ParseTreeWalker,而不是將它提供給解析器!

ParserRuleContext類的執行toString()只是在創建上下文時打印規則調用堆棧。當偵聽器輸入規則時,您打印一次,當它退出時打印一次。對於actionexpr,condcondexpr,您可以再次打印它,從而每個上下文總共會產生4條相同的輸出行。

你的目標現在的一些注意事項:

  • 內的enterCondexitCond,該MEASURE文本可致電ctx.MEASURE().getText()
  • enterActionexprexitActionexpr內部,ACTION文本可通過調用ctx.ACTION().getText()獲得。
  • 您可以更改COND令牌,方法是爲更新的令牌創建新的TerminalNodeImplCommonToken,並使用訪問者或偵聽器將其分配給字段CondContext.children中的正確索引。