Print, Increment, Decrement, Alias ​​- Interpretasikan Prindeal

30

Prindeal (diucapkan prin-dee-al ) adalah bahasa pemrograman esoterik baru yang hanya memiliki empat perintah: pr int , in crement , de crement , dan al ias . Meskipun minimalis, operasi matematika yang kompleks dapat dilakukan di Prindeal dengan menggabungkan empat perintah secara cerdik.

Tugas Anda dalam tantangan golf kode ini adalah menulis program terpendek yang dapat menjalankan kode Prindeal.

Speknya panjang tapi saya sudah mencoba membuatnya sejelas mungkin dan saya percaya bahwa jika Anda berusaha untuk belajar Prindeal Anda akan menemukannya cukup elegan!


Intrepreting Prindeal

Preprocessing

Sebelum sebuah program Prindeal dapat diartikan hal-hal ini perlu dihapus darinya dalam urutan ini:

  1. Apa pun setelah #tanda ke ujung garis itu aktif, ditambah tanda #itu sendiri. (Ini adalah komentar.)
  2. Membuntuti spasi putih pada baris apa pun.
  3. Baris benar-benar kosong.

Misalnya, program Prindeal

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

#p mouse

akan diolah menjadi

p cat
p dog

Dari sini kita akan menganggap langkah preprocessing ini telah dilakukan.

Variabel

Kita dengan cepat perlu mendefinisikan variabel sebelum menunjukkan bagaimana mereka digunakan.

Variabel (dan referensi ke variabel) adalah apa yang diteruskan ke argumen perintah Prindeal. Variabel selalu bersifat global , jadi modifikasi terhadap suatu variabel, di mana pun mereka terjadi, tercermin di mana-mana.

Setiap variabel memiliki integer presisi arbitrer non-negatif (0, 1, 2, 3, ...). Variabel tidak perlu diinisialisasi - mereka selalu mulai dengan nilai 0 saat pertama kali mereka digunakan atau dipanggil.

Nama variabel dapat berupa string alfanumerik dan garis bawah non-kosong yang tidak dimulai dengan digit - [a-zA-Z_][0-9a-zA-Z_]*dalam regex . Mereka peka huruf besar-kecil, jadi spiny_lumpsuck3rdan Spiny_lumpsuck3rmerupakan variabel yang berbeda.

Eksekusi

Prindeal adalah bahasa pemrograman yang sangat penting . Ketika program Prindeal dijalankan, pernyataannya dieksekusi dari atas ke bawah secara berurutan dan kemudian program berakhir.

Setiap baris non-indentasi dalam program Prindeal adalah pernyataan yang melibatkan eksekusi satu perintah yang mungkin atau tidak dapat mengambil argumen.

Baris indentasi hanya muncul setelah perintah alias . Secara khusus, tepat tiga baris yang ditandai dengan spasi tunggal muncul setelah setiap perintah alias dan dianggap sebagai bagian darinya. Jadi pernyataan alias benar-benar panjang empat baris. (Mereka bisa menjadi satu baris, empat hanya lebih mudah dibaca.)

Pernyataan Non- alias

Dengan pengecualian alias , setiap pernyataan dalam program Prindeal memiliki formulir:

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

Mungkin ada sejumlah argumen sewenang-wenang (termasuk tidak ada sama sekali). Setiap argumen selalu merupakan variabel atau (seperti yang akan kita lihat ketika membahas alias ) referensi ke variabel .

Setelah selesai dieksekusi, setiap pernyataan ditandai sebagai kegagalan atau keberhasilan tergantung pada apakah kesalahan ditemukan atau tidak. (Ini hanya masalah ketika kita menggunakan alias .)

Cetak built-in , increment , dan decrement adalah pernyataan dengan formulir di atas. Inilah yang mereka lakukan:

  1. print memiliki nama perintah pdan mengambil satu argumen. Ini mencetak nama variabel yang diteruskan dan nilainya (dalam desimal) dipisahkan oleh "=", lalu baris baru. Itu selalu ditandai sebagai keberhasilan .

    Misalnya, program Prindeal

    p _MyVariable_321
    p screaming_hairy_armadillo
    

    akan menghasilkan

    _MyVariable_321 = 0
    screaming_hairy_armadillo = 0
    

    karena semua variabel mulai dari 0. (Spasi sebelum dan sesudah tanda sama dengan diperlukan.)

  2. increment memiliki nama perintah idan mengambil satu argumen. Itu menambah nilai variabel yang dilewatkan oleh 1. Itu selalu ditandai sebagai sukses ..

    Misalnya saja programnya

    i alpaca
    p alpaca
    i alpaca
    p alpaca
    

    akan menghasilkan

    alpaca = 1
    alpaca = 2
    

    Perhatikan bagaimana alpacapeningkatan dari 0 menjadi 1 meskipun belum pernah diakses sebelumnya.

  3. decrement memiliki nama perintah ddan mengambil satu argumen. Jika variabel yang diteruskan adalah nol, nilainya dikurangi dengan 1 dan pernyataan ditandai sebagai sukses . Jika variabel yang dikirimkan adalah 0 maka tidak ada yang dilakukan dan pernyataan ditandai sebagai kegagalan .

    Misalnya saja programnya

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

    akan menghasilkan

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

    Perhatikan bahwa pengurangan variabel dengan nilai 0 adalah satu-satunya cara untuk menghasilkan kegagalan .

The alias Pernyataan dan Alias Perintah

The alias perintah memiliki sintaks khusus dan adalah yang paling kuat karena dapat digunakan untuk menentukan perintah baru. Nama perintah alias adalah adan pernyataan alias memiliki bentuk:

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

Dimana masing-masing [statement X]mewakili pernyataan non- alias , yaitu sesuatu dengan formulir [command name] [argument 1] [argument 2] [argument 3] ....

Nama perintah alias [name of new command]mungkin berupa string alfanumerik dan garis bawah yang tidak kosong yang tidak dimulai dengan digit - [a-zA-Z_][0-9a-zA-Z_]*dalam regex.

(Ini adalah kumpulan nama yang sama dengan variabel tetapi perintah dan variabel yang berbeda adalah hal yang berbeda yang digunakan di tempat yang berbeda . Suatu variabel dapat dinamai sama sebagai perintah tanpa konsekuensi buruk.)

Ketika pernyataan alias dijalankan, perintah baru ditambahkan di samping empat p i d aperintah asli. Perintah baru dapat digunakan sebagai [command name]pernyataan dalam dan dipanggil dengan argumen seperti halnya perintah non- alias lainnya .

Ketika pernyataan dengan nama perintah alias dijalankan, tepat dua pernyataan lagi dari pernyataan alias aslinya dijalankan:

  • [statement A] selalu dijalankan
  • [statement B]Dijalankan jika [statement A]sudah sukses
  • [statement C]dijalankan jika [statement A]sebuah kegagalan

Pernyataan A, B, dan C selalu dijalankan dengan malas , yaitu mereka dievaluasi dengan cepat pada saat dijalankan.

Ketika selesai dieksekusi, perintah alias ditandai dengan flag sukses atau gagal yang sama dengan pernyataan B atau C, mana pun yang dieksekusi . ( alias pernyataan itu sendiri tidak perlu ditandai karena tidak dapat muncul di dalam dirinya sendiri.)

Contoh Alias ​​1

Katakanlah kita menginginkan perintah baru yang menambah variabel frogdua kali. Pernyataan alias ini membuatnya:

a increment_frog_twice
 i frog
 i frog
 d frog

Pernyataan A ( i frog) selalu dijalankan dan selalu ditandai sebagai keberhasilan sehingga pernyataan B ( i frog) juga selalu dijalankan dan variabelnya frog bertambah dengan 2. increment_frog_twicePerintah selalu ditandai sebagai keberhasilan karena pernyataan B selalu dijalankan dan B selalu merupakan sukses . Pernyataan C ( d frog) tidak pernah dijalankan.

Jadi output untuk

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

akan menjadi

frog = 0
frog = 2

Kita dapat menggeneralisasi contoh ini sehingga variabel apa pun dapat ditambahkan dua kali dengan memberikan perintah alias argumen.

Dalam pernyataan alias , bilangan bulat positif 1, 2, 3, dll. Mewakili argumen 1, 2, 3, dll. Diteruskan ke perintah alias. (Argumen ini mungkin variabel biasa atau referensi ke variabel itu sendiri.) Angka-angka ini hanya dapat muncul dalam argumen pernyataan A, B, dan C dalam pernyataan alias . Tidak masuk akal bagi mereka untuk muncul di tempat lain.

Contoh Alias ​​2

Ini menggeneralisasi contoh terakhir - variabel apa pun yang dilewatkan increment_twiceakan ditambahkan oleh 2 karena 1merupakan referensi ke argumen pertama yang dilewatkan dalam:

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

Output dari program ini adalah

toad = 0
toad = 2

Kami kemudian dapat alias perintah lain yang mengambil dua argumen dan memanggil increment_twicekeduanya:

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

Outputnya di sini adalah

platypus = 2
duck = 2

Sangat penting untuk menyadari bahwa perintah alias dapat bersifat rekursif, karena di sinilah letak kekuatan mereka yang sebenarnya. Sebagai contoh, kita dapat membuat perintah yang menetapkan variabel apa pun yang diteruskan ke 0:

Contoh Alias ​​3

The set_to_zeroperintah mengambil satu argumen dan menetapkan variabel untuk 0 dan ditandai sebagai keberhasilan bila dilakukan:

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

Output dari program ini adalah

oryx = 3
oryx = 0

Apa yang terjadi adalah ketika set_to_zero oryxdijalankan, d 1berhasil mengurangi oryxdari 3 ke 2, kemudian set_to_zero 1dipanggil, yang sama dengan menelepon set_to_zero oryxlagi. Jadi mengulangi proses sampai d 1adalah kegagalan , menghentikan rekursi dan kenaikan _dummy_variabel sehingga sukses diproduksi.


Tantangan

Tulis program yang dapat menjalankan kode Prindeal persis seperti yang dijelaskan di atas. Ambil kode Prindeal melalui stdin, baris perintah, atau sebagai file teks. Cetak output program Prindeal ke stdout atau alternatif terdekat bahasa Anda.

Atau, Anda dapat menulis fungsi yang mengambil kode sebagai string dan mencetak atau mengembalikan string output.

Selain itu, Anda dapat mengasumsikan bahwa:

  • Kode Prindeal input hanya akan berisi baris baru dan ASCII yang dapat dicetak dan (secara opsional) berakhir dengan baris kosong.
  • Kode input akan valid Prindeal - terbentuk dengan baik dan secara sintaksis benar.
  • Menjalankan kode tidak akan menghasilkan loop tak terbatas atau referensi yang tidak valid untuk perintah yang belum didefinisikan atau argumen yang belum diberikan.
  • Nama perintah p, i, d, dan atidak akan pernah alias lebih. (Anda mungkin tidak berasumsi bahwa variabel tidak akan memiliki nama-nama ini.)

Juga, tidak masalah jika nilai variabel Anda tidak benar-benar bilangan bulat presisi arbitrer karena hanya angka kurang dari sekitar 1000 yang akan diuji. Tidak masalah jika bahasa Anda memiliki batas rekursi (seperti Python ) yang mungkin dihadapi oleh program Prindeal yang lebih kompleks selama program pengujian di bawah ini berfungsi.

Program Tes

Berikut ini adalah program Prindeal besar yang membangun operasi penambahan, perkalian, dan eksponensial melalui penggunaan variabel dummy (dimulai dengan _konvensi) dan banyak alias penolong:

#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

(Jika Anda bermain-main dengan kode ini, sadarilah bahwa banyak perintah akan gagal jika variabel yang sama diberikan beberapa kali sebagai argumen. Ini dapat dengan mudah diperbaiki tetapi kode yang dihasilkan lebih panjang.)

Penerjemah Prindeal Anda harus dapat menghasilkan output yang tepat:

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

Mencetak gol

Kode terpendek dalam byte menang. Tiebreak pergi ke pengiriman sebelumnya.

Brownie Bonus: Tulis program keren di Prindeal. Saya menerapkan penambahan dan perkalian, bisakah Anda melakukan pengurangan atau pembagian?

Hobi Calvin
sumber
Ya ampun, kupikir sekali ini aku akan meninggalkan Pyth sendirian, dan mengeluarkan Lisp! Satu pertanyaan - fungsi dan variabel hidup dalam ruang nama yang sama sekali berbeda, bukan? Jadi saya bisa menambah p, lalu p p, mana yang akan mencetak 1, kan?
orlp
@ orlp Benar. (Ada beberapa catatan tentang itu di sana.)
Hobi Calvin
2
Saya tidak bisa menjadi satu-satunya yang berpikir PRNDL ketika saya melihat nama bahasa.
Downgoat
Apakah ada jumlah maksimum argumen yang akan diteruskan ke perintah alias?
Zach Gates
@ZachGates Nggak
Hobi Calvin

Jawaban:

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

Demonstrasi.

Golf 26 karakter dengan inlining variabel dan berubah dari Idan Eberdasarkan aliran kontrol ke ?dan .xberdasarkan aliran kontrol.

Untuk pertama kalinya, saya kehabisan variabel dalam Pyth. Setiap variabel tunggal dalam Pyth ( bdkGHNTYdan JK) sedang digunakan, dan saya ingin menggunakan bsebagai baris baru. Secara luar biasa, saya dapat menggunakan Nuntuk mengartikan dua hal yang sama sekali berbeda di berbagai bagian program, dan masih berfungsi.

Tidak disatukan (dijalankan dengan -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
isaacg
sumber
3
Saya suka bagaimana saya masih tidak tahu apa fungsinya bahkan jika itu tidak dimakan ...
Jerry Jeremiah
Nah, itu menyimpulkan Pyth adalah Non-Turing-Complete ...
Erik the Outgolfer
8

Python 2, 600 584 397 373 byte

Ini adalah solusi referensi golf saya sendiri. Siapa pun boleh memperbaikinya atau mengikuti logikanya dalam jawaban mereka sendiri asalkan diberikan atribusi.

Bagian yang rapi tentang hal itu adalah bahwa tidak ada rekursi yang dilakukan, sehingga tidak akan pernah memiliki masalah dengan batas rekursi Python. Misalnya, Sp ini Program Countup Prindeal dapat berjalan tanpa batas.

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

Ini adalah program yang mengambil dalam string dikutip Program dengan baris baru lolos, misalnya
'p _MyVariable_321\np screaming_hairy_armadillo'.

Saya mengambil berbagai isyarat golf dari jawaban Sp dan Pietu . Terima kasih teman-teman :)

Hobi Calvin
sumber
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 terima kasih kepada @orlp)

Masih bermain golf. Menganggap program disimpan dalam file bernama P.

Menempatkan panggilan ke fdalam lambda dakan menghemat beberapa byte, tetapi itu akan membuat test case terakhir mencapai kedalaman rekursi maksimal.

Beberapa program Prindeal

Program pengurangan yang tidak berguna

Ini adalah program pengurangan yang tidak berguna . Tidak ada gunanya karena, meskipun dikurangi dengan benar, itu tidak mengembalikan keberhasilan / kegagalan yang sesuai.

Outputnya harus:

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

Countup

a helper
 p 1
 countup 1
 i success

a countup
 i 1
 helper 1
 d failure

countup n

Hitung ke atas dan cetak nselamanya. Mungkin bisa berfungsi sebagai tes untuk kecepatan juru bahasa (berhati-hatilah pada traceback yang panjang pada keyboard interrupt).

Sp3000
sumber
2
Semua orang dalam pertanyaan ini telah melewatkan golf ini, saya tidak mengerti mengapa. l[:(l+"#").find("#")]dan semua variasinya bisa diganti dengan yang sederhana l.split('#')[0].
orlp
@ Atlp Sangat fokus pada findyang saya lupa Anda bisa splitbahkan jika #s tidak ada di sana. Terima kasih :)
Sp3000
6

JavaScript (ES6), 273 258

Edit bug yang diperbaiki dan menambahkan paket uji nyata.

Tidak termasuk spasi dan baris baru.

Tentunya bisa bermain golf lebih sedikit.

Terlalu lelah untuk menulis penjelasan sekarang, saya pikir itu adalah contoh yang baik menggunakan penutupan untuk mempertahankan nilai sementara (parameter).

Tes menjalankan cuplikan pada peramban apa pun yang mendukung EcmaScript 6 (terutama bukan Chrome, bukan MSIE. Saya menguji pada Firefox, Safari 9 dapat berjalan)

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>

edc65
sumber
Saya telah menambahkan beberapa komentar lagi ke program pengujian dan sepertinya mereka membuat kode Anda tidak berfungsi.
Calvin Hobbies
@ Calvin'sHobbies tambalan cepat pertama
edc65
3

C # 6, 653 byte

Inilah entri saya, di tengah lautan 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;}}

Diperluas dan dikomentari:

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;
    }
}

Untuk menggunakannya, cukup instantiate kelas dan panggil R()metode, misalnya:

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

Gangguan umum, 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))))

Masukkan ini file.lispdan panggil misalnya sbcl --script file.lisp; input dibaca dari aliran input standar.

Versi ini mem-parsing superset dari Prindeal: tanpa banyak kesulitan, Anda dapat mengakses semua Common Lisp dari sumber Prindeal. Saya menganggap ini sebagai fitur dari intepreter.

Versi yang dikomentari

;; 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)))))

Contoh

~$ 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

Jika kita ganti evaldengan printdi loop baca / eval, maka kita dapat melihat apa yang sedang dievaluasi:

(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)

Ekspansi makro

Jika kita memilih definisi alias berikut:

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

... kita bisa melihat referensi ke variabel bernama gyang tidak ditemukan dalam lingkup leksikal. Tetapi setelah ekspansi makro, berikut adalah kode aktual yang sedang dievaluasi:

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

Sekarang, gmerujuk ke daftar argumen fungsi yang sedang didefinisikan.

coredump
sumber
2

Python 2, 486 byte

Ini adalah solusi referensi yang saya golf lebih banyak (saat ini -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:]

Perubahan (yang saya ingat):

  • konversi boolean-integer otomatis ( [l,l[:l.find('#')]]['#'in l]).
  • setel atau tambah dalam satu pernyataan ( V[k]=-~V[k]if k in V else 1)
  • lebih banyak alias untuk ekspresi yang lebih panjang ( k=s[1])
  • tidak ada penghitung di loop utama, sebagai gantinya membersihkan daftar input
  • printsecara otomatis menambahkan spasi ( print k,'=',V.get(k,0))
  • memeriksa digit 1-9 ( '0'<t[0]<':')
  • membalik nilai pengembalian rsekitar untuk menyimpan returns
  • menghapus pengulangan slicing dan splitting ( map(str.split,c[:3])))
PurkkaKoodari
sumber
1

Python 3, 1322 byte

Golf:

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

Tidak Disatukan:

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

Pemakaian:

P(c)

Di mana cisi teksnya.

Contoh:

String baris tunggal diterima:

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

String multi-baris juga diterima:

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

Atau:

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

Dll

Catatan:

Ini berfungsi dengan benar untuk semua kasus uji, tetapi mencapai batas rekursi pada:

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

Karena itu sys.setrecursionlimit(2000).

Zach Gates
sumber
1
Ini akan menggunakan beberapa byte tetapi tidak bisakah Anda menggunakan sys.setrecursionlimit () untuk membuatnya berfungsi dengan baik dengan pow alias?
Corwin
Saya bisa, tetapi OP menyatakan bahwa bahasa seperti Python (yang memiliki batas rekursi) diterima apa adanya. Namun, saya akan menambahkan perbaikan jika diminta oleh OP. @Corwin
Zach Gates
Cukup adil. Ketinggalan dalam spec. @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> adalah karakter tab literal.

pppery
sumber
1

C ++, 1111 bytes

Yang ini adalah C ++ - sebodoh yang saya bisa lakukan.
Itu berarti membuatnya lebih C ++ - ish dan lebih sedikit C-ish.
Itu juga berarti lebih besar dari program C yang setara.
Saya pikir C ++ saingan Java untuk perpustakaan standar verbose.
Ini mengkompilasi dengan VS2013 dan g ++ 4.9.2 (dengan -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;}}}

Di bawah ini adalah yang asli. Jika ada yang bisa memikirkan cara untuk membuatnya lebih idiomatis dan lebih pendek pada saat yang bersamaan tolong beri tahu saya.

#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;
}
Jerry Jeremiah
sumber
0

Haskell, 1009

Saya melakukan yang terbaik untuk golf itu; kode ungolfed saya terdiri dari lebih dari 3.000 karakter. Pada titik ini saya tidak dapat mengingat apa yang dilakukan semua fungsi sehingga bermain golf lebih berarti menebak apa yang akan merusaknya dan apa yang tidak.

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
ankh-morpork
sumber