Küçük bir dil küçük bir tercümanı hakediyor


21

İşte çok basit bir dil tanımı:

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

Örnek programlar (boş dizgenin bir değişken olduğuna dikkat edin, ancak netlik sağlamak için kullanışsız kullanacağım ve bazı değişkenler genellikle varsayılan olarak 0 olduklarında programda sıfırlanır):

<>: 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

Amacınız bu dil için en küçük tercümanı yazmak.

  1. Bir değişkenin değeri keyfi olarak büyük olabilir ve yalnızca dilinizin erişebildiği toplam bellekle sınırlandırılmalıdır, ancak teoride yalnızca 2 ^ 256 değerine kadar değerleri kullanmanız gerekir.

  2. Programınız teorik olarak keyfi olarak uzun programları yönetebilmelidir, ancak yalnızca 2 ^ 32 karakterden uzun olan programlar üzerinde çalışmanız gerekir. İç içe geçmiş derinlik döngülerini 2 ^ 32'ye kadar da kullanmanız gerekir.

  3. Programın geçerli bir program olduğunu ve girdi istediğinizde yalnızca negatif olmayan tam sayılar alacağınızı varsayabilirsiniz. Giriş dizesinde yalnızca ASCII yazdırılabilir karakterlerinin bulunduğunu da varsayabilirsiniz.

  4. Yorumladığınız programın hızı önemli değil, zaten optimizasyon olmadan 5 basamaklı çarpma kadar basit şeyler için acı verici bir şekilde yavaş olacak.

  5. Girdiyi makul şekilde kabul edemeyen bir dili kullanmak veya dili tarafından tarif edilen şekilde çıktı üretmek istiyorsanız, mümkün kılmak için herhangi bir yorum kullanın. Bu, dilinizin gerekli bazı davranışları yerine getirememesi nedeniyle geçerlidir. Tüm dillerin rekabet edebilmesini istiyorum.

  6. En kısa program kazanır. Standart boşluklar uygulanır.


Bir yan zorluk olarak, 2016 sayısını veren bir programın ne kadar kısa yazdığını görmek istiyorum, ancak önce kodumu test edebilmek için bir tercümanın yazılmasını beklemeliyim.
Neil,

1
Burada Python 2.7'de bir tercüman var .
Sürtünmeli Kavun

2
Bu dilin adı ne? Esolangs.org'da
wizzwizz4

@Neil 72 karakterde
yapmayı başardım

@FrikativeMelon 72? 43'te yapabilirim!
Neil

Yanıtlar:


4

Ruby, 182 bayt

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

Bu şekilde dene:

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

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

Nasıl çalışır

rFonksiyonu bir giriş dizesini sıfırlar ve her simge yürütür:

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

Biz bazı değişken adı aramaya $2eşleştirme [^!?^<>]*ya, ardından

  • <...>nerede ...sıfır veya daha fazla programları maçları ( \gvaka olduğu, tekrarlama olan) $4değilnil
  • Bir !, ?ya ^tarafından yakalanan karakter, $3dava ettiği, $4olduğu nil.

Sonra bir belirteç yürütme mantığı biraz girinti yaparken oldukça basittir:

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

Bunun nasıl çalıştığını gerçekten merak ediyorum.
Jerry Jeremiah

1

JavaScript (ES6) 184 194 209

Düzenle Basitleştirilmiş (giriş ve çıkış için işlev parametrelerini kullanmak hoş bir fikir gibi görünüyordu, ancak değildi), 1 bayt daha kaydedildi thx @ ӍѲꝆΛҐӍΛПҒЦꝆ

Düzenle 2 Değiştirilmiş ayrıştırma. Artırma / giriş mantığı @ Lynn'in cevabından ödünç alınmıştır.

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

Daha az golf oynadı

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

TEST Snippet, 2016'da @Neil tarafından yayınlanan programı kullanarak değerlendirmeye başlıyor. Sabırlı ol...

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>


Bir seçenek değil evalönlemek için kullanıyor returnmusunuz?
Mama Fun Roll

@ ӍѲꝆΛҐӍΛПҒЦꝆ evet, eval 1 byte kazandırır. Hala daha önemli bir şey arıyorum
edc65

0

Perl, 251 bayt

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

Sürümünü okumak daha kolay:

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

Bu, doğrudan atlamalar için döngüleri sabitleyen bir grup baytı boşa harcar, ancak döngü için geriye doğru tarama yapmak, estetik anlayışımı bozar.


0

Standart C ++, 400 bayt

Bu derler 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]);}

Biraz daha kısaltabilirim. Bazı önerileriniz varsa lütfen yorum yapın.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.