ANTLR语义谓词 - 不阻止规则

时间:2018-03-02 18:30:24

标签: python antlr grammar predicate

我在ANTLR解析器规则上使用语义谓词时遇到了一些麻烦。这是我的语法,旨在识别几种不同的日期格式:

grammar sample ;

options { language=Python3; }

@parser::header {
from datetime import datetime
}

month_number returns [val] : INTEGER { 1    <= int($INTEGER.text) <= 12   }?  {$val = int($INTEGER.text)} ;
day_number   returns [val] : INTEGER { 1    <= int($INTEGER.text) <= 31   }?  {$val = int($INTEGER.text)} ;
year_4digit  returns [val] : INTEGER { 1900 <= int($INTEGER.text) <= 2100 }?  {$val = int($INTEGER.text)} ;

year_2digit  returns [val] : '\''? INTEGER {(int($INTEGER.text) >= 65 or int($INTEGER.text) < 40)}?
                                     {$val = (1900 + int($INTEGER.text)) if (int($INTEGER.text) >= 65) else (2000 + int($INTEGER.text))} ;

year_digits  returns [val]
  : year_4digit {$val = $year_4digit.val}
  | year_2digit {$val = $year_2digit.val}
  ;


mdy returns [val]
  : month_number '-' day_number '-' year_digits  {$val = datetime($year_digits.val, $month_number.val, $day_number.val)}
  | month_number '/' day_number '/' year_digits  {$val = datetime($year_digits.val, $month_number.val, $day_number.val)}
  ;

ymd returns [val]
  : year_4digit '-' month_number '-' day_number  {$val = datetime($year_4digit.val, $month_number.val, $day_number.val)}
  | year_4digit '/' month_number '/' day_number  {$val = datetime($year_4digit.val, $month_number.val, $day_number.val)}
  ;

date_as_numbers returns [val]
  : ymd {$val = $ymd.val}
  | mdy {$val = $mdy.val}
  ;

INTEGER: '0'..'9'+ ;

我用以下程序测试:

from myPackage.sampleParser import sampleParser
from myPackage.sampleLexer import sampleLexer

from antlr4 import CommonTokenStream
from antlr4 import InputStream

date_input = InputStream("2/12/2017".lower())
lexer = sampleLexer(date_input)
stream = CommonTokenStream(lexer)
parser = sampleParser(stream)
result = parser.date_as_numbers()
print(result.val)

这会导致以下错误:

line 1:1 rule year_4digit failed predicate: { 1900 <= int($INTEGER.text) <= 2100 }?
line 1:9 rule day_number failed predicate: { 1    <= int($INTEGER.text) <= 31   }?
Traceback (most recent call last):
  File "/Users/kwilliams/Library/Preferences/IntelliJIdea2017.3/scratches/scratch_1.py", line 11, in <module>
    result = parser.date_as_numbers()
  File "/Users/kwilliams/git/myPackage/sampleParser.py", line 482, in date_as_numbers
    localctx._ymd = self.ymd()
  File "/Users/kwilliams/git/myPackage/sampleParser.py", line 436, in ymd
    localctx.val = datetime(localctx._year_4digit.val, localctx._month_number.val, localctx._day_number.val)
TypeError: an integer is required (got type NoneType)

所以我认为正在发生的是year_4digit中的谓词会引发异常,因为数字2不在其范围内,但无论如何都会返回year_4digit匹配,尚未填充其val属性,导致下游错误NoneType。这是对的吗?

如果是这样 - 什么是好的解决方案?我是否需要将语义谓词放在规则或其他内容的前面?如果这是正确的解决方案,我将如何对INTEGER令牌进行预测?

(另外 - 我希望能够$INTEGER.int而不是int($INTEGER.text),但也许这在Python目标中不可用?切向和小问题。)

顺便说一下,上面的语法是我真正语法的一个小摘录,我希望有一个解决方案不需要对这部分进行重大修改,可能会引起涟漪效应,可能需要一段时间才能解决。< / p>

感谢。

0 个答案:

没有答案