Как @ sepp2k упоминает в своем комментарии, строка, которую вы пытаетесь проанализировать , не является инфиксной нотацией, хотя вы можете в конечном итоге использовать ее как операнд в инфиксной нотации. И аргументы, которые вы передаете iif
, сами могут быть выражениями инфиксной нотации. Таким образом, инфиксная запись определенно будет частью этого синтаксического анализатора, но она не будет той частью, которая анализирует ваш iif
вызов функции.
Вот как будет выглядеть вызов функции в pyparsing:
fn_call = pp.Group(var_name + LPAREN - pp.Group(pp.Optional(pp.delimitedList(arith_expr))) + RPAREN)
Операнды, которые вы используете для определения арифметического выражения, могут сами включать вызов функции, поэтому рекурсия парсера потребует от вас использования класса Forward в pyparsing.
arith_expr = pp.Forward()
Это позволит вам использовать arith_expr
в других подвыражениях (как мы только что сделали в fn_call), прежде чем мы полностью определим, как выглядит arith_expr
.
Сокращение до погони, вот минимальный парсер для разбора вашей 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,),
]
)
Используя runTests, мы можем попробовать его на нескольких тестовых примерах:
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