在缩短和简化的伪代码中,我有如下内容:

arg = Forward()
...
...
func_call = somestuff + arg

term = ... | ... | arg

expression = infix_notation(term, operator_rules)
...
...
arg <<= expression | func_call | ... | ...
...
statement = var + ASSIGN + expression
code_line = Optional(White()) + (statement | func_call | expression) + Optional(dbl_slash_comment).leaveWhitespace()

所以我不知道如何在这里解决的问题是,我需要几乎相同的代码,但在operator_rules中有不同的parse_action.如果expression是这里最后定义的东西(不依赖于任何Forward()组件),那么我只需要创建一个模块,在其中保存其他所有内容,然后只需将term导入两个不同的模块,并根据需要在operator_rules中使用不同的解析操作来使用不同的expression infix_notation.

我目前的解决方案是使用此代码创建两个相同的模块,然后修改其中一个模块中的parse_action函数.但这感觉像是一种糟糕的做法.如果我需要更改此解析器中的某些内容,则需要在两个模块中都进行更改.

我觉得在这里我对pyparsing的工作原理一无所知.

我知道可以使用set_parse_action()来导入ParserElement并重写其解析操作,但不知道如何使用infix_notation元素来实现.Another issue是向前定义的arg依赖于infix_notation元素,所以即使我只需导入expression并在infix_notation中重写其解析操作,也不会重写expression和向前定义的arg之后的元素,对吗?

我try 将整个解析器放在一个函数中,然后使用查看输入的if语句创建具有不同运算符规则的infix_notation.它是有效的,但这看起来很笨重,仍然不能解决"一些涉及到远期定义项的元素的导入".事实上,由于我现在已经将所有内容放在一个函数中,所以我甚至不能导入最后的code_line个ParserElement以在我定义条件 struct 的另一个模块中使用.

因此,我认为问题有两个方面:

  1. 有什么方法可以覆盖infix_notation的OPERATOR_RULES(包括解析操作和运算符规则的总列表)吗?(为什么我真的需要它-部分原因是随着嵌套表达式的数量增加,执行时间似乎呈指数增长,所以我根据要解析的字符串限制了定义的运算符的数量).
  2. 在infix_notation中用作term的前向定义元素似乎阻止了我导入infix_notation元素来重写operator_rules,如果这是可能的话.

我甚至不确定这里是否有一个优雅的解决方案可以让代码保持干燥,但任何见解/建议都是非常感谢的!

推荐答案

与其修改中缀表示法表达式中的解析操作,不如try 将代码的infix_notation部分包装在一个函数中,该函数接受包含这些函数的参数.

下面是一个函数,它使用作为参数传入的类的静态方法构建中缀表示法解析器:

import pyparsing as pp

def make_custom_infix_notation(fn_object):
    operand = pp.common.number()

    expr = pp.infix_notation(
        operand,
        [
            (pp.oneOf("* /"), 2, pp.OpAssoc.LEFT, fn_object.mul),
            (pp.oneOf("+ -"), 2, pp.OpAssoc.LEFT, fn_object.add),
        ]
    )
    return expr

下面是一个类,它将每个二元操作转换为带有两个参数的函数调用:

class MakeIntoFunctions:
    @staticmethod
    def mul(tokens):
        tokens = tokens[0]
        cur_op = str(tokens[0])
        for operator, operand in zip(tokens[1::2], tokens[2::2]):
            function = {'*': 'MUL', '/': 'DIV'}[operator]
            cur_op = f"{function}({cur_op},{operand})"
        return cur_op

    @staticmethod
    def add(tokens):
        tokens = tokens[0]
        cur_op = str(tokens[0])
        for operator, operand in zip(tokens[1::2], tokens[2::2]):
            function = {'+': 'ADD', '-': 'SUB'}[operator]
            cur_op = f"{function}({cur_op},{operand})"
        return cur_op

下面是使用此函数的示例:

parser = make_custom_infix_notation(MakeIntoFunctions)
print(parser.parse_string("1+2/3+11/(12+7)"))

打印内容如下:

['ADD(ADD(1,DIV(2,3)),DIV(11,ADD(12,7)))']

例如,您可以编写另一个转换为后缀的类,然后只需传递该类即可.

编辑:传入的对象不一定是一个类,它可以很容易地是namedtupletyping.NamedTuple,带有对成员的解析操作.或者甚至只是一个字典(不过,您需要更改要完成的引用My Key字符串,而不是按属性名称).

Python相关问答推荐

如何调整spaCy token 化器,以便在德国模型中将数字拆分为行末端的点

如何在具有重复数据的pandas中对groupby进行总和,同时保留其他列

Pandas 在最近的日期合并,考虑到破产

如何在UserSerializer中添加显式字段?

Asyncio:如何从子进程中读取stdout?

如何使用scipy的curve_fit与约束,其中拟合的曲线总是在观测值之下?

从嵌套的yaml创建一个嵌套字符串,后面跟着点

SQLAlchemy bindparam在mssql上失败(但在mysql上工作)

Plotly Dash Creating Interactive Graph下拉列表

Python中的变量每次增加超过1

在嵌套span下的span中擦除信息

使用BeautifulSoup抓取所有链接

python panda ExcelWriter切换动态公式到数组公式

当条件满足时停止ODE集成?

如何在Gekko中使用分层条件约束

统计numpy. ndarray中的项目列表出现次数的最快方法

有没有办法让Re.Sub报告它所做的每一次替换?

如何获取包含`try`外部堆栈的`__traceback__`属性的异常

为什么我只用exec()函数运行了一次文件,而Python却运行了两次?

Django更新视图未更新