ภาษาเล็ก ๆ ควรเป็นล่ามขนาดเล็ก


21

นี่คือคำนิยามภาษาที่ง่ายมาก:

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

ตัวอย่างโปรแกรม (โปรดทราบว่าสตริงว่างเปล่าเป็นตัวแปร แต่ฉันจะใช้เท่าที่จำเป็นเพื่อความชัดเจนและตัวแปรบางตัวจะถูกทำให้เป็นศูนย์ในโปรแกรมเมื่อโดยปกติแล้วจะเป็น 0 ตามค่าเริ่มต้น):

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

เป้าหมายของคุณคือการเขียนล่ามที่เล็กที่สุดสำหรับภาษานี้

  1. ค่าของตัวแปรสามารถมีขนาดใหญ่โดยพลการและควรถูก จำกัด ด้วยหน่วยความจำทั้งหมดที่ภาษาของคุณเข้าถึงได้ในทางทฤษฎี แต่คุณจำเป็นต้องจัดการค่าสูงสุด 2 ^ 256 เท่านั้น

  2. โปรแกรมของคุณควรจะสามารถจัดการกับโปรแกรมที่มีความยาวได้ตามทฤษฎี แต่คุณจะต้องทำงานกับโปรแกรมที่มีความยาว 2 ^ 32 ตัวอักษรเท่านั้น คุณต้องจัดการลูปที่ซ้อนกันของความลึกสูงสุด 2 ^ 32 เช่นกัน

  3. คุณสามารถสมมติได้ว่าโปรแกรมนั้นเป็นโปรแกรมที่ถูกต้องและคุณจะได้รับจำนวนเต็มไม่เป็นลบเมื่อคุณขออินพุต คุณสามารถสันนิษฐานได้ว่ามีเพียงอักขระที่พิมพ์ได้ ASCII เท่านั้นที่รวมอยู่ในสตริงอินพุต

  4. ความเร็วของโปรแกรมที่คุณตีความไม่สำคัญมันจะช้าลงอย่างเจ็บปวดสำหรับสิ่งต่าง ๆ ที่เรียบง่ายเท่ากับการคูณ 5 หลักโดยไม่มีการเพิ่มประสิทธิภาพ

  5. หากคุณต้องการใช้ภาษาที่ไม่สามารถรับอินพุตได้อย่างสมเหตุสมผลหรือสร้างผลลัพธ์ตามวิธีที่อธิบายโดยภาษาให้ใช้การตีความที่คุณต้องการทำให้เป็นไปได้ สิ่งนี้ใช้กับเหตุผลใด ๆ ที่ภาษาของคุณใช้ไม่ได้ ฉันต้องการให้ทุกภาษาสามารถแข่งขันได้

  6. โปรแกรมที่สั้นที่สุดชนะ ช่องโหว่มาตรฐานใช้


ในฐานะที่เป็นความท้าทายด้านข้างฉันต้องการที่จะเห็นว่าโปรแกรมสั้น ๆ ที่ฉันสามารถเขียนที่ส่งออกหมายเลข 2016 แต่ก่อนอื่นฉันต้องรอล่ามที่จะเขียนเพื่อให้ฉันสามารถทดสอบรหัสของฉัน
Neil

1
ฉันมีล่ามในหลาม 2.7 ที่นี่
Melon Fricative

2
ภาษานี้เรียกว่าอะไร? มันสมควรได้รับสถานที่ที่esolangs.org
wizzwizz4

@ Neil ฉันพยายามที่จะทำมันใน 72 ตัวอักษร
Fricative Melon

@FricativeMelon 72 หรือไม่ ฉันทำได้ใน 43!
Neil

คำตอบ:


4

ทับทิมขนาด 182 ไบต์

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

ลองแบบนี้:

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

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

มันทำงานอย่างไร

rฟังก์ชั่น tokenizes สตริงการป้อนข้อมูลและดำเนินการในแต่ละโทเค็น:

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

เราค้นหาการ$2จับคู่ชื่อตัวแปร[^!?^<>]*ตามด้วย

  • <...>โดยที่...ตรงกับโปรแกรมศูนย์หรือมากกว่า\gนั้น( เรียกซ้ำ) ซึ่งในกรณี$4นี้จะไม่มีnil
  • !, ?หรือ^ตัวจับโดย$3ซึ่งในกรณีนี้คือ$4nil

จากนั้นตรรกะสำหรับการดำเนินการโทเค็นค่อนข้างง่ายเมื่อเยื้องมันเล็กน้อย:

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

ฉันอยากรู้จริงๆว่ามันทำงานอย่างไร
Jerry Jeremiah

1

JavaScript (ES6) 184 194 209

แก้ไขอย่างง่าย (โดยใช้ฟังก์ชั่นพารามิเตอร์สำหรับอินพุทและเอาท์พุทดูเหมือนจะเป็นความคิดที่ดี แต่มันก็ไม่ได้), 1 ไบต์ที่บันทึกเพิ่มเติมขอบคุณ @ ӍѲꝆΛҐӍΛПҒЦꝆ

แก้ไข 2 การแยกวิเคราะห์ที่แก้ไข ตรรกะสำหรับการเพิ่ม / การป้อนข้อมูลถูกยืมมาจากคำตอบของ @ 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")

น้อย golfed

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

ทดสอบตัวอย่างเริ่มประเมิน 2016 โดยใช้โปรแกรมที่โพสต์โดย @Neil อดทน ...

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>


ใช้evalเพื่อหลีกเลี่ยงreturnตัวเลือกไม่ใช่หรือไม่?
Mama Fun Roll

@ ӍѲꝆΛҐӍΛПҒЦꝆใช่ eval บันทึก 1 ไบต์ ฉันยังคงมองหาบางสิ่งบางอย่างที่สำคัญยิ่งกว่า
edc65

0

Perl, 251 ไบต์

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

ง่ายต่อการอ่านเวอร์ชั่น:

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

นี่เป็นการสิ้นเปลืองเวลาหลายไบต์ในการแก้ไขการวนซ้ำเป็นการกระโดดโดยตรง แต่การสแกนย้อนหลังเพื่อการวนซ้ำเริ่มทำให้ฉันรู้สึกไม่สบายใจ


0

มาตรฐาน C ++, 400 ไบต์

คอมไพล์นี้ด้วย 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]);}

ฉันอาจจะสั้นกว่านี้อีก หากคุณมีข้อเสนอแนะโปรดแสดงความคิดเห็น


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.