2011-03-08 68 views
2

我有表達一個平凡的ANTLR語法像a.b.c + d.e.f匹配:ANTLR的樹模式與重寫規則

grammar Test; 
options { 
    output=AST; 
} 
tokens { 
    VARIABLE_ID; 
    QUALIFIER_ID; 
} 

ID : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*; 
DOT : '.'; 
WS : (' ' | '\t' | '\r' | '\n') {$channel=HIDDEN;} ; 

variable_id : id=ID -> VARIABLE_ID[$id]; 
qualifier_id : id=ID -> QUALIFIER_ID[$id]; 

expr_start : expr EOF; 
expr : var (options {greedy=true;} : '+' expr)*; 

var : variable_id (DOT qualifier_id)*; 

現在我想要定義了這個語法,輪流a.b.c0.1.2模式匹配,所以我定義了一個樹模式匹配如下

tree grammar TestWalker; 
options { 
    tokenVocab=Test; 
    ASTLabelType=CommonTree; 
    filter=true; 
    backtrack=true; 
} 

@members { 
    TokenRewriteStream tokens; 

    public void setTreeNodeStream(TreeNodeStream input) { 
     super.setTreeNodeStream(input); 
     tokens = (TokenRewriteStream)input.getTokenStream(); 
    } 
} 

topdown : var; 

variable_id [int i] : id=VARIABLE_ID { 
    tokens.replace($id.getToken(), "" + $i); 
}; 

qualifier_id [int i] : id=QUALIFIER_ID { 
    tokens.replace($id.getToken(), "" + $i); 
}; 

var 
@init { int index = 0; } 
: variable_id[index] 
( DOT 
    { ++index; } 
    qualifier_id[index] 
)*; 

然後我把一個小的測試程序:

import org.antlr.runtime.*; 
import org.antlr.runtime.tree.*; 

public class Main { 
    public static void main(String[] args) throws Exception { 
     TestLexer lex = new TestLexer(new ANTLRInputStream(System.in)); 
     TokenStream tokens = new TokenRewriteStream(lex); 

     TestParser parser = new TestParser(tokens); 
     TestParser.expr_return expr = parser.expr(); 

     CommonTreeNodeStream nodes = new CommonTreeNodeStream((Tree)expr.getTree()); 
     nodes.setTokenStream(tokens); 
     TestWalker walker = new TestWalker(nodes); 
     walker.downup(expr.getTree()); 
     System.out.println(tokens.toString()); 
    } 
} 

當我運行這個程序與基本輸入,我看到了令人吃驚的結果:
a.b.c - >0.b.c
a.b + d.e - >0.b + 0.e
等。看起來,我的規則的(DOT qualifier_id)*部分從來沒有匹配,我不明白爲什麼。我嘗試將自己的規則添加到Tree Pattern Match的自上而下和自下而上的部分。如果我從一個過濾器匹配器切換到一個完整的樹匹配器並添加規則來適當地分支'+'的情況,它會起作用,但是當重寫只是一個更大的語法的較小片段時,這變得站不住腳。任何指針將不勝感激。

更新:使用antlr 3.3

回答

2

問題的關鍵在於解析不能正確生成一個AST。語法需要建立AST(請注意附加的^令牌)。

grammar Test; 
options { 
    output=AST; 
} 
tokens { 
    VARIABLE_ID; 
    QUALIFIER_ID; 
} 

ID : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*; 
DOT : '.'; 
WS : (' ' | '\t' | '\r' | '\n') {$channel=HIDDEN;} ; 

variable_id : id=ID -> VARIABLE_ID[$id]; 
qualifier_id : id=ID -> QUALIFIER_ID[$id]; 

expr_start : expr EOF; 
expr : var (options {greedy=true;} : '+'^ expr)*; 

var : variable_id (DOT^ qualifier_id)*; 

然後,樹模式匹配器需要走AST構建它。請注意expr規則的結構和用於處理狀態的參數。現在

tree grammar TestWalker; 
options { 
    tokenVocab=Test; 
    ASTLabelType=CommonTree; 
    filter=true; 
    backtrack=true; 
} 

@members { 
    TokenRewriteStream tokens; 

    public void setTreeNodeStream(TreeNodeStream input) { 
     super.setTreeNodeStream(input); 
     tokens = (TokenRewriteStream)input.getTokenStream(); 
    } 
} 

topdown : expr[0]; 

variable_id returns [int r] : id=VARIABLE_ID { 
    $r = 0; 
    tokens.replace($id.getToken(), "" + $r); 
}; 

qualifier_id [int i] returns [int r] : id=QUALIFIER_ID { 
    $r = $i + 1; 
    tokens.replace($id.getToken(), "" + $r); 
}; 

expr [int i] returns [int r] 
    : v=variable_id { $r = $v.r; } 
    | ^(DOT e=expr[$i] q=qualifier_id[$e.r] { $r = $q.r; }) 
    ; 

輸出會按預期運行:
a.b + d.e + c.d.e.f
0.1 + 0.1 + 0.1.2.3
和產生的AST看起來是正確的。

output AST

+0

太棒了!感謝您發佈解決方案+1。 – 2011-03-08 22:33:22

1

我不熟悉這種(較新的)模式樹行走。我在Wiki上瀏覽過它,但它不在我的ANTLR參考文獻中。

東西不是100%與您的考試語法雖然:當我從其生成一個解析器,我得到:

java -cp antlr-3.2.jar org.antlr.Tool Test.g 
warning(200): Test.g:18:46: Decision can match input such as "'+'" using multiple alternatives: 1, 2 
As a result, alternative(s) 2 were disabled for that input 

,當我想象你的解析器會產生使用上您的課AST(用少量添加):

import org.antlr.runtime.*; 
import org.antlr.runtime.tree.*; 
import org.antlr.stringtemplate.*; 

public class Main { 
    public static void main(String[] args) throws Exception { 
     TestLexer lex = new TestLexer(new ANTLRStringStream("a.b + d.e")); 
     TokenStream tokens = new TokenRewriteStream(lex); 

     TestParser parser = new TestParser(tokens); 
     TestParser.expr_return expr = parser.expr(); 

     CommonTreeNodeStream nodes = new CommonTreeNodeStream((Tree)expr.getTree()); 
     nodes.setTokenStream(tokens); 

     CommonTree tree = (CommonTree)expr.getTree(); 

     DOTTreeGenerator gen = new DOTTreeGenerator(); 
     StringTemplate st = gen.toDOT(tree); 
     System.out.println(st); 

     TestWalker walker = new TestWalker(nodes); 
     walker.downup(tree); 
     System.out.println(tokens.toString()); 
    } 
} 

我看到輸入a.b + d.e產生AST:

enter image description here

我想象你的樹漫步者遍歷所說的樹,這並不讓我感到驚訝,它不會產生所需的結果,因爲它只是一個帶有單根的節點的平坦列表。

+0

有趣的是,該錯誤信息不會antlr3.3顯示出來(這是我使用) – Matt 2011-03-08 20:58:12

+0

@馬特,嗯,這是不是一個嚴重的警告:_are_畢竟生成的詞法分析器和。什麼_is_嚴重(AFAIK)是一個平坦的AST產生的事實。至少,我覺得你的樹圖案語法不喜歡它... :) – 2011-03-08 21:01:47

+0

我看到使用DOTTreeGenerator同樣的事情,但是當我使用ANTLR作品我看到一個完整的解析樹。 – Matt 2011-03-08 21:17:56