Cythonized pyparser工作不正常,函数的参数计数错误

2024-05-23 16:08:36 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个python项目来解析一些汇编代码

asm_parser/
  - asm.py
  - AST.py
  - obj_code.py
  ...

在语法下面,我将这个解析操作类设置为成功匹配(init函数获取标记)

self.dir_map_code_fp = pp.OneOrMore(...).setParseAction(Body)

在AST.py中,函数Body.__init__()标记正在接收

class Body(Node):
    def __init__(self, tokens):
        super(Body,self).__init__()
        self.code = tokens

然后我使用输入文件字符串对语法调用parseString()

self.parser_asm.parseString(string, parseAll=True)

为了隐藏源代码,我使用cythonize将这些python文件转换为.so文件。下面是我用来创建.so文件的setup.py文件

class MyBuildExt(build_ext):
    def run(self):
        build_ext.run(self)
        build_dir = Path(self.build_lib)
        root_dir = Path(__file__).parent
        target_dir = build_dir if not self.inplace else root_dir
        self.copy_file(Path('assembler') / '__init__.py', root_dir, target_dir)
        self.copy_file(Path('assembler') / '__main__.py', root_dir, target_dir)

    def copy_file(self, path, source_dir, destination_dir):
        if not (source_dir / path).exists():
            return
        shutil.copyfile(str(source_dir / path), str(destination_dir / path))

if __name__ == '__main__':
    ext_modules = [
        Extension(...) for f in files
    ]

    setup(
        name="myasm",
        ext_modules=cythonize(ext_modules, nthreads=8),
        cmdclass=dict(build_ext=MyBuildExt),
        packages=["asm"]
    )

创建so文件后,我创建了一个run_asm.py文件,以将asm代码作为包装运行。我将所有so文件模块导入此run_asm.py

import argparse
from asm import Preprocessor

if __name__ == "__main__":
    argParser = argparse.ArgumentParser(description='Assembler')
    argParser.add_argument('-asm', '--asm', required=True, help="Assembly file")
    argParser.add_argument('-outdir', '--outdir', required=False, default='.', help="default_img directory")
    args = argParser.parse_args()
    prep = Preprocessor()

在纯python形式下,项目正在运行。在cythonized.so表单Argparsing中,在调用Body.__init__()函数之前,读取所有内容的文件都在工作。init函数只取两个,这里给出了四个

Traceback (most recent call last):
  File "run_asm.py", line 30, in <module>
    prep.generate_ast(f, args.outdir)
  File "pkg/asm.py", line 145, in pkg.assembler.Preprocessor.generate_ast
  File "/u/nalaka/intelpython2/lib/python2.7/site-packages/pyparsing.py", line 1206, in parseString
    loc, tokens = self._parse( instring, 0 )
  File "/u/nalaka/intelpython2/lib/python2.7/site-packages/pyparsing.py", line 1072, in _parseNoCache
    loc,tokens = self.parseImpl( instring, preloc, doActions )
  File "/u/nalaka/intelpython2/lib/python2.7/site-packages/pyparsing.py", line 2923, in parseImpl
    loc, tokens = self_expr_parse( instring, loc, doActions, callPreParse=False )
  File "/u/nalaka/intelpython2/lib/python2.7/site-packages/pyparsing.py", line 1072, in _parseNoCache
    loc,tokens = self.parseImpl( instring, preloc, doActions )
  File "/u/nalaka/intelpython2/lib/python2.7/site-packages/pyparsing.py", line 2607, in parseImpl
    return e._parse( instring, loc, doActions )
  File "/u/nalaka/intelpython2/lib/python2.7/site-packages/pyparsing.py", line 1098, in _parseNoCache
    tokens = fn( instring, tokensStart, retTokens )
  File "/u/nalaka/intelpython2/lib/python2.7/site-packages/pyparsing.py", line 819, in wrapper
    ret = func(*args[limit[0]:])
  File "pkg/AST.py", line 28, in pkg.AST.Body.__init__
TypeError: __init__() takes exactly 2 positional arguments (4 given)

我查看了pyparsing.py代码,下面的funcBody.__init__()函数。在纯python版本limit[0] = 2中,但在cythonized版本limit[0] = 0中,参数计数在这两个版本中发生了变化。我无法获得更多关于这方面的信息

def wrapper(*args):
    while 1:
        try:
            ret = func(*args[limit[0]:])
            foundArity[0] = True
            return ret

我还发现parseAction()是具有0-3个参数的可调用方法C{fn(s,loc,toks)}, C{fn(loc,toks)}, C{fn(toks)}, or just C{fn()}。我想知道这是否与此有关(不知怎么搞砸了争论的重点) 谁能帮我解决这个问题。我使用的是Intelpython2.7、pyparsing-2.4.7和Cython'0.25.2'


Tags: 文件inpyselfinitlibpackagesdir
2条回答

即使是Cython '0.29.17'也会出现同样的错误。如果你被python2困住了,这个变通方法会有帮助。 即使我将函数定义为def __init__(self, s, loc, tokens):,仍然会出现错误,因为对于匹配相同语法的不同标记序列,将使用不同数量的参数调用parseAction()中的注册函数。 由于这种动态行为,我修改了函数以接受可变数量的参数。当arg计数为2(自包含)时,第二个是令牌,当计数为4时,它是最后一个。所以得到最后一个arg就足够了

class Body(Node):
    def __init__(self, *args):
        super(Body,self).__init__()
        tokens = args[-1]
        self.code = tokens

我不熟悉cythonize,一定会调查的

Pyparsing处理各种方法签名的内部代码检查引发的TypeErrors,以检测TypeError是来自其自己的签名测试(它是内部创建的,因此被捕获并处理)还是来自解析操作的主体(这将是由用户提供的代码创建的TypeError,因此必须重新引发)。似乎此TypeError内部与用户提供的检测逻辑在cythonized代码中无法正常工作

能否尝试将Body.__init__签名从def __init__(self, tokens):更改为def __init__(self, s, loc, tokens):?这将在python和cython版本中继续工作

如果有任何方法可以让你转向Python3,我强烈鼓励你这么做

相关问题 更多 >