2013-02-03 53 views
0

我有以下的語法:如何使用類似的詞法分析器

cmds 
    : cmd+ 
    ; 

cmd 
    : include_cmd | other_cmd 
    ; 

include_cmd 
    : INCLUDE DOUBLE_QUOTE FILE_NAME DOUBLE_QUOTE 
    ; 

other_cmd 
    : CMD_NAME ARG+ 
    ; 


INCLUDE 
    : '#include' 
    ; 

DOUBLE_QUOTE 
    : '"' 
    ; 

CMD_NAME 
    : ('a'..'z')* 
    ; 

ARG 
    : ('a'..'z' | 'A'..'Z' | '0'..'9' | '_')+ 
    ; 

FILE_NAME 
    : ('a'..'z' | 'A'..'Z' | '0'..'9' | '_' | '.')+ 
    ; 

所以CMD_NAME,ARG和FILE_NAME之間的差別並不大,CMD_NAME必須是小寫字母,ARG可以有大寫字母和「_ 「和FILE_NAME可以有」。「。

但是這有一個問題,當我用 - #include「abc」測試規則時,'abc'被解釋爲CMD_NAME而不是FILE_NAME,我認爲這是因爲CMD_NAME在語法文件中的FILE_NAME之前,解析錯誤。

我是否必須依靠預測來處理這種技術?除了依賴主機編程語言之外,是否還有純粹的EBNF解決方案?

謝謝。

回答

1

但是,這裏有一個問題,當我測試與規則 - #包括「ABC」,「ABC」被解釋爲CMD_NAME而不是FILE_NAME,我想是因爲CMD_NAME是FILE_NAME之前在語法文件,這導致解析錯誤。

所有有效的CMD_NAME的集合與所有有效的集合FILE_NAME s相交。輸入abc符合兩者。詞法分析器將輸入與列出的第一條規則進行匹配(因爲您懷疑),因爲它是第一個匹配的規則。

我是否必須依靠[predicate]這樣的技術來處理這個問題?除了依賴主機編程語言之外,是否還有純粹的EBNF解決方案?

這取決於你願意接受你的語法。考慮更改include_cmd規則的東西更傳統的,就像這樣:

include_cmd : INCLUDE STRING; 

STRING 
    : '"' ~('"'|'\r'|'\n')* '"' {String text = getText(); setText(text.substring(1, text.length() - 1));} 
    ; 

現在輸入#include "abc"變成令牌[INCLUDE : #include] [STRING : abc]

我不認爲語法應負責確定文件名是否有效或無效:有效的文件並不意味着有效文件,和語法必須瞭解操作系統文件命名約定(有效字符,路徑等)可能不會影響語法本身。我認爲如果你願意放棄規則FILE_NAME就像上面的規則那樣你會沒事的。

另外值得注意的是,您的CMD_NAME規則匹配零長度輸入。考慮將('a'..'z')*更改爲('a'..'z')+,除非CMD_NAME確實可以爲空。


請記住,那就是,你有同樣的問題與ARG您使用FILE_NAME一樣。它在CMD_NAME之後列出,因此任何符合這兩條規則的輸入(如abc)都將達到CMD_NAME。考慮違反這些規則成更傳統的像這樣:

other_cmd : ID (ID | NUMBER)+ SEMI; //instead of CMD_NAME ARG+ 
ID  : ('a'..'z'|'A'..'Z'|'_')+; //instead of CMD_NAME, "id" part of ARG 
NUMBER : ('0'..'9')+;    //"number" part of ARG 
SEMI  : ';'; 

我添加規則SEMI標記命令的結束。否則解析器將不知道輸入a b c d應該是一個帶有三個參數的命令(a(b,c,d))還是兩個帶有一個參數的命令(a(b), c(d))。

+0

謝謝你這樣詳細的解釋,現在很清楚。我確實有一個問題,會問一個新的線程。 –

相關問題