使用args和kwargs对函数调用表达式进行递归pyparsing

问题描述 投票:0回答:1

我正在尝试使用

pyparsing
创建一个解析器来解析以下格式的表达式:

FUNC_NAME(ARG1, ARG2, ..., ARGN, K1=V1, K2=V2, ..., KN=VN)

ARG 和 KWARG 值可以是文字(带引号的字符串、数字、不带引号的日期表达式)或其本身是具有无限嵌套的函数。

我似乎无法解决的问题是 Forward() 的递归结构。

这是我所拥有的:

import pyparsing as pp 

LP, RP = map(pp.Suppress, "()")
ident = ppc.identifier("ident")
number = pp.pyparsing_common.number
string = (pp.QuotedString("\"") | pp.QuotedString("'"))
date = pp.Combine(pp.Word(pp.nums, exact=4) + "-" + pp.Word(pp.nums, exact=2) + "-" + pp.Word(pp.nums, exact=2))("date")
literal = date | number | string

body = pp.Forward()
body <<= body | (ident + pp.Suppress("=") + body) | (ident + LP + body + RP) | literal | pp.empty
expr = ident + (LP + pp.Optional(pp.Group(pp.delimitedList(body))) + RP)

运行这个表达式会给我一个递归深度错误。不知道我做错了什么。

python pyparsing
1个回答
0
投票

这是一个有趣的问题,支持您开始使用递归语法。

当前的问题在于

body
内容的定义:

body <<= body | (ident + pp.Suppress("=") + body) | (ident + LP + body + RP) | literal | pp.empty

这会创建一个左递归(或“LR”)表达式,因为要解析

body
,你首先必须解析
body
,但首先你必须解析
body
,但首先......等等。其他替代术语也可以使用
body
,但作为更大表达式的一部分(在括在括号中之后,或作为赋值的一部分)。因此,解决方案可能是删除领先的
body
术语:

body <<= (ident + pp.Suppress("=") + body) | (ident + LP + body + RP) | literal | pp.empty

但是您可能希望支持将

body
括在括号中,因此更改为这也可以解决您的 LR 问题:

body <<= LP + body + RP | (ident + pp.Suppress("=") + body) | (ident + LP + body + RP) | literal | pp.empty

这些更改中的任何一个都将解决您的 LR 问题。默认情况下,pyparsing 不支持 LR 解析器。您可以启用此功能,使用 pyparsing 3.0.0 中添加的功能:

pp.ParserElement.enable_left_recursion()

但是如果采用任何建议的更改,则没有必要。

我还添加了这些行,以生成解析器的铁路图。我发现这些图表对于可视化解析器的结构非常有帮助;

pp.autoname_elements()
expr.create_diagram("lr_function_parser.html")

生成此图:

祝您进一步的 pyparsing 工作顺利!

© www.soinside.com 2019 - 2024. All rights reserved.