จำลองเครื่องลงทะเบียน Minsky (I)


26

มีพิธีการมากมายดังนั้นในขณะที่คุณอาจพบว่ามีแหล่งข้อมูลอื่นที่เป็นประโยชน์ฉันหวังว่าจะระบุอย่างชัดเจนว่าพวกเขาไม่จำเป็น

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

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

สำหรับ "niceness" เป็นภาษาการเขียนโปรแกรมสถานะยุติการใช้สตริงแบบตายตัวในการพิมพ์ (เพื่อให้คุณสามารถระบุการเลิกจ้างพิเศษ)

อินพุตจาก stdin รูปแบบอินพุตประกอบด้วยหนึ่งบรรทัดต่อรัฐตามด้วยเนื้อหาการลงทะเบียนเริ่มต้น บรรทัดแรกคือสถานะเริ่มต้น BNF สำหรับสายสถานะคือ:

line       ::= inc_line
             | dec_line
inc_line   ::= label ' : ' reg_name ' + ' state_name
dec_line   ::= label ' : ' reg_name ' - ' state_name ' ' state_name
state_name ::= label
             | '"' message '"'
label      ::= identifier
reg_name   ::= identifier

มีความยืดหยุ่นในการกำหนดตัวบ่งชี้และข้อความ โปรแกรมของคุณต้องยอมรับสตริงตัวอักษรผสมตัวเลขที่ไม่ว่างเปล่าเป็นตัวระบุ แต่อาจยอมรับสตริงทั่วไปได้มากขึ้นหากคุณต้องการ (เช่นหากภาษาของคุณรองรับตัวระบุที่มีเครื่องหมายขีดล่างและคุณสามารถทำงานได้ง่ายขึ้น) ในทำนองเดียวกันสำหรับข้อความคุณต้องยอมรับสตริงที่ไม่ใช่ตัวอักษรและช่องว่าง แต่คุณอาจยอมรับสตริงที่ซับซ้อนมากขึ้นซึ่งอนุญาตให้มีการขึ้นบรรทัดใหม่และอักขระเว้นวรรคหากคุณต้องการ

บรรทัดสุดท้ายของอินพุตซึ่งให้ค่าการลงทะเบียนเริ่มต้นคือรายการ identifier = int ที่คั่นด้วยช่องว่างซึ่งจะต้องไม่ว่างเปล่า ไม่จำเป็นต้องกำหนดค่าเริ่มต้นการลงทะเบียนทั้งหมดที่มีชื่อในโปรแกรม: ใด ๆ ที่ไม่ได้เริ่มต้นจะถือว่าเป็น 0

โปรแกรมของคุณควรอ่านอินพุตและจำลอง RM เมื่อถึงสถานะสิ้นสุดมันควรปล่อยข้อความขึ้นบรรทัดใหม่แล้วค่าของการลงทะเบียนทั้งหมด (ในความสะดวกใด ๆ ที่มนุษย์สามารถอ่านได้รูปแบบและคำสั่งใด ๆ )

หมายเหตุ: การลงทะเบียนอย่างเป็นทางการควรมีจำนวนเต็มไม่ จำกัด อย่างไรก็ตามคุณอาจคิดว่าหากไม่มีค่าลงทะเบียนเกิน 2 ^ 30

ตัวอย่างง่ายๆ

a + = b, a = 0
s0 : a - s1 "Ok"
s1 : b + s0
a=3 b=4

ผลลัพธ์ที่คาดหวัง:

Ok
a=0 b=7
b + = a, t = 0
init : t - init d0
d0 : a - d1 a0
d1 : b + d2
d2 : t + d0
a0 : t - a1 "Ok"
a1 : a + a0
a=3 b=4

ผลลัพธ์ที่คาดหวัง:

Ok
a=3 b=7 t=0
กรณีทดสอบสำหรับเครื่องจักรที่ซับซ้อนกว่า
s0 : t - s0 s1
s1 : t + "t is 1"
t=17

ผลลัพธ์ที่คาดหวัง:

t is 1
t=1

และ

s0 : t - "t is nonzero" "t is zero"
t=1

ผลลัพธ์ที่คาดหวัง:

t is nonzero
t=0

ตัวอย่างที่ซับซ้อนมากขึ้น

นำมาจากการท้าทายรหัสปัญหา Josephus ของ DailyWTF อินพุตคือ n (จำนวนทหาร) และ k (ล่วงหน้า) และเอาต์พุตใน r คือตำแหน่ง (zero-indexed) ของบุคคลที่รอดชีวิต

init0 : k - init1 init3
init1 : r + init2
init2 : t + init0
init3 : t - init4 init5
init4 : k + init3
init5 : r - init6 "ERROR k is 0"
init6 : i + init7
init7 : n - loop0 "ERROR n is 0"
loop0 : n - loop1 "Ok"
loop1 : i + loop2
loop2 : k - loop3 loop5
loop3 : r + loop4
loop4 : t + loop2
loop5 : t - loop6 loop7
loop6 : k + loop5
loop7 : i - loop8 loopa
loop8 : r - loop9 loopc
loop9 : t + loop7
loopa : t - loopb loop7
loopb : i + loopa
loopc : t - loopd loopf
loopd : i + loope
loope : r + loopc
loopf : i + loop0
n=40 k=3

ผลลัพธ์ที่คาดหวัง:

Ok
i=40 k=3 n=0 r=27 t=0

โปรแกรมดังกล่าวเป็นรูปภาพสำหรับผู้ที่คิดด้วยสายตาและจะเป็นประโยชน์ในการเข้าใจไวยากรณ์: ฟัสปัญหา RM

หากคุณชอบกีฬากอล์ฟแห่งนี้มีลักษณะที่เป็นผลสืบเนื่อง


อินพุตมาจาก stdin จากไฟล์หรือจากที่อื่นหรือไม่?
Kevin Brown

@Bass จาก stdin
Peter Taylor

คุณควรเพิ่มกรณีทดสอบที่ยากต่อการจัดการกับปัญหา: 1) ข้อความที่มีช่องว่าง 2) ข้อความที่มีเครื่องหมายเท่ากับ 3) ข้อความใน inc_line, 4) ข้อความในสถานะแรกของ dec_line, 5) ข้อความในช่องว่างใน เคส 3 & 4
MtnViewMark

ไวยากรณ์มีข้อผิดพลาด: จำเป็นต้องมีช่องว่างที่แท้จริงระหว่างรายการ state_name สองรายการใน dec_line ยังไม่ชัดเจนหากคุณต้องการให้ผู้คนยอมรับหลายช่องว่างระหว่างโทเค็นในอินพุต
MtnViewMark

2
@Peter: +1 สำหรับการเล่นกอล์ฟเนื้อสัตว์ที่มีสเปคที่ดีและห้องซ้อม คำถามส่วนใหญ่ที่นี่ผอมเกินไป
MtnViewMark

คำตอบ:


10

Perl, 166

@p=<>;/=/,$_{$`}=$' for split$",pop@p;$o='\w+';(map{($r
,$o,$,,$b)=$'=~/".*?"|\S+/g if/^$o :/}@p),$_=$o=($_{$r}
+=','cmp$o)<0?do{$_{$r}=0;$b}:$,until/"/;say for eval,%_

perl -M5.010 fileทำงานด้วย

มันเริ่มแตกต่างกันอย่างดุเดือด แต่ฉันเกรงว่ามันจะรวมเข้ากับโซลูชัน Ruby ในหลาย ๆ ด้านจนจบ ดูเหมือนว่าประโยชน์ของรูบี้คือ "ไม่มี sigils" และ "การรวม regex ที่ดีกว่า" ของ Perl

รายละเอียดเล็กน้อยจากอวัยวะภายในถ้าคุณไม่อ่าน Perl:

  • @p=<>: อ่านรายละเอียดเครื่องทั้งหมดไปที่ @p
  • /=/,$_{$`}=$' for split$",pop@p: สำหรับแต่ละการforมอบหมาย ( split$") ( ) ในบรรทัดรายละเอียดเครื่องสุดท้าย ( @p) ค้นหาเครื่องหมายเท่ากับ ( /=/) จากนั้นกำหนดค่า$'ให้กับ%_คีย์Hask$`
  • $o='\w+': สถานะเริ่มต้นจะเป็นคนแรกที่ตรงกับ Perl regex "คำตัวอักษร"
  • until/"/: วนซ้ำจนกว่าเราจะถึงสถานะสิ้นสุด:
    • map{($r,$o,$,,$b)=$'=~/".*?"|\S+/g if/^$o :/}@p: วงในรายละเอียดเครื่อง@p: เมื่อเราอยู่บนเส้นตรงกับสถานะปัจจุบัน ( if/^$o :/) tokenize ( /".*?"|\S+/g) ส่วนที่เหลือของเส้นตัวแปร$' ($r,$o,$,,$b)Trick: ตัวแปรเดียวกัน$oหากใช้เริ่มต้นสำหรับชื่อฉลากและต่อมาสำหรับผู้ปฏิบัติงาน ทันทีที่ฉลากตรงกันผู้ปฏิบัติงานจะลบล้างและเมื่อป้ายกำกับไม่สามารถตั้งชื่อ + + - (หรือสมเหตุสมผล) จะไม่ตรงกันอีกเลย
    • $_=$o=($_{$r}+=','cmp$o)<0?do{$_{$r}=0;$b}:$,:
      - ปรับการลงทะเบียนเป้าหมาย$_{$r}ขึ้นหรือลง (เวทมนตร์ ASCII: ','cmp'+'1 ในขณะที่','cmp'-'-1);
      - ถ้าผลเป็นลบ ( <0?เท่านั้นที่สามารถเกิดขึ้น -)
      - แล้วอยู่ที่ 0 ( $_{$r}=0) และกลับฉลากสอง$b;
      - มิฉะนั้นให้ส่งคืนป้ายกำกับ (อาจเป็น แต่เพียงผู้เดียว) ก่อน$,
    • BTW มัน$,แทนที่จะเป็น$aดังนั้นจึงสามารถติดกับโทเค็นถัดไปuntilโดยไม่มีช่องว่างระหว่าง
  • say for eval,%_: รายงานการถ่ายโอนข้อมูล ( eval) และเนื้อหาของการลงทะเบียนใน%_

/^$o :/คุณไม่ได้จริงๆต้องลำไส้ใหญ่ใน เครื่องหมายรูปหมวกเพียงอย่างเดียวก็เพียงพอที่จะทำให้แน่ใจว่าคุณกำลังดูป้ายเท่านั้น
Lowjacker

@Lowjacker ฉันไม่จำเป็นต้องใช้ในการกำหนดฉันบนฉลากที่ถูกต้อง $'แต่ฉันต้องการมันจะถูกเก็บไว้ออกมาจาก มันเป็นตัวละครตัวหนึ่งใน regex มันจะมีสามตัวที่$c,ต้องคำนึงถึงจากภายนอก อีกวิธีหนึ่งที่ใหญ่กว่า แต่เปลี่ยนเป็น tokenizing regex
JB

10

Python + C, 466 ตัวอักษร

เพื่อความสนุกโปรแกรมหลามที่คอมไพล์โปรแกรม RM ไปที่ C จากนั้นก็คอมไพล์ & รันซี

import sys,os,shlex
G=shlex.shlex(sys.stdin).get_token
A=B=''
C='_:'
V={}
J=lambda x:'goto '+x+';'if'"'!=x[0]else'{puts('+x+');goto _;}'
while 1:
 L,c=G(),G()
 if''==c:break
 if':'==c:
  v,d=G(),G()
  V[v]=1;B+=L+c+v+d+d+';'
  if'+'==d:B+=J(G())
  else:B+='if('+v+'>=0)'+J(G())+'else{'+v+'=0;'+J(G())+'}'
 else:A+=L+c+G()+';'
for v in V:C+='printf("'+v+'=%d\\n",'+v+');'
open('C.c','w').write('int '+','.join(V)+';main(){'+A+B+C+'}')
os.system('gcc -w C.c;./a.out')

3
วิธีนี้จะใช้ไม่ได้หากผู้ลงทะเบียนมีชื่อเช่น ' main', ' if' ฯลฯ
Nabb

1
@Nabb: Buzzkill ฉันปล่อยให้ผู้อ่านเพิ่มคำนำหน้าขีดล่างในตำแหน่งที่ถูกต้อง
Keith Randall

6

Haskell, 444 ตัวอักษร

(w%f)(u@(s,v):z)|s==w=(s,f+v):z|t=u:(w%f)z
(w%f)[]=[(w,f)]
p#(a:z)|j==a=w p++[j]&z|t=(p++[a])#z;p#[]=w p
p&(a:z)|j==a=p:""#z|t=(p++[a])&z
c x=q(m!!0)$map((\(s,_:n)->(s,read n)).break(=='=')).w$last x where
 m=map(""#)$init x
 q[_,_,r,"+",s]d=n s$r%1$d
 q[_,_,r,_,s,z]d|maybe t(==0)(lookup r d)=n z d|t=n s$r%(-1)$d
 n('"':s)d=unlines[s,d>>=(\(r,v)->r++'=':shows v" ")]
 n s d=q(filter((==s).head)m!!0)d
main=interact$c.lines
t=1<3;j='"';w=words

ชายนั่นมันยาก! การจัดการข้อความอย่างเหมาะสมโดยมีช่องว่างในนั้นมีราคาสูงกว่า 70 อักขระ การจัดรูปแบบเอาต์พุตให้เป็น "มนุษย์ที่อ่านได้" มากกว่าและตรงกับตัวอย่างที่เสียค่าใช้จ่ายอีก 25


  • แก้ไข: (498 -> 482) อินไลน์เล็ก ๆ และคำแนะนำของ @ FUZxxl บางส่วน
  • แก้ไข: (482 -> 453) สลับกลับโดยใช้ตัวเลขจริงสำหรับการลงทะเบียน ใช้เทคนิคการเล่นกอล์ฟมากมาย
  • แก้ไข: (453 -> 444) การจัดรูปแบบเอาต์พุตแบบอินไลน์และการแยกวิเคราะห์ค่าเริ่มต้น

ฉันไม่รู้จัก Haskell ดังนั้นฉันไม่สามารถถอดรหัสไวยากรณ์ทั้งหมด แต่ฉันสามารถถอดรหัสได้เพียงพอที่จะเห็นว่าคุณกำลังใช้รายการสำหรับเนื้อหาการลงทะเบียน ฉันต้องบอกว่าฉันประหลาดใจที่สั้นกว่าการใช้ ints
Peter Taylor

การใส่การเชื่อมโยงโลคัลwhereลงในบรรทัดเดียวที่คั่นด้วยเซมิโคลอนสามารถช่วยคุณได้ 6 ตัวอักษร และฉันคิดว่าคุณสามารถบันทึกตัวอักษรบางตัวในคำจำกัดความของqการเปลี่ยน verbose if-then-else เป็น pattern ยาม
FUZxxl

และยัง: เพียงแค่สมมติว่าสุ่มค่าที่สามอยู่"-"ในความหมายของqและใช้ขีดเส้นใต้แทน
FUZxxl

ผมคิดว่าคุณจะสามารถประหยัดถ่านอีกโดยการเปลี่ยนสาย q[_,_,r,_,s,z]d|maybe t(==0)$lookup r d=n z d|t=n s$r%(-1)$d8 แต่อย่างไรก็ตามโปรแกรมนี้เล่นกอล์ฟได้ดีมาก
FUZxxl

คุณสามารถร่นรหัสการวิเคราะห์คำให้สั้นลงได้มากโดยใช้ประโยชน์lexจาก Prelude ตัวอย่างเช่นสิ่งที่ต้องการf[]=[];f s=lex s>>= \(t,r)->t:f rจะแบ่งบรรทัดเป็นโทเค็นในขณะที่จัดการสตริงที่ยกมาอย่างถูกต้อง
hammar

6

ทับทิม 1.9, 214 212 211 198 195 192 181 175 173 175

*s,k=*$<
a,=s
b=Hash.new 0
eval k.gsub /(\w+)=/,';b["\1"]='
loop{x,y,r,o,t,f=a.scan /".*?"|\S+/
l=(b[r]-=o<=>?,)<0?(b[r]=0;f):t
l[?"]&&puts(eval(l),b)&exit
a,=s.grep /^#{l} /}

ฉันคาดว่าสิ่งนี้จะล้มเหลวในส่วนนำหน้าของป้ายกำกับซึ่งกันและกัน คิด?
JB

ฉันดูเหมือนจะไม่สามารถใช้กับกรณีอื่นนอกเหนือจากตัวอย่างได้ เกิดอะไรขึ้นกับสิ่งนี้?
JB

ฉันคิดว่ามันคงที่แล้ว
Lowjacker

ดีกว่ามาก ขอขอบคุณ.
JB

3

Delphi, 646

Delphi ไม่ได้ให้อะไรมากกับการแยกสตริงและสิ่งของ โชคดีที่เรามีคอลเล็กชั่นทั่วไปซึ่งช่วยได้เล็กน้อย แต่นี่ยังคงเป็นวิธีการแก้ปัญหาที่ค่อนข้างใหญ่:

uses SysUtils,Generics.Collections;type P=array[0..99]of string;Y=TDictionary<string,P>;Z=TDictionary<string,Int32>;var t:Y;l,i:string;j,k:Int32;q:P;u:Z;v:TPair<string,Int32>;begin t:=Y.Create;repeat if i=''then i:=q[0];t.Add(q[0],q);ReadLn(l);for j:=0to 6do begin k:=Pos(' ',l+' ');q[j]:=Copy(l,1,k-1);Delete(l,1,k)end;until q[1]<>':';u:=Z.Create;j:=0;repeat k:=Pos('=',q[j]);u.Add(Copy(q[j],1,k-1),StrToInt(Copy(q[j],k+1,99)));Inc(j)until q[j]='';repeat q:=t[i];i:=q[4];u.TryGetValue(q[2],j);if q[3]='+'then Inc(j)else if j=0then i:=q[5]else Dec(j);u.AddOrSetValue(q[2],j)until i[1]='"';WriteLn(i);for v in u do Write(v.Key,'=',v.Value,' ')end.

นี่คือรุ่นที่เยื้องและแสดงความคิดเห็น:

uses SysUtils,Generics.Collections;
type
  // P is a declaration line, offsets:
  // 0 = label
  // 1 = ':'
  // 2 = register
  // 3 = operation ('-' or '+')
  // 4 = 1st state (or message)
  // 5 = 2nd state (or message)
  P=array[0..99]of string;
  // T is a dictionary of all state lines :
  Y=TDictionary<string,P>;
  // Z is a dictionary of all registers :
  Z=TDictionary<string,Int32>;
var
  t:Y;
  l,
  i:string;
  j,
  k:Int32;
  q:P;
  u:Z;
  v:TPair<string,Int32>;
begin
  // Read all input lines :
  t:=Y.Create;
  repeat
    // Put all lines into a record
    if i=''then i:=q[0];
    t.Add(q[0],q);
    // Split up each input line on spaces :
    ReadLn(l);
    for j:=0to 6do
    begin
      k:=Pos(' ',l+' ');
      q[j]:=Copy(l,1,k-1);
      Delete(l,1,k)
    end;
    // Stop when there are no more state transitions :
  until q[1]<>':';
  // Scan initial registers :
  u:=Z.Create;
  j:=0;
  repeat
    k:=Pos('=',q[j]);
    // Add each name=value pair to a dictionary :
    u.Add(Copy(q[j],1,k-1),StrToInt(Copy(q[j],k+1,99)));
    Inc(j)
  until q[j]='';
  // Execute the state machine :
  repeat
    q:=t[i];
    i:=q[4];
    u.TryGetValue(q[2],j);
    if q[3]='+'then
      Inc(j)
    else
      if j=0then
        i:=q[5]
      else
        Dec(j);
    u.AddOrSetValue(q[2],j)
  until i[1]='"';
  WriteLn(i);
  for v in u do
    Write(v.Key,'=',v.Value,' ')
end.

1

PHP, 446 441 402 398 395 389 371 370 366 ตัวอักษร

<?$t=trim;$e=explode;while($l=$t(fgets(STDIN))){if(strpos($l,"=")){foreach($e(" ",$l)as$b){list($k,$c)=$e("=",$b);$v[$k]=$c;}break;}list($k,$d)=$e(":",$l);$r[$z=$t($k)]=$t($d);$c=$c?:$z;}while($d=$e(" ",$r[$c],4)){$c=$v[$a=$d[0]]||!$d[3]?$d[2]:$d[3];if(!$r[$c]){eval("echo $c.'\n';");foreach($v as$k=>$c)echo$k."=".$c." ";die;}if(!$d[3]&&++$v[$a]||$v[$a]&&--$v[$a]);}

Ungolfed


<?php

$register = array();
$values = array();

while($line = trim(fgets(STDIN))){

    if(strpos($line, "=")){

        // Set each value and then continue to the calculations

        foreach(explode(" ", $line) as $var){
            list($key, $val) = explode("=", $var);

            $values[$key] = $val;
        }

        break;
    }

    list($key, $data) = explode(":", $line);

    // Add data to the register

    $register[$z = trim($key)] = trim($data);

    // Set the first register

    $current = $current?:$z;
}

while($data = explode(" ", $register[$current], 4)){

    // Determine next register and current register

    $current = $values[$target = $data[0]] || !$data[3]? $data[2] : $data[3];

    // Will return true if the register does not exist (Messages wont have a register)

    if(!$register[$current]){

        // No need to strip the quotes this way

        eval("echo$current.'\n';");

        // Print all values in the right formatting

        foreach($values as $key => $val)
            echo $key."=".$val." ";

        die();
    }

    // Only subtraction has a third index
    // Only positive values return true

    // If there is no third index, then increase the value
    // If there is a third index, increment the decrease the value if it is positive

    // Uses PHP's short-circuit operators

    if(!$data[3] && ++$values[$target] || $values[$target] && --$values[$target]);
}

การเปลี่ยนแปลง


446 -> 441 : รองรับสตริงสำหรับสถานะแรกและการบีบอัดเล็กน้อย
441 -> 402 : บีบอัด if / else และคำสั่งการกำหนดให้มากที่สุด
402 -> 398 : ชื่อฟังก์ชันสามารถใช้เป็นค่าคงที่ซึ่งสามารถใช้เป็นสตริงได้
398 -> 395 : ใช้ตัวดำเนินการลัดวงจร
395 -> 389 : ไม่ต้องการส่วนอื่น
389 -> 371 : ไม่จำเป็นต้องใช้ array_key_exists ()
371 -> 370 : ลบพื้นที่ที่ไม่จำเป็นออก
370 -> 366 : ลบช่องว่างที่ไม่ต้องการสองรายการใน foreach


1

Groovy, 338

m={s=r=[:];z=[:]
it.eachLine{e->((e==~/\w+=.*/)?{(e=~/((\w+)=(\d+))+/).each{r[it[2]]=it[3] as int}}:{f=(e=~/(\w+) : (.*)/)[0];s=s?:f[1];z[f[1]]=f[2];})()}
while(s[0]!='"'){p=(z[s]=~/(\w+) (.) (\w+|(?:".*?")) ?(.*)?/)[0];s=p[3];a=r[p[1]]?:0;r[p[1]]=p[2]=='-'?a?a-1:{s=p[4];0}():a+1}
println s[1..-2]+"\n"+r.collect{k,v->"$k=$v"}.join(' ')}


['''s0 : a - s1 "Ok"
s1 : b + s0
a=3 b=4''':'''Ok
a=0 b=7''',
'''init : t - init d0
d0 : a - d1 a0
d1 : b + d2
d2 : t + d0
a0 : t - a1 "Ok"
a1 : a + a0
a=3 b=4''':'''Ok
a=3 b=7 t=0''',
'''s0 : t - s0 s1
s1 : t + "t is 1"
t=17''':'''t is 1
t=1''',
'''s0 : t - "t is nonzero" "t is zero"
t=1''':'''t is nonzero
t=0''',
'''init0 : k - init1 init3
init1 : r + init2
init2 : t + init0
init3 : t - init4 init5
init4 : k + init3
init5 : r - init6 "ERROR k is 0"
init6 : i + init7
init7 : n - loop0 "ERROR n is 0"
loop0 : n - loop1 "Ok"
loop1 : i + loop2
loop2 : k - loop3 loop5
loop3 : r + loop4
loop4 : t + loop2
loop5 : t - loop6 loop7
loop6 : k + loop5
loop7 : i - loop8 loopa
loop8 : r - loop9 loopc
loop9 : t + loop7
loopa : t - loopb loop7
loopb : i + loopa
loopc : t - loopd loopf
loopd : i + loope
loope : r + loopc
loopf : i + loop0
n=40 k=3''':'''Ok
i=40 k=3 n=0 r=27 t=0'''].collect {input,expectedOutput->
    def actualOutput = m(input)
    actualOutput == expectedOutput
}

1
ผมทดสอบนี้ แต่ก็ดูเหมือนจะไม่เป็นสิ่งที่ส่งออกไปยัง stdout ฉันต้องเพิ่มอะไรเพื่อดูผลลัพธ์ (PS สเปคบอกว่าลำดับของรีจิสเตอร์ในเอาต์พุตนั้นไม่เกี่ยวข้องดังนั้นคุณจึงสามารถบันทึกได้ถึง 7 ตัวอักษร.sort())
Peter Taylor

@ ปีเตอร์ขอบคุณสำหรับเคล็ดลับ - ฉันจะต้องเพิ่ม 8 ตัวอักษรสำหรับprintln- อ่า!
อาร์มันด์

1

Clojure (344 ตัวอักษร)

ด้วย linebreaks เล็กน้อยสำหรับ "การอ่าน":

(let[i(apply str(butlast(slurp *in*)))]
(loop[s(read-string i)p(->> i(replace(zipmap":\n=""[] "))(apply str)(format"{%s}")read-string)]
(let[c(p s)](cond(string? s)(println s"\n"(filter #(number?(% 1))p))
(=(c 1)'-)(let[z(=(get p(c 0)0)0)](recur(c(if z 3 2))(if z p(update-in p[(c 0)]dec))))
1(recur(c 2)(update-in p[(c 0)]#(if %(inc %)1)))))))

1

Postscript () () (852) (718)

สำหรับ reals ในครั้งนี้ ดำเนินการกรณีทดสอบทั้งหมด มันยังต้องการโปรแกรม RM เพื่อติดตามในสตรีมโปรแกรมทันที

แก้ไข:แฟคตอริ่งเพิ่มเติมลดชื่อกระบวนงาน

errordict/undefined{& " * 34 eq{.()= !{& " .(=). load " .( ).}forall ^()=
stop}{^ ^ " 0 @ : 0}ifelse}put<</^{pop}/&{dup}/:{def}/#{exch}/*{& 0
get}/.{print}/~{1 index}/"{=string cvs}/`{cvn # ^ #}/+={~ load add :}/++{1
~ length 1 sub getinterval}/S{/I where{^}{/I ~ cvx :}ifelse}/D{/? # :/_ #
cvlit :}/+{D S({//_ 1 +=//?})$ ^ :}/-{/| # : D S({//_ load 0 ne{//_ -1
+=//?}{//|}ifelse})$ ^ :}/![]/@{~/! #[# cvn ! aload length & 1 add #
roll]:}/;{(=)search ^ # ^ # cvi @ :}/${* 32 eq{++}if * 34 eq{& ++(")search
^ length 2 add 4 3 roll # 0 # getinterval cvx `}{token ^
#}ifelse}>>begin{currentfile =string readline ^( : )search{`( + )search{`
$ ^ +}{( - )search ^ ` $ $ ^ -}ifelse}{( ){search{;}{; I}ifelse}loop}ifelse}loop

เยื้องและแสดงความคิดเห็นด้วยโปรแกรมต่อท้าย

%!
%Minsky Register Machine Simulation
errordict/undefined{ %replace the handler for the /undefined error
    & " * 34 eq{ % if, after conversion to string, it begins with '"',
        .()= !{ % print it, print newline, iterate through the register list
            & " .(=). load " .( ). % print regname=value
        }forall ^()= stop % print newline, END PROGRAM
    }{ % if it doesn't begin with '"', it's an uninitialized register
        ^ ^ " 0 @ : 0 %initialize register to zero, return zero
    }ifelse
}put
<<
/^{pop}
/&{dup}
/:{def} % cf FORTH
/#{exch}
/*{& 0 get} % cf C
/.{print} % cf BF

% these fragments were repeated several times
/~{1 index}
/"{=string cvs} % convert to string
/`{cvn # ^ #} % convert to name, exch, pop, exch
/+={~ load add :} % add a value to a variable
/++{1 ~ length 1 sub getinterval} % increment a "string pointer"

/S{/I where{^}{/I ~ cvx :}ifelse} %setINIT define initial state unless already done
/D{/? # :/_ # cvlit :} %sr define state and register for generated procedure
/+{D S({//_ 1 +=//?})$ ^ :} % generate an increment state and define
/-{/| # : D S({//_ load 0 ne{//_ -1 +=//?}{//|}ifelse})$ ^ :} % decrement state
/![] %REGS list of registers
/@{~/! #[# cvn ! aload length & 1 add # roll]:} %addreg append to REGS
/;{(=)search ^ # ^ # cvi @ :} %regline process a register assignment
/${ %tpe extract the next token or "string"
    * 32 eq{++}if %skip ahead if space
    * 34 eq{ %if quote, find the end-quote and snag both
        & ++(")search ^ length 2 add 4 3 roll # 0 # getinterval cvx `
    }{
        token ^ # %not a quote: pull a token, exch, pop
    }ifelse
}
>>begin

{
    currentfile =string readline ^
    ( : )search{ % if it's a state line
        `( + )search{ % if it's an increment
            ` $ ^ + %parse it
        }{
            ( - )search ^ ` $ $ ^ - %it's a decrement. Parse it
        }ifelse
    }{ % not a state, do register assignments, and call initial state
        ( ){search{;}{; I}ifelse}loop %Look Ma, no `exit`!
    }ifelse
}loop
init0 : k - init1 init3
init1 : r + init2
init2 : t + init0
init3 : t - init4 init5
init4 : k + init3
init5 : r - init6 "ERROR k is 0"
init6 : i + init7
init7 : n - loop0 "ERROR n is 0"
loop0 : n - loop1 "Ok"
loop1 : i + loop2
loop2 : k - loop3 loop5
loop3 : r + loop4
loop4 : t + loop2
loop5 : t - loop6 loop7
loop6 : k + loop5
loop7 : i - loop8 loopa
loop8 : r - loop9 loopc
loop9 : t + loop7
loopa : t - loopb loop7
loopb : i + loopa
loopc : t - loopd loopf
loopd : i + loope
loope : r + loopc
loopf : i + loop0
n=40 k=3

เป็นเวลานานแล้วที่ฉันเขียน PostScript แต่คุณกำหนดฟังก์ชั่นด้วยชื่ออย่างนั้นreglineหรือ คุณไม่สามารถประหยัดจำนวนมากได้ด้วยการโทรหาพวกเขาอย่างนั้นRใช่ไหม
Peter Taylor

ใช่อย่างแน่นอน. แต่ก็ยังมีปัญหาที่อาจเกิดขึ้นเนื่องจากคำจำกัดความเหล่านี้อยู่ร่วมกับรัฐและลงทะเบียนชื่อในพจนานุกรมเดียวกัน ดังนั้นผมจึงได้รับการพยายามที่จะหาตัวอักษรวรรคตอนที่มีบางส่วนมูลค่าความจำ (ดังนั้นฉันยังคงสามารถอ่านได้ :) ฉันหวังว่าจะได้พบกับการลดอัลกอริธึมเพิ่มเติมดังนั้นฉันจึงไม่ต้องการใช้พลังงานมากเกินไปก่อนที่จะมองด้วยตาที่สดใส
luser droog

1

AWK - 447

BEGIN{FS=":"}NF<2{split($1,x," ");for(y in x){split(x[y],q,"=");
g[q[1]]=int(q[2])}}NF>1{w=$1;l=$2;gsub(/ /,"",w);if(!a)a=w;for(i=0;;)
{sub(/^ +/,"",l);if(l=="")break;if(substr(l,1,1)=="\""){l=substr(l,2);
z=index(l,"\"")}else{z=index(l," ");z||z=length(l)+1}d[w,i++]=
substr(l,1,z-1);l=substr(l,z+1)}}END{for(;;){if(!((a,0)in d))break;h=d[a,0];
if(d[a,1]~/+/){g[h]++;a=d[a,2]}else{a=g[h]?d[a,2]:d[a,3];g[h]&&g[h]--}}
print a;for(r in g)print r"="g[r]}

นี่คือผลลัพธ์สำหรับการทดสอบครั้งแรก:

% cat | awk -f mrm1.awk
s0 : a - s1 "Ok"
s1 : b + s0
a=3 b=4
^D
Ok
a=0
b=7

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