2014-04-27 59 views
1

作爲一個初學者,當我從The Definitive ANTLR 4 Reference書學習ANTLR4,我試圖從第7章運行我練習的修改後的版本:ANTLR的:初學者的不匹配輸入期待ID

/** 
* to parse properties file 
* this example demonstrates using embedded actions in code 
*/ 
grammar PropFile; 

@header { 
    import java.util.Properties; 
} 
@members { 
    Properties props = new Properties(); 
} 
file 
    : 
    { 
     System.out.println("Loading file..."); 
    } 
     prop+ 
    { 
     System.out.println("finished:\n"+props); 
    } 
    ; 

prop 
    : ID '=' STRING NEWLINE 
    { 
     props.setProperty($ID.getText(),$STRING.getText());//add one property 
    } 
    ; 

ID : [a-zA-Z]+ ; 
STRING :(~[\r\n])+; //if use STRING : '"' .*? '"' everything is fine 
NEWLINE : '\r'?'\n' ; 

由於Java性能只是鍵值對我使用STRING來匹配除了NEWLINE(我不希望它只支持雙引號中的字符串)。當運行下面的句子,我得到:

D:\Antlr\Ex\PropFile\Prop1>grun PropFile prop -tokens 
driver=mysql 
^Z 
[@0,0:11='driver=mysql',<3>,1:0] 
[@1,12:13='\r\n',<4>,1:12] 
[@2,14:13='<EOF>',<-1>,2:14] 
line 1:0 mismatched input 'driver=mysql' expecting ID 

當我使用STRING : '"' .*? '"'相反,它的工作原理。

我想知道我錯在哪裏,以便將來避免類似的錯誤。

請給我一些建議,謝謝!

+0

因爲ID也會匹配字符串值,如果我想允許字符串作爲值,但不是在雙引號,如何做到這一點? – wangdq

回答

1

由於ID和STRING都可以匹配以「driver」開頭的輸入文本,詞法分析器將選擇儘可能最長的匹配,即使ID規則優先。

所以,你在這裏有幾個選擇。最直接的方法是通過要求字符串以等號開始,以消除ID和STRING之間的歧義(這是您的替代方法的工作原理)。

file : prop+ EOF ; 
prop : ID STRING NEWLINE ; 

ID  : [a-zA-Z]+ ; 
STRING : '=' (~[\r\n])+; 
NEWLINE : '\r'?'\n' ; 

然後,您可以使用操作從字符串標記的文本中修剪等號。

或者,您可以使用謂詞來消除規則的歧義。

file : prop+ EOF ; 
prop : ID '=' STRING NEWLINE ; 

ID  : [a-zA-Z]+ ; 
STRING : { isValue() }? (~[\r\n])+; 
NEWLINE : '\r'?'\n' ; 

其中isValue方法在字符流中向後查看以驗證它是否等於等號。像這樣:

@members { 
public boolean isValue() { 
    int offset = _tokenStartCharIndex; 
    for (int idx = offset-1; idx >=0; idx--) { 
     String s = _input.getText(Interval.of(idx, idx)); 
     if (Character.isWhitespace(s.charAt(0))) { 
      continue; 
     } else if (s.charAt(0) == '=') { 
      return true; 
     } else { 
      break; 
     } 
    } 
    return false; 
} 
} 
+0

感謝您的詳細回答。我誤解了如果ID先來,那麼當遇到歧義時,它會選擇ID作爲選擇。另外一些人建議不要使用與STRING相匹配的規則:(〜[\ r \ n]) +;在我的情況下,java屬性文件只包含String-String(未引用),所以我會按照你的方法。 – wangdq

相關問題