介紹
在文檔來看,ANTLR 2配合使用,有一些所謂predicated lexing,結合實例像這樣的(由帕斯卡啓發):句法斷言規則
RANGE_OR_INT
: (INT "..") => INT { $setType(INT); }
| (INT '.') => REAL { $setType(REAL); }
| INT { $setType(INT); }
;
我看到的樣子它在本規則開始時基本上是一個積極的預見性斷言:如果前瞻性匹配INT ".."
那麼第一個規則將應用(並匹配該輸入的INT
部分),依此類推。
我還沒有在ANTLR 4中找到過這樣的東西。該2 to 3 migration guide似乎並沒有提到這一點,而3 to 4 changes document狀態:
ANTLR 3和4之間的最大區別在於,ANTLR 4需要你給它,除非語法有間接左遞歸語法的任何。這意味着我們不需要語法謂詞或回溯,因此ANTLR 4不支持該語法;你會得到一個使用它的警告。
這是與錯誤信息,我得到行,如果我離開這個基本的是:
(...)=> syntactic predicates are not supported in ANTLR 4
雖然我能理解一個更智能解析器實施將如何解決這些模糊之處,我失敗看看這將如何工作詞法分析器。
再現例如
可以肯定,我們嘗試了這一點:
grammar Demo;
prog: atom (',' atom)* ;
atom: INT { System.out.println("INT: " + $INT.getText()); }
| REAL { System.out.println("REAL: " + $REAL.getText()); }
| a=INT RANGE b=INT { System.out.println("RANGE: " +
$a.getText() + " .. " + $b.getText()); }
;
WS : (' ' | '\t' | '\n' | '\r')+ -> skip ;
INT : ('0'..'9')+ ;
REAL: INT '.' INT? | '.' INT ;
RANGE: '..' ;
保存這Demo.g
,然後編譯並運行:
$ wget -nc http://www.antlr.org/download/antlr-4.5.2-complete.jar
$ java -jar antlr-4.5.2-complete.jar Demo.g
$ javac -cp antlr-4.5.2-complete.jar Demo*.java
$ java -cp .:antlr-4.5.2-complete.jar org.antlr.v4.gui.TestRig \
Demo prog <<< '1,2.,3.4,5 ..6,7..8'
INT: 1
REAL: 2.
REAL: 3.4
RANGE: 5 .. 6
REAL: 7.
line 1:17 extraneous input '.8' expecting {<EOF>, ','}
這樣看來我是正確的:雖然刪除語法預定可能適用於解析器,但詞法分析器不會突然猜出正確的標記類型。
核心問題
那麼一個會如何轉換這個具體的例子來ANTLR 4?有沒有辦法表達先行條件?或者也許有一個像INT '..'
這樣的單個規則發出兩個不同的標記的方法?
參考和可能的解決方案
望着ANTLR 4 Pascal grammar,我注意到,它不允許實數在.
沒有結束之後的數字,所以學習的解決方案從那裏不會出現是一個選擇。我看過Semantic predicates in ANTLR4?和syntactic predicates - Upgrading from Antlr 3 to Antlr 4。在解析器規則中都討論句法謂詞。後者也有詞法規則的例子,但前瞻與後面的規則是一致的,這意味着規則可以被移除而沒有不利影響。在我上面的例子中,情況並非如此。
答案check previous/left token in lexer提詞法分析器的emit
方法,帶有註釋的ANTLR 3維基引用How can I emit more than a single token per lexer rule? FAQ頁面,所以我想這是一種方法。如果沒有人打我的話,我會把它變成一個答案,如果我能在我的例子中得到它的工作。
對ANTLR4 negative lookahead in lexer的回答利用_input.LA(int)
方法來檢查前瞻。 ANTLR 4 lexical analysis faq提到_input.LA
沒有進入細節。這也適用於上面的例子,但對於不止一個字符的前瞻性考慮的場景來說很難。