我在命令行应用程序中使用 PLY,我将其打包为 Python 鸡蛋,通过pip
. 每次我从命令行运行脚本时,都会看到以下消息:
"Generating LALR tables"
此外,parser.out 和 parsetab.py 文件被写入调用脚本的目录。是否有某种方法可以将这些文件与应用程序一起发送,以便它不会每次都重新生成表?
采用
yacc.yacc(debug=0, write_tables=0)
您想通过调用 lex 来使用优化模式:
lexer = lex.lex(optimize=1)
.
值得强调(来自同一个链接):
在随后的执行中,将简单地导入 lextab.py 来构建词法分析器。这种方法大大提高了词法分析器的启动时间,并且可以在 Python 的优化模式下工作。
在优化模式下运行时,请务必注意 lex 禁用大多数错误检查。因此,仅当您确定一切正常并且准备好开始发布生产代码时,才真正推荐这样做。
由于这是生产代码,这听起来正是您想要的。
.
在研究这个问题时,我发现了一些Yacc 的杂项注释:
由于 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
wheresignature
与存储在parsetab.py
(as _lr_signature
) 中的校验和进行比较。
我最终做的是关闭优化。我正在浏览 PLY 3.4 源代码,我在词法分析器代码中发现了这个小块:
# 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
标志的结果。
虽然这暂时有效,但我不能说我对这种方法完全满意。据推测,有一些方法可以保持优化,同时保持工作目录干净,这将是一个更好的解决方案,可以带来更好的性能。如果其他人有更好的方法,我会更愿意接受。
这是一个老问题,但是当我尝试使用 yacc 关键字参数将生成的解析器表放置在我的项目中的特定目录中时,我遇到了与 ply 类似的问题outputdir
——它会将它们放置在那里,但每次都重新生成它们时间不管。我在 github 上找到了这个补丁,它解决了再生问题,没有明显的不良影响。基本上,它所做的只是修改类read_table
上的方法yacc
以采用额外的参数 -- outputdir
-- 并在重新生成之前搜索那里的目录。为了使其工作,read_table
(在方法中yacc
)的唯一调用站点也需要修改以传递outputdir
关键字参数。
显然,在 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):
因此,您只需传递不同的错误日志和调试日志(使用 debug() 等不打印到 stdout/stderr 的方法)。你指定一个固定的输出目录。这就是你需要做的。
更新:我刚刚检查过,这是正确的设置:
yacc.yacc(
debug=False, # do not create parser.out
outputdir=r"c:\temp\aaa" # instruct to place parsetab here
)
实际上你需要使用一个已经包含 parsetab.py 的输出目录。这不仅会消除消息,而且您的程序也不会写出 parsetab.py。它只会使用它。