我正在尝试使用Antlr 4扩展一个现有的语法。在.g4文件中,除了其他规则之外,还定义了以下规则:
Digit
: ZeroDigit
| NonZeroDigit
;
NonZeroDigit
: NonZeroOctDigit
| '8'
| '9'
;
NonZeroOctDigit
: '1'
| '2'
| '3'
| '4'
| '5'
| '6'
| '7'
;
OctDigit
: ZeroDigit
| NonZeroOctDigit
;
ZeroDigit
: '0' ;
SP
: ( WHITESPACE )+ ;
因此,除此之外(不仅仅是作为一种修辞手法),我添加了以下规则,这些规则应该利用这些现有规则:
ttQL_Query
: ttQL_TimeClause SP;
ttQL_TimeClause
: FROM SP? ttQL_DateTime SP? TO SP? ttQL_DateTime;
ttQL_DateTime
: ttQL_Date ('T' ttQL_Time ttQL_Timezone)?;
ttQL_Timezone: 'Z' | ( '+' | '-' ) ttQL_Hour ':' ttQL_Minute;
ttQL_Date: ttQL_Year '-' ttQL_Month '-' ttQL_Day;
ttQL_Time: ttQL_Hour (':' ttQL_Minute (':' ttQL_Second (ttQL_Millisecond)?)?)?;
ttQL_Year: Digit Digit Digit Digit;
ttQL_Month: Digit Digit;
ttQL_Day: Digit Digit;
ttQL_Hour: Digit Digit ;
ttQL_Minute: Digit Digit ;
ttQL_Second: Digit Digit ;
ttQL_Millisecond: '.' ( Digit )+;
FROM : ( 'F' | 'f' ) ( 'R' | 'r' ) ( 'O' | 'o' ) ( 'M' | 'm' ) ;
TO : ( 'T' | 't' ) ( 'O' | 'o' ) ;
这应该是开放密码查询语言的扩展(语法可以在这里找到:http://opencypher.org/resources/),但是我没有让它工作。它应该是一个密码查询的前缀。规则很简单:
ttQL
: SP? ttQL_Query SP? oC_Cypher ;
所以所有其他现有的规则以及我在开头提到的规则都被用在oC_Cypher中。我把我所有的规则放在antlr文件的顶部,当试图解析一个查询时,如下所示:
FROM 2123-12-13T12:34:39Z TO 2123-12-13T14:34:39.2222Z MATCH (a)-[x]->(b) WHERE a.ping > 22" RETURN a.ping, b"
我的解析器收到以下错误消息:
line 1:5 mismatched input '2123' expecting Digit
line 1:10 mismatched input '12' expecting Digit
line 1:13 mismatched input '13' expecting Digit
line 1:29 mismatched input '2123' expecting Digit
line 1:34 mismatched input '12' expecting Digit
line 1:37 mismatched input '13' expecting Digit
奇怪的是,当我把我的语法部分放到一个新的.g4文件中,并只为前缀部分FROM 2123-12-13T12:34:39Z TO 2123-12-13T14:34:39.2222Z
创建一个解析器时,一切都变得很顺利。我有点迷失在这里。我使用的是vscode、java、maven和ANTLR 4插件,ANTLR4.9.2版、mvn-compiler-plugin3.10.1版、java 11版
这里面有什么猫腻
2条答案
按热度按时间3ks5zfa01#
在kaby的帮助下,我可以为自己解决这个问题。我不知道这是否是正确的处理这个问题,但对于我想要实现的是足够的。所以请小心这个解决方案,如果你有类似的问题,并试图解决它。
正如kaby指出的,lexer会搜索可以连接最多字符的Token,所以我只是在日期和时间之外制定了lexer规则,这样数字就不会被识别为整数。
编辑:
我发现我的解决方案包含另一个陷阱,我将在这里添加。如果你正在解析整数或任何其他数字序列,其中有可能两个数字连接,我的TIME规则将被调用,并将创建一个TIME令牌-至少如果这个规则是高于其他规则,可以适合这里。作为一个第一次接触词法分析器和解析器的人,我发现最重要的是要小心已经存在的词法分析器规则,正如kaby提到的:首先关注词法分析器,打印出Example input的标记以供调试。在我的例子中,一个简单的解决方案是合并DATE、TIME和TIMEZONE规则,以使规则更加独特,从而不会遇到与现有词法分析器规则的兼容性问题:
p5fdfcr12#
我建议为所有lexer规则添加一个
fragment
前缀,Digits
和SP除外。