2011-02-12 19 views
4

我拿了一個虛擬語言,例如: 它只是接受一個或多個'!'。 其詞法和語法規則是:如何捕捉an​​tlr3的樹語法中的標記列表?

grammar Ns; 

options { 
    output=AST; 
    ASTLabelType=CommonTree; 
} 
tokens { 
    NOTS; 
} 

@header { 
    package test; 
} 
@lexer::header { 
    package test; 
} 

ns : NOT+ EOF -> ^(NOTS NOT+); 

NOT : '!'; 

OK,你可以看到,這代表其接受的語言「!」要麼 '!!!'或「!!!!!」 ......

,我定義了一些有意義的類來建立的AST:

public class Not { 
    public static final Not SINGLETON = new Not(); 

    private Not() { 
    } 
} 



public class Ns { 
    private List<Not> nots; 

    public Ns(String nots) { 
     this.nots = new ArrayList<Not>(); 
     for (int i = 0; i < nots.length(); i++) { 
      this.nots.add(Not.SINGLETON); 
     } 
    } 

    public String toString() { 
     String ret = ""; 
     for (int i = 0; i < this.nots.size(); i++) { 
      ret += "!"; 
     } 
     return ret; 
    } 
} 

和這裏的樹語法:

tree grammar NsTreeWalker; 

options { 
    output = AST; 
    tokenVocab = Ns; 
    ASTLabelType = CommonTree; 
} 
@header { 
    package test; 
} 
ns returns [Ns ret] : ^(NOTS n=NOT+) {$ret = new Ns($n.text);}; 

和主類代碼一些樣本數據來檢驗生成的類:「!」

public class Test { 

    public static void main(String[] args) throws Exception { 
     ANTLRInputStream input = new ANTLRInputStream(new ByteArrayInputStream("!!!".getBytes("utf-8"))); 
     NsLexer lexer = new NsLexer(input); 
     CommonTokenStream tokens = new CommonTokenStream(lexer); 
     NsParser parser = new NsParser(tokens); 
     CommonTree root = (CommonTree) parser.ns().getTree(); 
     NsTreeWalker walker = new NsTreeWalker(new CommonTreeNodeStream(root)); 
     try { 
      NsTreeWalker.ns_return r = walker.ns(); 
      System.out.println(r.ret); 
     } catch (RecognitionException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

但打印的最終輸出是,除了t他期待'!!!'。 這主要是因爲這行代碼:

ns returns [Ns ret] : ^(NOTS n=NOT+) {$ret = new Ns($n.text);}; 

的$ N以上捕獲只有一個,我不知道如何捕捉的所有三個令牌,換句話說,一個列表「!」「!」 '!'與$ n。 有沒有人可以幫忙?謝謝!

回答

4

只有一個!被印刷的事實是因爲您的規則:

ns returns [Ns ret] 
    : ^(NOTS n=NOT+) {$ret = new Ns($n.text);} 
    ; 

得到更多或更少的翻譯爲:

Token n = null 
LOOP 
    n = match NOT_token 
END 
return new Ns(n.text) 

爲此,n.text將永遠只是一個單一的!

你需要做的是收集這些NOT令牌在列表中。在ANTLR中,您可以使用+=運算符而不是「單個令牌」運算符=來創建令牌列表。因此,改變你的ns規則爲:

ns returns [Ns ret] 
    : ^(NOTS n+=NOT+) {$ret = new Ns($n);} 
    ; 

它被翻譯爲:

List n = null 
LOOP 
    n.add(match NOT_token) 
END 
return new Ns(n) 

一定要改變你的Ns類的構造函數採取List代替:

public Ns(List nots) { 
    this.nots = new ArrayList<Not>(); 
    for (Object o : nots) { 
     this.nots.add(Not.SINGLETON); 
    } 
} 

後你的測試類的輸出將是:

!!! 

祝你好運!