Perl может быть “статически” проанализирован?

Они не преподают такие темы, потому что большинство школ является академическим, не торгуют. Таким образом, они разработаны, чтобы преподавать идеи и теории, не обучить Вас в карьеру. Все понятие QA не имеет никакого отношения к информатике вне передачи математического доказательства. Кроме того, методы QA и рабочие процессы разработки отличаются дико от одного дома разработки до следующего, настолько обучающий их в школе пустая трата Вашего времени и денег.

9
задан Paul Biggar 14 August 2009 в 23:24
поделиться

5 ответов

Perl имеет четко определенную фазу «времени компиляции», за которой следует четко определенная фаза «времени выполнения». Однако есть способы перехода от одного к другому. Многие динамические языки имеют конструкции eval , которые позволяют компилировать новый код на этапе выполнения; в Perl возможно и обратное - и обычное дело. Блоки BEGIN (и неявный блок BEGIN , вызванный использованием ) вызывают временную фазу выполнения во время компиляции . Блок BEGIN выполняется, как только он скомпилирован, вместо ожидания компиляции остальной части модуля компиляции (т.е. текущего файла или текущего eval ) для компиляции. Поскольку BEGIN запускаются до компиляции кода, который следует за ними, они могут повлиять на компиляцию следующего кода практически любым способом (хотя на практике главное, что они делают, это импортировать или определять подпрограммы, или включать строгость или предупреждения).

A use Foo; в основном эквивалентен BEGIN {require foo; foo-> import (); } , с требованием (например, eval STRING ) одним из способов вызвать время компиляции из среды выполнения, что означает, что теперь мы находимся в пределах времени компиляции во время выполнения во время компиляции и всего рекурсивно.

В любом случае, для разрешимости синтаксического анализа Perl это сводится к тому, что, поскольку на компиляцию одного бита кода может влиять выполнение предыдущего фрагмента кода (который теоретически можем сделать что угодно ), мы ' мы попали в ситуацию типа проблемы с остановкой; единственный способ правильно проанализировать данный файл Perl в целом - это выполнить его.

19
ответ дан 4 December 2019 в 06:16
поделиться

Perl имеет блоки BEGIN, которые запускают пользовательский код Perl во время компиляции. Этот код может повлиять на значение другого кода, который будет скомпилирован, что сделает «невозможным» синтаксический анализ 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 интерпретируются в остальной части программа, потенциально сбрасывающая синтаксический анализ.)

Хорошая новость в том, что невозможные случаи - очень мелкие; технически возможно, но почти наверняка бесполезно в реальном коде. Итак, если вы пишете инструмент статического анализа, это, вероятно, не вызовет у вас проблем.

Честно говоря, в каждом достойном языке есть эта проблема или что-то подобное. В качестве примера поместите свой любимый обходчик кода в этот код Лиспа:

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

Вы, вероятно, не можете предсказать, что это цикл, который производит список, потому что макрос iter непрозрачен и требует специальных знаний понять. Реальность такова, что теоретически это раздражает (я не могу понять свой код, не запустив его или, по крайней мере, запустив макрос iter , который может никогда не перестать работать с этим вводом), но очень полезно в практика (итерацию легко написать программисту, а будущему программисту - прочитать).

Наконец, многие люди думают, что Perl не хватает инструментов статического анализа и рефакторинга, подобных Java, из-за относительной сложности его анализа. Я сомневаюсь, что это правда, я просто думаю, что в этом нет необходимости, и никто не удосужился написать это. (Людям действительно нужен «линт», поэтому есть Perl :: Critic, например.)

Любой статический анализ, который мне нужно было провести с Perl для генерации кода (некоторые макросы emacs для поддержки счетчиков тестов и Makefile.PL) работал нормально. Могут ли странные угловые случаи сбить мой код? Конечно, но я не стараюсь изо всех сил писать код, который невозможно поддерживать, даже если бы я мог.

11
ответ дан 4 December 2019 в 06:16
поделиться

People have used a lot of words to explain various phases, but it's really a simple matter. While compiling Perl source, the perl intrepreter may end up running code that changes how the rest of the code will parse. Static analysis, which runs no code, will miss this.

In that Perlmonks post, Jeffrey talks about his articles in The Perl Review that go into much more detail, including a sample program that doesn't parse the same way every time you run it.

5
ответ дан 4 December 2019 в 06:16
поделиться

С ++ имеет аналогичную проблему в системе шаблонов, но это не мешает компиляторам компилировать ее. Они просто вырвутся наружу или будут вечно бегать по крайним случаям, где применимы такие аргументы.

3
ответ дан 4 December 2019 в 06:16
поделиться

Perl имеет фазу компиляции, но она отличается от большинства обычных фаз компиляции, когда дело касается кода. Лексер Perl превращает код в токены, затем анализатор анализирует токены, чтобы сформировать дерево операций. Однако блоки BEGIN {} могут прервать этот процесс и позволить вам выполнить код. При выполнении используйте . Все блоки BEGIN выполняются раньше всего, что дает вам возможность настраивать модули и пространства имен. Во время общей «компиляции» сценария вы, скорее всего, будете использовать Perl, чтобы определить, как модуль Perl должен выглядеть после завершения. sub, bare, подразумевает добавление его в глобус пакета, но это не обязательно. Например, это (хотя и странный) способ настройки методов в модуле:

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:

3
ответ дан 4 December 2019 в 06:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: