Pyparsing Precedence 打破一元运算符

我正在尝试使用pyparsing. 我有以下代码实现我的解析器:


variable_names = pyparsing.Combine(pyparsing.Literal('$') + pyparsing.Word(pyparsing.alphanums + '_'))

integer = pyparsing.Word(pyparsing.nums)

double = pyparsing.Combine(pyparsing.Word(pyparsing.nums) + '.' + pyparsing.Word(pyparsing.nums))

parser = pyparsing.operatorPrecedence(variable_names | double | integer, [

                                ('**', 2, pyparsing.opAssoc.RIGHT),

                                ('-', 1, pyparsing.opAssoc.RIGHT),

                                (pyparsing.oneOf('* / // %'), 2, pyparsing.opAssoc.LEFT),

                                (pyparsing.oneOf('+ -'), 2, pyparsing.opAssoc.LEFT),

                                (pyparsing.oneOf('> >= < <= == !='), 2, pyparsing.opAssoc.LEFT),

                                ('not', 1, pyparsing.opAssoc.RIGHT),

                                ('and', 2, pyparsing.opAssoc.LEFT),

                                ('or', 2, pyparsing.opAssoc.LEFT)])

在大多数情况下,这工作正常,但有时当我使用一元时它会中断-。具体来说,我认为(我可能是错的)如果我-在更高优先级的操作数之后使用它会中断,在这种情况下就是**. 以下示例显示了该问题:


parsing 5 * 10 * -2             yields: ['5', '*', '10', '*', ['-', '2']]

parsing 5 * 10 ** -2            yields: ['5', '*', '10']               # Wrong

parsing 5 * 10 ** (-2)          yields: ['5', '*', ['10', '**', ['-', '2']]]

parsing 5 and not 8             yields: ['5', 'and', ['not', '8']]

parsing 5 and - 8               yields: ['5', 'and', ['-', '8']]

发生这种情况有什么原因吗?我错过了什么?


慕无忌1623718
浏览 96回答 2
2回答

米琪卡哇伊

至于我,你应该定义-为更高**('-', 1, pyparsing.opAssoc.RIGHT),('**', 2, pyparsing.opAssoc.RIGHT),这应该可以解决您的问题。最小的工作代码import pyparsingvariable_names = pyparsing.Combine(pyparsing.Literal('$') + pyparsing.Word(pyparsing.alphanums + '_'))integer = pyparsing.Word(pyparsing.nums)double = pyparsing.Combine(pyparsing.Word(pyparsing.nums) + '.' + pyparsing.Word(pyparsing.nums))parser = pyparsing.operatorPrecedence(            variable_names | double | integer,            [                ('-',  1, pyparsing.opAssoc.RIGHT),                ('**', 2, pyparsing.opAssoc.RIGHT),                (pyparsing.oneOf('* / // %'), 2, pyparsing.opAssoc.LEFT),                (pyparsing.oneOf('+ -'), 2, pyparsing.opAssoc.LEFT),                (pyparsing.oneOf('> >= < <= == !='), 2, pyparsing.opAssoc.LEFT),                ('not', 1, pyparsing.opAssoc.RIGHT),                ('and', 2, pyparsing.opAssoc.LEFT),                ('or',  2, pyparsing.opAssoc.LEFT)            ]        )examples = [    "5 * 10 ** -2",    "5 * 10 * -2",    "5 * 10 ** (-2)",    "5 * -10 ** 2",    "5 * (-10) ** 2",        "5 and not 8",    "5 and -8",    "1 ** -2",    "-1 ** 2",]longest = max(map(len, examples))for ex in examples:    result = parser.parseString(ex)    print(f'{ex:{longest}}  <=>  {result}')结果:5 * 10 ** -2    <=>  [['5', '*', ['10', '**', ['-', '2']]]]5 * 10 * -2     <=>  [['5', '*', '10', '*', ['-', '2']]]5 * 10 ** (-2)  <=>  [['5', '*', ['10', '**', ['-', '2']]]]5 * -10 ** 2    <=>  [['5', '*', [['-', '10'], '**', '2']]]5 * (-10) ** 2  <=>  [['5', '*', [['-', '10'], '**', '2']]]5 and not 8     <=>  [['5', 'and', ['not', '8']]]5 and -8        <=>  [['5', 'and', ['-', '8']]]1 ** -2         <=>  [['1', '**', ['-', '2']]]-1 ** 2         <=>  [[['-', '1'], '**', '2']]顺便说一句:为了比较:C 运算符优先级和Python - 运算符优先级编辑:我之前保留时可以得到-500( 5 * -10 ** 2)但我使用[[5, '*', ['-', [10, '**', 2]]]]**-integer = pyparsing.pyparsing_common.signed_integerimport pyparsingvariable_names = pyparsing.Combine(pyparsing.Literal('$') + pyparsing.Word(pyparsing.alphanums + '_'))#integer = pyparsing.Word(pyparsing.nums)integer = pyparsing.pyparsing_common.signed_integerdouble = pyparsing.Combine(pyparsing.Word(pyparsing.nums) + '.' + pyparsing.Word(pyparsing.nums))parser = pyparsing.operatorPrecedence(            variable_names | double | integer,            [                ('**', 2, pyparsing.opAssoc.RIGHT),                ('-',  1, pyparsing.opAssoc.RIGHT),                (pyparsing.oneOf('* / // %'), 2, pyparsing.opAssoc.LEFT),                (pyparsing.oneOf('+ -'), 2, pyparsing.opAssoc.LEFT),                (pyparsing.oneOf('> >= < <= == !='), 2, pyparsing.opAssoc.LEFT),                ('not', 1, pyparsing.opAssoc.RIGHT),                ('and', 2, pyparsing.opAssoc.LEFT),                ('or',  2, pyparsing.opAssoc.LEFT)            ]        )examples = [    "5 * 10 ** -2",    "5 * 10 * -2",    "5 * 10 ** (-2)",    "5 * -10 ** 2",    "5 * (-10) ** 2",        "5 and not 8",    "5 and -8",    "1 ** -2",    "-1 ** 2",]longest = max(map(len, examples))for ex in examples:    result = parser.parseString(ex)    print(f'{ex:{longest}}  <=>  {result}')结果:5 * 10 ** -2    <=>  [[5, '*', [10, '**', -2]]]5 * 10 * -2     <=>  [[5, '*', 10, '*', ['-', 2]]]5 * 10 ** (-2)  <=>  [[5, '*', [10, '**', ['-', 2]]]]5 * -10 ** 2    <=>  [[5, '*', ['-', [10, '**', 2]]]]5 * (-10) ** 2  <=>  [[5, '*', [['-', 10], '**', 2]]]5 and not 8     <=>  [[5, 'and', ['not', 8]]]5 and -8        <=>  [[5, 'and', ['-', 8]]]1 ** -2         <=>  [[1, '**', -2]]-1 ** 2         <=>  [['-', [1, '**', 2]]]Doc forpyparsing_common与其他预定义的表达式

翻阅古今

很抱歉带回这么老的主题,但我正在为我的项目编写一个非常相似的解析器,它混合了布尔逻辑和数学运算符,我最终得到了一个看起来很合适的相似代码。由于此处给出的解析器遇到与我相同的问题,因此我将使用它来说明我的问题。我无法让它解析“$true == not $false”,基本上,如果没有括号,比较后的任何“not”都不会起作用。$true == $false&nbsp; &nbsp; &nbsp; &nbsp; <=>&nbsp; [['$true', '==', '$false']]$true == not $false&nbsp; &nbsp; <=>&nbsp; ['$true']$true == (not $false)&nbsp; <=>&nbsp; [['$true', '==', ['not', '$false']]]如您所见,没有“not”或有括号,它解析得很好,但是有一个简单的“not”,它似乎忽略了“==”之后的所有内容在 infix_notation(以前的 operatorPrecedence)中先移动“not”运算符是什么修复方法。然后我得到了这些结果:$true == not $false&nbsp; &nbsp; <=>&nbsp; [['$true', '==', ['not', '$false']]]$true == (not $false)&nbsp; <=>&nbsp; [['$true', '==', ['not', '$false']]]这是伟大的,但当然它打破了诸如“$true and not 10 == 9”之类的运算符优先级,我想像在 python 中那样解析“$true and not (10 == 9)”而不是解析像那样:$true and not 10 == 9&nbsp; <=>&nbsp; [['$true', 'and', [['not', 10], '==', 9]]]我想知道您是否在解析器的实现中遇到过这些用例并找到了解决方法。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python