Tại sao chương trình này hợp lệ? Tôi đã cố gắng tạo ra một lỗi cú pháp


489

Tôi đang chạy ActivePerl 5.14.2 của ActiveState trên Windows 7. Tôi muốn tìm hiểu thêm về hook pre-commit Git để phát hiện các chương trình đang được kiểm tra với lỗi cú pháp. (Bằng cách nào đó tôi chỉ xoay sở để thực hiện một cam kết tồi tệ như vậy.) Vì vậy, như một chương trình thử nghiệm, tôi đã ngẫu nhiên ghi lại điều này:

use strict;
use warnings;

Syntax error!

exit 0;

Tuy nhiên, nó biên dịch và thực thi mà không có cảnh báo, và errorlevel bằng 0 khi thoát. Cú pháp hợp lệ này như thế nào?


121
Bạn đã chứng minh rằng việc gõ các từ ngẫu nhiên vào perl sẽ tạo ra các chương trình làm việc ??!?!?!?!
Peter M

10
@PeterM Từ khó ngẫu nhiên. Tôi đã chứng minh rằng tôi không biết đủ về cú pháp Perl. Bây giờ tôi biết thêm một chút.
Bill Ruppert

10
Bạn có thể muốn no indirectngăn chặn những điều đó xảy ra
LeoNerd

@LeoNerd Cảm ơn vì tiền boa!
Bill Ruppert

1
Đây là câu hỏi perl nổi tiếng nhất từ ​​trước đến nay. Thậm chí tốt hơn như đoạn trích của Schwartz :whatever / 25 ; # / ; die "this dies!";
jm666

Câu trả lời:


540

Perl có một cú pháp gọi là "ký hiệu phương pháp gián tiếp". Nó cho phép

Foo->new($bar)

được viết là

new Foo $bar

Vậy điều đó có nghĩa là

Syntax error ! exit 0;

giống như

error->Syntax(! exit 0);

hoặc là

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

Đây không chỉ là cú pháp hợp lệ, nó không gây ra lỗi thời gian chạy vì điều đầu tiên được thực hiện là exit(0).


1
@Hassan, tại sao? Tiếp theo là một biểu thức.
ikegami

3
Tôi đã đọc được như là "Lỗi cú pháp! Thoát 0;", nhưng tôi không nghĩ về việc gọi gián tiếp. Đã dành rất nhiều thời gian để quên điều đó!
Bill Ruppert

6
@Hassan, Hãy nghĩ về nó theo cách này, !exit(0)không thể là một lỗi loại hơn !$xvì không được gõ.
ikegami

11
@Hassan, Ngôn ngữ có các loại. Cụ thể, các giá trị có loại. Các toán tử và subs chỉ đơn giản là không giới hạn để trả về các loại giá trị cụ thể. Điều này hóa ra rất hữu ích với chi phí thấp (nhờ các cảnh báo).
ikegami

6
@Nawaz, Nó thực sự khá phổ biến. Nó được mọi người sử dụng để xây dựng các đối tượng trong Java và C ++ và một lượng lớn các lập trình viên Perl sử dụng new Classprint $fh ...thay vì Class->new(...)$fh->print(...). Tuy nhiên, tôi sẽ cấp cho bạn rằng nó gây ra một thông báo lỗi kỳ lạ
ikegami

112

Tôi không biết tại sao, nhưng đây là những gì Perl làm cho nó:

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

Có vẻ như trình phân tích cú pháp nghĩ rằng bạn đang gọi phương thức Syntaxtrên error-object ... Thật kỳ lạ!


3
Đó là cú pháp gọi phương thức gián tiếp. Nó (loại) hoạt động ở đây vì exit(0)được đánh giá đầu tiên, làm cho chương trình thoát ra trước khi nó cố gắng chuyển kết quả đến 'error'->Syntax().
duskwuff -inactive-

6
Perl dường như giả sử cú pháp "gián tiếp (đối tượng)", thường được sử dụng như new Classthay vì Class->new(). Để gọi phương thức Syntax, exithàm được thực thi, do đó lỗi thời gian chạy không bao giờ xảy ra.
amon

118
Xin chúc mừng. Bạn đã tìm thấy một chương trình mà bạn cần thêm dấu chấm phẩy để biên dịch thất bại.
mob

use strict; use warnings; error->Syntax(! print "hi"); Hiệu suất: Cú pháp Ok trên perl -MO = Không rõ ràng, nhưng với use warningsnó có lẽ nên nói điều gì đó vì nó có thể nhận ra rằng nó không được tải. Thay vào đó, nó đưa ra một lỗi thời gian chạy "Không thể định vị phương thức đối tượng ..".

53

Lý do bạn không gặp lỗi là mã được thực thi đầu tiên là

exit(0);

Bởi vì bạn không có dấu chấm phẩy trên dòng đầu tiên:

Syntax error!

Trình biên dịch sẽ đoán (không chính xác) rằng đây là một lệnh gọi chương trình con với một nottoán tử được !ném vào. Sau đó, nó sẽ thực thi các đối số cho chương trình con này exit(0), lúc đó, chương trình sẽ thoát ra và đặt errorlevel thành 0. Không có gì khác được thực thi , vì vậy không có lỗi thời gian chạy được báo cáo.

Bạn sẽ nhận thấy rằng nếu bạn thay đổi exit(0)thành một cái gì đó giống như print "Hello world!"bạn bị lỗi:

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

và mức độ lỗi của bạn sẽ được đặt:

> echo %errorlevel%
255

7
>The compiler will guess (incorrectly) Trình biên dịch không thể làm bất cứ điều gì không chính xác.
Liam Laverty 10/03/2015

14
@LiamLaverty Vâng, nó có thể. Nó có thể đoán không chính xác ý nghĩa của con người.
TLP

4
Con người là không chính xác trong phương trình. Trình biên dịch chỉ có thể là "chính xác" hoặc "bị hỏng". Nó không có ý kiến ​​về định nghĩa của ngôn ngữ hoặc ý định của người dùng.
Liam Laverty 10/03/2015

4
@LiamLaverty Nó sẽ là một trình biên dịch khá gọn gàng nếu nó có thể đoán được ý định của người dùng trong trường hợp này, vâng. Do đó, trình biên dịch không thể đoán chính xác. Bạn có thể đang thực hiện một số phân tích thuật ngữ kỹ thuật về tuyên bố của tôi, đó là, tôi có thể thêm, cách đọc không chính xác.
TLP

Nó không phải là một phiên dịch viên? ;-)
Rikki

33

Như đã lưu ý ở trên, điều này được gây ra bởi ký hiệu gọi phương thức gián tiếp. Bạn có thể cảnh báo về điều này:

use strict;
use warnings;
no indirect;

Syntax error!

exit 0;

Sản xuất:

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

Điều này đòi hỏi mô-đun CPAN gián tiếp .

Bạn cũng có thể sử dụng no indirect "fatal";để khiến chương trình bị chết (đây là những gì tôi làm)


8

Hãy thử Perl 6 , nó dường như đáp ứng mong đợi của bạn dễ dàng hơn:

===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

Trong bài báo này , chúng tôi hướng đến việc trả lời một vấn đề mở từ lâu trong cộng đồng ngôn ngữ lập trình: có thể bôi sơn lên tường mà không tạo ra Perl hợp lệ không?

TLDR; Khó khăn


Tôi thích nó. Tôi có thể phải quét trong một số hình ảnh.
Bill Ruppert
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.