gpt4 book ai didi

Python 的 pyparsing : Implementing grammar to parse logical AND expression

转载 作者:太空狗 更新时间:2023-10-30 01:19:55 26 4
gpt4 key购买 nike

我正在尝试解析和评估作为文件输入提供给我的表达式,其形式为:

var[3] = 0 and var[2] = 1
var[0] = 1 and var[2] = 0 and var[3] = 1
...

(实际上我也允许“多位访问”(即 var[X:Y] )但我们暂时忽略它...)
其中 var 是一个整数,[]表示位访问。
例如,对于 var = 0x9 ,上面的第一个表达式应该计算为 False ,第二个应该评估为 True0x9 = b1001 .
and=是我允许的唯一二元运算符,对于 =运算符,左操作数始终为 var[X]并且右操作数始终是一个数字。
我试着四处看看,发现这可以用 Python 的 pyparsing 来实现。 ,但我在尝试实现它时遇到了一些困难。
这是我到目前为止尝试过的,大致基于 this example (这是提供的众多示例之一 here ):

#!/usr/bin/env python
from pyparsing import Word, alphas, nums, infixNotation, opAssoc

class BoolAnd():
def __init__(self, pattern):
self.args = pattern[0][0::2]

def __bool__(self):
return all(bool(a) for a in self.args)

__nonzero__ = __bool__


class BoolEqual():
def __init__(self, pattern):
self.bit_offset = int(pattern[0][1])
self.value = int(pattern[0][-1])

def __bool__(self):
return True if (0xf >> self.bit_offset) & 0x1 == self.value else False # for now, let's assume var == 0xf

__nonzero__ = __bool__




variable_name = 'var'
bit_access = variable_name + '[' + Word(nums) + ']'
multibit_access = variable_name + '[' + Word(nums) + ':' + Word(nums) + ']'
value = Word(nums)

operand = bit_access | multibit_access | value

expression = infixNotation(operand,
[
('=', 2, opAssoc.LEFT, BoolEqual),
('AND', 2, opAssoc.LEFT, BoolAnd),
])


p = expression.parseString('var[3] = 1 AND var[1] = 0', True)

print 'SUCCESS' if bool(p) else 'FAIL'

我有三个问题需要帮助。

  1. 用于 var[X:Y] = Z 形式的多位访问,我该如何执行:
    一种。 X > Y
    b. Z < 2^{X - Y + 1}
    我假设这不能由语法本身强制执行(例如,对于形式的单位访问 var[X] = Y ,我可以通过语法强制执行 Y 将是 01 ,并且这将导致 expression.parseString() 失败,如果 Y != 0/1 出现异常。
  2. 最重要的是:为什么它总是打印 SUCCESS ?我做错了什么?
    对于输入 var[3] = 1 AND var[1] = 0应该打印 FAIL (您可以在我的示例中看到我将 var 硬编码为 0xf ,因此 var[3] = 1Truevar[1] = 0False )。
  3. 这引出了我的第三个问题:var不是 BoolEqual 的类成员它也不是全局性的......有没有办法以某种方式将它发送到BoolEqual__init__功能?

最佳答案

在着手解决问题之前,我建议对您的语法进行一些小的修改,主要是包含结果名称。添加这些名称将使您生成的代码更加清晰和健壮。我还在 pyparsing_common 命名空间类中使用了最近 pyparsing 版本中添加的一些表达式:

from pyparsing import pyparsing_common

variable_name = pyparsing_common.identifier.copy()
integer = pyparsing_common.integer.copy()
bit_access = variable_name('name') + '[' + integer('bit') + ']'
multibit_access = variable_name('name') + '[' + integer('start_bit') + ':' + integer('end_bit') + ']'

第 1a 部分:在“var[X:Y]”中强制使用有效值

这种工作最好使用解析操作和条件来完成。解析操作是解析时回调,您可以将其附加到 pyparsing 表达式以修改、增强、过滤结果,或者在验证规则失败时引发异常。这些是使用以下方法附加的:

expr.addParseAction(parse_action_fn)

并且 parse_action_fn 可以具有以下任何签名:

def parse_action_fn(parse_string, parse_location, matched_tokens):
def parse_action_fn(parse_location, matched_tokens):
def parse_action_fn(matched_tokens):
def parse_action_fn():

(查看更多信息 https://pythonhosted.org/pyparsing/pyparsing.ParserElement-class.html#addParseActio)n)

解析操作可以返回无、返回新标记、修改给定标记或引发异常。

如果所有解析操作都是根据输入标记评估某些条件,您可以将其编写为返回 True 或 False 的简单函数,如果返回 False,pyparsing 将引发异常。在您的情况下,您的第一个验证规则可以实现为:

def validate_multibit(tokens):
return tokens.end_bit > tokens.start_bit
multibit_access.addCondition(validate_multibit,
message="start bit must be less than end bit",
fatal=True)

或者甚至作为 Python lambda 函数:

multibit_access.addCondition(lambda t: t.end_bit > t.start_bit, 
message="start bit must be less than end bit",
fatal=True)

现在你可以试试这个:

multibit_access.parseString("var[3:0]")

你会得到这个异常:

pyparsing.ParseFatalException: start bit must be less than end bit (at char 0), (line:1, col:1)

第 1b 部分:在“var[X:Y] = Z”中强制使用有效值

您的第二条验证规则不仅涉及 v​​ar 位范围,还涉及与之比较的值。这将需要附加到完整 BoolEqual 的解析操作。我们可以将它放在 BoolEqual 的 __init__ 方法中,但我更喜欢尽可能分离独立的函数。由于我们将通过附加到 infixNotation 级别来添加验证,而 infixNotation 仅接受解析操作,因此我们需要将您的第二个验证规则编写为解析操作引发异常。 (我们还将使用最近才在 pyparsing 2.2.0 中发布的新功能,在 infixNotation 中的一个级别附加多个解析操作。)

这是我们希望执行的验证:

  • 如果是单个位表达式,值必须是0或1
  • 如果多位表达式 var[X:Y],值必须是 < 2**(Y-X+1)

    def validate_equality_args(tokens):    tokens = tokens[0]    z = tokens[-1]    if 'bit' in tokens:        if z not in (0,1):            raise ParseFatalException("invalid equality value - must be 0 or 1")    else:        x = tokens.start_bit        y = tokens.end_bit        if not z < 2**(y - x + 1):            raise ParseFatalException("invalid equality value")

And we attach this parse action to infixNotation using:

expression = infixNotation(operand,
[
('=', 2, opAssoc.LEFT, (validate_equality_args, BoolEqual)),
('AND', 2, opAssoc.LEFT, BoolAnd),
])

第 3 部分:支持除 0xf 之外的其他 var 名称和值

要处理各种名称的变量,可以在 BoolEqual 中添加一个类级别的字典:

class BoolEqual():
var_names = {}

并提前设置:

BoolEqual.var_names['var'] = 0xf

然后实现您的 __bool__ 方法:

返回 (self.var_names[self.var_name] >> self.bit_offset) & 0x1 == self.value

(这需要扩展以支持多位,但总体思路是相同的。)

关于Python 的 pyparsing : Implementing grammar to parse logical AND expression,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43088120/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com