如何防止PLY中的表再生

时间:2012-09-28 17:47:48

标签: python parsing ply

我在命令行应用程序中使用PLY,我将其打包为通过pip安装的Python egg。每次我从命令行运行脚本时,都会看到以下消息:

"Generating LALR tables"

此外,parser.out和parsetab.py文件将写入调用脚本的目录。有没有办法用应用程序发送这些文件,以便它不会每次都重新生成表?

5 个答案:

答案 0 :(得分:11)

使用

yacc.yacc(debug=0, write_tables=0)

答案 1 :(得分:2)

您希望使用optimized mode,将lex称为:

lexer = lex.lex(optimize=1)

值得强调的是(from the same link):

  

在后续执行中,将简单地导入lextab.py以构建词法分析器。这种方法大大改善了词法分析器的启动时间,并且可以在Python的优化模式下工作。

     

在优化模式下运行时,请务必注意lex禁用大多数错误检查。因此,如果您确定一切正常并且您已准备好开始发布生产代码,那么这只是的推荐。

由于这是生产代码,这听起来就像你想要的那样。

在调查此问题时,我遇到了miscellaneous Yacc notes

  

由于LALR表的生成相对昂贵,因此如果可能,先前生成的表将被高速缓存并重用。通过对所有语法规则和优先规则进行MD5校验和来确定重新生成表的决定。只有在不匹配的情况下才会重新生成表格。

深入研究yacc内的yacc.py函数,我们发现优化忽略了以下代码段中的这种不匹配:

if optimize or (read_signature == signature):
    try:
        lr.bind_callables(pinfo.pdict)
        parser = LRParser(lr,pinfo.error_func)
        parse = parser.parse
        return parser

其中signatureparsetab.py中存储的校验和(_lr_signature)进行比较。

答案 2 :(得分:0)

我最终做的是关闭优化。我正在浏览PLY 3.4源代码,并在lexer代码中找到了这个小块:

# If in optimize mode, we write the lextab
if lextab and optimize:
    lexobj.writetab(lextab,outputdir)

return lexobj

通过将构建词法分析器和解析器的代码更改为:

self.lexer = lex.lex(module=self, optimize=False, debug=False, **kwargs)

self.lexer = lex.lex(module=self, optimize=False, debug=False, **kwargs)

我避免了所有文件写出。调试器将.out文件写入目录,Python文件是optimize标志的结果。

虽然这暂时有效,但我不能说我对这种做法感到非常满意。据推测,有一些方法可以保持优化,同时保持工作目录的清洁将是一个优秀的解决方案将导致更好的性能。如果其他人有更好的方法论,我不仅仅对此持开放态度。

答案 3 :(得分:0)

这是一个老问题,但是当我尝试使用outputdir yacc关键字参数将生成的解析器表放在我的项目中的特定目录中时,我遇到了与ply类似的问题 - 它会放置它们在那里,但每次都重新生成它们。我在github上找到了this补丁,它解决了再生问题而没有明显的不良影响。基本上,它所做的就是修改read_table类上的yacc方法以获取额外的参数 - outputdir - 并在重新生成之前搜索那里的目录。为了实现这一目标,还需要修改read_table(方法yacc)的唯一调用站点以传递outputdir关键字参数。

答案 4 :(得分:-1)

显然,ply.yacc中存在争论:

def yacc(method='LALR', debug=yaccdebug, module=None, tabmodule=tab_module, start=None, 
     check_recursion=1, optimize=0, write_tables=1, debugfile=debug_file,outputdir='',
     debuglog=None, errorlog = None, picklefile=None):

因此,您只需传递不同的errorlog和debuglog(使用debug()等方法,这些方法不会打印到stdout / stderr)。并指定一个固定的outputdir。这就是你需要做的一切。

更新:我刚检查过,这是正确的设置:

yacc.yacc(
    debug=False,                         # do not create parser.out
    outputdir=r"c:\temp\aaa" # instruct to place parsetab here
)

实际上你需要使用已经包含parsetab.py的outputdir。这将不仅消除消息,而且程序不会写出parsetab.py。它只会使用它。