Вопрос по parsing, runtime, interpreter, perl, dynamic-languages – Может ли Perl анализироваться статически?

9

статья называетсяPerl не может быть проанализирован, формальное доказательство делает раунды. Итак, решает ли Perl значение синтаксического анализа ввремя выполнения» или же "время компиляции "?

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

Редактировать:

Это н'т о статическом анализе. Это теоретический вопрос о Perlс поведением

Также из хакерских новостей:news.ycombinator.com/item?id=770072 draegtun
@ Пол Биггар: Часть этого похожа на традиционный переводчик. Та часть, в которой он переходит в исполнение до завершения интерпретации остальной части кода, не является. Robert P
@ Роберт П: Это не имеет ничего общего с переводом, это просто языковая особенность. Вы можете также сказать, что это не традиционный переводчик, потому что он использует$_ (или выберите функцию). Paul Biggar

Ваш Ответ

5   ответов
3

но этоотличается от большинства обычных фаз компиляции, когда дело доходит до кода. 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
@ Пол Биггар: статья нене говоря о дереве разбора для небольшого изменения кода во время выполнения, эторечь идет о невозможности (в общем случае) определить дерево разбора для этого кода без выполнения чего-либо. Michael Carman
Хорошо, но этоЯ просто играю с таблицей символов. Но линия можетне может ли изменить смысл во время программы (в смысле цитируемой статьи), не так ли? Paul Biggar
Предположительно, вы можете заставить блок BEGIN проверять что-то в файловой системе или сети, что приводит к двум анализам идентичной программы с двумя различными значениями? Paul Biggar
Абсолютно. Я'Мы видели (возможно, ошибочно), что разработчики Perl используют блок BEGIN для анализа аргументов в командной строке, а затем изменяют переменные, доступные для выполнения, на основании этого. На самом деле, вы недаже не нужно делать это во времякомпилировать» фаза; приведенный выше код может быть выполнен несколько раз. Вы могли бы иметь это в функции, и даже изменить поведение модуля после этого 's был "скомпилирован», Податливость perl-кода - это то, чтодействительно конкурирует только с другими динамическими языками; LISP-подобные языки приходят на ум в качестве яркого примера. Robert P
5

чтобы объяснить различные фазы, но этоэто действительно простой вопрос. Во время компиляции исходного кода Perl intrepreter perl может в конечном итоге запустить код, который изменяет способ синтаксического анализа остальной части кода. Статический анализ, который не выполняет код, пропустит это.

В этом посте Perlmonks Джеффри рассказывает о своих статьях вОбзор Perl которые идут в гораздо более подробно, в том числе пример программы, которая неразбирать один и тот же способ каждый раз, когда вы запускаете его.

19

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

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

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

Чаще всего на компиляцию одного бита кода может влиять компиляция предыдущего фрагмента кода - особенно, является ли идентификатор именем пакета или подпрограммы. ysth
11

которые запускают пользовательский код 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) работал нормально. Могут ли странные угловые случаи скинуть мой код? Конечно, но я нене изо всех сил писать код, которыйНевозможно поддерживать, хотя я мог.

Да, хотя конец начальной фазы компиляции особенный. ysth
@brian d foy: Да, но имена, данные для этих фаз сообществом Perl, не однозначно отражают то, что делают эти фазы, и названия, выбранные для этих фаз, были бы точно такими же иными. Paul Biggar
@ Пол, нет, имена отражают Большую Задачу каждого из этих этапов. Имена являются целенаправленными, описательными и точными. brian d foy
Так почему вы используете термины?запустить код Perl во время компиляции " скорее, чем "компилировать код Perl во время выполнения, В чем разница? Тот'Вот почему я спросил о терминологии. Paul Biggar
2

но это неостановить компиляторы от его компиляции. Они просто вырвутся или будут работать вечно в тех случаях, когда такой аргумент применим.

Да, хорошо сказано. Та же идея, что и в моем посте, и много меньше слов :) jrockway
@Segfault: статический анализ выполняется до выполнения. Paul Nathan
Это'не очень похожи - для шаблонов C ++ все используемые значения также являются выражениями времени компиляции, и они явно отличаются от выражений времени выполнения. В Perl с примером, приведенным в связанной статье, функция может быть определена по-разному в зависимости, например, от пользовательский ввод строки, поэтому остальная часть программы будет передаваться иначе, чем с момента ввода. Там'Нет ничего даже отдаленно похожего в C ++. Pavel Minaev
@Pavel Вы можете создать (почти) точный аналог примера в статье на C ++, используя шаблоны и неоднозначность объявления / инициализации. Тот факт, что Perl может использовать это во время выполнения, тогда как компилятор C ++ должен разрешать его во время компиляции, не имеет значения. Captain Segfault

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