In, Tăng, Giảm, Bí danh - Giải thích Giải thích


30

Prindeal (phát âm là prin-dee-al ) là một ngôn ngữ lập trình bí truyền mới chỉ có bốn lệnh: pr int , in crement , de cremental ias . Bất chấp sự tối giản của nó, các phép toán phức tạp có thể được thực hiện trong Prindeal bằng cách kết hợp khéo léo bốn lệnh.

Nhiệm vụ của bạn trong thử thách chơi gôn mã này là viết chương trình ngắn nhất có thể chạy mã Prindeal.

Thông số kỹ thuật dài nhưng tôi đã cố gắng làm cho nó rõ ràng nhất có thể và tôi tin rằng nếu bạn nỗ lực để học Prindeal, bạn sẽ thấy nó khá thanh lịch!


Giải thưởng nội bộ

Sơ chế

Trước khi chương trình Giải thưởng có thể được diễn giải, những điều này cần phải được loại bỏ khỏi chương trình theo thứ tự sau:

  1. Bất cứ điều gì sau khi một #dấu hiệu đến cuối dòng, nó cộng với #chính nó. (Đây là những bình luận.)
  2. Trailing khoảng trắng trên bất kỳ dòng.
  3. Dòng hoàn toàn trống rỗng.

Ví dụ, chương trình Giải thưởng

p cat #The next line has 7 trailing spaces.
p dog       

#p mouse

sẽ được xử lý trước thành

p cat
p dog

Từ đây trở đi, chúng tôi sẽ giả định bước tiền xử lý này đã được thực hiện.

Biến

Chúng ta cần nhanh chóng xác định các biến trước khi hiển thị cách chúng được sử dụng.

Các biến (và tham chiếu đến các biến) là những gì được truyền vào các đối số của các lệnh Prindeal. Các biến luôn luôn là toàn cục , do đó, sửa đổi cho một biến, bất kể chúng xảy ra ở đâu, được phản ánh ở mọi nơi.

Mỗi biến chứa một số nguyên không chính xác tùy ý không âm (0, 1, 2, 3, ...). Các biến không cần phải được khởi tạo trước - chúng luôn bắt đầu bằng giá trị 0 trong lần đầu tiên chúng được sử dụng hoặc được gọi cho.

Một tên biến có thể là bất kỳ chuỗi chữ và số không trống nào không bắt đầu bằng một chữ số - [a-zA-Z_][0-9a-zA-Z_]*trong regex . Chúng là trường hợp nhạy cảm, vì vậy spiny_lumpsuck3rSpiny_lumpsuck3rlà các biến khác nhau.

Chấp hành

Prindeal là một ngôn ngữ lập trình bắt buộc . Khi một chương trình Prindeal được chạy, các câu lệnh của nó được thực thi từ trên xuống dưới theo thứ tự và sau đó chương trình kết thúc.

Mỗi dòng không thụt lề trong chương trình Prindeal là một câu lệnh liên quan đến việc thực thi một lệnh duy nhất có thể hoặc không thể lấy các đối số.

Các dòng thụt lề chỉ xảy ra sau các lệnh bí danh . Cụ thể, chính xác ba dòng thụt vào với các khoảng trắng đơn xảy ra sau mỗi lệnh bí danh và được coi là một phần của nó. Vì vậy, các tuyên bố bí danh thực sự dài bốn dòng. (Chúng có thể là một dòng, bốn chỉ đơn giản là dễ đọc hơn.)

Tuyên bố không bí danh

Ngoại trừ bí danh , mọi tuyên bố trong chương trình Giải thưởng đều có dạng:

[command name] [argument 1] [argument 2] [argument 3] ...

Có thể có một số lượng đối số tùy ý (bao gồm cả không có đối số). Mỗi đối số luôn là một biến hoặc (như chúng ta sẽ thấy khi thảo luận về bí danh ) một tham chiếu đến một biến .

Sau khi thực hiện xong, mỗi câu lệnh được gắn cờ là thất bại hoặc thành công tùy thuộc vào việc có gặp phải lỗi hay không. (Điều này chỉ thực sự quan trọng khi chúng ta sử dụng bí danh .)

Bản in , tănggiảm tích hợp là các câu lệnh có dạng ở trên. Đây là những gì họ làm:

  1. print có tên lệnh pvà lấy một đối số. Nó in tên của biến được truyền vào và giá trị của nó (theo số thập phân) được phân tách bằng "=", sau đó là một dòng mới. Nó luôn được gắn cờ là một thành công .

    Ví dụ, chương trình Giải thưởng

    p _MyVariable_321
    p screaming_hairy_armadillo
    

    sẽ xuất

    _MyVariable_321 = 0
    screaming_hairy_armadillo = 0
    

    bởi vì tất cả các biến bắt đầu từ 0. (Không gian trước và sau dấu bằng được yêu cầu.)

  2. gia tăng có tên lệnh ivà nhận một đối số. Nó tăng giá trị của biến được truyền vào 1. Nó luôn được gắn cờ là thành công ..

    Ví dụ, chương trình

    i alpaca
    p alpaca
    i alpaca
    p alpaca
    

    sẽ xuất

    alpaca = 1
    alpaca = 2
    

    Lưu ý cách alpacatăng từ 0 lên 1 mặc dù trước đó chưa bao giờ được truy cập.

  3. decrement có tên lệnh dvà lấy một đối số. Nếu biến được truyền vào là khác 0 thì giá trị của nó bị giảm đi 1 và câu lệnh được gắn cờ là thành công . Nếu biến được truyền vào là 0 thì không có gì được thực hiện và câu lệnh được gắn cờ là thất bại .

    Ví dụ, chương trình

    i malamute
    p malamute
    d malamute    #success
    p malamute
    d malamute    #failure
    p malamute
    d akita       #failure
    p akita
    

    sẽ xuất

    malamute = 1
    malamute = 0
    malamute = 0
    akita = 0
    

    Lưu ý rằng việc giảm một biến có giá trị 0 là cách duy nhất để tạo ra lỗi .

Các bí danh Tuyên bố và bí danh Commands

Lệnh bí danh có một cú pháp đặc biệt và mạnh nhất vì nó có thể được sử dụng để xác định các lệnh mới. Tên lệnh bí danhavà một câu lệnh bí danh có dạng:

a [name of new command]
 [statement A]
 [statement B]
 [statement C]

Trong đó mỗi [statement X]đại diện cho bất kỳ câu lệnh không bí danh nào , tức là một cái gì đó với biểu mẫu [command name] [argument 1] [argument 2] [argument 3] ....

Tên của lệnh bí danh [name of new command]có thể là bất kỳ chuỗi chữ và số không trống nào không bắt đầu bằng một chữ số - [a-zA-Z_][0-9a-zA-Z_]*trong biểu thức chính quy.

(Đây là cùng một tập hợp các tên như các biến nhưng các lệnh và biến bí danh là những thứ khác nhau được sử dụng ở những nơi khác nhau . Một biến có thể được đặt tên giống như một lệnh không có hậu quả xấu.)

Khi một câu lệnh bí danh được thực thi, một lệnh mới sẽ được thêm vào cùng với bốn p i d alệnh gốc . Lệnh mới có thể được sử dụng như các [command name]câu lệnh trong và được gọi với các đối số giống như bất kỳ lệnh không bí danh nào khác .

Khi một câu lệnh có tên lệnh bí danh được thực thi, chính xác hai câu lệnh nữa từ câu lệnh bí danh ban đầu của nó được chạy:

  • [statement A] luôn luôn chạy
  • [statement B]đang chạy nếu [statement A]là một thành công
  • [statement C]đang chạy nếu [statement A]là một thất bại

Các câu A, B và C luôn được chạy một cách lười biếng , tức là chúng được đánh giá một cách nhanh chóng tại thời điểm chúng được chạy.

Khi thực hiện xong, lệnh bí danh được gắn cờ với cùng một thành công hoặc thất bại giống như câu lệnh B hoặc C, bất kỳ lệnh nào được thực thi . ( bản thân các tuyên bố bí danh không cần phải được gắn cờ vì chúng không thể xảy ra trong chính chúng.)

Bí danh Ví dụ 1

Nói rằng chúng tôi muốn một lệnh mới làm tăng biến frog hai lần. Tuyên bố bí danh này đạt được nó:

a increment_frog_twice
 i frog
 i frog
 d frog

Câu lệnh A ( i frog) luôn được chạy và luôn được gắn cờ là thành công, vì vậy câu lệnh B ( i frog) cũng luôn luôn chạy và frog do đó biến được tăng thêm 2. increment_frog_twiceLệnh luôn được gắn cờ là thành công vì câu lệnh B luôn chạy và B luôn luôn là một thành công . Tuyên bố C ( d frog) không bao giờ được chạy.

Vì vậy, đầu ra để

a increment_frog_twice
 i frog
 i frog
 d frog
p frog
increment_frog_twice
p frog

sẽ là

frog = 0
frog = 2

Chúng ta có thể khái quát ví dụ này để bất kỳ biến nào có thể được tăng lên hai lần bằng cách đưa ra lệnh đối số.

Trong một câu lệnh bí danh, các số nguyên dương 1, 2, 3, v.v. đại diện cho các đối số 1, 2, 3, v.v. được truyền vào lệnh bí danh. (Các đối số này có thể là các biến đơn giản hoặc tham chiếu đến chính các biến.) Các số này chỉ có thể xuất hiện trong các đối số của câu lệnh A, B và C trong câu lệnh bí danh . Nó không có ý nghĩa đối với họ xuất hiện ở nơi khác.

Bí danh Ví dụ 2

Điều này khái quát hóa ví dụ cuối cùng - bất kỳ biến nào được truyền vào increment_twicesẽ được tăng thêm 2 vì 1là tham chiếu đến đối số đầu tiên được truyền vào:

a increment_twice
 i 1
 i 1
 d 1 #never reached
p toad
increment_twice toad
p toad

Đầu ra của chương trình này sẽ là

toad = 0
toad = 2

Sau đó chúng ta có thể đặt bí danh cho một lệnh khác có hai đối số và gọi increment_twicecả hai:

a increment_twice
 i 1
 i 1
 d 1 #never reached
a increment_both_twice
 increment_twice 1
 increment_twice 2
 d 1 #never reached
increment_both_twice platypus duck
p platypus
p duck

Đầu ra ở đây sẽ là

platypus = 2
duck = 2

Điều quan trọng là phải nhận ra rằng các lệnh bí danh có thể được đệ quy, vì đây là nơi sức mạnh thực sự của chúng nằm. Ví dụ: chúng ta có thể tạo một lệnh đặt bất kỳ biến nào được truyền vào 0:

Bí danh Ví dụ 3

Các set_to_zerolệnh có một đối số và thiết lập biến của nó để 0 và được gắn cờ là một thành công khi thực hiện:

a set_to_zero
 d 1
 set_to_zero 1
 i _dummy_
i oryx
i oryx
i oryx
p oryx
set_to_zero oryx
p oryx

Đầu ra của chương trình này sẽ là

oryx = 3
oryx = 0

Điều đang xảy ra là khi set_to_zero oryxđược chạy, d 1giảm thành công oryxtừ 3 ​​xuống 2, sau đó set_to_zero 1được gọi, tương tự như gọi set_to_zero oryxlại. Vì vậy, lặp đi lặp lại quá trình cho đến khi d 1là một thất bại , ngăn chặn sự đệ quy và tăng các _dummy_biến do đó, một thành công được sản xuất.


Thử thách

Viết chương trình có thể thực thi mã Prindeal chính xác như được mô tả ở trên. Lấy mã Prindeal thông qua stdin, dòng lệnh hoặc dưới dạng tệp văn bản. In kết quả đầu ra của chương trình Prindeal lên thiết bị xuất chuẩn hoặc ngôn ngữ thay thế gần nhất với ngôn ngữ của bạn.

Ngoài ra, bạn có thể viết một hàm lấy mã dưới dạng chuỗi và in hoặc trả về chuỗi đầu ra.

Ngoài ra, bạn có thể giả định rằng:

  • Mã Prindeal đầu vào sẽ chỉ chứa các dòng mới và ASCII có thể in được và (tùy chọn) mà nó kết thúc bằng một dòng trống.
  • Mã đầu vào sẽ hợp lệ Prindeal - được hình thành tốt và đúng về mặt cú pháp.
  • Chạy mã sẽ không tạo ra bất kỳ vòng lặp vô hạn cũng như bất kỳ tham chiếu không hợp lệ nào cho các lệnh chưa được xác định hoặc các đối số chưa được đưa ra.
  • Các tên lệnh p, i, d, và asẽ không bao giờ được aliased kết thúc. (Bạn có thể không cho rằng các biến sẽ không có các tên này.)

Ngoài ra, sẽ không có vấn đề gì nếu các giá trị biến của bạn không thực sự là các số nguyên chính xác tùy ý vì chỉ các số nhỏ hơn khoảng 1000 sẽ được kiểm tra. Cũng không sao nếu ngôn ngữ của bạn có giới hạn đệ quy (như Python ) mà các chương trình Prindeal phức tạp hơn có thể gặp phải miễn là chương trình thử nghiệm bên dưới hoạt động.

Chương trình kiểm tra

Đây là một chương trình Prindeal lớn, xây dựng các hoạt động cộng, nhân và lũy thừa thông qua việc sử dụng các biến giả (bắt đầu _bằng quy ước) và nhiều bí danh trợ giúp:

#Command Definitions:
a s             #flag as a success
 i _
 d _
 d _
a f             #flag as a failure
 d _
 d _
 d _
a z             #1 = zero
 d 1
 z 1
 s
a n             #1 = one
 z 1
 i 1
 s
a move          #2 += 1, 1 = zero
 moveH 1 2
 move 1 2
 s
a moveH         #move helper
 d 1
 i 2
 f
a dupe          #2 += 1, 3 += 1, 1 = zero
 dupeH1 1 2 3
 dupe 1 2 3
 s
a dupeH1        #dupe helper
 d 1
 dupeH2 2 3
 f
a dupeH2        #dupe helper
 i 1
 i 2
 s
a copy          #2 = 1
 z 2
 copyH 1 2
 s
a copyH         #copy helper
 dupe 1 2 _copy
 move _copy 1
 s
a addTo         #1 += 2
 copy 2 _add
 #testing comments #
 move _add 1#in weird places # just because #
 s
#it's a g##d idea
###
a add           #1 = 2 + 3
 #its a good idea
 z 1
 addH 1 2 3
 s
##

#
a addH          #add helper
#this is a comment
 addTo 1 2 #as is this
 addTo 1 3
 s
a mul           #1 = 2 * 3
 mulH1 1 2
 mulH2 1 3
 s
a mulH1         #mul helper
 z 1
 copy 2 _mul
 s
a mulH2         #mul helper
 mulH3 1 2
 mulH2 1 2
 s
a mulH3         #mul helper
 d _mul
 addTo 1 2
 f
a mulBy         #1 *= 2
 mul _mulBy 1 2
 copy _mulBy 1
 s
a pow           #1 = 2^3
 powH1 1 3
 powH2 1 2
 s
a powH1         #pow helper
 n 1
 copy 2 _pow
 s
a powH2         #pow helper
 powH3 1 2
 powH2 1 2
 s
a powH3         #pow helper
 d _pow
 mulBy 1 2
 f

#Running Tests:
p A
p B
p C
n A         #A = 1
n B         #B = 1
add C A B   #C = A + B = 1 + 1 = 2
p ____
p A
p B
p C
add B A C   #B = A + C = 1 + 2 = 3
p ____
p A
p B
p C
mul d B C   #d = B * C = 3 * 2 = 6
p ____
p d
mulBy d B   #d = d * B = 6 * 3 = 18
p ____
p d
d A         #A = A - 1 = 1 - 1 = 0
mulBy d A   #d = d * A = 18 * 0 = 0
p ____
p d
pow A C B   #A = C ^ B = 2 ^ 3 = 8
p ____
p A
p B
p C
pow A B C   #A = B ^ C = 3 ^ 2 = 9
p ____
p A
p B
p C
pow C A B   #C = A ^ B = 9 ^ 3 = 729
p ____
p A
p B
p C

(Nếu bạn đang chơi xung quanh với mã này, hãy lưu ý rằng nhiều lệnh sẽ thất bại nếu cùng một biến được đưa ra nhiều lần làm đối số. Điều này có thể dễ dàng được sửa nhưng mã kết quả dài hơn.)

Trình thông dịch Prindeal của bạn sẽ có thể tạo đầu ra chính xác:

A = 0
B = 0
C = 0
____ = 0
A = 1
B = 1
C = 2
____ = 0
A = 1
B = 3
C = 2
____ = 0
d = 6
____ = 0
d = 18
____ = 0
d = 0
____ = 0
A = 8
B = 3
C = 2
____ = 0
A = 9
B = 3
C = 2
____ = 0
A = 9
B = 3
C = 729

Chấm điểm

Mã ngắn nhất tính bằng byte thắng. Tiebreaker đi đến trình trước đó.

Phần thưởng Brownie: Viết một chương trình thú vị trong Prindeal. Tôi đã thực hiện phép cộng và phép nhân, bạn có thể thực hiện phép trừ hoặc phép chia không?


Ôi trời, tôi nghĩ lần đầu tiên tôi sẽ rời khỏi Pyth một mình và rút ra một Lisp! Một câu hỏi - hàm và biến sống trong các không gian tên hoàn toàn khác nhau, phải không? Vì vậy, tôi có thể tăng p, và sau đó p p, sẽ in 1, phải không?
orlp

@orlp Đúng. (Có một số lưu ý về điều đó trong đó.)
Sở thích của Calvin

2
Tôi không thể là người duy nhất nghĩ PRNDL khi tôi thấy tên ngôn ngữ.
Hạ cấp

Có số lượng đối số tối đa sẽ được truyền cho một lệnh bí danh không?
Zach Gates

@ZachGates Không
Sở thích của Calvin

Câu trả lời:


9

Pyth, 162 136 byte

JfTmchcd\#).zKHW<ZlJI!e=T@J~+Z1=@Tk)=k0 .x=J+]h=Nm.xL@Tskd@K=NhT+]+tN0>J~Z0,=Y.x@H=eT0?qN\pps[Td\=dYb)?xGN?qN\iXHThY?YXTH_1=k1XKT:JZ=+Z3

Trình diễn.

Đánh ra 26 ký tự bằng cách đặt các biến số và thay đổi luồng điều khiển từ IEdựa trên ?.x luồng điều khiển dựa trên.

Lần đầu tiên, tôi hết các biến trong Pyth. Mỗi biến số trong Pyth ( bdkGHNTYJK) đã được sử dụng và tôi muốn sử dụng blàm dòng mới. Một cách ngẫu nhiên, tôi đã có thể sử dụngN để chỉ hai điều hoàn toàn khác nhau trong các phần khác nhau của chương trình, và vì vậy nó vẫn hoạt động.

Ungolfed (chạy với -m):

JfTmchcd\#).z
KH
W<ZlJ
  I!e=T@J~+Z1
    =@Tk)
  =k0
     .x
      =J+]h=Nm.xL@Tskd@K=NhT+]+tN0>J~Z0
      ,
        =Y.x@H=eT0
        ?qN\p
          ps[Td\=dYb)
          ?xGN
            ?qN\i
              XHThY
              ?Y
                XTH_1
                =k1
            XKT:JZ=+Z3

3
Tôi yêu cách mà tôi vẫn không thể biết nó làm gì ngay cả khi nó không được ...
Jerry Jeremiah

Chà, kết luận đó là Pyth là không hoàn hảo ...
Erik the Outgolfer

8

Python 2, 600 584 397 373 byte

Đây là giải pháp tham khảo golf của riêng tôi. Bất cứ ai cũng được hoan nghênh cải thiện nó hoặc tuân theo logic của nó trong câu trả lời của riêng họ miễn là được quy kết.

Phần gọn gàng của nó là không có đệ quy được thực hiện, do đó nó sẽ không bao giờ gặp vấn đề với giới hạn đệ quy của Python. Ví dụ, chương trình Giải thưởng Countup của Sp có thể chạy vô thời hạn.

p=filter(len,[l.split('#')[0].split()for l in input().split('\n')]);m={};v={};i=0
while i<len(p):
 s=p[i]
 if'('in`s`:s=s[f]
 n,f=s[0],0
 if n in m:a,b,c=([s[int(g)]if g.isdigit()else g for g in t]for t in m[n]);p=[a,(b,c)]+p[i+1:];i=0;continue
 s=s[1]
 q=v.get(s,0)
 if'd'>n:m[s]=p[i+1:i+4];i+=3
 elif'i'<n:print s,'=',q
 elif'd'<n:v[s]=q+1
 elif q:v[s]-=1
 else:f=1
 i+=1

Đây là một chương trình lấy chuỗi chương trình được trích dẫn với các dòng mới được thoát, ví dụ:
'p _MyVariable_321\np screaming_hairy_armadillo' .

Tôi lấy nhiều tín hiệu golf từ câu trả lời của SpPietu . Cảm ơn các bạn :)


6

Python 3, 345 336 335 328 byte

a=0
A={}
V={}
def f(l):
 if l[0]in"d p i":c,u=l;U=V[u]=V.get(u,0)+"pi".find(c);S=U<0;V[u]+=S;c<"p"or print(u,"=",U)
 else:d=lambda q:[w.isdigit()and l[int(w)]or w for w in A[l[0]][q]];S=f(d(1+f(d(0))))
 return S
for z in open("P"):
 l=z.split("#")[0].split()
 if"a "==z[:2]:a,s,*x=3,l[1]
 elif l*a:x+=l,;a-=1;A[s]=x
 elif l:f(l)

(-6 byte nhờ @orlp)

Vẫn chơi golf. Giả sử chương trình được lưu trữ trong một tệp có tênP .

Đặt các cuộc gọi vào fbên trong lambdad sẽ tiết kiệm được một vài byte, nhưng nó sẽ làm cho trường hợp thử nghiệm cuối cùng đạt được độ sâu đệ quy tối đa.

Một số chương trình giải thưởng

Chương trình trừ vô dụng

Đây là một chương trình trừ vô dụng . Điều đó là vô ích bởi vì, mặc dù nó trừ đúng, nhưng nó không trả lại thành công / thất bại tương ứng.

Đầu ra phải là:

a = 15
b = 6
__________ = 0
a = 9
b = 6

Đếm dần lên

a helper
 p 1
 countup 1
 i success

a countup
 i 1
 helper 1
 d failure

countup n

Đếm lên và in nmãi mãi. Có thể có thể hoạt động như một bài kiểm tra tốc độ thông dịch viên (hãy cẩn thận với các dấu vết dài trên ngắt bàn phím).


2
Mọi người trong câu hỏi này đã bỏ lỡ môn đánh gôn này, tôi không hiểu tại sao. l[:(l+"#").find("#")]và tất cả các biến thể của nó có thể được thay thế bằng một đơn giản l.split('#')[0].
orlp

@orlp Đã quá tập trung vào findviệc tôi quên bạn có thể splitngay cả khi #không có ở đó. Cảm ơn :)
Sp3000

6

JavaScript (ES6), 273 258

Chỉnh sửa các lỗi đã sửa và thêm một bộ kiểm tra thực tế.

Không tính không gian hàng đầu và dòng mới.

Chắc chắn có thể được chơi golf nhiều hơn một chút.

Quá mệt mỏi để viết một lời giải thích bây giờ, tôi nghĩ đó là một ví dụ tốt về việc sử dụng các bao đóng để giữ các giá trị (tham số) tạm thời còn sống.

Thử nghiệm chạy đoạn mã trên bất kỳ trình duyệt tuân thủ EcmaScript 6 nào (đáng chú ý không phải Chrome không phải MSIE. Tôi đã thử nghiệm trên Firefox, Safari 9 có thể đi)

F=p=>(
  p=p.match(/^[^#\n]+/gm).filter(r=>r.trim(o='',v=[])),
  s={
    '':_=>1,
    p:a=>o+=a+` = ${v[a]||0}\n`,
    i:a=>v[a]=-~v[a],
    d:a=>v[a]&&v[a]--,
    a:(n,j)=>s[n]=(u,t,a)=>x(p[!x(p[j+1],0,a,1)+j+2],0,a,1)
  },
  p.map(x=(r,i,w,l,a=r.split(/ +/).slice(l).map(x=>-x?w[x]:x))=>s[a[0]](a[1],i,a)),
  o
)

// TEST

$('#O tr').each(function() {
  var $cells = $(this).find('td')
  var prg = $cells.eq(0).text()
  console.log(prg)
  var output = F(prg)
  $cells.eq(1).text(output)
})
#O td { vertical-align:top; white-space: pre; border: 1px solid #888; font-family:monospace }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<table>
<tr><th>Program</th><th>Outpout</th></tr>
<tbody id=O>  
<tr><td>p _MyVariable_321
p screaming_hairy_armadillo</td><td></td></tr>
<tr><td>i alpaca
p alpaca
i alpaca
p alpaca</td><td></td></tr>
<tr><td>i malamute
p malamute
d malamute    #success
p malamute
d malamute    #failure
p malamute
d akita       #failure
p akita</td><td></td></tr>
<tr><td>a increment_frog_twice
 i frog
 i frog
 d frog
p frog
increment_frog_twice
p frog</td><td></td></tr>
<tr><td>a increment_twice
 i 1
 i 1
 d 1 #never reached
a increment_both_twice
 increment_twice 1
 increment_twice 2
 d 1 #never reached
increment_both_twice platypus duck
p platypus
p duck</td><td></td></tr>
<tr><td>a set_to_zero
 d 1
 set_to_zero 1
 i _dummy_
i oryx
i oryx
i oryx
p oryx
set_to_zero oryx
p oryx</td><td></td></tr>
<tr><td>#Command Definitions:
a s             #flag as a success
 i _
 d _
 d _
a f             #flag as a failure
 d _
 d _
 d _
a z             #1 = zero
 d 1
 z 1
 s
a n             #1 = one
 z 1
 i 1
 s
a move          #2 += 1, 1 = zero
 moveH 1 2
 move 1 2
 s
a moveH         #move helper
 d 1
 i 2
 f
a dupe          #2 += 1, 3 += 1, 1 = zero
 dupeH1 1 2 3
 dupe 1 2 3
 s
a dupeH1        #dupe helper
 d 1
 dupeH2 2 3
 f
a dupeH2        #dupe helper
 i 1
 i 2
 s
a copy          #2 = 1
 z 2
 copyH 1 2
 s
a copyH         #copy helper
 dupe 1 2 _copy
 move _copy 1
 s
a addTo         #1 += 2
 copy 2 _add
 #testing comments #
 move _add 1#in weird places # just because #
 s
#it's a g##d idea
###
a add           #1 = 2 + 3
 #its a good idea
 z 1
 addH 1 2 3
 s
##

#
a addH          #add helper
#this is a comment
 addTo 1 2 #as is this
 addTo 1 3
 s
a mul           #1 = 2 * 3
 mulH1 1 2
 mulH2 1 3
 s
a mulH1         #mul helper
 z 1
 copy 2 _mul
 s
a mulH2         #mul helper
 mulH3 1 2
 mulH2 1 2
 s
a mulH3         #mul helper
 d _mul
 addTo 1 2
 f
a mulBy         #1 *= 2
 mul _mulBy 1 2
 copy _mulBy 1
 s
a pow           #1 = 2^3
 powH1 1 3
 powH2 1 2
 s
a powH1         #pow helper
 n 1
 copy 2 _pow
 s
a powH2         #pow helper
 powH3 1 2
 powH2 1 2
 s
a powH3         #pow helper
 d _pow
 mulBy 1 2
 f

#Running Tests:
p A
p B
p C
n A         #A = 1
n B         #B = 1
add C A B   #C = A + B = 1 + 1 = 2
p ____
p A
p B
p C
add B A C   #B = A + C = 1 + 2 = 3
p ____
p A
p B
p C
mul d B C   #d = B * C = 3 * 2 = 6
p ____
p d
mulBy d B   #d = d * B = 6 * 3 = 18
p ____
p d
d A         #A = A - 1 = 1 - 1 = 0
mulBy d A   #d = d * A = 18 * 0 = 0
p ____
p d
pow A C B   #A = C ^ B = 2 ^ 3 = 8
p ____
p A
p B
p C
pow A B C   #A = B ^ C = 3 ^ 2 = 9
p ____
p A
p B
p C
pow C A B   #C = A ^ B = 9 ^ 3 = 729
p ____
p A
p B
p C  
</td><td></td></tr>
</tbody>
</table>


Tôi đã thêm một số nhận xét vào chương trình thử nghiệm và có vẻ như họ đã làm cho mã của bạn không hoạt động.
Sở thích của Calvin

@ Calvin'sHob sở thích một bản vá đầu tiên, nhanh chóng
edc65

3

C # 6, 653 byte

Đây là mục nhập của tôi, giữa một biển Python ...

class P{string[]l;string r="";Dictionary<string,int>v=new Dictionary<string,int>();Dictionary<string,int>s=new Dictionary<string,int>();public string R(string t){l=t.Split('\n');for(int i=0;i<l.Length;i++){var z=l[i].Split(' ');if(z[0]=="a"){s.Add(z[1],i);i+=3;}else E(i, null);}return r;}bool E(int n,string[]p){var z=l[n].Split(' ');var a=z.Skip(1).Select(x=>Char.IsDigit(x[0])?p[int.Parse(x)-1]:x).ToArray();if(a.Length>0&&!v.ContainsKey(a[0]))v[a[0]]=0;if (z[0]=="p")r+=$"{a[0]} = {v[a[0]]}\n";else if(z[0]=="i")v[a[0]]++;else if(z[0]=="d")if(v[a[0]]>0)v[a[0]]--;else return false;else{var y=s[z[0]];return E(y+1,a)?E(y+2,a):E(y+3,a);}return true;}}

Mở rộng và bình luận:

class Prindeal
{
    string[] lines;
    string result = "";
    Dictionary<string, int> variables = new Dictionary<string, int>();
    Dictionary<string, int> statements = new Dictionary<string, int>();

    public string Run(string text)
    {
        lines = text.Split('\n');

        for (int i = 0; i < lines.Length; i++)
        {
            // Split on spaces to get the statement and any arguments
            var z = lines[i].Split(' ');

            // Are we defining a new statement?
            if (z[0] == "a")
            {
                // Add to the statements dictionary, step over definition statements
                statements.Add(z[1], i);
                i += 3;
            }
            else
            {
                // Execute the statement
                Execute(i, null);
            }
        }

        return result;
    }

    bool Execute(int lineNumber, string[] parameters)
    {
        // Split on spaces to get the statement and any arguments
        var z = lines[lineNumber].Split(' ');

        // Parse the arguments - if it's a number, get the corresponding 
        // parameter from the calling statement
        var arguments = z.Skip(1).Select(
            x => Char.IsDigit(x[0]) ? 
            parameters[int.Parse(x) - 1] : 
            x)
            .ToArray();

        // If the first argument isn't already in the variables dict, add it
        if (arguments.Length > 0 && !variables.ContainsKey(arguments[0])) variables[arguments[0]] = 0;

        // Print statement, using string interpolation
        if (z[0] == "p")
            result += $"{arguments[0]} = {variables[arguments[0]]}\n";
        // Increment statement
        else if (z[0] == "i")
            variables[arguments[0]]++;
        // Decrement statement
        else if (z[0] == "d")
            if (variables[arguments[0]] > 0)
                variables[arguments[0]]--;
            else
                return false;
        else
        {
            // Get the line number to jump to
            var y = statements[z[0]];

            // Execute A ? B : C
            return Execute(y + 1, arguments) ? Execute(y + 2, arguments) : Execute(y + 3, arguments);
        }

        // If we reach this point, it's from a 'p', 'i' or 'd' statement which has succeeded
        return true;
    }
}

Để sử dụng nó, chỉ cần khởi tạo lớp và gọi R()phương thức, ví dụ:

string prindealText = new StreamReader("prindeal.txt").ReadToEnd();
Console.WriteLine(new P().R(prindealText));

3

Lisp thông thường, 758 646 619

(progn(set-macro-character #\#(get-macro-character #\;))(setf(readtable-case *readtable*):invert)(#3=defun v(s)(if(boundp s)(eval s)0))(#3# i(s)(set s(1+ (v s))))(#3# d(s)(and(plusp(v s))(set s(1-(v s)))))(#3# p(s)(format t"~A = ~A~%"s(v s)))(defmacro a(n . p)`(#3#,(cadr n)(&rest g)(if,@p)))(#3# k(s)(typecase s(integer`(nth,(1- s)g))(symbol `',s)(t(list*(car s)(mapcar 'k(cdr s))))))(#3# r()(prog(l p q)$(setf p()l(make-string-input-stream(or(read-line()()())(return))))@(when(setf p(read l()()))(push p q)(go @))(if q(return(k(reverse q)))(go $))))(do ((x(r)(r)))((not x))(eval(if(eq(car x)'a)`(,@x,(r),(r),(r))x))))

Đặt cái này vào file.lispvà gọi ví dụ sbcl --script file.lisp; đầu vào được đọc từ luồng đầu vào tiêu chuẩn.

Phiên bản này phân tích một superset của Prindeal: không gặp nhiều khó khăn, bạn có thể truy cập tất cả Lisp thông thường từ một nguồn Prindeal. Tôi coi đây là một tính năng của intepreter.

Phiên bản đã bình luận

;; copy-readtable is only used during development, so that I do not 
;; mess with my running environment. The real code starts with the
;; progn below, which is superfluous of course inside a let.
(let ((*readtable* (copy-readtable)))

  ;; I use PROGN in the golfed version so that I can have the whole
  ;; program as a unique tree. This allows me to define reader 
  ;; variables like #3=defun in order to gain a few bytes by writing
  ;; #3# instead of defun. Reader variables are removed in
  ;; this human-friendly version.
  (progn
    ;; Let # point to the same reader function as ;
    ;; Of course, ; is still usable as a comment delimiter
    (set-macro-character #\#
                         (get-macro-character #\;))

    ;; :invert does what is necessary to enable case-sensitive reading
    ;; and printing of symbols
    (setf (readtable-case *readtable*) :invert)

    ;; value of symbol, or zero
    (defun v(s)(if(boundp s)(eval s)0))

    ;; increment
    (defun i(s)(set s(1+ (v s))))

    ;; decrement
    (defun d(s)(and(plusp(v s))(set s(1-(v s)))))

    ;; print
    (defun p(s)(format t"~A = ~A~%"s(v s)))

    ;; alias: wrap an "if" inside a "defun".
    ;; YES, that means you can redefine ANY lisp function with "a" !
    ;; A safer version would properly intern symbols in a dedicated package.
    ;;
    ;; Notice the G variable.  We take advantage of the "unhygienic"
    ;; (what a bad adjective) nature of macros to create a context
    ;; where G is bound to the argument list. The same G is referenced
    ;; implicitely later.
    (defmacro a(n . p)`(defun,(cadr n)(&rest g)(if,@p)))

    ;; Canonicalize expressions:
    ;;
    ;; - if s is a symbol, return s quoted. All functions manipulate
    ;; symbols in order to allow the undeclared use of variables. With
    ;; symbols, we can check for boundness.
    ;;
    ;; - if s is an integer, then we are inside an alias definition. The
    ;; integer is replaced by an access to the s'th element of the
    ;; implicit argument list G using (nth (1- s) g). G will be bound
    ;; when the expressions is injected in the defun corresponding to
    ;; the alias, or else an error will be signaled: either because G
    ;; is unbound, or because you defined a variable named G which is
    ;; by construction not a list. Since we do not sanitize properly
    ;; the input, you could bind G globally to a list, but that would be
    ;; nasty.
    ;; 
    ;; - Finally, if s is a list, apply k to all but the first
    ;; elements of s.  The first element is a symbol but we do not
    ;; need to quote it because we want to call the function
    ;; associated with the symbol. Due to the Lisp-2-ness
    ;; of Common Lisp, functions and variables can coexist
    ;; with the same name.
    ;;
    (defun k(s)(typecase s
                 (integer`(nth,(1- s)g))
                 (symbol`',s)
                 (t(list*(car s)(mapcar #'k(cdr s))))))

    ;; Reader function
    (defun r()
      (prog (l ; current line, as an input-stream reading a string
             p ; current read form
             q ; whole line and return value, as a list
             )

         ;; PROG includes an implicit TAGBODY. Below, $ and @ are
         ;; labels for GO statements (gotos).

       $ (setf
          ;; emtpy p
          p ()

          ;; Read a whole line and if we do not fail, build an input
          ;; stream to read from it.
          l (make-string-input-stream
             (or (read-line()()()) ;; try to read a line,
                 (return)          ;; but return from prog if we reach
                                   ;; the end of file.
                 )))
       @ (when (setf p (read l()()))
           ;; Read a lisp expression, put it in p and if p is not nil
           ;; push it into q.  A nil could happen at the end of the
           ;; line or if someone (you know who) inserted an empty list
           ;; in the file being read.
           ;; 
           ;; Thanks to the readtable which now handles comments
           ;; and spaces for us, nothing needs to be done here to
           ;; preprocess the input.

           (push p q) (go @))

         ;; If we read an empty line, q can be nil. In this case, go
         ;; back to $ and read another line. If q is not nil, reverse
         ;; it (we pushed, remember), canonicalize it and return the
         ;; result.
         (if q (return(k(reverse q))) (go $)))
      )

    ;; Read/eval loop.  When reading "(a name)", we read the three
    ;; next lines and append them to the first so that it builds a
    ;; call the the alias definition macro a. Otherwise, just eval x.
    (do((x(r)(r))((not x))
      (eval (if (eq(car x'a))
                `(,@x,(r),(r),(r))
                x)))))

Thí dụ

~$ sbcl --script file.lisp < testfile

A = 0
B = 0
C = 0
____ = 0
A = 1
B = 1
C = 2
____ = 0
A = 1
B = 3
C = 2
____ = 0
d = 6
____ = 0
d = 18
____ = 0
d = 0
____ = 0
A = 8
B = 3
C = 2
____ = 0
A = 9
B = 3
C = 2
____ = 0
A = 9
B = 3
C = 729

Nếu chúng ta thay thế evalbằng printvòng lặp read / eval, thì chúng ta có thể thấy những gì đang được đánh giá:

(a 's (i '_) (d '_) (d '_)) 
(a 'f (d '_) (d '_) (d '_)) 
(a 'z (d (nth 0 g)) (z (nth 0 g)) (s)) 
(a 'n (z (nth 0 g)) (i (nth 0 g)) (s)) 
(a 'move (moveH (nth 0 g) (nth 1 g)) (move (nth 0 g) (nth 1 g)) (s)) 
(a 'moveH (d (nth 0 g)) (i (nth 1 g)) (f)) 
(a 'dupe (dupeH1 (nth 0 g) (nth 1 g) (nth 2 g))
   (dupe (nth 0 g) (nth 1 g) (nth 2 g)) (s)) 
(a 'dupeH1 (d (nth 0 g)) (dupeH2 (nth 1 g) (nth 2 g)) (f)) 
(a 'dupeH2 (i (nth 0 g)) (i (nth 1 g)) (s)) 
(a 'copy (z (nth 1 g)) (copyH (nth 0 g) (nth 1 g)) (s)) 
(a 'copyH (dupe (nth 0 g) (nth 1 g) '_copy) (move '_copy (nth 0 g)) (s)) 
(a 'addTo (copy (nth 1 g) '_add) (move '_add (nth 0 g)) (s)) 
(a 'add (z (nth 0 g)) (addH (nth 0 g) (nth 1 g) (nth 2 g)) (s)) 
(a 'addH (addTo (nth 0 g) (nth 1 g)) (addTo (nth 0 g) (nth 2 g)) (s)) 
(a 'mul (mulH1 (nth 0 g) (nth 1 g)) (mulH2 (nth 0 g) (nth 2 g)) (s)) 
(a 'mulH1 (z (nth 0 g)) (copy (nth 1 g) '_mul) (s)) 
(a 'mulH2 (mulH3 (nth 0 g) (nth 1 g)) (mulH2 (nth 0 g) (nth 1 g)) (s)) 
(a 'mulH3 (d '_mul) (addTo (nth 0 g) (nth 1 g)) (f)) 
(a 'mulBy (mul '_mulBy (nth 0 g) (nth 1 g)) (copy '_mulBy (nth 0 g)) (s)) 
(a 'pow (powH1 (nth 0 g) (nth 2 g)) (powH2 (nth 0 g) (nth 1 g)) (s)) 
(a 'powH1 (n (nth 0 g)) (copy (nth 1 g) '_pow) (s)) 
(a 'powH2 (powH3 (nth 0 g) (nth 1 g)) (powH2 (nth 0 g) (nth 1 g)) (s)) 
(a 'powH3 (d '_pow) (mulBy (nth 0 g) (nth 1 g)) (f)) 
(p 'A) 
(p 'B) 
(p 'C) 
(n 'A) 
(n 'B) 
(add 'C 'A 'B) 
(p '____) 
(p 'A) 
(p 'B) 
(p 'C) 
(add 'B 'A 'C) 
(p '____) 
(p 'A) 
(p 'B) 
(p 'C) 
(mul 'd 'B 'C) 
(p '____) 
(p 'd) 
(mulBy 'd 'B) 
(p '____) 
(p 'd) 
(d 'A) 
(mulBy 'd 'A) 
(p '____) 
(p 'd) 
(pow 'A 'C 'B) 
(p '____) 
(p 'A) 
(p 'B) 
(p 'C) 
(pow 'A 'B 'C) 
(p '____) 
(p 'A) 
(p 'B) 
(p 'C) 
(pow 'C 'A 'B) 
(p '____) 
(p 'A) 
(p 'B) 
(p 'C)

Mở rộng vĩ mô

Nếu chúng ta chọn định nghĩa bí danh sau:

(a 'powH2 (powH3 (nth 0 g) (nth 1 g)) (powH2 (nth 0 g) (nth 1 g)) (s))

... Chúng ta có thể thấy các tham chiếu đến một biến có tên gkhông thể tìm thấy trong phạm vi từ vựng. Nhưng sau khi mở rộng vĩ mô, đây là mã thực tế đang được đánh giá:

(defun powH2 (&rest g)
  (if (powH3 (nth 0 g) (nth 1 g))
      (powH2 (nth 0 g) (nth 1 g))
      (s))) 

Bây giờ, gđề cập đến danh sách đối số của hàm được xác định.


2

Python 2, 486 byte

Đây là giải pháp tham chiếu mà tôi đã đánh gôn nhiều hơn (hiện tại là -98 byte).

import sys;sys.setrecursionlimit(2000)
def r(s):
 n=s[0]
 if n in A:f=lambda i:r([s[int(t)]if'0'<t[0]<':'else t for t in A[n][i]]);return f(1+(f(0)or 0))
 k=s[1]
 if'i'<n:print k,'=',V.get(k,0)
 elif'd'<n:V[k]=-~V[k]if k in V else 1
 elif'a'<n:
    if~-(k in V)or V[k]<1:return 1
    V[k]-=1
 else:A[k]=s[2:]
A={};V={};c=filter(bool,([l,l[:l.find('#')]]['#'in l]for l in input().split('\n')))
while c:
 s=c[0].split();c=c[1:]
 if'a'!=s[0]:r(s)
 else:r(['a',s[1]]+map(str.split,c[:3]));c=c[3:]

Thay đổi (mà tôi nhớ lại):

  • tự động chuyển đổi số nguyên boolean ( [l,l[:l.find('#')]]['#'in l]).
  • đặt hoặc tăng trong một câu lệnh ( V[k]=-~V[k]if k in V else 1)
  • nhiều bí danh cho các biểu thức dài hơn ( k=s[1])
  • không có bộ đếm trong vòng lặp chính, thay vào đó xóa danh sách đầu vào
  • printtự động thêm dấu cách ( print k,'=',V.get(k,0))
  • kiểm tra các chữ số 1-9 ( '0'<t[0]<':')
  • lật các giá trị trả về của rxung quanh để lưu returns
  • loại bỏ sự lặp lại của cắt và tách ( map(str.split,c[:3])))

1

Python 3, 1322 byte

Chơi gôn

import re,sys;sys.setrecursionlimit(2000);F,L=filter,list
class P:
 N,O,F=0,{},{}
 def __init__(S,c):
  S.B,S.E={"p":S.P,"i":S.I,"d":S.D,"a":S.L},dict(enumerate(F(None,[i.split('#')[0].rstrip()for i in c.splitlines()])))
  while S.N in S.E:S.X(S.E[S.N])
 def V(S, v, y, z=0):
  if re.match("[\w_][\d\w_]*",v):
   if not v in y:
    if z is not None:y[v]=z
    else:return False
   return True
  return False
 def A(S):S.N+=1
 def P(S,v):
  if S.V(v,S.O):print("{0} = {1}".format(v, S.O[v]));return True
  return False
 def I(S,v):
  if S.V(v, S.O):S.O[v]+=1;return True
  return False
 def D(S,v):
  if S.V(v,S.O)and S.O[v]>0:S.O[v]-=1;return True
  return False
 def L(S,v):
  e=[]
  if S.V(v,S.F,e):
   for i in range(3):S.A();e.append(S.E[S.N].lstrip())
   return True
  return False
 def C(S,c,v):
  def R(Z,v):
   for i in re.findall("\s(\d+)", Z):Z=Z.replace(" %s"%i," %s"%v[int(i)-1])
   return Z
  Q,m,f=map(lambda l:R(l,v),S.F[c])
  if S.X(Q,False):return S.X(m,False)
  return S.X(f,False)
 def X(S,Z,C=True):
  u=re.match("\s?([\w_][\d\w_]*)\s?([\w_][\d\w ]*)?",Z)
  if u:
   c,v=map(lambda i:''if i is None else i,u.groups());v=L(F(None,v.split(' ')))
   if S.V(c,S.F,None):
    T=S.C(c, v)
    if C:S.A()
   elif S.V(c,S.B,None):
    T=S.B[c](*v)
    if C:S.A()
   else:return False
   return T
  return False

Ung dung:

import re

class Prindeal:
    iline = 0
    local = {}
    udef = {}
    content  = {}

    def __init__(self, c):
        self.built = {
            "p": self.print,
            "i": self.increment,
            "d": self.decrement,
            "a": self.alias,
        }
        self.content = dict(enumerate(filter(None, [i.split('#')[0].rstrip()for i in c.splitlines()])))
        while self.iline in self.content:
            self.execute_line(self.content[self.iline])

    def validate_name(self, varname, stack, default=0):
        if re.match("[\w_][\d\w_]*", varname):
            if not varname in stack:
                if default is not None:
                    stack[varname] = default
                else:
                    return False
            return True
        return False

    def advance_stack(self):
        self.iline += 1

    def print(self, varname):
        if self.validate_name(varname, self.local):
            print("{0} = {1}".format(varname, self.local[varname]))
            return True
        return False

    def increment(self, varname):
        if self.validate_name(varname, self.local):
            self.local[varname] += 1
            return True
        return False

    def decrement(self, varname):
        if self.validate_name(varname, self.local) and self.local[varname] > 0:
            self.local[varname] -= 1
            return True
        return False

    def alias(self, aliasname):
        indexed_lines = []
        if self.validate_name(aliasname, self.udef, indexed_lines):
            for i in range(3):
                self.advance_stack()
                indexed_lines.append(self.content[self.iline].lstrip())
            return True
        return False

    def execute_alias(self, cmd, variables):
        def parse_args(line, variables):
            for i in re.findall("\s(\d+)", line):
                line = line.replace(" %s" % i, " %s" % variables[int(i) - 1])
            return line
        init, success, failure = map(lambda l: parse_args(l, variables), self.udef[cmd])
        if self.execute_line(init, False):
            return self.execute_line(success, False)
        return self.execute_line(failure, False)

    def execute_line(self, line, cont=True):
        valid_execution = re.match("\s?([\w_][\d\w_]*)\s?([\w_][\d\w ]*)?", line)
        if valid_execution:
            cmd, variables = map(lambda i: '' if i is None else i, valid_execution.groups())
            variables = list(filter(None, variables.split(' ')))
            if self.validate_name(cmd, self.udef, None):
                temp = self.execute_alias(cmd, variables)
                if cont:
                    self.advance_stack()
            elif self.validate_name(cmd, self.built, None):
                temp = self.built[cmd](*variables)
                if cont:
                    self.advance_stack()
            else:
                return False
            return temp
        return False

Sử dụng:

P(c)

Trong trường hợp clà nội dung văn bản.

Ví dụ:

Chuỗi đơn được chấp nhận:

  • P("p cat")
  • P("p dog\ni dog\np dog")

Chuỗi nhiều dòng cũng được chấp nhận:

P("""
p dog
i dog
p dog
""")

Hoặc là:

P("""p dog
i dog
p dog""")

V.v.

Ghi chú:

Điều này hoạt động chính xác cho tất cả các trường hợp thử nghiệm, nhưng đạt đến giới hạn đệ quy trên:

pow C A B   #C = A ^ B = 9 ^ 3 = 729

Do đó sys.setrecursionlimit(2000).


1
Nó sẽ sử dụng hết một số byte nhưng bạn không thể sử dụng sys.setrecursionlimit () để làm cho điều này hoạt động đúng với bí danh pow?
Corwin

Tôi có thể, nhưng OP tuyên bố rằng các ngôn ngữ như Python (có giới hạn đệ quy) được chấp nhận nguyên trạng. Tuy nhiên, tôi sẽ thêm bản sửa lỗi nếu OP yêu cầu. @Corwin
Zach Gates

Đủ công bằng. Bỏ lỡ điều đó trong thông số kỹ thuật. @ZachGates
Corwin

1

Python - 695 688 byte

def p(v):print v,"=",w.get(v,0)
def i(v):w[v]=w.get(v,0)+1
def d(v):
 if v in w:
<TAB>w[v]-=1
<TAB>if not w[v]:del w[v]
 else:return 1
def a(n,b,d,h):
 def g(*a):
<TAB>i=1;f=b;s=d;t=h
<TAB>for v in a:v=q+v+q;k=q+j(i)+q;f=c(f,k,v);s=c(s,k,v);t=c(t,k,v);i+=1
<TAB>y=u(t,e)if u(f,e)else u(s,e);i=1;return y
 e[n]=g
q="'";w=x={};u=eval;e={'a':a,'d':d,'i':i,'p':p};import sys;l=sys.stdin.readlines();r="";j=str;c=j.replace;sys.setrecursionlimit(2000)
for h in l:
 h = h.strip()
 if not h:continue
 l = h.split();f=l[0];n=f+"("
 if "#" in f:continue
 for g in l[1:]:
<TAB>b=g.find("#")+1
<TAB>if b:g=g[:b-1]
<TAB>if g:n+="'%s',"%g
<TAB>if b:break
 if x:x-=1;d+='"%s)",'%n
 else:x=(f=="a")*3;d=n
 if not x:d+=")\n";r+=d
exec r in e

<TAB> là một ký tự tab theo nghĩa đen.


1

C ++, 1111 byte

Đây là C ++ - thành ngữ như tôi có thể làm cho nó.
Điều đó có nghĩa là làm cho nó nhiều C ++ hơn - ish và ít C-ish.
Điều đó cũng có nghĩa là nó lớn hơn chương trình C tương đương.
Tôi nghĩ rằng C ++ là đối thủ của Java đối với thư viện tiêu chuẩn dài dòng.
Nó biên dịch với VS2013 và g ++ 4.9.2 (với -std = c ++ 11)

#include<array>
#include<iostream>
#include<map>
#include<regex>
#include<sstream>
#include<stack>
#define B std::
#define a first
#define b second
#define c(s);else if(x.a==s)
#define d(n)B getline(B cin,r##n)
#define e(n)r##n=B regex_replace(r##n,q,"$1");
#define f(n)do{d(n);e(n)}while(r##n.empty());
#define g B string
#define h B istream_iterator<g>
#define i p.top().a
#define j p.empty()
#define k B pair
#define u continue;
#define w B back_inserter
typedef B vector<g>s;typedef B array<g,3>A;typedef k<k<long,A>,s>t;B map<g,A>m;B map<g,long>n;B stack<t>p;B regex q("^ *(.*?) *(#.*)?$");int main(){g r0,r1,r2,r3;while(d(0)){e(0)if(r0.empty())u p.push(t{{0,{{r0,"",""}}},{}});bool z;while(!j){k<g,s>x;B istringstream ss(i.b[i.a]);ss>>x.a;B copy(h(ss),h(),w(x.b));s o;B transform(B begin(x.b),B end(x.b),w(o),[](g y){int v=atoi(y.c_str());return v>0?p.top().b[v-1]:y;});z=true;if(0)c("")c("p")B cout<<o[0]<<" = "<<n[o[0]]<<B endl c("i")n[o[0]]++c("d")n[o[0]]-=(z=n[o[0]])c("a"){f(1)f(2)f(3)m.insert(B make_pair(o[0],A{{r1,r2,r3}}));}else{p.push(t{{0,m[x.a]},o});u}while(!j&&i.a)p.pop();if(!j)i.a+=1+!z;}}}

Dưới đây là bản gốc. Nếu bất cứ ai có thể nghĩ ra một cách để làm cho nó thành ngữ hơn và ngắn hơn cùng một lúc xin vui lòng cho tôi biết.

#include <array>
#include <iostream>
#include <map>
#include <regex>
#include <sstream>
#include <stack>

typedef std::vector<std::string> List;
typedef std::pair<std::string, List> Statement;
typedef std::array<std::string, 3> Alias;
typedef std::pair<long, Alias> IndexedAlias;
typedef std::pair<IndexedAlias, List> Item;

std::map<std::string, Alias> aliases;
std::map<std::string, long> variables;
std::stack<Item> stack;
std::regex re("^ *(.*?) *(#.*)?$");

int main()
{
    std::string line, line1, line2, line3;
    while (std::getline(std::cin, line)) // control-Z to exit
    {
        line = std::regex_replace(line, re, "$1");
        if (line.empty()) continue;
        stack.push(Item{ { 0, { { line, "", "" } } }, {} });

        bool flag;
        while (!stack.empty())
        {
            Statement statement;
            std::istringstream ss(stack.top().first.second[stack.top().first.first]);
            ss >> statement.first;
            std::copy(std::istream_iterator<std::string>(ss), std::istream_iterator<std::string>(), std::back_inserter(statement.second));

            List arguments;
            std::transform(std::begin(statement.second), std::end(statement.second), std::back_inserter(arguments),
                [](std::string arg){ int i = atoi(arg.c_str()); return i > 0 ? stack.top().second[i - 1] : arg; });

            flag = true;
            if (statement.first == "")
                ;
            else if (statement.first == "p")
                std::cout << arguments[0] << " = " << variables[arguments[0]] << std::endl;
            else if (statement.first == "i")
                variables[arguments[0]]++;
            else if (statement.first == "d")
                variables[arguments[0]] -= (flag = variables[arguments[0]]);
            else if (statement.first == "a")
            {
                do { std::getline(std::cin, line1); line1 = std::regex_replace(line1, re, "$1"); } while (line1.empty());
                do { std::getline(std::cin, line2); line2 = std::regex_replace(line2, re, "$1"); } while (line2.empty());
                do { std::getline(std::cin, line3); line3 = std::regex_replace(line3, re, "$1"); } while (line3.empty());
                aliases.insert(std::make_pair(arguments[0], Alias{ { line1, line2, line3 } }));
            }
            else
            {
                stack.push(Item{ { 0, aliases[statement.first] }, arguments });
                continue;
            }

            while (!stack.empty() && stack.top().first.first) stack.pop();
            if (!stack.empty()) stack.top().first.first += 1 + !flag;
        }
    }

    std::cout << "-- Variables --" << std::endl;
    std::transform(std::begin(variables), std::end(variables), std::ostream_iterator<std::string>(std::cout, "\n"),
        [](std::map<std::string, long>::value_type pair){ std::ostringstream ss; ss << pair.first << " = " << pair.second; return ss.str(); });
    std::cout << "-- Aliases --" << std::endl;
    std::transform(std::begin(aliases), std::end(aliases), std::ostream_iterator<std::string>(std::cout, "\n"),
        [](std::map<std::string, Alias>::value_type pair){ std::ostringstream ss; ss << pair.first << " = [1]:" << pair.second[0] << " [2]:" << pair.second[1] << " [3]:" << pair.second[1]; return ss.str(); });
    std::cout << "---------------" << std::endl;

    return 0;
}

0

Haskell, 1009

Tôi đã làm hết sức để chơi nó; mã không mã hóa của tôi bao gồm hơn 3.000 ký tự. Tại thời điểm này, tôi không thể nhớ tất cả các chức năng đang làm gì để chơi golf, điều đó có nghĩa là đoán xem cái gì sẽ phá vỡ nó và cái gì sẽ không.

import qualified Data.Map as M
import Control.Monad.State.Lazy
import Data.List
type A=M.Map String
data P=P(A Int)(A([String]->StateT P IO Int))
a f=evalStateT f(P M.empty$M.fromList[("i",\(b:_)->(+1)%b),("d",\(b:_)->pred%b),("p",\(b:_)->i b>>= \v->liftIO(putStrLn$b++"="++show v)>>q 1)])
e(k:l)=do{(P v a)<-get;put.P v$M.insert k(m l)a;q 1}
g t s f= \a->t a>>= \b->if b>0then s a else f a
f%k=f<$>i k>>= \v->if v<0then k#0>>q 0else k#v>>q 1
i k=get>>= \(P v _)->q$M.findWithDefault 0 k v
k#v=get>>= \(P b a)->put$P(M.insert k v b)a
l k=get>>= \(P _ a)->q$a M.!k
f s=let(f:a)=r s in($a)<$>l f>>=id
m(t:s:f:_)=g(k t)(k s)(k f)
k s=let(f:b)=r s in\a->($(map((\y z->if all(\c->c>'/'&&c<':')z then y!!(read z-1)else z)a)b))<$>l f>>=id
n=dropWhileEnd(==' ').takeWhile(not.(=='#')).dropWhile(==' ')
o[]=[]
o(l:ls)|(head.r$l)=="a"=(l:take 3 ls):(o$drop 3 ls)|1>0=[l]:o ls
p s|length s>1=e$(n.tail.head$s):tail s|1>0=f.head$s
q=return
main=join$a.(\s->mapM_ p(o.filter(not.null).map n.lines$s))<$>getContents
r=words
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.