Antlr:初学者期望ID的不匹配输入

作为初学者,当我从The Definitive ANTLR 4参考书中学习ANTLR4时,我尝试从第7章开始运行我修改过的练习版本:

/** * 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之外的eveything(我不希望它只支持双引号中的字符串)。 在运行以下句子时,我得到了:

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

当我使用STRING : '"' .*? '"'相反,它有效。

我想知道我错在哪里,这样我就可以避免将来出现类似的错误。

请给我一些建议,谢谢!

由于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方法在字符流上向后查看以validation它是否遵循等号。 就像是:

 @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; } }