9

「Perlは解析できません。正式な証明」という記事がラウンドを行っています。では、Perlは解析されたコードの意味を「実行時」または「コンパイル時」で決定しますか?

私が読んだいくつかの議論では、議論は不正確な用語に由来しているという印象を受けるので、あなたの答えの中であなたの専門用語を定義するようにしてください。私は意図的に「ランタイム」、「静的」、「解析」を定義していないので、おそらくこれらの用語を私とは異なる方法で定義している人々からの視点を得ることができます。

編集:

これは静的分析に関するものではありません。Perlの振る舞いについての理論的な質問です。

4

5 に答える 5

19

Perl には明確に定義された「コンパイル時」フェーズがあり、その後に明確に定義された「実行時」フェーズが続きます。ただし、一方から他方へ移行する方法はあります。多くの動的言語evalには、ランタイム段階で新しいコードをコンパイルできる構造があります。Perl では逆も可能であり、一般的です。ブロック (およびによって引き起こされるBEGIN暗黙のブロック) は、コンパイル時に一時的なランタイム フェーズを呼び出します。ブロックは、コンパイル単位の残り (つまり、 current ファイルまたは current ) がコンパイルされるのを待つのではなく、コンパイルされるとすぐに実行されます。以来BEGINuseBEGINevalBEGINそれらに続くコードがコンパイルされる前に s が実行されると、実質的には次のコードのコンパイルに影響を与える可能性があります (ただし、実際には、サブルーチンをインポートまたは定義するか、厳密性または警告を有効にすることが主に行われます)。

Ause Foo;は基本的に と同等でBEGIN { require foo; foo->import(); }、 require は ( のようにeval STRING) ランタイムからコンパイル時間を呼び出す方法の 1 つです。

とにかく、Perl の構文解析の決定可能性について要約すると、1 ビットのコードのコンパイルは先行するコード片の実行によって影響を受ける可能性があるため (理論的には何でもできる)、停止問題タイプの状況。一般に、特定の Perl ファイルを正しく解析する唯一の方法は、それを実行することです。

于 2009-08-14T23:31:08.990 に答える
11

Perl には、コンパイル時にユーザー Perl コードを実行する BEGIN ブロックがあります。このコードは、コンパイルされる他のコードの意味に影響を与える可能性があるため、Perl の解析が「不可能」になります。

たとえば、コードは次のとおりです。

sub foo { return "OH HAI" }

本当に":

BEGIN {
    *{"${package}::foo"} = sub { return "OH HAI" };
}

これは、誰かが Perl を次のように書けることを意味します:

BEGIN {
    print "Hi user, type the code for foo: ";
    my $code = <>;
    *{"${package}::foo"} = eval $code;
}

明らかに、静的分析ツールは、ユーザーがここに入力しようとしているコードを推測できません。(また、ユーザーがsub ($) {}の代わりにと言うと、 のsub {}呼び出しがfooプログラムの残りの部分でどのように解釈されるかにさえ影響し、解析が中断される可能性があります。)

良いニュースは、不可能なケースが非常にまれであることです。技術的には可能ですが、実際のコードではほぼ確実に役に立ちません。したがって、静的分析ツールを作成している場合、これで問題が発生することはほとんどありません。

公平を期すために言うと、すべての言語にはこの問題、またはそれに類似した問題があります。例として、お気に入りのコード ウォーカーを次の Lisp コードに投げます。

(iter (for i from 1 to 10) (collect i))

iterマクロは不透明であり、理解するには特別な知識が必要になるため、これがリストを生成するループであるとはおそらく予測できません。現実には、これは理論的には煩わしいことです (コードを実行しないと理解できないか、少なくともiterマクロを実行すると、この入力で実行が停止することはありません) が、実際には非常に便利です (繰り返しは簡単です書くプログラマーと将来のプログラマーが読む)。

最後に、Perl には構文解析が比較的難しいため、Java にあるような静的解析ツールやリファクタリング ツールがないと多くの人が考えています。私はこれが真実であるとは思えません。その必要性はなく、誰もそれを書くことを気にしていないと思います。(人々は「リント」を必要とするので、たとえば Perl::Critic があります。)

コードを生成するために必要な Perl の静的解析 (テスト カウンターと Makefile.PL を維持するためのいくつかの emacs マクロ) は正常に機能しました。奇妙なコーナーケースが私のコードを狂わせることはありますか? もちろん、保守が不可能なコードを無理に書くつもりはありません。

于 2009-08-14T23:18:20.250 に答える
5

さまざまなフェーズを説明するために多くの言葉が使われてきましたが、実際には単純なことです。Perl ソースのコンパイル中に、perl インタープリターは、残りのコードの解析方法を変更するコードを実行することになる場合があります。コードを実行しない静的解析では、これが見逃されます。

その Perlmonks の投稿で、Jeffrey はThe Perl Reviewの記事について、実行するたびに同じ方法で解析しないサンプル プログラムなど、より詳細に説明しています。

于 2009-08-15T17:20:26.813 に答える
3

C++ のテンプレート システムにも同様の問題がありますが、それによってコンパイラがコンパイルを停止することはありません。この種の議論が適用されるコーナーケースでは、それらはただ発生するか、永久に実行されます。

于 2009-08-14T23:27:42.743 に答える
3

Perl にはコンパイル フェーズがありますが、コードに関しては、ほとんどの通常のコンパイル フェーズとは異なります。Perl のレクサーはコードをトークンに変換し、次にパーサーがトークンを分析して op ツリーを形成します。ただし、BEGIN {} ブロックはこのプロセスを中断し、コードを実行できるようにすることができます。を行うときuse。すべてのBEGINブロックは何よりも先に実行されるため、モジュールと名前空間を設定できます。スクリプトの全体的な「コンパイル」中に、Perl を使用して、完了時の Perl モジュールの外観を決定する可能性が最も高くなります。sub、bare は、パッケージの glob に追加することを意味しますが、その必要はありません。たとえば、これはモジュールでメソッドをセットアップする (奇妙ではありますが) 方法です。

package Foo;

use strict;
use warnings;
use List::Util qw/shuffle/;

my @names = qw(foo bar baz bill barn);
my @subs = (
    sub { print "baz!" },
    sub { die; },
    sub { return sub { die } },
);
@names = shuffle @names;
foreach my $index (0..$#subs) {
   no strict 'refs';
   *{$names[$index]} = $subs[$index];
}

1;

これが何をするのかを知るためにも、これを解釈する必要があります! あまり役に立ちませんが、事前に判断できるものではありません。しかし、それは 100% 有効な perl です。この機能は悪用される可能性がありますが、非常によく似た複雑なサブルーチンをプログラムで作成するなど、優れたタスクを実行することもできます。また、すべてが何をしているのかを確実に知ることも難しくなります。

これは、perl スクリプトを「コンパイル」できないと言っているわけではありません。perl では、コンパイルとは単にモジュールがどのように見えるべきかを決定することです。あなたはそれを行うことができます

perl -c myscript.pl

メインモジュールの実行を開始するポイントに到達できるかどうかがわかります。「静的に」見るだけではわかりません。

ただし、PPIが示すように、近づくことができます。本当に近い。(ほとんど静的な) コード分析など、非常に興味深いことを行うのに十分近い。

「実行時間」は、すべてのBEGINブロックが実行された後に起こることになります。(これは単純化したものです。これにはさらに多くの機能があります。詳しくはperlmodを参照してください。) まだ実行中の perl コードですが、実行の別のフェーズであり、優先順位の高いすべてのブロックが実行された後に実行されます。

chromatic は彼の Modern::Perl ブログにいくつかの詳細な投稿をしています:

于 2009-08-14T23:28:54.847 に答える