2011-05-16 184 views
3

我對ANTLR非常陌生,並且試圖理解Lexer和Parser規則是如何工作的。我遇到了一個我寫過的語法問題,它似乎與多個字符被視爲「匹配」的詞法分析符號相關,即使只有前幾個字符實際匹配時也是如此。爲了證明這一點,我寫了一個簡單的ANTLR 3語法:ANTLRv3沒有閱讀選項

grammar test; 
options { 
    k=3; 
} 

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

sentence : (CHARACTER)*; 

CHARACTER : 'a'..'z'|' '; 
SPECIAL  : 'special'; 

我使用AntlrWorks來分析下面的測試輸入:

apple basic say sponsor speeds speckled specific wonder 

我得到的輸出是:

apple basic say nsor ds led ic wonder 

在我看來,LEXER使用k = 1,因此將我的SPECIAL標記與包含兩個字母'sp'的任何東西進行匹配。一旦遇到字母'sp',它就會匹配SPECIAL文字中的成年字符,直到實際輸入不符合預期的標記爲止 - 此時它會拋出一個錯誤(消耗該字符),然後繼續處理其餘的句子。每個錯誤的形式如下:

line 1:18 mismatched chracter 'o' expecting 'e' 

但是,這不是我嘗試創建的行爲。我希望創建一個與關鍵字('special')匹配的詞法分析器標記,以用於此測試示例中未包含的其他分析器規則。不過,我不希望其他規則/輸入,只是碰巧包括相同的初始人物受到影響

總結:

  1. 實際上,我怎麼設置ANTLR 3個選項(如K = 2或k = 3等)?至少在我看來,我嘗試在這裏使用的選項沒有設置。
  2. 有沒有更好的方法來創建解析器或詞法分析器規則來匹配我的輸入中的特定關鍵字,而不會影響輸入中不包含完整匹配的其他部分的處理?
+0

當我在ANTLRWorks 1.4.2中運行你的示例時,它解析得很好,你指的是什麼輸出? – 2011-05-16 06:17:26

+0

這很有趣,@Bas。我也使用ANTLRWorks 1.4.2(通常在IntelliJ 10.0.3中運行)。在調試模式下,我有一個顯示錯誤的「輸出」選項卡。我還可以檢查分析樹(Parse Tree選項卡)以查看「spe ..」位被丟棄。同樣,「堆棧選項卡」顯示我的機器上的問題。你的沒有出現任何問題嗎?你能檢查ParseTree並看到完整的句子,包括以字母「spec ...」開始的位嗎? – Glennn 2011-05-16 07:23:05

+0

我使用解釋器選項卡時,它會在您的示例輸入上運行語句規則時生成解析樹。 – 2011-05-16 07:30:01

回答

4

options { ... }部分的k定義瞭解析器而不是詞法分析器的前面。

注意語法

CHARACTER : 'a'..'z'|' '; 
SPECIAL  : 'special'; 

是模糊的:你'special'也可以被認爲是7 'a'..'z'的。

grammar Test; 

sentence : (special | word | space)+ EOF; 
special : SPECIAL; 
word  : WORD; 
space : SPACE; 

SPECIAL : 'special'; 
WORD  : 'a'..'z'+; 
SPACE : ' '; 

這將解析輸入:

specia special specials 

如下:

enter image description here

即正常情況下,如下它會被lexed它將(或多或少)標記爲LL(1)和「最長匹配」的組合。對不起,我意識到這有點含糊,但Definitive ANTLR Reference並沒有完全澄清(至少,我找不到它......)。但我意識到這可能不是你想要的。

據我所知,產生單個字符的令牌定義從這些單個字符的令牌由關鍵字,通過在一個單一的規則合併這兩個標記完成,並使用謂詞和手動look-的唯一途徑提前查看它們是否符合關鍵詞,如果不符合,則在「fall through」子規則中更改該標記的類型。一個演示:

grammar test; 

tokens { 
    LETTER; 
} 

@lexer::members { 
    // manual look ahead 
    private boolean ahead(String text) { 
    for(int i = 0; i < text.length(); i++) { 
     if(input.LA(i+1) != text.charAt(i)) { 
     return false; 
     } 
    } 
    return true; 
    } 
} 

sentence 
    : (t=. {System.out.printf("\%-7s :: '\%s'\n", tokenNames[$t.type], $t.text);})+ EOF 
    ; 

SPECIAL 
    : {ahead("special")}?=> 'special' 
    | {ahead("keyword")}?=> 'keyword' 
    | 'a'..'z' {$type = LETTER;} // Last option and no keyword is found: 
           // change the type of this token 
    ; 

SPACE 
    : ' ' 
    ; 

從上面的語法產生的解析器可以與類進行測試:

import org.antlr.runtime.*; 

public class Main { 
    public static void main(String[] args) throws Exception { 
     ANTLRStringStream in = new ANTLRStringStream("apple basic special speckled keyword keywor"); 
     testLexer lexer = new testLexer(in); 
     CommonTokenStream tokens = new CommonTokenStream(lexer); 
     testParser parser = new testParser(tokens); 
     parser.sentence(); 
    } 
} 

正如你可以看到,解析輸入時:

apple basic special speckled keyword keywor 

以下產生輸出:

LETTER :: 'a' 
LETTER :: 'p' 
LETTER :: 'p' 
LETTER :: 'l' 
LETTER :: 'e' 
SPACE :: ' ' 
LETTER :: 'b' 
LETTER :: 'a' 
LETTER :: 's' 
LETTER :: 'i' 
LETTER :: 'c' 
SPACE :: ' ' 
SPECIAL :: 'special' 
SPACE :: ' ' 
LETTER :: 's' 
LETTER :: 'p' 
LETTER :: 'e' 
LETTER :: 'c' 
LETTER :: 'k' 
LETTER :: 'l' 
LETTER :: 'e' 
LETTER :: 'd' 
SPACE :: ' ' 
SPECIAL :: 'keyword' 
SPACE :: ' ' 
LETTER :: 'k' 
LETTER :: 'e' 
LETTER :: 'y' 
LETTER :: 'w' 
LETTER :: 'o' 
LETTER :: 'r' 

請參閱Q & A What is a 'semantic predicate' in ANTLR?以瞭解有關ANTLR中的謂詞的更多信息。

+0

真棒回覆! – John 2011-05-16 22:31:30

+0

Thanks @Bart。非常明確和有益的答覆!非常感謝。 – Glennn 2011-05-16 22:49:05

+0

@John,謝謝! @Glennn,不客氣。 – 2011-05-17 05:53:25