近似语法检查Perl代码,比Perl -c快



有没有一种方法来语法检查Perl程序不运行Perl ?众所周知的答案是"不"。无需启动完整的perl运行时来评估代码对于导入等,您无法判断程序语法是否正确。

但是如果你想要一个近似的答案呢?语法检查器要么说'bad',要么说'maybe'。如果"坏",那么这个程序肯定是坏的不是有效的perl代码(假设是普通的perl解释器)。如果"可能",那么它看起来不错,但只有perl自己才能确定。

一个总是打印'maybe'的程序显然是这样一个检查器,但不是很有用。一个更好的尝试使用PPI。可能有一些有效的Perl程序是被PPI拒绝,但如果发生这种情况,它被接受为PPI错误(我认为)。

题外话:为什么这个有用?其中一个用途可能是支票。捕捉各种各样的"d’oh"表示$WORK上的版本控制系统运行所有Perl代码Perl -c在允许提交之前。(我不建议将此作为通用方法练习一下,注意它在我们的站点上是有用的。)但是perl -c是不安全,因为它执行代码(这是必须的)。使用保守语法检查器反而会更安全,但代价是在某些情况下,检查器说"可能",但实际上程序不是有效的Perl。

我真正想要的(题外话):但事实上,安全并不是我目前申请的激励因素。我对速度感兴趣。是否有一种方法可以粗略地检查和拒绝格式不佳的Perl代码,然后再花费大量的时间来运行整个Perl翻译吗?PPI比perl本身慢,所以不是一个好的选择。你可以编写一个近似的Perl语法,并使用解析器生成器来构建一个一个简单的C程序,可以接受或拒绝伪perl。

我的应用程序是'delta调试'。从一个大的开始具有特定属性的程序(例如,分段故障);然后在保留其属性的同时去掉其中的一部分。我使用http://delta.tigris.org/它以一种简单的面向线的方式工作。它生成的许多测试用例都不是有效的Perl代码。的如果能在之前迅速消除这些问题,增量调试将会进行得更快完整的perl可执行文件被启动。

因为启动perl解释器的开销可能是最大的部分时间,你可以实现某种服务器监听套接字,接受程序文本,并返回'bad'或'maybe' by试图eval()文本或通过PPI运行文本。

另一种加快速度的方法是使perl更快地失败。通常它打印它能找到的所有语法错误和诊断信息。如果可以的话如果在第一个点停下来,可以节省一些时间。

但是我确实喜欢几乎perl的语法的想法,它可以被检查通过一个简单的C程序。这样的东西存在吗?

(相关:Perl浅语法检查?ie。不要检查导入的语法,但我的问题更多的是关于速度,我很高兴有一个粗略的检查,它会接受一些无效的程序,只要它不拒绝有效的。

给定源过滤器、原型和Perl(5.14+)关键字API,导入可以从根本上改变哪些语法有效,哪些语法无效。如果您导入了中的任何内容,那么这样的检查将没有多大用处。

如果您导入nothing,那么您可能可以安全地加载require而不是use的所有外部模块,并且perl -c将变得闪电般快(因为require在运行时被处理)。

PPI在这里不是特别有用,因为它在解析时采用了一种非常宽容的最佳猜测方法,因此可以毫无怨言地接受非常无效的输入:

#!perl
use strict;
use warnings;
use PPI::Document;
use PPI::Dumper;
PPI::Dumper->new(
   PPI::Document->new("foo q[}")
)->print;

Perl::Lexer可能会更有帮助,尽管它只会检测到严重到甚至无法标记的错误。我前面的例子恰好是其中之一,所以这确实有问题:

#!perl
use strict;
use warnings;
use Perl::Lexer;
print $_->inspect, $/
   for @{ Perl::Lexer->new->scan_string("foo q[}") };

即便如此,像Perl关键字API、Devel::Declare和源过滤器这样的东西都是在词法分析之前应用的,所以如果您导入了任何利用这些技术的模块,Perl::Lexer就会卡住。(这些技术中的任何一种都可以很容易地使foo q[}语法有效。)

Compiler::Lexer和Compiler::Parser可能有些用处。以下转储核心:

#!perl
use strict;
use warnings;
use Compiler::Lexer;
use Compiler::Parser;
my $t = Compiler::Lexer->new("eg.pl")->tokenize("foo q[}");
my $a = Compiler::Parser->new->parse($t);

如果你纠正了foo q[}foo q[]不匹配的引号,它不再转储核心。这似乎是一个结果。: -)

最终,答案取决于您正在编写的代码类型以及您希望发现的错误类型。perl -c将为您提供相当严格的语法检查。Perl::Lexer可能更快,但是有很多错误它无法发现。编译器::Lexer/编译器::Parser可能在将来有用,但现在的行为似乎不稳定。

就我个人而言,我会坚持使用perl -c,如果它太慢了,试着减少你在编译时加载的模块数量,以支持运行时加载。

TL;DR:如果你想要静态分析,不要使用Perl。

如果您想要的只是一个快速的可编译性检查,让perl进程保持运行,为您检查每个文件:

perl -MFile::Slurp -lne'print 0+!! eval "sub {" . read_file($_) . "}"'

相关内容

  • 没有找到相关文章

最新更新