为什么我们需要指定标准的 Lark lexer 才能捕获注释终端?

问题描述

我正在开发一个基于 Lark 的项目,我需要能够“捕捉”正在解析的代码中的注释。

但是,在没有明确指定标准词法分析器的情况下使用标准词法分析器时,它不起作用。

我从 the Lark recipes提取了第二个示例并将其修改为使用认解析器并解析类似 C++ 的单行注释:

import lark

comments = []

grammar = r'''
start: INT*

COMMENT: "//" /[^\n]*/

%import common (INT,WS)
%ignore COMMENT
%ignore WS
'''

# This doesn't work,comments are not appended to the list
# parser = lark.Lark(grammar,lexer_callbacks={'COMMENT': comments.append})

# But this does work
parser = lark.Lark(grammar,lexer='standard',lexer_callbacks={'COMMENT': comments.append})

source = r'''
1 2 3  // hello
// world
4 5 6
'''

parser.parse(source)

print(comments)

如果我没有 lexer='standard',结果是一个空列表。

但是当没有明确指定时,它不应该已经使用了 'standard' 词法分析器吗?是我代码中的错误,还是 Lark 中可能存在的错误


进一步的实验似乎表明它是在认情况下使用的 'dynamic''dynamic_complete'(未指定 lexer)。

解决方法

Lark 支持 parserlexer 的不同组合。有些支持lexer_callbacks,有些不支持:

解析器 词法分析器 lexer_callbacks
啦啦 标准
啦啦 上下文
早期 标准
早期 动态 没有
早期 dynamic_complete 没有
啦啦 自定义 (也许)
早期 自定义 (也许)

lexer="auto" 根据解析器选择词法分析器:对于 lalr,它选择 contextual,对于 earley,它选择 dynamic。默认解析器为 earley,因此如果不选择 parserlexer,则不支持 lexer_callbacks

这方面的issue已经打开又关闭了。