java 数字的Antlr规则无法识别数字-

zzlelutf  于 2023-02-07  发布在  Java
关注(0)|答案(2)|浏览(190)

我正在尝试使用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版
这里面有什么猫腻

3ks5zfa0

3ks5zfa01#

在kaby的帮助下,我可以为自己解决这个问题。我不知道这是否是正确的处理这个问题,但对于我想要实现的是足够的。所以请小心这个解决方案,如果你有类似的问题,并试图解决它。
正如kaby指出的,lexer会搜索可以连接最多字符的Token,所以我只是在日期和时间之外制定了lexer规则,这样数字就不会被识别为整数。

ttQL_Query
     : ttQL_TimeClause SP?;

ttQL_TimeClause
     : FROM SP? DATETIME SP? TO SP? DATETIME; 

DATETIME:  DATE ('T' TIME TIMEZONE)?;

TIMEZONE: 'Z' | ( '+' | '-' ) Digit Digit ':' Digit Digit; 

DATE: Digit Digit Digit Digit '-' Digit Digit '-' Digit Digit;
TIME: Digit Digit (':' Digit Digit (':' Digit Digit ('.' (Digit)+ )?)?)?;

FROM : ( 'F' | 'f' ) ( 'R' | 'r' ) ( 'O' | 'o' ) ( 'M' | 'm' ) ;
TO : ( 'T' | 't' ) ( 'O' | 'o' ) ;

编辑:
我发现我的解决方案包含另一个陷阱,我将在这里添加。如果你正在解析整数或任何其他数字序列,其中有可能两个数字连接,我的TIME规则将被调用,并将创建一个TIME令牌-至少如果这个规则是高于其他规则,可以适合这里。作为一个第一次接触词法分析器和解析器的人,我发现最重要的是要小心已经存在的词法分析器规则,正如kaby提到的:首先关注词法分析器,打印出Example input的标记以供调试。在我的例子中,一个简单的解决方案是合并DATE、TIME和TIMEZONE规则,以使规则更加独特,从而不会遇到与现有词法分析器规则的兼容性问题:

DATETIME:  (Digit Digit Digit Digit '-' Digit Digit '-' Digit Digit) ('T' (Digit Digit (':' Digit Digit (':' Digit Digit ('.' (Digit)+ )?)?)?) ('Z' | ( '+' | '-' ) Digit Digit ':' Digit Digit))?;
p5fdfcr1

p5fdfcr12#

我建议为所有lexer规则添加一个fragment前缀,Digits和SP除外。

相关问题