Không tệ cho một tarpit Turing khá dài ...
N
Count i while _%128-9 {
Count x while _/128%2 {
Write 40
_+128
}
Write _%128
_+128-_%128+N
}
Count j while _/256-j {
Write 41
}
(Vâng, tất cả khoảng trắng đó là bắt buộc.)
Lưu ý: vì những hạn chế đầu vào của Acc !! , không thể đọc một chuỗi ký tự tùy ý mà không có dấu phân cách kết thúc. Do đó, chương trình này dự kiến đầu vào (trên stdin) dưới dạng một chuỗi theo sau là một ký tự tab.
Acc !! ?
Đó là ngôn ngữ tôi tạo ra chỉ có vẻ không sử dụng được . Kiểu dữ liệu duy nhất là số nguyên, cấu trúc luồng điều khiển duy nhất là Count x while y
vòng lặp và cách duy nhất để lưu trữ dữ liệu là một bộ tích lũy duy nhất _
. Đầu vào và đầu ra được thực hiện một ký tự tại một thời điểm, sử dụng giá trị đặc biệt N
và Write
câu lệnh. Mặc dù có những hạn chế này, tôi khá chắc chắn rằng Acc !! là Turing-hoàn thành.
Giải trình
Chiến lược cơ bản trong Acc !! lập trình là sử dụng %
phân chia mod và số nguyên /
để phân chia khái niệm bộ tích lũy, cho phép nó lưu trữ nhiều giá trị cùng một lúc. Trong chương trình này, chúng tôi sử dụng ba phần như vậy: bảy bit ( _%128
) thứ tự thấp nhất lưu trữ mã ASCII từ đầu vào; bit tiếp theo ( _/128%2
) lưu trữ giá trị cờ; và các bit còn lại ( _/256
) đếm số lượng parens gần mà chúng ta sẽ cần.
Đầu vào trong Acc !! xuất phát từ giá trị đặc biệt N
, đọc một ký tự đơn và đánh giá mã ASCII của nó. Bất kỳ câu lệnh nào chỉ bao gồm một biểu thức đều gán kết quả của biểu thức đó cho bộ tích lũy. Vì vậy, chúng tôi bắt đầu bằng cách lưu trữ mã của ký tự đầu tiên trong bộ tích lũy.
_%128
sẽ lưu trữ các nhân vật được đọc gần đây nhất. Vì vậy, vòng lặp đầu tiên chạy trong khi _%128-9
là khác không - nghĩa là, cho đến khi ký tự hiện tại là một tab.
Trong vòng lặp, chúng tôi muốn in (
trừ khi chúng tôi ở lần lặp đầu tiên. Vì Acc !! không có câu lệnh if, chúng ta phải sử dụng các vòng lặp cho các điều kiện. Chúng tôi sử dụng bit 128 của bộ tích lũy _/128%2
, làm giá trị cờ. Trên đường chuyền đầu tiên, điều duy nhất trong bộ tích lũy là giá trị ASCII <128, do đó cờ là 0 và vòng lặp bị bỏ qua. Trên mỗi lần vượt qua tiếp theo, chúng tôi sẽ đảm bảo cờ là 1.
Bên trong Count x
vòng lặp (bất cứ khi nào cờ là 1), chúng ta viết một paren mở (ASCII 40
) và thêm 128 vào bộ tích lũy, từ đó đặt cờ thành 0 và thoát khỏi vòng lặp. Điều này cũng xảy ra để tăng giá trị của _/256
, mà chúng ta sẽ sử dụng như là kiểm đếm gần đúng của chúng để làm đầu ra.
Bất kể giá trị của cờ là gì, chúng tôi viết char đầu vào gần đây nhất, đơn giản là vậy _%128
.
Bài tập tiếp theo ( _+128-_%128+N
) thực hiện hai điều. Đầu tiên, bằng cách thêm 128, nó đặt cờ cho lần tiếp theo thông qua vòng lặp. Thứ hai, nó thoát ra khỏi _%128
khe, đọc một ký tự khác và lưu nó ở đó. Sau đó, chúng tôi lặp.
Khi Count i
vòng lặp thoát, chúng ta vừa đọc một ký tự tab và giá trị bộ tích lũy bị phá vỡ như sau:
_%128
: 9
(ký tự tab)
_/128%2
: 1
(cờ)
_/256
: số ký tự được đọc, trừ 1
(Điểm trừ 1 là bởi vì chúng ta chỉ thêm 128 vào bộ tích lũy một lần trong lần đầu tiên đi qua vòng lặp chính.) Tất cả những gì chúng ta cần bây giờ là các parens gần. lần Count j while _/256-j
lặp _/256
, viết một paren gần (ASCII 41
) mỗi lần. Voila!