如何解决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)
现在是两个复杂类型,map
和 array
。对于这些,我们将在可能出现复杂类型的任何地方使用 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 举报,一经查实,本站将立刻删除。