我在一个命令行应用程序中使用PLY,将其打包为Python egg以通过pip
进行安装。每次我从命令行运行脚本时,都会看到以下信息:
"Generating LALR tables"
此外,解析器输出文件parser.out和parsetab.py文件将被写入调用脚本的目录。有没有办法将这些文件随应用程序一起打包,以便它不必每次都重新生成表格?
yacc.yacc(debug=0, write_tables=0)
debug=False, write_tables=False
。虽然 0
可以工作,但使用 True
/False
更明确,文档也使用布尔值而不是整数。 - Bakuriulexer = lex.lex(optimize=1)
值得强调的是(来自同一链接):
在后续执行中,lextab.py将被简单地导入以构建词法分析器。这种方法极大地提高了词法分析器的启动时间,并且它在Python的优化模式下工作。
当运行在优化模式下时,需要注意的是lex禁用了大多数错误检查。因此,只有当您确定一切正常并准备开始发布生产代码时,才推荐使用这种方法。
由于这是生产代码,这听起来正是您想要的。
.
在研究此问题时,我发现杂项Yacc笔记:
由于LALR表的生成相对昂贵,如果可能的话,先前生成的表将被缓存和重复使用。重新生成表的决定是通过取所有语法规则和优先级规则的MD5校验和来确定的。只有在不匹配的情况下,表格才会重新生成。
深入研究yacc.py
中的yacc
函数,我们发现优化在以下代码片段中忽略了此不匹配:
if optimize or (read_signature == signature):
try:
lr.bind_callables(pinfo.pdict)
parser = LRParser(lr,pinfo.error_func)
parse = parser.parse
return parser
其中signature
与存储在parsetab.py
中的校验和进行比较(作为_lr_signature
)。
这是一个老问题,但我在使用 outputdir
yacc 关键字参数将生成的解析器表放置在项目特定目录中时遇到了与 ply 相似的问题。它会将它们放在那里,但每次重新生成它们。我在 Github 上找到了 this 补丁,它解决了再生成的问题,没有明显的不良影响。基本上,它只是修改了 yacc
类上的 read_table
方法以接受一个额外的参数 -- outputdir
-- 并在重新生成之前在该目录中查找。为了使其工作,yacc
方法中对 read_table
的唯一调用站点还需要修改以传递 outputdir
关键字参数。
# 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
标志的结果。显然,在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):
所以,您只需要传递一个不同的错误日志和调试日志(具有不会打印到stdout/stderr的debug()等方法)。并且您需要指定一个固定的输出目录。那就是您需要做的全部。
更新:我刚刚检查了一下,这是正确的设置:
yacc.yacc(
debug=False, # do not create parser.out
outputdir=r"c:\temp\aaa" # instruct to place parsetab here
)
debug=False
确实可以抑制错误消息,但无法抑制文件生成。当我将其与部署位置一起使用(文件已经存在的地方),它仍然会尝试覆盖它们。 - MichaelLRGeneratedTable.write_table
方法(例如,将其变成一个什么也不做的方法)。或者,您可以使用 picklefile
参数(传递类似文件的对象),并覆盖 LRGeneratedTable.pickle_table
以什么也不做。不幸的是,LRGeneratedTable 类的使用被硬编码到 yacc.yacc
中,因此您无法对其进行子类化。 :-( - nagylzs
ply
来完成这个任务。您可以更改要使用的文件名或目录,或选择始终重新生成表格(这可能取决于语法的大小)。但是要生成解析器表格以进行发布...我不确定。 :/ - Elias Dorneles