Bahasa kecil layak mendapat juru bahasa kecil

21

Berikut ini definisi bahasa yang sangat sederhana:

A Variable is any string that does not contain ^, <, >, !, or ?
The empty string is a valid variable identifier
The value of every variable starts at 0.
A Statement is one of (var is a Variable, P is a Program):
    var^   -> changes var to be equal to 1 more than itself
    var<P> -> while var > 0, changes var to be equal to 1 less than itself, then runs P
    var! -> output value of var
    var? -> ask for non-negative integer as input, increase var by that value
A Program is a concatenation of Statements, running a Program means running each Statement in order

Contoh program (perhatikan bahwa string kosong adalah variabel, tetapi saya akan menggunakannya dengan hemat demi kejelasan, dan beberapa variabel diberi nol pada program ketika biasanya 0 secara default):

<>: sets the value of the empty string variable to 0
b<>b?b<a^>: asks for b, then adds the value stored in b to a, zeroing b in the process
b<>b?a<>b<a^>: asks for b, then sets a to the value of b, zeroing b in the process
a<>c<>b<a^c^>c<b^> : copies the value in b into a without zeroing it
b<>c<>a<c^c^c<b^>>b! : outputs a multiplied by 2
b^b<a<>a?a!b^> : outputs what you input, forever

Tujuan Anda adalah untuk menulis juru bahasa terkecil untuk bahasa ini.

  1. Nilai suatu variabel bisa besar secara sewenang-wenang dan seharusnya hanya dibatasi oleh total memori yang dapat diakses oleh bahasa Anda, secara teori, tetapi Anda hanya diminta untuk menangani nilai hingga 2 ^ 256.

  2. Program Anda seharusnya dapat menangani program panjang yang sewenang-wenang, secara teori, tetapi Anda hanya akan diminta untuk mengerjakan program dengan panjang 2 ^ 32 karakter. Anda diminta untuk menangani loop bersarang dengan kedalaman hingga 2 ^ 32 juga.

  3. Anda dapat mengasumsikan bahwa program tersebut adalah program yang valid, dan bahwa Anda hanya akan mendapatkan bilangan bulat non-negatif saat Anda meminta input. Anda juga dapat berasumsi bahwa hanya karakter yang dapat dicetak ASCII yang dimasukkan dalam string input.

  4. Kecepatan program yang Anda tafsirkan tidak masalah, itu akan sangat lambat untuk hal-hal sesederhana perkalian 5 digit, tanpa optimasi.

  5. Jika Anda ingin menggunakan bahasa yang tidak dapat menerima input atau menghasilkan output dengan cara yang dijelaskan oleh bahasa, gunakan interpretasi apa pun yang Anda inginkan. Ini berlaku untuk alasan apa pun bahasa Anda tidak dapat menerapkan beberapa perilaku yang diperlukan. Saya ingin semua bahasa dapat bersaing.

  6. Kemenangan program terpendek. Celah standar berlaku.

Melon Fricative
sumber
Sebagai tantangan sampingan saya ingin melihat betapa singkatnya sebuah program yang dapat saya tulis yang menghasilkan angka 2016, tetapi pertama-tama saya harus menunggu penerjemah ditulis sehingga saya dapat menguji kode saya.
Neil
1
Saya memiliki juru bahasa di Python 2.7 di sini .
Melon Fricative
2
Apa sebutan bahasa ini? Itu layak mendapat tempat di esolangs.org
wizzwizz4
@Neil Saya berhasil melakukannya dalam 72 karakter
Fricative Melon
@FricativeMelon 72? Saya bisa melakukannya dalam 43!
Neil

Jawaban:

4

Ruby, 182 byte

$h=Hash.new 0
def r(c)c.scan(/(([^!?^<>]*)(<(\g<1>*)>|[!?^]))/){$4?($1=~/(.*?)<(.*)>/
($h[$1]-=1;r$2)while$h[$1]>0):$3<?"?p($h[$2]):$h[$2]+=$3<?@?STDIN.gets.to_i:
1}end
r IO.read *$*

Coba seperti ini:

$ cat code
a?b<>c<>a<c^c^c<b^>>b!

$ ruby lynn.rb code
3                           <-- input
6                           <-- output

Bagaimana itu bekerja

The rFungsi tokenizes string input dan mengeksekusi setiap token:

def r(c)
    c.scan(/(([^!?^<>]*)(<(\g<1>*)>|[!?^]))/){
        ...
    }
end

Kami mencari beberapa $2pencocokan nama variabel [^!?^<>]*, diikuti oleh salah satunya

  • <...>di mana ...cocok dengan nol atau lebih program ( \grekursi), dalam hal $4ini tidaknil
  • A !,, ?atau ^karakter, ditangkap oleh $3, dalam hal $4ini nil.

Maka logika untuk mengeksekusi token cukup sederhana ketika membuat indentasi sedikit:

$4 ? (                                    # If it's a loop:
    $1 =~ /(.*?)<(.*)>/                   #   Re-match token*
    ($h[$1]-=1; r $2) while $h[$1] > 0    #   Recurse to run loop
) :                                       # Else:
    $3 < ?"                               #   If it's an !:
      ? p($h[$2])                         #     Print the var
      : $h[$2] +=                         #   Else, increment it by:
          $3 < ?@                         #     If it's a ?:
              ? STDIN.gets.to_i           #       User input
              : 1                         #     Else: 1

* There's an oniguruma bug, I think, that keeps me from simply using $3 here.
Lynn
sumber
Saya benar-benar ingin tahu bagaimana ini bekerja.
Jerry Jeremiah
1

JavaScript (ES6) 184 194 209

Sunting Sederhana (menggunakan parameter fungsi untuk input dan output sepertinya ide yang bagus, tetapi ternyata tidak), 1 byte lebih disimpan thx @ ӍѲꝆΛҐӍΛПҒЦꝆ

Edit 2 Penguraian yang dimodifikasi. Logika untuk kenaikan / input dipinjam dari jawaban @ Lynn

F=(p,i=0,v={},n='')=>eval("for(;c='>?^!<'.indexOf(q=p[i++]||'');n=~c?'':n+q)if(c>3){for(;v[n]--;)F(p,i,v);i=F(p,i,v[n]=0)}else~c&&v?c>2?alert(v[n]|0):v[n]=~~v[n]+(--c||+prompt()):0;i")

Kurang golf

F=(p,      // program 
   i = 0,  // initial instruction pointer  
   v = {}, // variables (default to empty) or if 0, flag of dummy execution
   n = ''    // name of current variable (has to be local for recursive calls)
{
  for(; c='>?^!<'.indexOf(q=p[i++]||''); )
  // q = current character
  // c = current command (int 0..4 or -1 id not recognized)
  //     note 0 end of subprogram or end of program
  {
    if(c>3) // 4='<' call subprogram - recursive
    {
      for(;v[n]--;)
        F(p,i,v); // conditional call, repeated - using real environment
      v[n] = 0; // Reset variable at loop end
      i=F(p,i,0) // one more unconditional dummy call, just to advance i
    }
    else
      ~c&&v? // if valid command (1..3) and not dummy
      c>2?
        alert(v[n]|0) // output, undefined becomes 0
        :v[n]=~~v[n]+(--c||+prompt()) // inc with 1 or user input
      :0     // not valid command or dummy, do nothing
    n=~c?'':n+q // reset or update current variable name
  }
  return i // return current istruction pointer (for recursive calls)
}

UJI Potongan mulai mengevaluasi 2016 menggunakan program yang diposting oleh @Neil. Sabar...

F=(p,i=0,v={},n='')=>eval("for(;c='>?^!<'.indexOf(q=p[i++]||'');n=~c?'':n+q)if(c>3){for(;v[n]--;)F(p,i,v);i=F(p,i,v[n]=0)}else~c&&v?c>2?alert(v[n]|0):v[n]=~~v[n]+(--c||+prompt()):0;i")

// TEST
function definput(){  I.disabled = KI.checked; }
function defoutput(){  O.disabled = KO.checked; }

function run()
{
  var prog=P.value, irows = I.value.split('\n'), pi=0;
  var fout=x=>O.value+=x+'\n';
  var fin=x=>irows[pi++];
  var saveAlert=alert, savePrompt=prompt
  if (!KO.checked) alert=fout,O.value=''
  if (!KI.checked) prompt=fin
  
  F(prog);
  
  alert=saveAlert
  prompt=savePrompt
}

P.value="^^^^<a^a^>a<^^^^><a^b^>a<c<b^^>b<c^^>>!"

run()
Program <button onclick="run()">RUN</button><br>
<textarea id=P></textarea><br>
Input (or <input type=checkbox id=KI onclick="definput()"> interactive prompt)<br>
<textarea id=I>5</textarea><br>
Output (or <input type=checkbox id=KO onclick="defoutput()"> popup)<br>
<textarea id=O readonly></textarea><br>

edc65
sumber
Apakah menggunakan evaluntuk menghindari returnbukan pilihan?
Mama Fun Roll
@ ӍѲꝆΛҐӍΛПҒЦꝆ ya, eval menghemat 1 byte. Saya masih mencari sesuatu yang lebih substansial
edc65
0

Perl, 251 byte

@p=split/([<>!?^])/,<>;for$c(0..$#p){$_=$p[$c];/</&&push@j,$c;if(/>/){$a=pop@j;$p[$c]=">$a";$p[$a]="<$c";}}while($c<$#p){$_=$p[$c];/\^/&&$v{$l}++;/!/&&print$v{$l};/\?/&&($v{$l}=<>);/<(\d+)/&&($v{$l}?$v{$l}--:($c=$1));/>(\d+)/&&($c=$1-2);$l=$_;$c++;} 

Versi yang lebih mudah dibaca:

# treat the first line of input as a program

# split on punctuation keywords; @p will contain the program as a list
# of tokens (including whitespace between adjacent punctuation)
@p = split /([<>!?^])/, <>;

# rewrite jump addresses

# the interpreter could scan backwards to avoid this, but that idea
# makes me feel dirty
for $c (0..$#p) {
    $_ = $p[$c];
    # save loop-start address on stack
    /</ && push @j, $c;
    if (/>/) {
        # if we encounter a loop-end instruction, rewrite it and the
        # corresponding loop-start to include the address (of the
        # instruction---jumps have to offset from this)
        $a = pop @j;
        $p[$c] = ">$a";
        $p[$a] = "<$c";
    }
}

# execute the program

# our program is already in @p

# $c will contain our program counter

# $l will contain the name of the last-referenced variable

while ($c < $#p) {
    # move current instruction into $_ for shorter matching
    $_ = $p[$c];

    # increment instruction
    /\^/ && $v{$l}++;

    # output instruction
    /!/ && print $v{$l};

    # input instruction
    /\?/ && ($v{$l} = <>);

    # loop start, including address
    /<(\d+)/ && ($v{$l} ? $v{$l}-- : ($c = $1));

    # loop end, including address
    />(\d+)/ && ($c = $1-2);

    # copy current instruction into "last variable name"---this will
    # sometimes contain operators, but we have null-string
    # instructions between adjacent operators, so it'll be fine
    $l = $_;

    # advance the program counter
    $c++;
}

Ini membuang banyak byte memperbaiki loop menjadi lompatan langsung, tetapi pemindaian mundur untuk loop mulai menyinggung perasaan saya tentang estetika.

David Morris
sumber
0

Standar C ++, 400 byte

Ini mengkompilasi dengan g++ -g test.cpp -Wall -Wextra -pedantic -std=gnu++11

#include<map>
#include<cstring>
#define b ;break;case
#define u unsigned long long
std::map<std::string,u>V;void r(char*s){char*p,*q,*e;for(u c;*s;s=p){p=strpbrk(s,"^<?!");c=*p;*p++=0;switch(c){b'^':V[s]++b'<':for(e=p,c=0;*e!='>'||c;e++)c+=(*e=='<')-(*e=='>');*e++=0;while(V[s]>0){V[s]--;r(q=strdup(p));free(q);}p=e;b'?':scanf("%llu",&V[s])b'!':printf("%llu",V[s]);}}}int main(int,char*v[]){r(v[1]);}

Saya mungkin bisa mempersingkat lagi. Jika Anda memiliki beberapa saran, silakan komentar.

Jerry Jeremiah
sumber
367 byte
ceilingcat