我正在为过程演算开发一个解析器。我正在使用this pattern自动创建带解析对象的AST树。
我的问题是,由于我的语法在结果树中的递归性质,我得到了解析文本中不存在的对象(AST节点)。
即。
A = a.b
我得到了
[Procdef:{'rest': ([Choice:{'lhs': ([Prefix:{'lhs': (['a'], {}), 'rhs': ([Prefix:{'lhs': (['b'], {}), 'rhs': ([], {})}], {})}], {}), 'rhs': ([], {})}], {}), 'proc': 'A'}]
但我希望如此:
[Procdef:{'rest': ([Prefix:{'lhs': (['a'], {}), 'rhs': ([Prefix:{'lhs': (['b'], {}), 'rhs': ([], {})}], {})}], {}), 'proc': 'A'}]
这里的区别是缺少Choice
节点。在我过去的项目中,我使用自己的AST结构和函数传递给setParseAction
,然后我只检查rhs是否为null并传递令牌。对象通过后我不知道该怎么做。
简化代码如下:
#!/usr/bin/env python
from pyparsing import *
class ASTNode(object):
def __init__(self, tokens):
self.tokens = tokens
self.assignFields()
def __str__(self):
return self.__class__.__name__ + ":" + str(self.__dict__)
__repr__ = __str__
class Procdef(ASTNode):
def assignFields(self):
self.proc, self.rest = self.tokens
del self.tokens
class Choice(ASTNode):
def assignFields(self):
self.lhs, self.rhs = self.tokens
del self.tokens
class Prefix(ASTNode):
def assignFields(self):
self.lhs, self.rhs = self.tokens
del self.tokens
class RasParser(object):
def grammar(self):
prefix_op = Literal('.').suppress()
choice_op = Literal('+').suppress()
lpar = Literal('(').suppress()
rpar = Literal(')').suppress()
define = Literal('=').suppress()
Ident = Word(alphas.upper(), alphanums + "_")
ident = Word(alphas.lower(), alphanums + "_")
choice = Forward()
prefix = Forward()
process = ident | lpar + choice + rpar
prefix << Group(process) + Group(ZeroOrMore(prefix_op + prefix))
choice << Group(prefix) + Group(ZeroOrMore(choice_op + prefix))
rmdef = Ident + define + Group(choice)
rmdef.setParseAction(Procdef)
prefix.setParseAction(Prefix)
choice.setParseAction(Choice)
ras = ZeroOrMore(rmdef)
return ras
def parse(self, string):
oo = self.grammar().parseString(string, parseAll=True).asList()
print(oo)
if __name__ == "__main__":
p = RasParser()
model = "A = a.b"
print(model)
p.parse(model)
答案 0 :(得分:0)
实际上,表达式中的那些元素是,它们只是简并版本(没有运算符的单个操作数)。递归定义意味着单个进程将被解析为简并前缀(没有运算符的前缀),然后被解析为简并选择(没有运算符的选择)。
您已经以正确关联的方式定义了前缀。如果你的意思是左联想,那么它应该是:prefix << Group(process) + Group(ZeroOrMore(prefix_op + process))
&#39;。&#39; s&#34;运营商&#34;这里?您是否正在尝试支持类似&#34; A = b。(c + d)&#34; ?如果没有,那么最好将基本操作数定义为Combine(ident + ZeroOrMore('.' + ident))
,然后添加为operand + ZeroOrMore( '+' + operand)
。或者使用操作数作为infixNotation中的基本元素(参见下文)。
如果这个表示法符合您的意图,请考虑使用infixNotation
助手来定义此语法:
choice = infixNotation(process,
[
('.', 2, opAssoc.LEFT, Prefix),
('+', 2, opAssoc.LEFT, Choice),
]
rmdef = ident("destination") + define + choice("rhs")
infixNotation
将处理任何()覆盖已定义的操作优先级。