2013-08-28 29 views
18

一個星期前我開始了以下項目:識別Java代碼後綴的語法。ANTLR:如何解釋識別Java代碼後綴的語法行爲?

我使用Java的官方ANTLR語法(Java.g4)作爲基準,並開始添加一些規則。但是,這些新規則還引入了我也必須處理的左遞歸。

經過幾天的工作,我得到了following code。當我開始測試時,我發現了一些我仍然無法解釋的異常。當給定輸入{ }時,解析器告訴我no viable alternative at input '<EOF>',但是當我切換規則s2右手側的終端順序時,特別是如果我們將右手側從v2_1 | v2_2 | v2_3 ...更改爲v2_36 | v2_1 | v2_2 ...(將終端v2_36移動到第一個位置),序列{ }被接受。

我的第一個想法是認爲Antlr不走回頭路,因爲我注意到,與輸入{ }解析器的第一個版本開始遵循規則v2_3和公正的報道,沒有被發現,不會嘗試考慮其他的選擇(這是我認爲但可能不是這樣),如v2_36這給出了肯定的答案。

但是,經過一番研究,我發現ANTLR實際上會回溯,但只有在其他一切都失敗的情況下。至少在v3.3中這是正確的(在官方的ANTLR論文中可以看到它),但我想這也適用於v4。現在我有點困惑。在這個項目上花了這麼多小時之後,如果我沒有成功,我會覺得非常糟糕。有人可以提供某種小費或什麼?非常感謝,謝謝。

編輯

管理隔離問題

grammar Java; 
@parser::members {String ruleName; } 

start : compilationUnitSuf EOF; 

compilationUnitSuf 
    : {ruleName = "typeDeclarationSuf"; } s2 
    ; 

s2: '{' '}' v2_81 | '{' '}'; 
v2_81 : {ruleName.equals("enumBodyDeclarationsSuf")}? t173 | t173 '}'; 
t173: '}' | '{'*; 

LBRACKET: '{'; 
RBRACKET: '}'; 

WS : [ \t\r\n\u000C]+ -> skip 
    ; 

那麼,爲什麼預測算法建議我跟着s2 -> v'{' '}' v2_81 -> ...,而不是s2 -> '{' '}'

+1

我不知道你的意思是_「後綴的Java代碼」_。 –

+0

如果我們有給定Java代碼的標記序列'a [1..n]',我們將後綴定義爲序列'a [j],a [j + 1],...,a [對於某些'1 <= j <= n'(對於代碼'class A {int a;}'''可能的後綴是'A {int a;}','{int a;}','int a ;}'等),但我認爲這與問題無關 – svs

+2

您有使用ANTLR的原因嗎?對於後綴解析,一個GLR解析器會容易得多,並且它會後綴解析LR(1)語法的大致線性時間,iirc。關於Grune&Jacobs中的後綴解析有一整章(解析技巧:實用指南)。 – rici

回答

1

我認爲你會發現它不是以你期望的方式回溯。原因是它找到了{},然後期望看到它找不到的v2_181。因爲它不會回溯,它沒有找到你想要的替代方案。另一種方法是讓v2_181可選,然後你不需要回溯。像下面這樣:

grammar Java; 
@parser::members {String ruleName; } 

start : compilationUnitSuf EOF; 

compilationUnitSuf 
    : {ruleName = "typeDeclarationSuf"; } s2 
    ; 

s2: '{' '}' v2_81?; 
v2_81 : {ruleName.equals("enumBodyDeclarationsSuf")}? t173 | t173 '}'; 
t173: '}' | '{'*; 

LBRACKET: '{'; 
RBRACKET: '}'; 

WS : [ \t\r\n\u000C]+ -> skip 
    ;