3

我正在解析一个格式可以包括的文件:

INT32  price   min 10  max 100   alertIfSold ; 

min、max 和 alertIfSold 标记都是可选的,可以以任何顺序出现。那是

INT32  price    max 100   alertIfSold ; 
INT32  price  max 100   min 10    alertIfSold ;
INT32  price  alertIfSold ;
INT32  price; 

都是有效的例子。

下面是我正在测试的语法的简单版本。运行 python test.py 生成此错误:

lark.common.ParseError:检测到无限递归!(规则 <__anon_star_1 : __anon_star_1>)

我尝试使用其他语法规则表达相同的可选标记,结果相似(无限递归)。

表达可选参数的正确语法是什么?

#test.py
from lark import lark

simplified_grammar = """
    start: line+
    line:  TYPE  CNAME [MIN MAX ALERT]* ";"    -> foo

     TYPE: "INT32" | "INT64"

     MIN: "min" /[0-9]+/
     MAX: "max" /[0-9]+/
     ALERT: "alertIfSold"

     %import common.CNAME
     %import common.WS
     %ignore WS
  """

sample = """
    INT32  price    max 100   alertIfSold ; 
    INT32  price  max 100   min 10    alertIfSold ;
    INT32  price  alertIfSold ;
    INT32  price; 

"""

parser = lark.Lark(simplified_grammar)


def main():
    parse_tree = parser.parse(sample)

if __name__ == '__main__':
    main()
4

1 回答 1

5

你要:

line:  TYPE  CNAME (MIN | MAX | ALERT)* ";"    -> foo

(注意:()而不是[]。)

在 lark 的 EBNF 语法中,[item]表示“可选item”,item*表示“任意数量(可能为零)的item”。所以[item]*意思是“任何数量(可能为零)的任何一个item或什么都没有”。但是“任何数量的无”是无限含糊的;你无法说出一个空字符串中有多少个空。

由于您实际上并不打算要求条款严格连续出现,您可能一直在考虑

line:  TYPE  CNAME ([MIN] [MAX] [ALERT])* ";"    -> foo

那会更准确,但也会产生相同的错误消息。通常,您不能在可为空的子模式上使用 Kleene 星号。一些 EBNF 生成器会通过从重复集中移除 ε(然后将重复作为一个整体作为可选)来纠正这一点,但 Lark 不是其中之一。在这种情况下,修复是微不足道的,但在其他情况下它更烦人。

作为正则表达式,(a* b*)*(a? b?)*(a|b)*它们都识别相同语言的意义上是等价的。但是正则表达式的歧义是出了名的,解析器通常更喜欢明确的语法,或者最坏的情况是有限歧义的语法。只有最后一个正则表达式属于该类别,它是您通常应该喜欢的形式。

于 2018-06-05T05:50:36.383 回答