Чому ця програма діє? Я намагався створити синтаксичну помилку


489

У мене працює 32-розрядний ActivePerl 5.14.2 ActivePerl 5.14.2 в Windows 7. Мені хотілося зіпсуватись із гаком попереднього вчинення Git, щоб виявити програми, що перевіряються в синтаксичних помилках. (Якось мені просто вдалося зробити такий поганий вчинок.) Отож, як тестова програма, я випадково зафіксував це:

use strict;
use warnings;

Syntax error!

exit 0;

Однак вона компілюється та виконується без попереджень, а рівень помилок є нульовим при виході. Як це дійсний синтаксис?


121
Ви щойно довели, що введення випадкових слів у perl створює робочі програми ??!?!?!?!
Пітер М

10
@PeterM Навряд чи випадкові слова. Я довів, що не знаю достатньо синтаксису Perl. Тепер я знаю трохи більше.
Білл Рупперт

10
Ви, мабуть, хочете no indirectне
допустити

@LeoNerd Дякую за пораду!
Білл Рупперт

1
Це найвідоміше запитання Перла. Ще краще, як фрагмент Шварца :whatever / 25 ; # / ; die "this dies!";
jm666

Відповіді:


540

У Perl є синтаксис, який називається "непряма нотація методу". Це дозволяє

Foo->new($bar)

писати як

new Foo $bar

Так це означає

Syntax error ! exit 0;

те саме, що

error->Syntax(! exit 0);

або

error->Syntax(!exit(0));

Це не тільки правильний синтаксис, це не призводить до помилки під час виконання, оскільки перше, що виконується exit(0).


1
@Hassan, чому? За ним слідує вираз.
ikegami

3
Я прочитав це як "Синтаксична помилка! Вихід 0;", але не подумав про непряме виклик. Витратили багато часу, забувши це!
Білл Рупперт

6
@Hassan, подумайте про це таким чином, !exit(0)більше не може бути помилкою типу, !$xоскільки не введено жодного.
ikegami

11
@Hassan, Мова має типи. Зокрема, значення мають типи. Оператори та допоміжні програми просто не обмежуються поверненням певних типів значень. Це виявляється дуже корисним за невеликих витрат (завдяки попередженням).
ikegami

6
@Nawaz, насправді це досить популярно. Його використовують усі, хто створює об’єкти на Java та C ++, і великий масив програмістів Perl, який використовує new Classі print $fh ...замість, Class->new(...)і $fh->print(...). Я
дозволю

112

Я не знаю чому, але Perl робить це:

perl -MO=Deparse -w yuck
BEGIN { $^W = 1; }
use warnings;
use strict 'refs';
'error'->Syntax(!exit(0));
yuck syntax OK

Здається, що аналізатор думає, що ви викликаєте метод Syntaxна error-об'єкт ... Дивно, але!


3
Це непрямий синтаксис виклику методу. Тут (свого роду) це працює, тому що exit(0)спочатку оцінюється, виходячи з програми, перш ніж вона намагається передати результат 'error'->Syntax().
сутінки -надія-

6
Схоже, Perl припускає "непрямий (об'єктний) синтаксис", який зазвичай використовується як new Classзамість Class->new(). Для виклику методу Syntax, то exitфункція виконується, тому помилка часу ніколи не зустрічається , .
амон

118
Вітаю. Ви знайшли програму, де вам потрібно додати крапку з двокрапкою, щоб компіляція не вийшла з ладу.
моб

use strict; use warnings; error->Syntax(! print "hi"); Виходи: Синтаксис Добре на perl -MO = Deparse також, але з use warningsним, мабуть, слід щось сказати, оскільки він може зрозуміти, що його не завантажують. Натомість він видає помилку під час виконання програми "Неможливо знайти об'єктний метод ..".

53

Причиною не помилки є те, що перший виконаний код

exit(0);

Тому що у вас не було крапки з комою в першому рядку:

Syntax error!

Компілятор здогадається (неправильно), що це виклик підпрограми з введеним notоператором !. Потім він виконає аргументи цієї підпрограми, що трапляється exit(0), і в цей момент програма виходить з програми і встановлює рівень помилки на 0. Нічого іншого не виконується , тому більше помилок виконання не повідомляється.

Ви помітите, що якщо ви перейдете exit(0)на щось подібне, print "Hello world!"ви отримаєте помилку:

Can't locate object method "Syntax" via package "error" ...

і ваш рівень помилок буде встановлено:

> echo %errorlevel%
255

7
>The compiler will guess (incorrectly) Компілятор не може зробити щось неправильно.
Ліам Лаверті

14
@LiamLaverty Так, це може. Він може неправильно здогадатися, що означала людина.
TLP

4
Людина - це неправильне в рівнянні. Компілятор може бути лише "правильним" або "зламаним". Він не отримує думки щодо визначення мови чи наміру користувача.
Ліам Лаверті

4
@LiamLaverty Це був би досить акуратний компілятор, якби він міг здогадатися про намір користувача в цьому випадку, так. Отже, компілятор не може правильно здогадатися. Ви можете зробити якийсь технічний жаргонний аналіз мого твердження, який, я можу додати, неправильний спосіб його прочитати.
TLP

Хіба це не перекладач? ;-)
Ріккі

33

Як зазначалося вище, це викликано непрямим методом виклику нотацій. Про це можна попередити:

use strict;
use warnings;
no indirect;

Syntax error!

exit 0;

Виробляє:

Indirect call of method "Syntax" on object "error" at - line 5.

Для цього потрібно непрямий модуль CPAN .

Ви також можете використовувати, no indirect "fatal";щоб програма померла (це я роблю)


8

Спробуйте Perl 6 , схоже, ви готовіше виконати ваші очікування:

===SORRY!=== Error while compiling synerror.p6
Negation metaoperator not followed by valid infix
at synerror.p6:1
------> Syntax error!⏏<EOL>
    expecting any of:
        infix
        infix stopper

1

У цій роботі ми прагнемо відповісти на давню відкриту проблему у спільноті мов програмування: чи можна замазати фарбу на стіні без створення дійсного Perl?

TLDR; Навряд чи


Мені це подобається. Можливо, мені доведеться сканувати деякі фотографії.
Білл Рупперт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.