Pyparsing Precedence 打破一元运算符
Pyparsing Precedence breaks with Unary operator
我正在尝试使用 pyparsing
实现 Python 的算术解析运算符的子集。我有以下代码实现我的解析器:
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']]
发生这种情况有什么原因吗?我错过了什么?
至于我,你应该将 -
定义为高于 **
('-', 1, pyparsing.opAssoc.RIGHT),
('**', 2, pyparsing.opAssoc.RIGHT),
这应该可以解决您的问题。
最少的工作代码
import 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,
[
('-', 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 Operator Precedence and Python - Operator precedence
编辑:
当我在 -
之前保留 **
但我使用
时,我可以获得 -500
for 5 * -10 ** 2
([[5, '*', ['-', [10, '**', 2]]]]
)
integer = pyparsing.pyparsing_common.signed_integer
import pyparsing
variable_names = pyparsing.Combine(pyparsing.Literal('$') + pyparsing.Word(pyparsing.alphanums + '_'))
#integer = pyparsing.Word(pyparsing.nums)
integer = pyparsing.pyparsing_common.signed_integer
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)
]
)
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]]]
pyparsing_common
的文档 other predefined expressions
我正在尝试使用 pyparsing
实现 Python 的算术解析运算符的子集。我有以下代码实现我的解析器:
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']]
发生这种情况有什么原因吗?我错过了什么?
至于我,你应该将 -
定义为高于 **
('-', 1, pyparsing.opAssoc.RIGHT),
('**', 2, pyparsing.opAssoc.RIGHT),
这应该可以解决您的问题。
最少的工作代码
import 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,
[
('-', 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 Operator Precedence and Python - Operator precedence
编辑:
当我在 -
之前保留 **
但我使用
-500
for 5 * -10 ** 2
([[5, '*', ['-', [10, '**', 2]]]]
)
integer = pyparsing.pyparsing_common.signed_integer
import pyparsing
variable_names = pyparsing.Combine(pyparsing.Literal('$') + pyparsing.Word(pyparsing.alphanums + '_'))
#integer = pyparsing.Word(pyparsing.nums)
integer = pyparsing.pyparsing_common.signed_integer
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)
]
)
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]]]
pyparsing_common
的文档 other predefined expressions