Golf a Purple Interpreter

13

Golf a Purple Interpreter

Ungu adalah esolang yang dirancang dengan dua tujuan utama:

  • Untuk menjadi minimalisasi terong , karena tidak ada cukup bahasa satu instruksi yang memodifikasi sendiri sekitar.
  • Untuk mengakui kemungkinan penerjemah golf yang sangat kecil . Pass pertama saya pada interpreter Python 2 dengan fitur cukup lengkap hanya 702 byte, dan saya yakin pegolf yang lebih berpengalaman bisa mencukur sedikit dari itu.

Tujuan Anda adalah menulis penerjemah untuk bahasa ini.

Informasi tentang Ungu:

Program Ungu adalah urutan karakter yang ditempatkan ke dalam array memori yang tak terbatas dan dapat dialamatkan sehingga karakter pertama dari program ditempatkan pada alamat nol. Sisa array (baik sebelum dan sesudah di mana program Ungu disimpan) diinisialisasi ke nol.

Ada tiga register dalam warna Ungu, disebut a dan b dan i , yang masing-masing dapat menyimpan bilangan bulat yang ditandatangani dan diinisialisasi ke nol. i juga penunjuk instruksi, dan selalu menunjuk ke instruksi Ungu yang sedang dijalankan.

Setiap siklus, juru bahasa akan membaca urutan tiga karakter yang berdekatan mulai dari lokasi memori yang ditunjukkan oleh penunjuk instruksi dan mencoba untuk mengeksekusi urutan ini sebagai instruksi Ungu. Setelah itu, penunjuk instruksi selalu bertambah 3.

Secara sintaksis, instruksi Ungu terdiri dari tiga karakter (atau penyandiannya) berturut-turut, seperti " xyz ".

Karakter pertama x dapat berupa salah satu dari yang berikut:

abABio

Simbol-simbol ini memiliki arti sebagai berikut:

a - Place the result in register a.
b - Place the result in register b.
A - Place the result in the location in memory referred to by register a.
B - Place the result in the location in memory referred to by register b.
i - Set the instruction pointer to the result.
o - Output the result to stdout.

Dua byte lain y dan z dapat berupa salah satu dari yang berikut:

abABio1

Masing-masing simbol ini memiliki arti sebagai berikut:

a - Return the contents of register a.
b - Return the contents of register b.
A - Return the contents of the memory array at the address stored in register a.
B - Return the contents of the memory array at the address stored in register b.
i - Return the contents of register i (the instruction pointer).
o - Return the value of a single character read from stdin.
1 - Return the literal numeric value 1.

Setelah mengambil instruksi, penerjemah Ungu akan mengevaluasi y dan kemudian z , kurangi hasil z dari hasil y , dan kemudian lakukan tindakan yang ditunjukkan oleh x pada perbedaan.

Jika urutan tiga karakter (atau penyandiannya) bukan instruksi Ungu yang valid, penerjemah segera berhenti tanpa memberikan kesalahan apa pun.

Penerjemah Anda harus:

  • Jadilah program yang lengkap, bukan fungsi.
  • Jangan pernah output ke stderr, kecuali EOF dibaca .
  • Berperilaku identik dengan implementasi referensi pada semua input yang terbentuk dengan baik yang tidak melibatkan jumlah yang sangat besar, termasuk program pengujian yang diberikan di bawah ini. (Yah, identik dengan waktu - itu bisa berjalan lebih lambat, tetapi tidak terlalu banyak!)

Anda dapat memberikan program kepada penerjemah dalam bentuk apa pun yang Anda inginkan: membacanya dari file, menanamkannya dalam program sebagai string, atau membacanya dari stdin.

Kasus uji:

Program

ooo

saat dijalankan dengan input

z!

harus menghasilkan

Y

Program

bbboobiii

saat dijalankan dengan input

It's a cat program.

(atau input lainnya) harus menghasilkan

It's a cat program.

(atau input apa pun yang diterima) dan kemudian mulai lagi dan lakukan hal yang sama lagi .


Program

Aoab11bi1bABoAaiba

saat dijalankan dengan input

0

harus menghasilkan

0

dan kemudian berhenti, tetapi ketika dijalankan dengan input

1

harus melanjutkan keluaran

1

selama-lamanya.


Program

b1bbb1oAbabaa1ab1Ab1Bi1b

harus menghasilkan

b1bbb1oAbabaa1ab1Ab1Bi1b

Program

aA1aa1bb1oAbbi1bb1bbAb1Bi1b Purple is the awesomest! Why haven't you tried it yet?
!dlroW ,olleG

harus menghasilkan

Hello, World!

Mencetak:

Ini adalah , jadi sumber terpendek dalam byte, yang berpotensi dimodifikasi oleh bonus berikut, menang.

Bonus:

  • -10% jika penerjemah Anda membaca nama file dari stdin atau dari argumen baris perintah dan memuat program dari file.
kuintopia
sumber
1
Berapa ukuran sel memori? byte, karakter (yang unicode?), (sewenang-wenang) bilangan bulat besar? Sepertinya Anda menggunakan "karakter" dan "byte" dengan arti yang sama.
Paŭlo Ebermann
@ PaŭloEbermann dugaan saya adalah itu khusus implementasi; misalnya saya perlu menggunakanuint32 untuk karakter dan MAXINT untuk ints
cat
2
@ sysreq Apakah itu benar-benar pemblokir? Implementasi Anda dapat dengan mudah memiliki dua kaset, satu untuk negatif dan satu untuk indeks positif. (Ya, saya pikir ini membutuhkan lebih banyak kode, tapi tidak terlalu banyak.)
Paŭlo Ebermann
1
@sysreq pada dasarnya, penerjemah mandiri Ungu akan menjadi program yang membaca program Ungu dari stdin dan kemudian melakukan apa pun yang akan dilakukan oleh program itu. Program Ungu pertama (interpreter) dapat berjalan dalam interpreter apa pun yang Anda suka. Sebuah program yang sepenuhnya menimpa alamat memori terendah dengan input, kemudian menghapus dirinya sendiri sebelum entah bagaimana melompat ke kode baca akan memenuhi syarat (meskipun saya tidak berpikir ini sebenarnya mungkin).
kuintopia
2
Saya nyaris memiliki runtime yang mampu menafsirkan diri sendiri, tetapi saya sudah terlambat.
kucing

Jawaban:

7

Pyth, 148 128 121 byte (atau 124 * .9 = 111.6, lihat bagian bawah)

J,00=kjb.z .eXHkCbz#=b-Fm?=zx"oabABi1"C@H+Zd@s[0Jm.x@Hk0JZ1H)zCh~tkS2 ?hKx"abAB"=YC@HZ?PKXH@JKbXJKb?qY\i=Zb?qY\opCbvN=+Z3

Suite uji

Kode diberikan pada baris pertama STDIN, masukan ke program Ungu pada sisa STDIN. Untuk menggunakan kode dengan baris baru, gunakan versi alternatif di bagian bawah.

Cukup bermain golf. Ini dia dengan linebreak dan lekukan untuk kejelasan:

J,00
=kjb.z
 .eXHkCbz
#
  =b-Fm
    ?=zx"oabABi1"C@H+Zd
      @
        s[0Jm.x@Hk0JZ1H)
        z
      Ch~tk
    S2
   ?hKx"abAB"=YC@HZ
    ?PK
      XH@JKb
      XJKb
  ?qY\i=Zb
  ?qY\opCb
  vN
  =+Z3

Pada dasarnya, sebuah #loop melakukan eksekusi dan berhenti melalui error-break.

adan bdigabungkan menjadi satu variabel tunggal J,. Zadalah penunjuk instruksi. kadalah input ke program Ungu. Hadalah rekaman itu, direpresentasikan sebagai kamus. badalah hasil saat ini.Yadalah byte pertama dari instruksi tersebut.

Membaca dari file:

J,00=kjb.z .eXHkCbjb'z#=b-Fm?q\o=zC@H+ZdCh~tk@s[Jm.x@Hk0JZ1H)x"abABi1"zS2 ?hKx"abAB"=YC@HZ?PKXH@JKbXJKb?qY\i=Zb?qY\opCbvN=+Z3

Berikan nama file sebagai baris pertama STDIN. Uji coba:

$ cat purple-final.pyth 
J,00=kjb.z .eXHkCbjb'z#=b-Fm?=zx"oabABi1"C@H+Zd@s[0Jm.x@Hk0JZ1H)zCh~tkS2 ?hKx"abAB"=YC@HZ?PKXH@JKbXJKb?qY\i=Zb?qY\opCbvN=+Z3
$ cat purple-code.txt 
aA1aa1bb1oAbbi1bb1bbAb1Bi1b Purple is the awesomest! Why haven't you tried it yet?
!dlroW ,olleG
$ pyth purple-final.pyth <<< 'purple-code.txt' 
Hello, World!
isaacg
sumber
5

JavaScript (ES6), 292 byte

eval(`a=b=i=d=0;v=n=>(x=m[i+n])==97?a_98?b_65?m[a]_66?m[b]_105?i_111?p()[c]()_49?1:d=1;for(m=[...(p=prompt)()].map(b=>b[c="charCodeAt"]());!d;i+=3)(y=v(1),d)||(z=v(2),d)?1:(x=m[r=y-z,i])==97?a=r_98?b=r_65?m[a]=r_66?m[b]=r_105?i=r-3_111?alert(String.fromCharCode(r)):d=1`.replace(/_/g,":x=="))

Penjelasan

Jawaban JavaScript selalu aneh ketika STDINdanSTDOUT diperlukan ...

Prompt pertama adalah input untuk string program. Setiap prompt yang dihasilkan dari oinstruksi hanya akan membaca karakter pertama.

evaldigunakan untuk mengganti frasa umum yang menyimpan beberapa byte. Tidak disatukan dan tanpa evalprogram terlihat seperti ini:

// Initialisation
a=b=i=                            // initialise registers to 0
  d=0;                            // d is set to true when the program should die

// Gets the result of Y or Z
v=n=>                             // n = offset from i
  (x=m[i+n])==97?a:               // x = value of instruction
  x==98?b:
  x==65?m[a]:
  x==66?m[b]:
  x==105?i:
  x==111?p()[c]():
  x==49?1:
  d=1;                            // if it was none of the valid values, die

// Execution loop
for(
  m=                              // m = memory array
    [...(p=prompt)()]             // receive the program
    .map(b=>b[c="charCodeAt"]()); // initialise m to the ASCII values of the program
  !d;                             // finish if an error occured
  i+=3                            // increment i
)
  (y=v(1),d)||                    // get the value of Y and check for errors
  (z=v(2),d)?1:                   // get the value of Z and check for errors

    // Get the result of X
    (x=m[r=y-z,i])==97?a=r:       // r = result of y - z
    x==98?b=r:
    x==65?m[a]=r:
    x==66?m[b]=r:
    x==105?i=r-3:
    x==111?alert(String.fromCharCode(r)):
    d=1
pengguna81655
sumber
2
Bisakah yang kedua c="charCodeAt"diganti dengan adil c?
Dendrobium
Apakah akses array dengan indeks negatif berfungsi dalam JavaScript?
nimi
@Dendrobium Wow, saya tidak tahu bagaimana saya merindukan haha ​​itu! Terima kasih.
user81655
2
@nimi Berhasil. Array sendiri tidak mendukung indeks negatif, tetapi ini memanfaatkan fakta bahwa mereka juga berperilaku sebagai objek. array[-1] = 1sama dengan array = { "-1": 1 }. Keduanya dapat diakses dengan array[-1].
user81655
@ user81655: Ah bagus, tidak tahu itu.
nimi
3

Ceylon, 827 792 671 byte

import ceylon.language{l=variable,I=Integer,x=nothing,p=process,m=map}shared void run(){try{if(exists d=p.arguments[0]){l value t=m{*d*.hash.indexed};l I a=0;l I b=0;l I i=0;I g(I j)=>t[j]else 0;l{I*}c=[];I o{if(c==[]){if(exists e=p.readLine()){c=e*.hash.chain{10};}else{c={-1}.cycled;}}assert(is I r=c.first);c=c.rest;return r;}value f=m{97->{a},98->{b},65->{g(a)},66->{g(b)},105->{i},111->{o},49->{1}};value s=m{97->((I v)=>a=v),98->((I v)=>b=v),65->((I v)=>t=m{a->v,*t}),66->((I v)=>t=m{b->v,*t}),105->((I v)=>i=v),111->((I v)=>p.write("``v.character``"))};I h(I v)=>f[v]?.first else x;while(0<1){(s[g(i)]else x)(h(g(i+1))-h(g(i+2)));i+=3;}}}catch(AssertionError e){}}

Itu berperilaku sedikit berbeda dari implementasi referensi ketika program mencoba membaca input di EOF - implementasi referensi crash dengan TypeError, yang terlalu mahal untuk direproduksi di sini (dan juga kemungkinan bug), jadi ini akan mengembalikan -1 sebagai gantinya berulang kali, jika perlu).

(Ketika mencoba menulis -1 ini ke stdout, interpreter akan selesai dengan OverflowError, meskipun. Serupa akan terjadi jika Integer di luar kisaran Unicode adalah output.)

Penerjemah mengambil program sebagai argumen baris perintah pertama (pastikan untuk mengutipnya untuk shell Anda ketika berisi spasi putih atau hal-hal menarik lainnya).

Dalam Ceylon kita hanya dapat dengan mudah membaca input-bijaksana (saya kira ini akan berubah di salah satu versi berikutnya), jadi ketika odigunakan untuk membaca, saya membaca seluruh baris dan buffer bagian-bagian untuk penggunaan masa depan. Saya kira itu bekerja serupa dalam implementasi Python ketika terhubung ke terminal.


Saat mencoba menjalankan perintah (bagian) yang bukan salah satu karakter yang valid, nothingakan menyebabkan AssertionError dilempar, yang kemudian kita tangkap di blok tangkap di sekitar loop utama.

Saya pikir ini lebih baik menjadi tipe Pengecualian khusus (seperti AssertionError juga dapat terjadi di tempat lain jika saya memiliki bug), tetapi itu akan memakan banyak ruang, memakan sebagian besar perbaikan yang saya buat dari versi pertama.

Beberapa trik yang digunakan untuk bermain golf:

  • Versi sebelumnya menggunakan ceylon.collection.HashMap - sebagai gantinya kami sekarang menggunakan peta yang tidak dapat diubah sebagaimana dibuat oleh mapfungsi, dan membuat yang baru setiap kali Aatau Bdigunakan sebagai x .
  • Saya menggunakan alias-impor untuk semua pengidentifikasi dari ceylon.language yang digunakan lebih dari sekali (termasuk variableanotasi, yang sekarang l).
  • Saya menyingkirkan kelas E(untuk lingkungan) dan metode s(langkah) - semuanya sekarang terjadi di dalam runfungsi.
  • Alih-alih menggunakan .integeruntuk mendapatkan codepoint karakter, .hashmemberikan hasil yang sama. Jadi string*.hashsama dengan string.map(Character.integer)(memberikan iterable dari codepoint dari sebuah string).
  • Ketika suatu jenis alias diimpor, is I ...lebih pendek dariexists ... .
  • Ketika mengubah sesuatu (misalnya x) menjadi string, "``t``"lebih pendek dari t.string(atau, apa yang saya gunakan untuk karakter,String{t} ).
  • fungsi yang digunakan sekali saja sering dapat digarisbawahi.

Ini adalah versi yang diformat (dan dikomentari):

// Purple – a self-modifying, "one-instruction" language.
//
// Question:  http://codegolf.stackexchange.com/q/65411/2338
// My answer: http://codegolf.stackexchange.com/a/65492/2338

import ceylon.language {
    l=variable,
    I=Integer,
    x=nothing,
    p=process,
    m=map
}

shared void run() {
    try {
        // Reading code from file certainly takes more than 73 characters,
        // this isn't worth the 10% bonus.
        if (exists d = p.arguments[0]) {

            // The memory tape, as a Map<Integer, Integer>.
            // We can't modify the map itself, but we
            // can replace it by a new map when update is needed.
            l value t = m {
                // It is initialized with the code converted to Integers.
                // We use `.hash` instead of `.integer` because it is shorter.
                *d*.hash.indexed };

            // three registers
            l I a = 0;
            l I b = 0;
            l I i = 0;

            // get value from memory
            I g(I j) =>
                    t[j] else 0;

            // cached input which is still to be read
            l {I*} c = [];

            // get value from stdin.
            // we can only comfortably access stdin by line, so we read a whole line
            // and cache the rest for later.
            I o {
                if (c == []) {
                    if (exists e = p.readLine()) {
                        c = e*.hash.chain { 10 }; // convert string into ints, append \n
                    } else {
                        // EOF – return just -1 from now on.
                        c = { -1 }.cycled;
                    }
                }
                assert (is I r = c.first);
                c = c.rest;
                return r;
            }


            // Map of "functions" for fetching values.
            // We wrap the values in iterable constructors for lazy evaluation
            //  – this is shorter than using (() => ...).
            // The keys are the (Unicode/ASCII) code points of the mapped
            // source code characters.
            value f = m {
                // a
                97 -> { a },
                // b
                98 -> { b },
                // A
                65 -> { g(a) },
                // B
                66 -> { g(b) },
                // i
                105 -> { i },
                // o
                111 -> { o },
                // 1
                49 -> { 1 }
            };

            // Map of functions for "storing" results.
            // The values are void functions taking an Integer,
            // the keys are the ASCII/Unicode code points of the corresponding
            // source code characters.
            value s = m {
                // a
                97 -> ((I v) => a = v),
                // b
                98 -> ((I v) => b = v),
                // Modification of the memory works by replacing the map with a new one.
                // This is certainly not runtime-efficient, but shorter than importing
                // ceylon.collections.HashMap.
                // A
                65 -> ((I v) => t = m { a->v, *t }),
                // B
                66 -> ((I v) => t = m { b->v, *t }),
                // i
                105 -> ((I v) => i = v),
                // o – output as a character.
                111 -> ((I v) => p.write("``v.character``"))
            };

            // accessor function for the f map
            I h(I v) =>
                    f[v]?.first else x;

            // the main loop, can only be left by exception
            while (0 < 1) {
                (s[g(i)] else x)(h(g(i + 1)) - h(g(i + 2)));
                i += 3;
            }
        }
    } catch (AssertionError e) {
        // abort silently
    }
}
Paŭlo Ebermann
sumber
Saya menggunakan kembali bagian dari kode itu untuk "penerjemah paralel" yang mencoba menemukan semua program penghentian. (Ada banyak dari mereka.) (Di sana saya menggunakan versi non-I / O dari Ungu, karena I / O membutuhkan banyak ruang dan tidak digunakan dalam tugas itu.)
Paŭlo Ebermann