我希望能够使用pyparsing来解析以下语法:
1?1:0?1:0它应该被理解为一个标准的三元操作符condition ? true_part : false_part,其中两个简单地连接在一起,这样第一个的结果就成为了第二个的条件。
到目前为止,我有以下代码(简化):
import pyparsing as pp
TERNARY_INFIX = pp.infixNotation(
pp.pyparsing_common.integer, [
(("?", ":"), 3, pp.opAssoc.LEFT),
])
TERNARY_INFIX.parseString("1?1:0?1:0", parseAll=True)产生的结果:
ParseException:文本的预期结尾(第5节),(行:1,col:6)
除非我在这两个三元表达式中的一个附近添加括号,例如,"(1?1:0)?1:0"和"1?1:(0?1:0)"可以工作。
但是,我怎样才能使它没有括号,基本上只是从左到右阅读,以严格的left-associative方式工作呢?
编辑:
很好地阅读了三元操作符的结合性是如何工作的:Ternary operator left associativity -和左assoc的结果没有多大意义。然而,我试图模仿的语言实际上从左到右处理这样的表达。
发布于 2019-12-11 02:46:18
我认为这个运算符实际上是右结合的,而不是左的。如果我将您的代码更改为:
import pyparsing as pp
TERNARY_INFIX = pp.infixNotation(
pp.pyparsing_common.integer, [
(("?", ":"), 3, pp.opAssoc.RIGHT),
])
TERNARY_INFIX.runTests("""\
1?1:(0?1:0)
(1?1:0)?1:0
1?1:0?1:0
""", fullDump=False)然后,我得到了合理的输出,在没有家长的情况下,输入没有错误:
1?1:(0?1:0)
[[1, '?', 1, ':', [0, '?', 1, ':', 0]]]
(1?1:0)?1:0
[[[1, '?', 1, ':', 0], '?', 1, ':', 0]]
1?1:0?1:0
[[1, '?', 1, ':', [0, '?', 1, ':', 0]]]下面是一个更大的表达式,用于计算3个变量中最大的一个(来自本C教程:http://cprogramming.language-tutorial.com/2012/01/biggest-of-3-numbers-using-ternary.html):
TERNARY = pp.infixNotation(
pp.Char("abc"), [
(pp.oneOf("> <"), 2, pp.opAssoc.LEFT),
(("?", ":"), 3, pp.opAssoc.RIGHT),
])
TERNARY.runTests("""\
(a > b) ? ((a > c) ? a : c) : ((b > c) ? b : c)
a > b ? a > c ? a : c : b > c ? b : c
""", fullDump=False)给予:
(a > b) ? ((a > c) ? a : c) : ((b > c) ? b : c)
[[['a', '>', 'b'], '?', [['a', '>', 'c'], '?', 'a', ':', 'c'], ':', [['b', '>', 'c'], '?', 'b', ':', 'c']]]
a > b ? a > c ? a : c : b > c ? b : c
[[['a', '>', 'b'], '?', [['a', '>', 'c'], '?', 'a', ':', 'c'], ':', [['b', '>', 'c'], '?', 'b', ':', 'c']]]编辑:我现在看到了类似于重复二进制操作符的情况,比如"1 +2+ 3“。左关联的、化简解析不是将它们解析为[['1' '+' '2'] '+' '3'],而是将其解析为['1' '+' '2' '+' '3'],这取决于执行从左到右重复的计算。
当我添加三元运算符时,我没有想象像您正在解析的那种链式形式。对infixNotation的一行更改将成功地用左结合来解析表达式,但就像链接的二进制运算符一样,会给出一个未分组的结果:
[1, '?', 1, ':', 0, '?', 1, ':', 0]与重复的加法示例一样,由评估器执行连续的从左到右的计算,有时类似于:
def eval_ternary(tokens):
operands = tokens[0]
ret = bool(operands[0])
i = 1
while i < len(operands):
ret = bool(operands[i+1]) if ret else bool(operands[i+3])
i += 4
return ret如果您想手动修补您的patch解析代码,请更改:
elif arity == 3:
matchExpr = _FB(
lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr
) + Group(lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr)至:
elif arity == 3:
matchExpr = _FB(
lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr
) + Group(lastExpr + OneOrMore(opExpr1 + lastExpr + opExpr2 + lastExpr))
^^^^^^^^^^在pyparsing.py中进行此更改,或者将infxNotation的定义复制到您自己的代码中,并在那里进行更改。
我将在下一个版本的pyparsing解析中进行此更改。
编辑--修正了pyparation2.4.6中刚刚发布的版本。
发布于 2019-12-10 14:48:17
您可以尝试分别编写每个操作符。
import pyparsing as pp
TERNARY_INFIX = pp.infixNotation(
pp.pyparsing_common.integer, [
(("?"), 2, pp.opAssoc.LEFT),
((":"), 2, pp.opAssoc.LEFT)
])
TERNARY_INFIX.parseString("1?1:0?1:0", parseAll=True)输出:
[[[1, '?', 1], ':', [0, '?', 1], ':', 0]]https://stackoverflow.com/questions/59269200
复制相似问题