Python pyparsing如何使用infixNotation表示iif(cond,如果为true,如果为false)

Python pyparsing如何使用infixNotation表示iif(cond,如果为true,如果为false),python,python-3.x,pyparsing,Python,Python 3.x,Pyparsing,我需要使用pyparsing来解析它:iif(条件,值如果为真,值如果为假),但是这种三元比较应该有另一个比较,我的意思是: `iif(iif(condition1,value1,value2)>iif(condition2,value1,value2),value3,value4)` 我发现: integer = Word(nums) variable = Word(alphas, alphanums) boolLiteral = oneOf("true false") operand

我需要使用pyparsing来解析它:
iif(条件,值如果为真,值如果为假)
,但是这种三元比较应该有另一个比较,我的意思是:

`iif(iif(condition1,value1,value2)>iif(condition2,value1,value2),value3,value4)`
我发现:

integer = Word(nums)
variable = Word(alphas, alphanums)
boolLiteral = oneOf("true false")
operand = boolLiteral | variable | integer
comparison_op = oneOf("== <= >= != < >")
QM,COLON = map(Literal,"?:")
expr = infixNotation(operand,
    [
    (comparison_op, 2, opAssoc.LEFT),
    ((QM,COLON), 3, opAssoc.LEFT),
    ])

我在使用我以前的一些规则。现在我投票结束这篇文章。

正如@sepp2k在他的评论中提到的,您试图解析的字符串不是中缀符号,尽管您最终可能会在中缀符号中用作操作数。传递给
iif
的参数本身可能是中缀符号表达式。所以中缀符号肯定是这个解析器的一部分,但它不是解析
iif
函数调用的部分

以下是pyparsing中函数调用的外观:

fn_call = pp.Group(var_name + LPAREN - pp.Group(pp.Optional(pp.delimitedList(arith_expr))) + RPAREN)
用于定义算术表达式的操作数本身可能包含函数调用,因此解析器的递归将要求您使用pyparsing的Forward类

arith_expr = pp.Forward()
这将允许您在完全定义
arith_expr
外观之前,在其他子表达式中使用
arith_expr
(就像我们刚才在fn_调用中所做的那样)

切中要害的是,这里有一个最小的解析器来解析您的
iif
函数:

import pyparsing as pp

# for recursive infix notations, or those with many precedence levels, it is best to enable packrat parsing
pp.ParserElement.enablePackrat()
LPAREN, RPAREN = map(pp.Suppress, "()")

arith_expr= pp.Forward()

var_name = pp.pyparsing_common.identifier()
integer = pp.pyparsing_common.integer()
fn_call = pp.Group(var_name + LPAREN - pp.Group(pp.Optional(pp.delimitedList(arith_expr))) + RPAREN)
arith_operand = fn_call | var_name | integer

rel_comparison_operator = pp.oneOf("< > <= >=")
eq_comparison_operator = pp.oneOf("== !=")
plus_minus_operator = pp.oneOf("+ -")
mult_div_operator = pp.oneOf("* / %")

arith_expr <<= pp.infixNotation(arith_operand,
                                [
                                    # add other operators here - in descending order of precedence
                                    # http://www.tutorialspoint.com/cprogramming/c_operators_precedence.htm
                                    (mult_div_operator, 2, pp.opAssoc.LEFT,),
                                    (plus_minus_operator, 2, pp.opAssoc.LEFT,),
                                    (rel_comparison_operator, 2, pp.opAssoc.LEFT,),
                                    (eq_comparison_operator, 2, pp.opAssoc.LEFT,),
                                ]
                                )
印刷品:

cos(60)
[['cos', [60]]]
[0]:
  ['cos', [60]]
  [0]:
    cos
  [1]:
    [60]


sqrt(1 - sin(60) * sin(60))
[['sqrt', [[1, '-', [['sin', [60]], '*', ['sin', [60]]]]]]]
[0]:
  ['sqrt', [[1, '-', [['sin', [60]], '*', ['sin', [60]]]]]]
  [0]:
    sqrt
  [1]:
    [[1, '-', [['sin', [60]], '*', ['sin', [60]]]]]
    [0]:
      [1, '-', [['sin', [60]], '*', ['sin', [60]]]]
      [0]:
        1
      [1]:
        -
      [2]:
        [['sin', [60]], '*', ['sin', [60]]]
        [0]:
          ['sin', [60]]
          [0]:
            sin
          [1]:
            [60]
        [1]:
          *
        [2]:
          ['sin', [60]]
          [0]:
            sin
          [1]:
            [60]


divmod(a, 100)
[['divmod', ['a', 100]]]
[0]:
  ['divmod', ['a', 100]]
  [0]:
    divmod
  [1]:
    ['a', 100]


iif(iif(condition1,value1,value2)>iif(condition2,value1,value2),value3,value4)
[['iif', [[['iif', ['condition1', 'value1', 'value2']], '>', ['iif', ['condition2', 'value1', 'value2']]], 'value3', 'value4']]]
[0]:
  ['iif', [[['iif', ['condition1', 'value1', 'value2']], '>', ['iif', ['condition2', 'value1', 'value2']]], 'value3', 'value4']]
  [0]:
    iif
  [1]:
    [[['iif', ['condition1', 'value1', 'value2']], '>', ['iif', ['condition2', 'value1', 'value2']]], 'value3', 'value4']
    [0]:
      [['iif', ['condition1', 'value1', 'value2']], '>', ['iif', ['condition2', 'value1', 'value2']]]
      [0]:
        ['iif', ['condition1', 'value1', 'value2']]
        [0]:
          iif
        [1]:
          ['condition1', 'value1', 'value2']
      [1]:
        >
      [2]:
        ['iif', ['condition2', 'value1', 'value2']]
        [0]:
          iif
        [1]:
          ['condition2', 'value1', 'value2']
    [1]:
      value3
    [2]:
      value4

iif
不是中缀运算符。它的语法与函数调用相同,因此您应该查看如何解析函数调用的示例,而不是如何解析
?:
@sepp2k我没有理解你的意思,我的意思是a)
iif
不是中缀运算符(即出现在其操作数之间的运算符),b)
iif
的语法是
iif(foo,bar,baz)
,这与函数调用的语法非常相似(与
foo?bar:baz
的语法根本不相似)三值运算
?:
是“中缀”,因为运算符位于操作数->
cond\u值之间?真值:假值
。相比之下,
iif(cond\u value,true\u value,false\u value)
只是一个函数调用,用3个参数调用
iif
函数。谢谢你,PaulMcG先生,你的建议非常有效,但是我想知道如何修复它,以便使用
iif
作为关键字。如果
iif
是关键字而不是函数调用,语法会是什么?您是否为您正在构建的语言编写了BNF?这将是决定什么应该是关键字以及其各自语法如何工作的一大步。然后编写一些您要解析的示例代码,看看BNF是否可以使用它,或者是否有歧义。在这一点上,转换到pyparsing、PLY或其他包将更加简单。。。您的代码允许我输入
iff(…
iiif(
)。但是没关系。我可以在将输入的文本交给解析器之前检查它。您是否也接受类似
x=iif(条件、真值、假值)的代码
?如果是这样,那么我认为
iif
实际上更像是一个内置函数,而不是一个关键字。同样,您的BNF和代码示例将帮助您决定如何继续。如果继续使用此语法,您可能应该将
iif
定义为
关键字(“iif”)+LPAREN+arith_expr+'、“+arith_expr+”、“+arith_expr+RPAREN
强制使用3个参数。我认为您应该能够解析像“iff”或“iif”这样的函数-难道用户不可能在自己的代码中使用这些名称定义函数吗?]此语法不使用标识符,因为在上一步中,我获取标识符并将其替换为其值,因此语法将仅是带有数字和内联条件的数学运算。我使用的唯一关键字是
iif
。问题是是可以嵌套的数学运算和条件。
tests = """\
    cos(60)
    sqrt(1 - sin(60) * sin(60))
    divmod(a, 100)
    iif(iif(condition1,value1,value2)>iif(condition2,value1,value2),value3,value4)
    """
arith_expr.runTests(tests)
cos(60)
[['cos', [60]]]
[0]:
  ['cos', [60]]
  [0]:
    cos
  [1]:
    [60]


sqrt(1 - sin(60) * sin(60))
[['sqrt', [[1, '-', [['sin', [60]], '*', ['sin', [60]]]]]]]
[0]:
  ['sqrt', [[1, '-', [['sin', [60]], '*', ['sin', [60]]]]]]
  [0]:
    sqrt
  [1]:
    [[1, '-', [['sin', [60]], '*', ['sin', [60]]]]]
    [0]:
      [1, '-', [['sin', [60]], '*', ['sin', [60]]]]
      [0]:
        1
      [1]:
        -
      [2]:
        [['sin', [60]], '*', ['sin', [60]]]
        [0]:
          ['sin', [60]]
          [0]:
            sin
          [1]:
            [60]
        [1]:
          *
        [2]:
          ['sin', [60]]
          [0]:
            sin
          [1]:
            [60]


divmod(a, 100)
[['divmod', ['a', 100]]]
[0]:
  ['divmod', ['a', 100]]
  [0]:
    divmod
  [1]:
    ['a', 100]


iif(iif(condition1,value1,value2)>iif(condition2,value1,value2),value3,value4)
[['iif', [[['iif', ['condition1', 'value1', 'value2']], '>', ['iif', ['condition2', 'value1', 'value2']]], 'value3', 'value4']]]
[0]:
  ['iif', [[['iif', ['condition1', 'value1', 'value2']], '>', ['iif', ['condition2', 'value1', 'value2']]], 'value3', 'value4']]
  [0]:
    iif
  [1]:
    [[['iif', ['condition1', 'value1', 'value2']], '>', ['iif', ['condition2', 'value1', 'value2']]], 'value3', 'value4']
    [0]:
      [['iif', ['condition1', 'value1', 'value2']], '>', ['iif', ['condition2', 'value1', 'value2']]]
      [0]:
        ['iif', ['condition1', 'value1', 'value2']]
        [0]:
          iif
        [1]:
          ['condition1', 'value1', 'value2']
      [1]:
        >
      [2]:
        ['iif', ['condition2', 'value1', 'value2']]
        [0]:
          iif
        [1]:
          ['condition2', 'value1', 'value2']
    [1]:
      value3
    [2]:
      value4