微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何在ANTLR中解析部分日期?

如何解决如何在ANTLR中解析部分日期?

我正在第一步使用antlr4,并尝试解析欧洲格式DD.MM.YYYY的部分日期。

我想识别正常日期,例如15.05.20207.5.20,但也要识别仅包含月份和年份的日期,例如05.20205.20,此外还需要识别仅包含202020之类的年份。在我的应用程序中,我想访问日期的所有部分(日,月和年),其中某些部分可能为空/空。

到目前为止,这是我的语法。

grammar LogicalDateExpressions;

stmt    :   date EOF
        ;

date    :   (YEAR)
        |   (MONTH DOT YEAR)
        |   (DAY DOT MONTH DOT YEAR)
        ;

YEAR    :   ([12] [0-9] [0-9] [0-9])
        |   ([0-9] [0-9])
        ;

MONTH   :   ('0'? [1-9])
        |   ('1' [012])
        ;

DAY     :   ('0'? [1-9])
        |   ([12][0-9])
        |   ('3'[01])
        ;

DOT     :   '.';
WS      :  [ \t\r\n\u000C]+ -> skip;

此语法适用于单个年份(2020),但无法识别月份-年份组合(05.2020)。 grun -tokens告诉了我以下内容

[@0,0:1='05',<YEAR>,1:0]
[@1,2:2='.',<'.'>,1:2]
[@2,3:6='2020',1:3]
[@3,9:8='<EOF>',<EOF>,2:0]
line 1:2 mismatched input '.' expecting <EOF>

所以我不知所措,发现解析器规则date是问题所在,我将其重写为

date : (
          (DAY DOT)?      
          MONTH DOT     
       )?
       YEAR               
     ;

但是我仍然遇到同样的错误。然后我想也许我需要重新排列词法分析器规则。因此,我将它们写为DAY-> MONTH-> YEAR,而不是YEAR-> MONTH-> DAY。但是grun告诉了我。

[@0,<DAY>,2:0]
line 1:3 mismatched input '2020' expecting MONTH

我还试图更改解析器规则date中or'ed替代项的顺序,但这也没有解决。然后,我尝试更改词法分析器规则DAY,MONTH,YEAR,使它们成为解析器规则(日,月,年)。由于看到了解析器规则中显然不允许使用[0-9]表示法而遇到一些错误后,我将语法更改为此。

date    :   (year)
        |   (month DOT year)
        |   (day DOT month DOT year)
        ;

[...]
  
year    :   (('1'|'2') DIGIT DIGIT DIGIT)
        |   (DIGIT DIGIT)
        ;

month   :   ('0'? DIGIT_NO_ZERO)
        |   ('1' ('0'|'1'|'2'))
        ;

day     :   ('0'? DIGIT_NO_ZERO)
        |   (('1'|'2') DIGIT)
        |   ('3' ('0'|'1'))
        ;

[...]

DIGIT         :   [0-9];
DIGIT_NO_ZERO :   [1-9];

那真是太可惜了。 grun告诉我。

[@0,0:0='0',<'0'>,1:1='5',<DIGIT>,1:1]
[@2,1:2]
[@3,3:3='2',<'2'>,1:3]
[@4,4:4='0',1:4]
[@5,5:5='2',1:5]
[@6,6:6='0',1:6]
[@7,2:0]
line 1:1 no viable alternative at input '05'

据我了解,我所寻找的语言是普通语言。每个输入都是明确的。因此,我尝试将整个“逻辑”纳入词法分析器,并成功完成了以下语法。

grammar LogicalDateExpressions;

stmt :   date EOF
     ;

date :   DT
     ;

DT   :  (
            ((('0'? [1-9])|([12][0-9])|('3'[01])) DOT)? // Day
            (('0'? [1-9])|('1' [012])) DOT              // Month
        )?
        ((DIGIT DIGIT DIGIT DIGIT)|(DIGIT DIGIT))       // Year
    ;

DIGIT   :   [0-9];
DOT     :   '.';
WS      :  [ \t\r\n\u000C]+ -> skip;

它解析我给它的每个输入。但是问题在于,每个输入都只是一个DT

[@0,0:6='05.2020',<DT>,2:0]

我无法区分访问者/收听者中的日期,月份和年份,因为词法分析器规则中不允许使用标签


所以我的问题是,第一个给定的语法在哪里出现问题,我需要对其进行更改以使其起作用?

通过查看grun的令牌输出,我想我可能会理解一天,一个月和/或一年中每个输入的问题可能是模棱两可的,但从整体上来说,与点结合起来应该不是问题。我该如何告诉antlr?

解决方法

所以我的问题是,第一个给定的语法在哪里出现问题,我需要对其进行更改以使其起作用?

问题在于语法分析器没有驱动词法分析器。这意味着当解析器尝试匹配令牌DAY DOT MONTH且输入为01.01时,词法分析器将不会为这两个{创建一个DAY和一个MONTH {1}},但有两个01令牌。 ANTLR的词法分析器是这样工作的:尝试为令牌捕获尽可能多的字符,并且当有两个或多个匹配相同字符的令牌时(例如MONTH和{{ 1}}),让令牌定义第一个“获胜”(即01令牌)。无法解决这个问题。

您可以做的事情是这样的(未经测试):

DAY

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。