Вопрос по parsing, runtime, interpreter, perl, dynamic-languages – Может ли Perl анализироваться статически?
статья называетсяPerl не может быть проанализирован, формальное доказательство делает раунды. Итак, решает ли Perl значение синтаксического анализа ввремя выполнения» или же "время компиляции "?
В некоторых дискуссиях япрочитав, у меня сложилось впечатление, что аргументы проистекают из неточной терминологии, поэтому, пожалуйста, постарайтесь определить свои технические термины в своем ответе. Я сознательно не определиласьвремя выполнения ","статически" или же "разобранный» так что я могу узнать мнение людей, которые, возможно, определяют эти термины по-другому для меня.
Редактировать:Это н'т о статическом анализе. Это теоретический вопрос о Perlс поведением
$_
(или выберите функцию).
Paul Biggar
но этоотличается от большинства обычных фаз компиляции, когда дело доходит до кода. Perl»s лексер превращает код в токены, затем анализатор анализирует токены для формирования дерева операций. Однако блоки BEGIN {} могут прервать этот процесс и позволить вам выполнить код. При выполненииuse
, Все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;
Выиметь интерпретировать это, чтобы даже знать, что он делает! Это'не очень полезно, но этоэто не то, что вы можете определить заранее. Но это's 100% действительный перл. Несмотря на то, что этой функцией можно злоупотреблять, она также может выполнять большие задачи, например, создавать сложные сабвуферы, которые все выглядят очень похожими программно. Это также затрудняет, наверняка, знать, что все делает.
Тот'Нельзя сказать, что Perl-скрипт можетбытьскомпилированных» - в perl компиляция просто определяет, как именно тогда должен выглядеть модуль. Вы можете сделать это с
perl -c myscript.pl
и он скажет вам, может ли он добраться до точки, где он начнет выполнять основной модуль. Вы просто можетепросто знаю, глядя на этостатически'.
Тем не менее, какPPI демонстрирует, мы можем подобраться. Действительно близко. Достаточно близко, чтобы делать очень интересные вещи, такие как (почти статический) анализ кода. "
Run Time "то становится тем, что происходит после всехBEGIN
блоки выполнены. (Это упрощение; есть еще много чего.perlmod для большего.) Это 'все еще выполняется Perl-код, но этоОтдельная фаза выполнения, выполняемая после запуска всех блоков с более высоким приоритетом.
У chromatic есть несколько подробных сообщений в его блоге Modern :: Perl:
Как работает программа Perl 5При разборе Perl 5чтобы объяснить различные фазы, но этоэто действительно простой вопрос. Во время компиляции исходного кода Perl intrepreter perl может в конечном итоге запустить код, который изменяет способ синтаксического анализа остальной части кода. Статический анализ, который не выполняет код, пропустит это.
В этом посте Perlmonks Джеффри рассказывает о своих статьях вОбзор Perl которые идут в гораздо более подробно, в том числе пример программы, которая неразбирать один и тот же способ каждый раз, когда вы запускаете его.
за которой следует четко определеннаяво время выполнения» фаза. Однако есть способы перехода от одного к другому. Многие динамические языки имеютeval
конструкции, позволяющие компилировать новый код на этапе выполнения; в Perl возможно и обратное - и обычное дело.BEGIN
блоки (и неявныеBEGIN
блок вызванuse
) вызвать временную фазу выполненияв течение время компиляции.BEGIN
блок выполняется, как только онскомпилировано, вместо ожидания остальной части модуля компиляции (то есть текущий файл или текущийeval
) Скомпилировать. посколькуBEGIN
Выполняемые до того, как код, следующий за ними, компилируется, они могут влиять на компиляцию следующего кода практически любым способом (хотя на практике они в основном импортируют или определяют подпрограммы, или включают строгость или предупреждения) .A
use Foo;
в основном эквивалентноBEGIN { require foo; foo->import(); }
с требованием быть (вродеeval STRING
) один из способов вызова времени компиляции из среды выполнения, означающий, что мытеперь во время компиляции во время выполнения во время компиляции, и все это рекурсивно.
В любом случае, все сводится к разрешимости синтаксического анализа Perl, так как компиляция одного бита кода может зависеть отвыполнение предыдущего куска кода (который в теории может сделатьчто-нибудь) мыу нас есть ситуация типа проблемы остановки; единственный способ правильно разобрать данный файл Perlв общем это путем его выполнения.
которые запускают пользовательский код 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) работал нормально. Могут ли странные угловые случаи скинуть мой код? Конечно, но я нене изо всех сил писать код, которыйНевозможно поддерживать, хотя я мог.
но это неостановить компиляторы от его компиляции. Они просто вырвутся или будут работать вечно в тех случаях, когда такой аргумент применим.