解析用pyparsing进行扩展

时间:2014-07-15 06:43:19

标签: python nested pyparsing

我们正在研究减少Make语法的语法,并遇到嵌套扩展的障碍。

以下是我们要解析的内容的一个示例:

$(error Not implemented for this OS: $(filter XYZ_OS_%, $(.VARIABLES)))

这是嵌套表达式问题的一个变种,许多人似乎都在努力解决这个问题。这有点困难,因为嵌套表达式可以包含自由格式字符串,包括括号和美元:

$(error Something went wrong (you owe me $$$$$$.))

$字符会在此重复转义。)

我有一个初步语法,但我想不出定义text规则的方法。

name = Word(alphanums + '_')
text = CharsNotIn('$)')  # This does not work generally.

expansion = Suppress('$(') + name + Suppress(')')

sub_expression = Forward()
expression = ZeroOrMore(sub_expression)

error = Suppress('$(error ') + expression + Suppress(')')
info = Suppress('$(info ') + expression + Suppress(')')
pattern = Word(alphanums + '._%')
filter = Suppress('$(filter ') + pattern + Suppress(',') + expression + Suppress(')')

sub_expression << (text | error | filter | info | expansion)

# This accepts all kinds of invalid Make syntax,
# but is useful for testing line-by-line.
test_grammar = OneOrMore(text | expansion | error | filter | info)

这可以捕获天真的案例,但不能用于不属于扩展的括号和美元。

有什么想法吗?谢谢!

1 个答案:

答案 0 :(得分:0)

我们想通了!

我们意识到Make允许在$(error)和朋友中使用括号,但前提是它们必须平衡。它必须是这样的,否则它不会知道如何处理悬挂的表达式,如:

$(error This(thing(is)crazy)

所以我们错过了语法的一个重要部分:将括号内的文本与其他不透明文本匹配的规则。

然后我们终于找到SkipTo,这是我们最初寻找的那种东西。它会消耗所有文本,直到传递给它的规则匹配为止,这样我们就可以(减少):

name = Word(alphanums + '_')
expansion = Suppress('$(') + name + Suppress(')')

end_of_text = Literal('$(') | Literal('(') | Literal(')')
text = NotAny(end_of_text) + SkipTo(end_of_text).leaveWhitespace()
parenthesized_text = Combine(Literal('(') + SkipTo(')').leaveWhitespace() + Literal(')'))

sub_expression = Forward()
expression = ZeroOrMore(sub_expression | parenthesized_text | text)

error = Suppress('$(error ') + expression + Suppress(')')

sub_expression << (error | expansion)

grammar = OneOrMore(error)

我们看到,当我们在表达式中时,文本以带括号的文本和扩展交错排列。为了识别文字,我们会注意$(,它会启动扩展,(,它会启动带括号的文本和),这会结束整个事情。

基本上,error匹配$(error后跟一系列表达式,并巧妙地将它们作为树返回。 E.g。

$(error Something went wrong (you owe me.) Status: $(status))

解析成:

error: $(error
    text: Something went wrong
    parenthesized_text: (you owe me.)
    text: Status:
    expansion: $(status)

我现在看到这可能不正确,例如我们不承认括号内的文字扩展。我们看看能否弄明白。

我唯一能解释的是为什么在NotAny中需要text,解析器在没有它的情况下挂起,所以我想它需要一些东西来启动规则。

希望这有助于其他人!