微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Pyparsing DSL 中的递归类型定义

如何解决Pyparsing DSL 中的递归类型定义

我正在解析具有多个类型定义的特定领域语言。原始类型的解析相对简单,但在 DSL 中转向复杂类型已被证明更具挑战性。我正在寻找一种策略来递归匹配可以包含对自身的引用的定义。

例如,地图数据类型在高层次上可能如下所示:

map<primitive_type,complex_type>

可以作为递归定义出现在输入中的:

map<string,map<int,map<string,...>>>=

这张地图理论上可以是任意深度的。

为了让事情变得更复杂,这些嵌套的复杂类型也可以是其他复杂类型。

map<string,array<array<string>>>>>

我正在寻找一种策略来处理解析这个问题,以便我得到一个包含解析出的嵌套映射类型的准确类型。我考虑过只使用正则表达式,但这对我来说并不理想。我也知道递归语法存在 Forward ,但我还没有弄清楚如何将它应用于这种情况。如果有关于此类解析的任何好的模式或参考资料,我将非常感谢您的指导!

解决方法

前进是这样做的方法。由于类型声明本身可能包含类型声明,这可能是 Forward 将去哪里的一个不错的选择:

import pyparsing as pp
type_decl = pp.Forward()

看看你的例子,我可以看到我们需要一些标点符号,我们可以为它们定义一些抑制表达式,以便它们解析,但不会破坏解析的结果:

LANGLE,RANGLE,COMMA = map(pp.Suppress,"<>,")

# if we get an ellipsis,we want to keep it,so use Literal instead of Suppress
ELLIPSIS = pp.Literal("...")

接下来我们可以做简单的类型:

simple_type = pp.oneOf("string int float",asKeyword=True)

现在是两个复杂类型,maparray。对于这些,我们将在可能出现复杂类型的任何地方使用 Forward:

MAP,ARRAY = map(pp.Keyword,["map","array"])
map_type = MAP - LANGLE + pp.Group(simple_type + COMMA + (type_decl | ELLIPSIS)) + RANGLE
array_type = ARRAY - LANGLE + type_decl + RANGLE
complex_type = pp.Group(map_type | array_type)

我在这里使用“-”运算符,因为如果在看到有效的“map”或“array”关键字后出现语法错误,pyparsing 将在该表达式中给出错误。

此时我们有了复杂和简单的类型,因此我们可以使用 <<= 运算符将它们“注入”到先前定义的 Forward 中:

type_decl <<= (complex_type | simple_type)

使用 runTests 检查:

type_decl.runTests("""\
    string
    int
    float
    map<string,map<int,map<string,...>>>
    map<string,array<array<string>>>>>
    """,fullDump=False)

给出:

string
['string']

int
['int']

float
['float']

map<string,...>>>
[['map',['string',['map',['int','...']]]]]]]

map<string,array<array<string>>>>>
[['map',['array','string']]]]]]]]]

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。