ทำไมโปรแกรมนี้ถึงใช้ได้? ฉันพยายามสร้างข้อผิดพลาดทางไวยากรณ์


489

ฉันใช้ActivePerl 5.14.2 32 บิตของ ActiveState ใน Windows 7 ฉันต้องการยุ่งกับ Git pre-commit hook เพื่อตรวจสอบโปรแกรมที่กำลังเช็คอินพร้อมข้อผิดพลาดทางไวยากรณ์ (อย่างใดฉันก็สามารถที่จะทำเช่นนั้นมุ่งมั่นที่ไม่ดี.) ดังนั้นเป็นโปรแกรมทดสอบฉัน jotted แบบสุ่มนี้:

use strict;
use warnings;

Syntax error!

exit 0;

อย่างไรก็ตามมันรวบรวมและดำเนินการโดยไม่มีคำเตือนและ errorlevel เป็นศูนย์เมื่อออก ไวยากรณ์ที่ถูกต้องนี้เป็นอย่างไร


121
คุณเพิ่งพิสูจน์ได้ว่าการพิมพ์คำแบบสุ่มเข้าไปใน Perl สร้างโปรแกรมทำงานหรือไม่?!?!?!?!
ปีเตอร์ M

10
@PeterM คำที่สุ่มยาก ฉันพิสูจน์แล้วว่าฉันมีความรู้เกี่ยวกับไวยากรณ์ Perl ไม่เพียงพอ ตอนนี้ฉันรู้อีกเล็กน้อย
Bill Ruppert

10
คุณอาจต้องการno indirectหยุดสิ่งเหล่านั้นไม่ให้เกิดขึ้น
LeoNerd

@LeoNerd ขอบคุณสำหรับเคล็ดลับ!
Bill Ruppert

1
นี่เป็นคำถาม Perl ที่มีชื่อเสียงที่สุดเท่าที่เคยมีมา ดียิ่งขึ้นตามตัวอย่างของ Schwartz :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
@ ฮัสซานทำไม? ตามด้วยการแสดงออก
ikegami

3
ฉันได้เท่าที่อ่านมันเป็น "ข้อผิดพลาดของไวยากรณ์! exit 0;" แต่ฉันไม่ได้คิดถึงการภาวนาทางอ้อม ใช้เวลามากมายกับการลืมสิ่งนั้น!
Bill Ruppert

6
@ ฮัสซันลองคิดดูด้วยวิธีนี้!exit(0)จะไม่สามารถเป็นข้อผิดพลาดประเภทได้อีกกว่า!$xจะไม่มีการพิมพ์
ikegami

11
@ ฮัสซันภาษามีประเภท โดยเฉพาะค่ามีประเภท ผู้ประกอบการและผู้ใต้บังคับบัญชานั้นไม่ได้ จำกัด อยู่เฉพาะการคืนค่าชนิดที่เฉพาะเจาะจง สิ่งนี้กลายเป็นประโยชน์อย่างมากในราคาเพียงเล็กน้อย (ขอบคุณคำเตือน)
ikegami

6
@ นาวาซจริงๆแล้วมันค่อนข้างได้รับความนิยม โดยจะใช้โดยทุกคนว่าวัตถุโครงสร้างใน Java และ C ++ และร่างกายขนาดใหญ่ของโปรแกรมเมอร์ Perl ที่ใช้new Classและprint $fh ...แทนและClass->new(...) $fh->print(...)ฉันจะให้คุณว่ามันทำให้เกิดข้อความแสดงข้อผิดพลาดแปลก ๆ
ikegami

112

ฉันไม่รู้ว่าทำไม แต่นี่คือสิ่งที่ Perl ทำให้มัน:

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

ดูเหมือนว่า parser คิดว่าคุณกำลังเรียกวิธีการSyntaxในerror-object ... แปลกจริง ๆ !


3
นั่นคือไวยากรณ์การเรียกเมธอดทางอ้อม มัน (ประเภท) ทำงานที่นี่เพราะได้รับการประเมินครั้งแรกทำให้ออกจากโปรแกรมก่อนที่มันพยายามที่จะผ่านผลให้exit(0) 'error'->Syntax()
duskwuff -inactive-

6
Perl ดูเหมือนจะถือว่า "อ้อม (วัตถุ) ไวยากรณ์" มักจะใช้เช่นแทนnew Class Class->new()ที่จะเรียกวิธีการSyntaxที่exitฟังก์ชั่นจะถูกดำเนินการเพื่อให้เกิดข้อผิดพลาดเวลาทำงานไม่เคย occures
amon

118
ขอแสดงความยินดี คุณพบโปรแกรมที่คุณต้องการเพิ่มเซมิโคลอนเพื่อให้คอมไพล์ล้มเหลว
ม็อบ

use strict; use warnings; error->Syntax(! print "hi"); Yields: Syntax Ok บน perl -MO = Deparse เช่นกัน แต่ด้วยuse warningsมันอาจจะพูดอะไรบางอย่างเพราะมันสามารถเข้าใจได้ว่ามันไม่ได้โหลด แต่จะพ่นข้อผิดพลาดรันไทม์ "ไม่สามารถหาวิธีวัตถุ .. "

53

เหตุผลที่คุณไม่ได้รับข้อผิดพลาดคือรหัสที่เรียกใช้ครั้งแรกคือ

exit(0);

เนื่องจากคุณไม่มีเครื่องหมายอัฒภาคในบรรทัดแรก:

Syntax error!

คอมไพเลอร์จะเดา (อย่างไม่ถูกต้อง) ว่านี่เป็นการเรียกรูทีนย่อยด้วยnotโอเปอเรเตอร์ที่!ถูกโยนทิ้งจากนั้นมันจะดำเนินการโต้แย้งกับรูทีนย่อยนี้ซึ่งเกิดขึ้นเป็นexit(0)ที่จุดที่โปรแกรมออกจาก ดังนั้นจึงไม่มีรายงานข้อผิดพลาดรันไทม์อีก

คุณจะสังเกตเห็นว่าหากคุณเปลี่ยนexit(0)เป็นบางอย่างเช่นprint "Hello world!"คุณได้รับข้อผิดพลาด:

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

และระดับข้อผิดพลาดของคุณจะถูกตั้งค่า:

> echo %errorlevel%
255

7
>The compiler will guess (incorrectly) คอมไพเลอร์ไม่สามารถทำอะไรผิดพลาดได้
Liam Laverty

14
@LiamLaverty ใช่มันสามารถ มันสามารถเดาได้ไม่ถูกต้องว่าความหมายของมนุษย์คืออะไร
TLP

4
มนุษย์เป็นสิ่งที่ไม่ถูกต้องในสมการ คอมไพเลอร์สามารถ "ถูกต้อง" หรือ "แตกหัก" ได้เท่านั้น ไม่ได้รับความเห็นเกี่ยวกับคำจำกัดความของภาษาหรือความตั้งใจของผู้ใช้
Liam Laverty

4
@LiamLaverty มันคงจะเป็นคอมไพเลอร์ที่ค่อนข้างดีถ้ามันสามารถคาดเดาความตั้งใจของผู้ใช้ในกรณีนี้ได้ใช่ ดังนั้นคอมไพเลอร์ไม่สามารถคาดเดาได้อย่างถูกต้อง คุณอาจทำการวิเคราะห์ศัพท์แสงทางเทคนิคของคำสั่งของฉันซึ่งก็คือฉันอาจเพิ่มวิธีที่ไม่ถูกต้องในการอ่าน
TLP

มันแปลไม่ได้เหรอ? ;-)
Rikki

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; แทบจะไม่


ฉันชอบแบบนั้น. ฉันอาจต้องสแกนภาพบางภาพ
Bill Ruppert
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.