Perl可以"静态"解析吗?

Pau*_*gar 9 perl parsing interpreter dynamic-languages runtime

一个叫文章"Perl的无法解析,正式的证明"是做两轮.那么,Perl是否在"运行时"或"编​​译时"决定了其解析代码的含义?

在一些讨论我读过,我得到的印象参数不精确,从干的术语,所以请尽量在你的答案来定义你的技术术语.我故意没有定义"运行时","静态"或"解析",以便我可以从那些可能以不同方式定义这些术语的人那里获得观点.

编辑:

这与静态分析无关.它是关于Perl行为的理论问题.

hob*_*bbs 19

Perl有一个定义明确的"编译时"阶段,后面是一个明确定义的"运行时"阶段.但是,有一些方法可以从一个过渡到另一个.许多动态语言都有eval允许在运行时阶段编译新代码的构造; 在Perl中,反转也是可能的 - 并且很常见.BEGIN块(以及由此BEGIN引起的隐式块use)编译时调用临时运行时阶段.一个BEGIN块,只要它是编译执行的,而不是等待编译单元的剩余部分(即当前文件或当前,eval)进行编译.由于BEGIN在编译之后的代码运行之前运行,它们几乎可以以任何方式影响以下代码的编译(尽管在实践中,他们做的主要事情是导入或定义子例程,或者启用严格性或警告).

A use Foo;基本上等同于BEGIN { require foo; foo->import(); },需要(比如eval STRING)从运行时调用编译时的方法之一,这意味着我们现在在编译时在运行时内的编译时间内并且整个事情是递归的.

无论如何,解析Perl的可解决性的原因在于,由于前一段代码的执行(理论上可以做任何事情)可以影响一位代码的编译,我们自己得到了一个停止问题类型的情况; 一般来说,正确解析给定Perl文件的唯一方法是执行它.

  • 更常见的是,前一段代码的编译会影响一位代码的编译 - 特别是标识符是包的名称还是子包的名称. (4认同)

jro*_*way 11

Perl有BEGIN块,它在编译时运行用户Perl代码.此代码可能会影响要编译的其他代码的含义,从而使"解析Perl"变得"不可能".

例如,代码:

sub foo { return "OH HAI" }
Run Code Online (Sandbox Code Playgroud)

是真的":

BEGIN {
    *{"${package}::foo"} = sub { return "OH HAI" };
}
Run Code Online (Sandbox Code Playgroud)

这意味着有人可以编写Perl,如:

BEGIN {
    print "Hi user, type the code for foo: ";
    my $code = <>;
    *{"${package}::foo"} = eval $code;
}
Run Code Online (Sandbox Code Playgroud)

显然,没有静态分析工具可以猜出用户将在这里输入什么代码.(如果用户说sub ($) {}而不是sub {},它甚至会影响foo在整个程序的其余部分解释调用,可能会导致解析.)

好消息是,不可能的案件非常严重; 技术上可行,但在实际代码中几乎肯定无用.因此,如果您正在编写静态分析工具,这可能会给您带来麻烦.

公平地说,每种语言都有这个问题,或类似的东西.举个例子,在这个Lisp代码中抛出你最喜欢的代码walker:

(iter (for i from 1 to 10) (collect i))
Run Code Online (Sandbox Code Playgroud)

您可能无法预测这是一个产生列表的循环,因为iter宏是不透明的,需要特殊的知识才能理解.实际情况是这在理论上很烦人(我无法理解我的代码而不运行它,或者至少运行iter宏,这可能永远不会停止使用此输入),但在实践中非常有用(迭代很容易程序员写和未来的程序员阅读).

最后,很多人认为Perl缺乏静态分析和重构工具,就像Java一样,因为解析它相对困难.我怀疑这是真的,我只是认为没有必要,没有人愿意写它.(人们需要一个"lint",所以有Perl :: Critic,例如.)

我需要做Perl生成代码的静态分析(一些用于维护测试计数器和Makefile.PL的emacs宏)运行良好.奇怪的角落案件会丢掉我的代码吗?当然,但即使我可以,我也不会忘记编写无法维护的代码.

  • 这不仅仅是术语.虽然Perl可能在Compile阶段运行一些代码,并且可能在Run阶段编译一些代码,但每个代码也都有在阶段开始和结束时运行的钩子.虽然它们在内部有点模糊,但它们在其他事情发生时具有界限. (2认同)

bri*_*foy 5

人们用了很多词来解释各个阶段,但这真的很简单.在编译Perl源代码时,perl intrepreter最终可能会运行代码来改变代码的其余部分将如何解析.没有代码的静态分析会错过这个.

在Perlmonks的帖子中,Jeffrey谈到他在Perl Review中的文章更详细,包括每次运行时都不会以相同方式解析的示例程序.