Tafsirkan bahasa Anda, tetapi bukan diri Anda sendiri?

21

Ada banyak tantangan yang mengatakan "menafsirkan X", di mana X adalah bahasa yang sederhana. Menurut saya, itu terlalu membosankan. Untuk memberikan semua orang yang suka menunda-nunda di internet sesuatu yang menarik untuk dilakukan, Anda dapat mencoba melakukan tantangan ini:

Tantangan

Pilih bahasa $LANG. $LANGbisa berupa turing bahasa pemrograman lengkap atau subset lengkap turing bahasa pemrograman. Berhati-hatilah bahwa jika Anda menghilangkan fitur bahasa Anda $LANGuntuk ditafsirkan, Anda juga tidak boleh menggunakannya untuk program Anda sendiri, karena kiriman Anda juga harus ditulis $LANG.

Tulis kompiler / juru bahasa untuk $LANGditulis $LANG. Anda dapat menggunakan semua fasilitas (termasuk evaldan teman) bahasa Anda yang tersedia untuk menulis kompiler ini. Untuk membuat tugas lebih menantang, ada satu batasan: Program Anda harus bisa menginterpretasikan / mengkompilasi semua program yang valid $LANGkecuali juru bahasa / kompiler Anda sendiri. Jika program yang akan ditafsirkan / dikompilasi adalah juru bahasa Anda atau kompiler itu sendiri (terlepas dari nama file), program Anda harus melakukan sesuatu yang sama sekali tidak terkait dengan fungsi juru bahasa atau kompiler (seperti barfing atau pencetakan Hello, world!).

Untuk membuat tugas ini semakin rumit, program Anda tidak boleh membaca sumbernya sendiri saat kompilasi atau interpretasi.

Spesifikasi

  • Tugas ini adalah kode golf. Kiriman dengan karakter paling sedikit menang benar. Dalam kasus seri, solusi yang diajukan pertama kali menang.
  • Program / skrip Anda harus membaca program yang akan ditafsirkan dari suatu file. Anda dapat membuat hardcode path dan namanya. Ketika file dibaca, Anda dapat mengkompilasi file ke file lain (Itu harus dapat dieksekusi pada sistem Anda) atau menjalankannya secara langsung. Jika $LANGtidak memiliki kemampuan membaca file, Anda dapat memilih cara lain untuk membaca kode yang sesuai $LANG. Anda tidak dapat memilih $LANGsebagai bagian dari bahasa lain tetapi dengan kapabilitas membaca file dihapus.
  • Aturan golf-aturan biasa berlaku. Yaitu: bahasa hewan peliharaan pribadi Anda yang Anda buat hanya untuk memecahkan tantangan ini dilarang, jika solusinya menjadi sepele menggunakannya (Seperti mendefinisikan program char tunggal yang persis mengimplementasikan solusi). Penyalahgunaan aturan dianjurkan.
FUZxxl
sumber
Apakah kami diizinkan untuk mendefinisikan bahasa untuk ini, asalkan turing selesai?
Cruncher
@Cruncher Ya, Anda. Lihat poin terakhir dari spesifikasi untuk lebih jelasnya.
FUZxxl

Jawaban:

8

Ruby, 63

b=$<.read
t="b=$<.read\nt=%p\nb!=t%%t&&eval(b)"
b!=t%t&&eval(b)
Lowjacker
sumber
Jawaban diterima selama tidak ada solusi yang lebih kecil.
FUZxxl
11

Perl, 89 karakter, tidak ada kecurangan

$_=q($_=q(Q);s/Q/$_/;($q=join"",<>)eq$_?die:eval$q);s/Q/$_/;($q=join"",<>)eq$_?die:eval$q

Perhatikan bahwa kode ini sangat pilih-pilih tentang apa yang dianggap sebagai "dirinya sendiri". Secara khusus, ia tidak akan mengenali dirinya sendiri jika ada baris baru yang tertinggal atau spasi kosong lainnya di input. Untuk mengujinya, simpan ke dalam file bernama (misalnya) unquine.pldan lakukan ini:

$ perl unquine.pl unquine.pl
Died at unquine.pl line 1, <> line 1.

Ingat, panjang unquine.plfile harus tepat 89 byte, tidak lebih, tidak kurang. Menjalankannya dengan beberapa skrip Perl lainnya sebagai input hanya menjalankan skrip lainnya, sebagaimana mestinya:

$ perl unquine.pl hello.pl
Hello, world!

Seperti namanya, implementasi didasarkan pada quine - khususnya, yang ini:

$_=q($_=q(Q);s/Q/$_/);s/Q/$_/

Kode ini disetel $_sama dengan dirinya sendiri; sisa program (yang, tentu saja, harus digandakan di dalam $_) hanya membandingkan $_dengan input, mati jika mereka cocok dan mengevaluasi input sebaliknya.

Ilmari Karonen
sumber
Anda dapat mengganti itu &&/ ;memasangkan dengan ternary (satu char off, dua kali lipat dengan quining). Ide bagus dan implementasi!
JB
@ JK: Tangkapan bagus! Turun ke 89 karakter sekarang.
Ilmari Karonen
5

GolfScript, 30 karakter

{`".~"+"#{$<.read}".@=!{~}*}.~

Program ini membaca konten file yang disebutkan pada baris perintah dan, jika tidak persis sama dengan kode di atas, menafsirkannya sebagai GolfScript. Jika inputnya persis sama dengan kode di atas, itu hanya akan dicetak tidak berubah (kecuali untuk baris baru ditambahkan ke akhir).

Ini adalah adaptasi yang cukup mudah dari program identifikasi diri ini . Secara khusus:

  • { } adalah kode blok literal dalam GolfScript.
  • .~, diterapkan pada blok kode, menduplikasi blok dan mengeksekusi salinan.

Di dalam blok kode:

  • ` merefleksikan salinan blok kode.
  • ".~"+menambahkan karakter .~ke dalamnya, menghasilkan string yang berisi kode sumber program.
  • "#{$<.read}"adalah hack terdokumentasi yang memungkinkan eksekusi kode Ruby dalam GolfScript. Dalam hal ini, ia mengeksekusi pernyataan Ruby $<.read(tanpa malu dicuri dari solusi Ruby Lowjacker ), yang membaca dan mengembalikan konten file yang ditentukan pada baris perintah. Peretasan ini diperlukan karena GolfScript sendiri tidak menyediakan kemampuan I / O file yang eksplisit.
  • .@ menduplikasi dan mengacak elemen di atas tumpukan sehingga tumpukan berisi dua salinan dari isi file diikuti oleh kode sumber program ini.
  • =! membandingkan dua item teratas pada stack (yaitu konten file dan sumber), mengembalikan 1 jika mereka berbeda dan 0 jika mereka sama.
  • {~}*mengevaluasi salinan sisa isi file sebagai kode GolfScript, tetapi hanya jika hasil perbandingannya adalah 1. (Secara teknis, ia mengeksekusi blok kode {~}sebanyak yang diberikan oleh angka pada tumpukan, yaitu 0 atau 1 kali. blok, ~adalah operator eval GolfScript.)

Ps. Jika membaca kode untuk dieksekusi dari stdin diizinkan, tantangan ini dapat diselesaikan dalam 21 karakter tanpa harus keluar ke Ruby:

{`".~"+1$=!{""\~}*}.~

Program ini akan membaca string input dari stdin dan, jika tidak cocok dengan sumbernya sendiri, jalankan (dengan input kosong). Seperti program di atas, input yang tidak cocok dengan sumber hanya akan ditampilkan kembali.

Ilmari Karonen
sumber
Terlihat bagus, tetapi sepertinya Anda tidak membaca input dari file.
FUZxxl
Diperbaiki, sekarang ia membaca dari file (tepatnya) seperti solusi Lowjacker.
Ilmari Karonen
5

Python, 167 130 118 byte

Ini adalah usaha pertama saya bermain golf, jadi begini! Ini menafsirkan program apa pun kecuali dirinya sendiri

Versi yang ditingkatkan:

i=open(raw_input()).read();q='i=open(raw_input()).read();q=%s;i==q%%repr(q)and a;exec(i)\n';i==q%repr(q)and a;exec(i)

Jika ia mendapatkan dirinya sendiri maka ia muntah dengan:

Traceback (most recent call last):
  File "pygolf.py", line 1, in <module>
    i=open(raw_input()).read();q='i=open(raw_input()).read();q=%s;i==q%%repr(q)and a;exec(i)\n';i==q%repr(q)and a;exec(i)
NameError: name 'a' is not defined

Saya pikir solusi ini bekerja dengan cara yang hampir sama dengan Ilmari Karonen, ide dasarnya adalah seperti:

input = read_some_file()
if input == some_quine()
    barf()
interpret(input)

Quine yang saya gunakan didasarkan pada yang ini:

(lambda x: x + repr((x,)))('(lambda x: x + repr((x,)))',)

Tetapi saya menyadari bahwa quine yang jauh lebih pendek adalah:

q='q=%s;q%%repr(q)';q%repr(q)

Dan itu bisa lebih pendek jika Anda mengizinkan shell python interaktif, dalam hal ini Anda dapat melakukan:

'%s;_%%repr(_)';_%repr(_)

Karena python tidak memiliki cara pendek untuk mendapatkan args baris perintah, saya menggunakan raw_input () (yang masih cukup panjang, tetapi tidak selama

import sys;sys.argv[1]

Penggunaannya adalah:

echo "foobar.py" | python quinterpretter.py

atau

python quinterpretter.py
<type filename and hit enter>

Saya menemukan quine yang lebih pendek untuk digunakan, tetapi ini adalah versi lama saya (untuk anak cucu):

i=open(raw_input()).read();a if i==(lambda x,y:x+repr((x,y))+y)('i=open(raw_input()).read();a if i==(lambda x,y:x+repr((x,y))+y)', ' else 1;exec(i)\n') else 1;exec(i)
Gordon Bailey
sumber
Ganti% s dengan% r dan hapus repr. % r berarti mentah dan pada dasarnya ia adalah hal yang sama.
Loovjo
4

Saya tidak bisa benar-benar membaca dari file menggunakan Javascript (ok, saya bisa, menggunakan hal FileReader HTML5, tapi itu membuat banyak hal lebih rumit daripada yang saya butuhkan). Jadi, ini adalah fungsi yang menerima program Javascript sebagai string dan menjalankannya.

Ini mungkin tidak golf seperti yang seharusnya, tapi ini dia:

Javascript, 252

function c(p){q='\"';s='\\';a="function c(p){q='\"';s='\\';a=%;a=a.slice(0,17)+s+a.slice(17,24)+a[23]+a.slice(24);a=q+a.replace('%',q+a+q)+q;alert(a);}";a=a.slice(0,17)+s+a.slice(17,24)+a[23]+a.slice(24);a=a.replace('%',q+a+q);alert(a);if(p!=a)eval(p)}

Beritahu saya jika ada yang tahu teknik yang lebih baik untuk membentuk quine di Javascript.

Peter Olson
sumber
1
Saya memposting solusi 135-char JS di bawah ini, berdasarkan pada kode Anda dan solusi Perl saya. +1 untuk inspirasi!
Ilmari Karonen
2
read p<p;read c<c;[ "$p" = "$c" ]||. ./c

45 karakter sh (POSIX shell). Kode yang akan dijalankan harus dalam file ./c.

Kode untuk penerjemah itu sendiri harus ada dalam file ./p, jadi saya kira saya agak tertipu, meskipun tantangannya tampaknya tidak melarangnya. Atau apakah ini akan mendiskualifikasi "bahasa" saya dari menjadi "bahasa pemrograman turing-complete"?

Menggunakan alat yang biasanya dapat dieksekusi eksternal, tetapi secara teoritis dapat dibangun ke dalam shell, kode dapat disingkat:

cmp -s p c||. ./c

Itu 18 karakter, dan -sbit hanya untuk menekan garis yang kalau tidak akan selalu dicetak untuk program (non-mandiri) yang valid.

Dan kemudian Anda selalu dapat membangun versi bahasa shell yang melakukan hal di atas dengan sintaksis yang lebih ringkas.

Dan kemudian Anda selalu dapat membangun program itu, ketika input terdiri dari satu '.' --atau neraka, string kosong-- mengevaluasi isi file lain sebagai kode normal, dan menyebutnya bahasa pemrograman. Jadi string kosong akan menjadi solusi Anda untuk tantangan, dalam bahasa yang Anda buat. Sebenarnya, inilah penerjemah untuk bahasa seperti itu:

read code; if [ "$code" ]; then eval "$code"; else . ./othercode; fi

Menggunakan bahasa yang diterjemahkan oleh skrip di atas, solusinya adalah string kosong. Dan lokasi kode tidak perlu dikodekan lagi.

Masalah?

TaylanUB
sumber
2
Tantangannya mengatakan bahwa "program Anda tidak boleh membaca sumbernya sendiri".
Ilmari Karonen
Sialan, terbuang beberapa waktu kemudian. Dan saya melihatnya bahkan mengatakan Anda tidak boleh menggunakan fitur yang akan Anda hilangkan. Ini akan bertentangan dengan fitur string kosong. Kemudian lagi, juru bahasa harus menghilangkan / mengubah fungsi jika kode untuk kompiler / juru bahasa itu sendiri menyebabkan perilaku yang berbeda dalam bahasa baru. Bagaimanapun, saya senang menulis kesalahan.
TaylanUB
@ TaylanUB Yah, Anda benar-benar harus menafsirkan semua program $ lang yang valid kecuali juru bahasa itu sendiri.
FUZxxl
@FUZxxl Ya, bahasa "sh + string kosong" setara dengan sh (jika kode tersebut bukan string kosong), dan program string kosong yang tertulis di dalamnya juga mengartikan kode sh (yang harus dimasukkan ke dalam ./othercode), dan tidak tidak apa-apa ketika kode adalah string kosong. Saya seharusnya tidak memanggil file ./othercode, itu menyesatkan; hanya kode yang diterjemahkan oleh penerjemah yang ditulis dalam bahasa string kosong.
TaylanUB
2

JavaScript, 135 karakter

function c(p){q='function c(p){q=%27Q%27;p!=unescape(q).replace(/Q/,q)?eval(p):alert()}';p!=unescape(q).replace(/Q/,q)?eval(p):alert()}

Solusi JavaScript Peter Olson menginspirasi saya untuk mencoba porting solusi Perl saya ke JS. Seperti solusinya, kode ini mendefinisikan fungsi cyang menerima string, dan mengevaluasinya jika tidak sama dengan kode di atas.

Butuh beberapa waktu untuk mencari tahu cara yang baik untuk berurusan dengan tidak adanya pemisah string seimbang dalam JavaScript, sampai saya menemukan apa yang di belakang adalah solusi yang jelas: unescape().

Dengan mudah, kode saya tidak mengandung garis miring terbalik atau tanda kutip ganda, sehingga dapat disimpan dengan aman dalam string yang dikutip ganda. Ini membuatnya mudah untuk diuji:

e = "function c(p){q='function c(p){q=%27Q%27;p!=unescape(q).replace(/Q/,q)?eval(p):alert()}';p!=unescape(q).replace(/Q/,q)?eval(p):alert()}"
h = "alert('Hello, world!')"

eval(e)  // defines the function c()

c(h)     // evaluates h
c(e)     // does not evaluate e, alerts "undefined" instead
Ilmari Karonen
sumber
Anda dapat menggantinya alert()dengan 0untuk membuatnya tidak melakukan apa-apa selain memperingatkan undefineddan menyimpan 13 karakter.
Peter Olson
@PeterOlson: Ya, tapi tugasnya mengatakan bahwa "program Anda harus melakukan sesuatu yang sama sekali tidak berhubungan" jika ia mendeteksi dirinya sendiri. Saya menafsirkan bahwa itu berarti harus melakukan sesuatu - lebih disukai sesuatu yang terlihat oleh pengguna, saya kira. Selain itu, saya hanya suka lebih baik dengan cara ini. :) (Mz. Yay, salju turun di luar! Musim dingin akhirnya tiba di sini!)
Ilmari Karonen
1
@Ilmari Melakukan apa-apa tidak ada hubungannya dengan menafsirkan Javascript IMHO.
FUZxxl
Anda bisa pergi p=>...bukannyafunction c(p)
FireCubez
2

Common Lisp, 59

#+~ #.(#:a)(defun L(p)(compile-file p))(push :~ *features*)
  • Dalam REPL Lisp baru, kompilasi file Anda (misalnya sbcl --load)
  • Anda sekarang memiliki fungsi L, yang dapat mengkompilasi file Common Lisp
  • Namun, jika Anda menelepon (L <your file>), kesalahan ditandai saat membaca file.

Mengapa?

Karena pertama kali, Anda memasukkan :~kata kunci ke dalam *features*. Sekarang, lingkungan Anda tahu tentang ~fitur tersebut, dan pembaca makro #+, setelah mengevaluasi ~ ekspresi fitur , akan berhasil dan membaca formulir berikut daripada melewatkannya seperti yang pertama kali dilakukan. Di file Anda, formulir berikut adalah #.(#:a), yang meminta untuk mengevaluasi (#:a)pada waktu-baca dan menggunakan nilai yang dihasilkan sebagai kode yang sedang dibaca. Tetapi (#:a)memanggil fungsi yang terkait dengan simbol yang tidak diinginkan #:a. Karena #:atidak diketahui, ini adalah simbol baru yang tidak terikat pada fungsi apa pun (yaitu tidak fboundp). Kesalahan.

coredump
sumber
1

Skema, 48 atau 51 karakter

Skema adalah bahasa dengan banyak implementasi yang berbeda. Meskipun implementasi harus sesuai dengan RnRS terbaru, standar kerja terbaru (R6RS) tidak populer karena kurangnya minimalis. R7RS akan segera dirilis sebagai obat, sambil membagi bahasa menjadi 2. Bahasa pertama menjadi kuat dan minimalis dan yang kedua, superset dari yang pertama dimaksudkan untuk menyediakan ekstensi fitur untuk interoperabilitas antar implementasi. Sampai saat itu, kami bergantung pada SRFI (Skema Permintaan Implementasi), yang menyediakan (jika diimplementasikan dalam implementasi host atau secara manual (seperti yang umum dalam skema)) sarana untuk menyelesaikan tugas-tugas umum dengan mudah. Semua ini untuk mengatakan bahwa potongan kode pertama (51 karakter), sementara tetap portabel seperti itu, bergantung pada SRFI-22 (menjalankan skrip skema di UNIX) untuk akses ke argumen baris perintah:

(define(main x y)(case y(x => error)(else => load)))

atau lebih mudah dibaca:

(define (main current-file arg)
  (case arg
    [current-file => error]
    [else => load]))

Yang kedua (48 karakter) adalah sarana tanpa file untuk interpretasi yang tidak dapat mengevaluasi dirinya sendiri (dalam lingkungan nol):

(define(e)(write(eval(read)null-environment))(e))

atau lebih mudah dibaca:

(define (interpret)
  (write (eval (read) null-environment))
  (interpret))
Samuel Duclos
sumber
Kode Anda tidak berfungsi jika Anda menyalin juru bahasa Anda.
FUZxxl
1
Biarkan jawaban skema untuk berisi tanda kurung bersarang di prosa.
Cyoce
1

Groovy, 13 byte

{Eval.me(it)}

Ini harus menafsirkan subset dari Groovy.

kasus uji:

p={Eval.me(it)}

p'''
    (0..37).each{println"1234567890JIHGFEDCBAKLMNOPQRST!?,.ZYXWVU"[it..it+2]}
'''

p'''
    {Eval.me(it)}
'''

Sayangnya sementara itu pasti muntah, ia melakukannya dengan cara yang sepenuhnya seperti juru bahasa, dan ia melakukannya untuk input yang cukup banyak.

Armand
sumber
Di baris mana Anda membaca program yang akan ditafsirkan? Kode Anda menarik meskipun bukan pengiriman yang valid untuk tugas ini.
FUZxxl
Saya berasumsi kesalahannya adalah sesuatu seperti "batas rekursi terlampaui"?
Ilmari Karonen