我们正在研究减少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)
这可以捕获天真的案例,但不能用于不属于扩展的括号和美元。
有什么想法吗?谢谢!
答案 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
,解析器在没有它的情况下挂起,所以我想它需要一些东西来启动规则。
希望这有助于其他人!