Mô phỏng máy đăng ký Minsky (I)


26

Có nhiều hình thức, vì vậy trong khi bạn có thể thấy các nguồn khác hữu ích, tôi hy vọng sẽ chỉ rõ điều này đủ rõ ràng rằng chúng không cần thiết.

Một RM bao gồm một máy trạng thái hữu hạn và một số hữu hạn các thanh ghi có tên, mỗi thanh chứa một số nguyên không âm. Để dễ dàng nhập văn bản, nhiệm vụ này yêu cầu các trạng thái cũng được đặt tên.

Có ba loại trạng thái: tăng và giảm, cả hai đều tham chiếu một thanh ghi cụ thể; và chấm dứt. Một trạng thái tăng làm tăng thanh ghi của nó và chuyển điều khiển cho một người kế vị của nó. Một trạng thái giảm có hai người kế vị: nếu thanh ghi của nó khác không thì nó sẽ giảm giá trị và chuyển quyền điều khiển cho người kế vị đầu tiên; mặt khác (tức là thanh ghi bằng 0) nó chỉ đơn giản chuyển quyền điều khiển cho người kế vị thứ hai.

Đối với "tính độc đáo" là ngôn ngữ lập trình, các trạng thái chấm dứt lấy một chuỗi mã hóa cứng để in (để bạn có thể chỉ ra sự chấm dứt đặc biệt).

Đầu vào là từ stdin. Định dạng đầu vào bao gồm một dòng trên mỗi trạng thái, theo sau là nội dung thanh ghi ban đầu. Dòng đầu tiên là trạng thái ban đầu. BNF cho các dòng trạng thái là:

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

Có một số linh hoạt trong định nghĩa của định danh và thông điệp. Chương trình của bạn phải chấp nhận một chuỗi ký tự chữ và số không trống làm định danh, nhưng nó có thể chấp nhận các chuỗi chung hơn nếu bạn thích (ví dụ: nếu ngôn ngữ của bạn hỗ trợ mã định danh có dấu gạch dưới và bạn dễ dàng làm việc hơn). Tương tự, đối với tin nhắn, bạn phải chấp nhận một chuỗi chữ và số không trống, nhưng bạn có thể chấp nhận các chuỗi phức tạp hơn cho phép thoát các dòng mới và ký tự trích dẫn kép nếu bạn muốn.

Dòng cuối cùng của đầu vào, cung cấp các giá trị thanh ghi ban đầu, là một danh sách định danh được phân tách bằng dấu cách = int gán, phải không trống. Không bắt buộc phải khởi tạo tất cả các thanh ghi có tên trong chương trình: bất kỳ thanh ghi nào không được khởi tạo đều được coi là 0.

Chương trình của bạn nên đọc đầu vào và mô phỏng RM. Khi đạt đến trạng thái kết thúc, nó sẽ phát ra thông báo, dòng mới và sau đó là các giá trị của tất cả các thanh ghi (theo bất kỳ định dạng thuận tiện, dễ đọc của con người, và bất kỳ thứ tự nào).

Lưu ý: chính thức các thanh ghi nên giữ các số nguyên không giới hạn. Tuy nhiên, bạn có thể nếu bạn muốn cho rằng không có giá trị nào của người đăng ký sẽ vượt quá 2 ^ 30.

Một số ví dụ đơn giản

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

Kết quả dự kiến:

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

Kết quả dự kiến:

Ok
a=3 b=7 t=0
Các trường hợp thử nghiệm cho các máy khó phân tích hơn
s0 : t - s0 s1
s1 : t + "t is 1"
t=17

Kết quả dự kiến:

t is 1
t=1

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

Kết quả dự kiến:

t is nonzero
t=0

Một ví dụ phức tạp hơn

Lấy từ thử thách mã vấn đề Josephus của DailyWTF. Đầu vào là n (số lượng binh sĩ) và k (tạm ứng) và đầu ra trong r là vị trí (không có chỉ số) của người sống sót.

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

Kết quả dự kiến:

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

Chương trình đó như một bức tranh, dành cho những người suy nghĩ trực quan và sẽ thấy hữu ích khi nắm bắt cú pháp: Josephus vấn đề RM

Nếu bạn thích môn golf này, hãy xem phần tiếp theo .


Là đầu vào đến từ stdin, từ một tập tin, hoặc từ một nơi khác?
Kevin Brown

@Bass, từ stdin.
Peter Taylor

Bạn nên thêm một số trường hợp kiểm tra với các vấn đề khó xử lý sau: 1) tin nhắn có dấu cách, 2) tin nhắn có dấu bằng, 3) tin nhắn trong inc_line, 4) tin nhắn ở trạng thái đầu tiên của dec_line, 5) tin nhắn trong khoảng trắng trong trường hợp 3 & 4.
MtnViewMark

Ngữ pháp có lỗi: Cần phải có một khoảng trắng giữa hai mục nhập state_name trong dec_line. Cũng không rõ nếu bạn muốn yêu cầu mọi người chấp nhận nhiều khoảng trống giữa các mã thông báo trong đầu vào.
MtnViewMark

2
@Peter: +1 cho một môn đánh gôn mã thực sự với sự cân bằng tốt về đặc điểm kỹ thuật và khả năng cơ động! Hầu hết các câu hỏi ở đây đã quá mỏng.
MtnViewMark

Câu trả lời:


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,%_

Chạy với perl -M5.010 file.

Nó bắt đầu cực kỳ khác biệt, nhưng tôi sợ nó hội tụ với giải pháp Ruby ở nhiều khu vực cho đến cuối cùng. Có vẻ như lợi thế của Ruby là "không có sigils" và "tích hợp regex tốt hơn" của Perl.

Một chút chi tiết từ các bộ phận bên trong, nếu bạn không đọc Perl:

  • @p=<>: đọc toàn bộ mô tả máy để @p
  • /=/,$_{$`}=$' for split$",pop@p: cho mỗi forphép gán ( split$") trong dòng mô tả máy cuối cùng ( @p), xác định vị trí dấu bằng ( /=/) sau đó gán giá trị $'cho %_khóa hask$`
  • $o='\w+': trạng thái ban đầu sẽ là trạng thái đầu tiên khớp với "ký tự từ" của Perl regex
  • until/"/: loop cho đến khi chúng ta đạt đến trạng thái chấm dứt:
    • map{($r,$o,$,,$b)=$'=~/".*?"|\S+/g if/^$o :/}@p: loop trên mô tả máy @p: khi chúng tôi ở trên dòng khớp với trạng thái hiện tại ( if/^$o :/), tokenize ( /".*?"|\S+/g) phần còn lại của dòng $'với các biến ($r,$o,$,,$b). Thủ thuật: cùng một biến $onếu được sử dụng ban đầu cho tên nhãn và sau đó cho toán tử. Ngay khi nhãn khớp, toán tử sẽ ghi đè lên nó và vì nhãn không thể được đặt tên + hoặc - một cách hợp lý, nó sẽ không bao giờ khớp nữa.
    • $_=$o=($_{$r}+=','cmp$o)<0?do{$_{$r}=0;$b}:$,:
      - điều chỉnh thanh ghi mục tiêu $_{$r}lên hoặc xuống (ma thuật ASCII: ','cmp'+'là 1 trong khi ','cmp'-'là -1);
      - nếu kết quả là âm ( <0?, chỉ có thể xảy ra cho -)
      - sau đó giữ ở mức 0 ( $_{$r}=0) và trả lại nhãn thứ hai $b;
      - khác trả lại nhãn đầu tiên (có thể duy nhất)$,
    • BTW, $,thay vì $avậy nó có thể được dán vào mã thông báo tiếp theo untilmà không có khoảng trắng ở giữa.
  • say for eval,%_: báo cáo kết xuất ( eval) và nội dung của các thanh ghi trong%_

Bạn không thực sự cần đại tràng trong /^$o :/. Chỉ riêng dấu mũ là đủ để đảm bảo bạn chỉ nhìn vào nhãn.
Lowjacker

@Lowjacker Tôi không cần nó để xác định tôi đang ở đúng nhãn, nhưng tôi cần phải tránh xa nó $'. Đó là một nhân vật trong regex, nó sẽ là ba nhân $c,từ bên ngoài. Thay phiên một số lớn hơn nhưng thay đổi thành regexizing tokenizing.
JB

10

Python + C, 466 ký tự

Để cho vui, một chương trình python biên dịch chương trình RM thành C, sau đó biên dịch và chạy 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
Điều này sẽ không hoạt động nếu các thanh ghi có tên như ' main', ' if', v.v.
Nabb

1
@Nabb: Buzzkill. Tôi để nó cho người đọc thêm tiền tố gạch dưới vào đúng chỗ.
Keith Randall

6

Haskell, 444 ký tự

(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

Người đàn ông, thật khó! Xử lý đúng các thư có khoảng trắng trong đó có giá trên 70 ký tự. Định dạng đầu ra để "dễ đọc hơn" với con người và phù hợp với các ví dụ có giá 25 khác.


  • Chỉnh sửa: (498 -> 482) nhiều lớp lót nhỏ khác nhau và một số đề xuất của @ FUZxxl
  • Chỉnh sửa: (482 -> 453) chuyển trở lại bằng cách sử dụng số thực cho các thanh ghi; nhiều thủ thuật golf được áp dụng
  • Chỉnh sửa: (453 -> 444) định dạng đầu ra được nội tuyến và phân tích giá trị ban đầu

Tôi không biết Haskell, vì vậy tôi không thể giải mã tất cả cú pháp, nhưng tôi có thể giải mã đủ để thấy rằng bạn đang sử dụng danh sách cho nội dung đăng ký. Tôi phải nói rằng tôi ngạc nhiên rằng nó ngắn hơn so với sử dụng ints.
Peter Taylor

Đặt các ràng buộc cục bộ sau wherevào một dòng duy nhất được phân tách bằng dấu chấm phẩy có thể giúp bạn tiết kiệm 6 ký tự. Và tôi đoán bạn có thể lưu một số ký tự trong định nghĩa qbằng cách thay đổi verbose if-then-other thành một mẫu bảo vệ.
FUZxxl

Và cũng: Chỉ cần giả định một cách mù quáng, rằng giá trị thứ ba nằm "-"trong định nghĩa qvà sử dụng dấu gạch dưới thay thế.
FUZxxl

Tôi đoán, bạn có thể lưu một char khác bằng cách thay đổi dòng 8 thành q[_,_,r,_,s,z]d|maybe t(==0)$lookup r d=n z d|t=n s$r%(-1)$d. Nhưng dù sao, chương trình này được chơi golf cực kỳ tốt.
FUZxxl

Bạn có thể rút ngắn mã phân tích đáng kể bằng cách tận dụng lextừ Prelude. Ví dụ, một cái gì đó giống như f[]=[];f s=lex s>>= \(t,r)->t:f rsẽ phân chia một dòng thành mã thông báo trong khi xử lý các chuỗi được trích dẫn chính xác.
hammar

6

Ruby 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} /}

Tôi hy vọng điều này sẽ thất bại trên các tiền tố nhãn của nhau. Suy nghĩ?
JB

Tôi dường như không thể làm cho nó hoạt động với bất kỳ trường hợp nào khác ngoài các ví dụ. Có chuyện gì với cái này vậy?
JB

Tôi nghĩ bây giờ nó đã được sửa.
Lowjacker

Ah, tốt hơn nhiều. Cảm ơn bạn.
JB

3

Delphi, 646

Delphi không cung cấp rất nhiều liên quan đến việc tách chuỗi và công cụ. May mắn thay, chúng tôi có các bộ sưu tập chung, giúp ích một chút, nhưng đây vẫn là một giải pháp khá lớn:

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.

Ở đây phiên bản thụt lề và nhận xét:

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 ký tự

<?$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]);}

Bị đánh cắp


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

Thay đổi


446 -> 441 : Hỗ trợ các chuỗi cho trạng thái đầu tiên và một số nén nhẹ
441 -> 402 : Được nén nếu / khác và các câu lệnh gán càng nhiều càng tốt
402 -> 398 : Tên hàm có thể được sử dụng làm hằng số có thể được sử dụng làm chuỗi
398 -> 395 : Sử dụng toán tử ngắn mạch
395 -> 389 : Không cần phần khác
389 -> 371 : Không cần sử dụng mảng_key_exists ()
371 -> 370 : Đã xóa không gian không cần thiết
370 -> 366 : Đã xóa hai không gian không cần thiết trong lời nói


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
Tôi đã thử nghiệm điều này nhưng dường như nó không tạo ra bất cứ điều gì cho thiết bị xuất chuẩn . Tôi cần thêm gì để xem kết quả? (PS thông số kỹ thuật nói rằng thứ tự của các thanh ghi trong đầu ra là không liên quan, vì vậy bạn có thể lưu 7 ký tự từ .sort())
Peter Taylor

@Peter cảm ơn vì tiền boa - Tôi sẽ phải thêm 8 ký tự cho println- à tốt!
Armand

1

Clojure (344 ký tự)

Với một vài ngắt dòng cho "khả năng đọc":

(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

Phần tái bút () () (852) (718)

Đối với thực tế lần này. Thực hiện tất cả các trường hợp thử nghiệm. Nó vẫn yêu cầu chương trình RM phải theo dõi ngay lập tức trong luồng chương trình.

Chỉnh sửa: Bao thanh toán nhiều hơn, giảm tên thủ tục.

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

Được thụt lề và nhận xét với chương trình được nối thêm.

%!
%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

Lâu rồi tôi mới viết PostScript, nhưng bạn có định nghĩa các hàm với tên như thế reglinenào không? Bạn có thể tiết kiệm rất nhiều bằng cách gọi cho họ những thứ như thế Rnào?
Peter Taylor

Vâng chắc chắn. Nhưng cũng có một vấn đề tiềm ẩn vì tất cả các định nghĩa này cùng tồn tại với trạng thái và đăng ký tên trong cùng một từ điển. Vì vậy, tôi đã cố gắng tìm các ký tự dấu chấm câu với một số giá trị ghi nhớ (vì vậy tôi vẫn có thể đọc nó :). Tôi cũng hy vọng sẽ tìm thấy nhiều thuật toán giảm hơn, vì vậy tôi không muốn tiêu tốn quá nhiều năng lượng trước khi tôi có thể nhìn vào nó bằng đôi mắt mới.
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]}

Đây là đầu ra cho thử nghiệm đầu tiên:

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

1

Stax , 115 100 byte

╥áípßNtP~£G±☼ΩtHô⌐╒╡~·7╝su9êq7h50Z`╩ë&ñ╝←j╞.½5└∩√I|ù┤╧Åτ╘8┼ç╕╒Æ►^█₧♫÷?²H½$IG☺S╚]«♀_≥å∩A+∩╣Δ└▐♫!}♥swα

Chạy và gỡ lỗi nó

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.