首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >连连三值算子

连连三值算子
EN

Stack Overflow用户
提问于 2019-12-10 14:13:11
回答 2查看 236关注 0票数 2

我希望能够使用pyparsing来解析以下语法:

代码语言:javascript
复制
1?1:0?1:0

它应该被理解为一个标准的三元操作符condition ? true_part : false_part,其中两个简单地连接在一起,这样第一个的结果就成为了第二个的条件。

到目前为止,我有以下代码(简化):

代码语言:javascript
复制
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的结果没有多大意义。然而,我试图模仿的语言实际上从左到右处理这样的表达。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-12-11 02:46:18

我认为这个运算符实际上是右结合的,而不是左的。如果我将您的代码更改为:

代码语言:javascript
复制
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)

然后,我得到了合理的输出,在没有家长的情况下,输入没有错误:

代码语言:javascript
复制
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):

代码语言:javascript
复制
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)

给予:

代码语言:javascript
复制
(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的一行更改将成功地用左结合来解析表达式,但就像链接的二进制运算符一样,会给出一个未分组的结果:

代码语言:javascript
复制
[1, '?', 1, ':', 0, '?', 1, ':', 0]

与重复的加法示例一样,由评估器执行连续的从左到右的计算,有时类似于:

代码语言:javascript
复制
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解析代码,请更改:

代码语言:javascript
复制
       elif arity == 3:
            matchExpr = _FB(
                lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr
            ) + Group(lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr)

至:

代码语言:javascript
复制
       elif arity == 3:
            matchExpr = _FB(
                lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr
            ) + Group(lastExpr + OneOrMore(opExpr1 + lastExpr + opExpr2 + lastExpr))
                                 ^^^^^^^^^^

在pyparsing.py中进行此更改,或者将infxNotation的定义复制到您自己的代码中,并在那里进行更改。

我将在下一个版本的pyparsing解析中进行此更改。

编辑--修正了pyparation2.4.6中刚刚发布的版本。

票数 2
EN

Stack Overflow用户

发布于 2019-12-10 14:48:17

您可以尝试分别编写每个操作符。

代码语言:javascript
复制
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)

输出:

代码语言:javascript
复制
[[[1, '?', 1], ':', [0, '?', 1], ':', 0]]
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59269200

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档