2010-04-26 117 views
8

我有一個簡單的語法:ANTLR AST規則失敗,RewriteEmptyStreamException

grammar sample; 
options { output = AST; } 
assignment 
    : IDENT ':=' expr ';' 
    ; 
expr  
    : factor ('*' factor)* 
    ; 
factor 
    : primary ('+' primary)* 
    ; 
primary 
    : NUM 
    | '(' expr ')' 
    ; 
IDENT : ('a'..'z')+ ; 
NUM : ('0'..'9')+ ; 
WS : (' '|'\n'|'\t'|'\r')+ {$channel=HIDDEN;} ; 

現在我想添加一些重寫規則生成AST。從我在線閱讀和語言模式書中,我應該能夠修改語法如下:

assignment 
    : IDENT ':=' expr ';' -> ^(':=' IDENT expr) 
    ; 
expr  
    : factor ('*' factor)* -> ^('*' factor+) 
    ; 
factor 
    : primary ('+' primary)* -> ^('+' primary+) 
    ; 
primary 
    : NUM 
    | '(' expr ')' -> ^(expr) 
    ; 

但它不起作用。雖然它編譯得很好,但當我運行解析器時,我得到一個RewriteEmptyStreamException錯誤。這是事情變得奇怪的地方。

如果我定義僞令牌ADD和MULT並使用它們代替樹節點文字,它將正常工作。

tokens { ADD; MULT; } 

expr  
    : factor ('*' factor)* -> ^(MULT factor+) 
    ; 
factor 
    : primary ('+' primary)* -> ^(ADD primary+) 
    ; 

或者,如果我使用節點後綴符號,它也顯得做工精細:

expr  
    : factor ('*'^ factor)* 
    ; 
factor 
    : primary ('+'^ primary)* 
    ; 

這種差異的行爲的錯誤嗎?

回答

10

不,不是一個錯誤,AFAIK。把你的expr規則,例如:

expr  
    : factor ('*' factor)* -> ^('*' factor+) 
    ; 

因爲*可能不存在,它應該也不會在你的AST重寫規則。所以,以上是不正確的,ANTLR抱怨是正確的。

expr  
    : factor ('*' factor)* -> ^(MULT factor+) 
    ; 

全部是好的,因爲你的規則總是會產生一個或多個factor的:如果你插入一個假想的令牌一樣MULT,而不是現在

什麼你可能是指做的是這樣的:

expr  
    : (factor -> factor) ('*' f=factor -> ^('*' $expr $f))* 
    ; 

另見第7章:從The Definitive ANTLR Reference樹建設。特別是段落重寫規則(第173頁)和在重寫規則(第174/175頁)中引用先前規則AST。

7

如果你想在同一水平,以產生用於所有兒童的「*」操作符的N叉樹,你可以這樣做:

expr 
    : (s=factor -> factor) (('*' factor)+ -> ^('*' $s factor+))? 
    ; 

下面是什麼,這將返回一些例子:

Tokens: AST 
factor: factor 
factor '*' factor: ^('*' factor factor) 
factor '*' factor '*' factor: ^('*' factor factor factor) 

巴特的第三上面的例子會產生一個嵌套的樹,因爲$ expr的每個連續迭代的結果是有兩個孩子的節點,就像這樣:

factor * factor * factor: ^('*' factor ^('*' factor factor)) 

你可能不需要,因爲乘法是可交換的。

+0

感謝ton @JoelPM。這正是我所期待的。評估時,我們遇到了深層嵌套樹和堆棧溢出的問題。這使我們有機會生成一棵N-tree樹並大幅減少樹的深度 – 2016-11-30 15:07:51