INTERCAL (C-INTERCAL), 15 mã, 313 + 2 = 315 byte
PLEASE WRITE IN .1
(8) PLEASE CREATE .1 A
PLEASE A
PLEASE COME FROM #2$!1/#1'
DO X
(123) DO (123) NEXT
DO COME FROM (222)
(222) DO STASH .2
(240) DO ,1 <- #0
(241) DO ,1 SUB #0 <- #1
(19) DO .2 <- #256 $ #0
(21) DO .1 <- #2
(148) DO GO BACK
(180) DO RETRIEVE .2
DO COME FROM (50)
(50) DO WRITE IN .2
(109) DO RESUME #0
(120) DO RESUME #9
MAYBE COME FROM (223)
(223) DO COME FROM (223)
(121) PLEASE NOT X
Hãy thử trực tuyến!
Tất cả khoảng trắng ở đây là không liên quan. (Chương trình ban đầu chứa các tab, nhưng tôi đã chuyển đổi chúng thành khoảng trắng để nó xếp hàng chính xác trên SE; thông thường sử dụng chiều rộng tab là 8 cho INTERCAL. Tôi đã thử nghiệm phiên bản chương trình với tất cả các tab, khoảng trắng và các dòng mới đã bị xóa, tuy nhiên, và nó hoạt động tốt.)
Biên dịch với -abm
(hình phạt 2 byte, vì -b
được yêu cầu cho trình biên dịch có tính xác định).
Như thường lệ đối với INTERCAL, điều này nhận đầu vào số ở định dạng, ví dụ: ONE TWO THREE
cho 123
.
Giải trình
Khi chương trình C-INTERCAL bị lỗi, trạng thái thoát là mã lỗi modulo 256. Do đó, chúng ta có thể nhắm đến việc viết một chương trình có khả năng tạo ra càng nhiều lỗi thời gian chạy càng tốt. Chương trình này chỉ bỏ qua hai lỗi thời gian chạy không chỉ ra các vấn đề của trình biên dịch nội bộ: ICL200I, vì việc sao chép nó yêu cầu sử dụng các thư viện bên ngoài chỉ tương thích với một chương trình đơn luồng (và các chương trình đa luồng có nhiều lỗi hơn); và ICL533I, vì 533 có cùng giá trị modulo 256 như 277 và chương trình có khả năng sản xuất ICL277I.
Chương trình luôn bắt đầu theo cùng một cách. Đầu tiên, chúng ta nhập ( WRITE IN
) một giá trị cho biến .1
. Sau đó, chúng tôi sử dụng một CREATE
câu lệnh được tính toán để tạo cú pháp mới (ở đây, A
); nhưng vì nó được tính toán nên định nghĩa của cú pháp thay đổi dựa trên giá trị của .1
. Cuối cùng, trong hầu hết các trường hợp, chúng tôi chạy A
câu lệnh mới , đã được xác định để tạo ra lỗi; bảng định nghĩa có thể có mà chúng tôi có chứa một định nghĩa cho từng lỗi thời gian chạy có thể xảy ra (trừ các trường hợp ngoại lệ được liệt kê ở trên).
Đầu tiên, có hai trường hợp ngoại lệ cho sơ đồ chung này. (0)
không phải là số dòng hợp lệ, vì vậy nếu người dùng nhập vào ZERO
, chúng ta sẽ nhảy từ dòng thứ hai (được đánh số (8)
) sang dòng thứ tư bằng COME FROM
câu lệnh được tính toán . Điều này sau đó rơi vào một lỗi cú pháp DO X
, tạo ra lỗi ICL000I
. (Trong INTERCAL, lỗi cú pháp xảy ra trong thời gian chạy, do xu hướng của các lệnh bị vô hiệu hóa, cú pháp được xác định lại theo bạn, v.v.). Các COME FROM
tuyên bố cũng có một tác dụng phụ, ngay cả khi không thực tế COME FROM
xảy ra, tạo ra một tình trạng quá tải toán hạng từ .1
để #1
bất cứ khi nào một phù hợp với một số dòng được thực hiện; điều này được sử dụng sau này khi tạo đầu ra 21. (Tác dụng phụ toàn cầu ngẫu nhiên khá thành ngữ trong INTERCAL.)
Ngoại lệ khác là với đầu vào ONE TWO NINE
. Không có số dòng (129)
trong chương trình, vì vậy chúng tôi gặp lỗi cho số dòng bị thiếu ICL129I
. Vì vậy, tôi đã không phải viết bất kỳ mã nào để bao gồm cả trường hợp đó.
Dưới đây là các lỗi khác và nguyên nhân gây ra chúng:
- 123 là một
NEXT
ngăn xếp tràn ( DO (123) NEXT
). Câu NEXT
lệnh cần các bộ sửa đổi ( FORGET
hoặc RESUME
) khác để xác định hồi tố loại câu lệnh điều khiển đó là gì. Không có những nguyên nhân gây ra lỗi ICL123I khi có 80 câu lệnh `NEXT chưa được giải quyết.
- 222 là một tràn stash (
DO STASH .2
trong một COME FROM
vòng lặp). Các bản lưu chỉ bị giới hạn bởi bộ nhớ khả dụng, nhưng cuối cùng sẽ hết, gây ra lỗi ICL222I.
- 240 là kích thước một mảng để kích thước bằng không. Đó chính xác là những gì
DO ,1 <- #0
có nghĩa là, và nó gây ra lỗi ICL240I.
- 241 được gây ra bởi việc gán bên ngoài giới hạn của một mảng. Trong trường hợp này,
,1
chưa được phân bổ ( ,
được sử dụng cho các biến kiểu mảng trong INTERCAL), do đó, việc lập chỉ mục nó gây ra lỗi ICL241I.
- 19 gán 65536 (
#256 $ #0
) cho biến 16 bit .2
. Nó không phù hợp, gây ra lỗi ICL275I.
- 21 giao
#2
cho .1
. Điều đó có thể trông giống như một nhiệm vụ đủ đơn giản, nhưng chúng tôi đã quá tải .1
có nghĩa là #1
sớm hơn và cố gắng thay đổi giá trị 1 mà không có -v
tùy chọn nào trên dòng lệnh gây ra lỗi ICL277I.
- 148 cố gắng quay lại mục trên cùng của ngăn xếp điểm lựa chọn (
GO BACK
), không tồn tại vào thời điểm này trong chương trình (chúng tôi không chạy bất kỳ lệnh nào để thao tác ngăn xếp điểm lựa chọn, vì vậy nó vẫn trống). Điều đó gây ra lỗi ICL404I.
- 180 lần thử
RETRIEVE .2
từ một ngăn không tồn tại (vì chúng tôi đã không bỏ bất kỳ thứ gì có trong nhánh này của chương trình), gây ra lỗi ICL436I.
- 50 yêu cầu đầu vào (
WRITE IN
) mãi mãi trong một COME FROM
vòng lặp. Cuối cùng, chúng tôi sẽ đọc hết EOF, gây ra lỗi ICL562I.
- 109 chạy câu lệnh
DO RESUME #0
, điều này là vô nghĩa và được ghi lại cụ thể là gây ra lỗi (ICL621I).
- 120 chạy các tuyên bố
DO RESUME #9
. Chúng tôi chưa chạy nhiều NEXT
câu lệnh đó và do đó chúng tôi gặp lỗi ICL120I. (Thật thú vị, lỗi cụ thể này được xác định trong tài liệu INTERCAL là thoát khỏi chương trình một cách bình thường và sau đó gây ra lỗi, thay vì thoát khỏi chương trình có lỗi. Tuy nhiên, tôi không tin hai trường hợp này khác nhau.
- Về cơ bản, 223 là một mớ phức tạp của các nguyên thủy đa luồng mà tất cả đều quay về dòng 223, gây ra một vòng lặp vô hạn làm nổ tung bộ nhớ. Cuối cùng, có sự cạn kiệt bộ nhớ trong hệ thống con đa luồng, dẫn đến lỗi ICL991I.
- 121 thực sự là một tuyên bố hợp lệ (đó là một nhận xét), nhưng nó xuất hiện ở cuối chương trình. Như vậy, việc thực thi rơi ra khỏi phần cuối của chương trình ngay sau khi nó thực thi, gây ra lỗi ICL633I.
xác minh
Một số lỗi liên quan đến việc cố tình chạy chương trình ra khỏi bộ nhớ, vì vậy tôi khuyên bạn nên đặt giới hạn bộ nhớ khá nhỏ. Đây là lệnh shell tôi đã sử dụng để kiểm tra chương trình (với các dòng mới được thêm vào để dễ đọc; xóa chúng nếu bạn tự chạy nó):
for x in "ZERO" "ONE NINE" "TWO ONE" "FIVE ZERO" "ONE ZERO NINE"
"ONE TWO ZERO" "ONE TWO ONE" "ONE TWO THREE" "ONE TWO NINE"
"ONE FOUR EIGHT" "ONE EIGHT ZERO" "TWO TWO TWO"
"TWO TWO THREE" "TWO FOUR ZERO" "TWO FOUR ONE";
do echo;
echo $x;
echo $x | (ulimit -Sd 40000; ulimit -Sv 40000; ulimit -Ss 40000;
./errors; echo $?);
done
Và đây là đầu ra (với số dòng và thông báo "XIN NGUỒN NGUỒN" đã bị xóa để tiết kiệm dung lượng), tôi đã thêm một phần để chứng minh chương trình hoạt động nhưng chủ yếu là để hiển thị các thông báo lỗi ngớ ngẩn của INTERCAL:
ZERO
ICL000I PLEASEWRITEIN.1(8)PLEASECREATE.1APLEASEAPLEASECOMEFROM#2$!1/#1'DOX(123)DO(123)NEXTDOCOMEFROM(222)(222)DOSTASH.2(240)DO,1<-#0(241)DO,1SUB#0<-#1(19)DO.2<-#256$#0(21)DO.1<-#2(148)DOGOBACK(180)DORETRIEVE.2DOCOMEFROM(50)(50)DOWRITEIN.2(109)DORESUME#0(120)DORESUME#9MAYBECOMEFROM(223)(223)DOCOMEFROM(223)(121)PLEASENOTX
0
ONE NINE
ICL275I DON'T BYTE OFF MORE THAN YOU CAN CHEW
19
TWO ONE
ICL277I YOU CAN ONLY DISTORT THE LAWS OF MATHEMATICS SO FAR
21
FIVE ZERO
ICL562I I DO NOT COMPUTE
50
ONE ZERO NINE
ICL621I ERROR TYPE 621 ENCOUNTERED
109
ONE TWO ZERO
ICL632I THE NEXT STACK RUPTURES. ALL DIE. OH, THE EMBARRASSMENT!
120
ONE TWO ONE
ICL633I PROGRAM FELL OFF THE EDGE
121
ONE TWO THREE
ICL123I PROGRAM HAS DISAPPEARED INTO THE BLACK LAGOON
123
ONE TWO NINE
ICL129I PROGRAM HAS GOTTEN LOST
129
ONE FOUR EIGHT
ICL404I I'M ALL OUT OF CHOICES!
148
ONE EIGHT ZERO
ICL436I THROW STICK BEFORE RETRIEVING!
180
TWO TWO TWO
ICL222I BUMMER, DUDE!
222
TWO TWO THREE
ICL991I YOU HAVE TOO MUCH ROPE TO HANG YOURSELF
223
TWO FOUR ZERO
ICL240I ERROR HANDLER PRINTED SNIDE REMARK
240
TWO FOUR ONE
ICL241I VARIABLES MAY NOT BE STORED IN WEST HYPERSPACE
241