3

我一直在尝试百灵鸟,但遇到了一个小问题。假设我有以下语法。

parser = Lark('''
    ?start: value 
            | start "or" value -> or
    ?value: DIGIT -> digit 
            | ID -> id

    DIGIT: /[1-9]\d*/

    %import common.CNAME -> ID

    %import common.WS
    %ignore WS
    ''', parser='lalr')

假设我要解析1orfoo

print(parser.parse("1orfoo").pretty())

我希望 lark 将其视为数字1后跟标识符orfoo(因此抛出错误,因为语法不接受这种表达式)。

但是,解析器运行没有错误并输出:

or
  digit 1
  id    foo

如您所见,Lark 将标识符拆分,并将表达式视为or语句。

为什么会这样?我错过了什么吗?我怎样才能防止这种行为?

先感谢您。

4

1 回答 1

1

Lark 可以使用不同的词法分析器将输入文本结构化为标记。默认值为“auto”,它根据解析器选择词法分析器。对于 LALR,选择“上下文”词法分析器(参考)。上下文词法分析器使用 LALR 前瞻来丢弃不符合语法的标记选择(参考):

上下文词法分析器与解析器通信,并使用解析器的前瞻预测来缩小其标记的选择范围。因此,在每一点,词法分析器只匹配在该解析器状态下合法的终端子组,而不是所有终端。它在解决常见的终端冲突方面非常有效,并且允许解析 LALR(1) 以前无法解析的语言。

在您的代码中,由于您使用lalr解析器,因此使用了contextual词法分析器。词法分析器首先DIGIT1. 接下来,词法分析器必须决定是为or文字创建标记还是为标记创建ID标记。由于解析状态不需要ID标记,因此词法分析器消除了后一种选择并标记化or

要更改此行为,您可以选择standard词法分析器:

parser = Lark('''...''', parser='lalr', lexer='standard')

在您的示例中,它将生成:

lark.exceptions.UnexpectedToken: Unexpected token Token(ID, 'orfoo') at line 1, column 2.
Expected one of: 
    * OR
    * $END
于 2020-05-20T19:33:24.323 回答