Minsky-Registermaschine simulieren (I)


26

Es gibt viele Formalismen, so dass Sie vielleicht andere nützliche Quellen finden. Ich hoffe, dass ich dies klar genug formulieren kann, damit sie nicht notwendig sind.

Ein RM besteht aus einer endlichen Zustandsmaschine und einer endlichen Anzahl benannter Register, von denen jedes eine nicht negative ganze Zahl enthält. Um die Texteingabe zu vereinfachen, müssen für diese Aufgabe auch die Status benannt werden.

Es gibt drei Arten von Zuständen: Inkrementieren und Dekrementieren, die beide auf ein bestimmtes Register verweisen. und kündigen. Ein Inkrementierungszustand inkrementiert sein Register und übergibt die Steuerung an seinen einen Nachfolger. Ein Dekrementierungszustand hat zwei Nachfolger: Wenn sein Register nicht Null ist, dekrementiert es es und übergibt die Steuerung an den ersten Nachfolger; Andernfalls (dh das Register ist Null) übergibt es die Steuerung einfach an den zweiten Nachfolger.

Für "Nizza" als Programmiersprache benötigen die Endzustände eine fest codierte Zeichenfolge, um gedruckt zu werden (sodass Sie auf eine außergewöhnliche Beendigung hinweisen können).

Die Eingabe erfolgt von stdin. Das Eingabeformat besteht aus einer Zeile pro Status, gefolgt vom Anfangsregisterinhalt. Die erste Zeile ist der Ausgangszustand. BNF für die Landesgrenzen ist:

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

Die Definition von Bezeichner und Nachricht ist flexibel. Ihr Programm muss eine nicht leere alphanumerische Zeichenfolge als Bezeichner akzeptieren , es kann jedoch auch allgemeinere Zeichenfolgen akzeptieren, wenn Sie dies bevorzugen (z. B. wenn Ihre Sprache Bezeichner mit Unterstrichen unterstützt und dies für Sie einfacher ist). In ähnlicher Weise für die Nachrichten Sie müssen eine nicht leere Zeichenfolge von alphanumerischen Zeichen und Leerzeichen akzeptieren, aber Sie können komplexere Strings akzeptieren , die maskierten Newlines und doppelte Anführungszeichen zulassen , wenn Sie wollen.

Die letzte Eingabezeile, die die Anfangsregisterwerte enthält, ist eine durch Leerzeichen getrennte Liste von Zuweisungen von bezeichner = int, die nicht leer sein dürfen. Es ist nicht erforderlich, dass alle im Programm genannten Register initialisiert werden: Alle nicht initialisierten Register werden als 0 angenommen.

Ihr Programm sollte die Eingabe lesen und den RM simulieren. Wenn es einen Beendigungszustand erreicht, sollte es die Nachricht, eine neue Zeile und dann die Werte aller Register (in jeder geeigneten, für den Menschen lesbaren, formatierten und beliebigen Reihenfolge) ausgeben.

Hinweis: Formal sollten die Register unbegrenzte ganze Zahlen enthalten. Sie können jedoch davon ausgehen, dass der Wert eines Registers niemals 2 ^ 30 überschreitet.

Einige einfache Beispiele

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

Erwartete Ergebnisse:

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

Erwartete Ergebnisse:

Ok
a=3 b=7 t=0
Testfälle für schwieriger zu analysierende Maschinen
s0 : t - s0 s1
s1 : t + "t is 1"
t=17

Erwartete Ergebnisse:

t is 1
t=1

und

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

Erwartete Ergebnisse:

t is nonzero
t=0

Ein komplizierteres Beispiel

Entnommen aus der Josephus-Problemcode-Herausforderung des DailyWTF. Die Eingabe ist n (Anzahl der Soldaten) und k (Vorrücken) und die Ausgabe in r ist die (durch Nullen indizierte) Position der Person, die überlebt.

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

Erwartete Ergebnisse:

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

Das Programm als Bild für diejenigen, die visuell denken und es hilfreich finden, die Syntax zu verstehen: Josephus Problem RM

Wenn Sie dieses Golfspiel mögen, schauen Sie sich die Fortsetzung an .


Kommt die Eingabe von stdin, aus einer Datei oder von einem anderen Ort?
Kevin Brown

@Bass, von stdin.
Peter Taylor

Sie sollten einige Testfälle mit den folgenden Problemen hinzufügen: 1) Nachrichten mit Leerzeichen, 2) Nachrichten mit Gleichheitszeichen, 3) Nachrichten in inc_line, 4) Nachrichten im ersten Zustand einer dec_line, 5) Nachrichten in Leerzeichen in Fälle 3 & 4.
MtnViewMark

Die Grammatik hat einen Fehler: Zwischen den beiden Einträgen state_name in dec_line muss ein Literal stehen. Es ist auch unklar, ob Sie möchten, dass Personen mehrere Leerzeichen zwischen Token in der Eingabe akzeptieren.
MtnViewMark

2
@Peter: +1 für ein wirklich fleischiges Code-Golfspiel mit einem ausgewogenen Verhältnis von Spezifikation und Handlungsspielraum! Die meisten Fragen hier waren viel zu dünn.
MtnViewMark

Antworten:


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

Laufen Sie mit perl -M5.010 file.

Es begann völlig anders, aber ich fürchte, es hat sich gegen Ende in vielen Bereichen der Ruby-Lösung angenähert. Rubys Vorteil scheint "keine Siegel" und Perls "bessere Integration von Regex" zu sein.

Ein bisschen Detail aus den Innereien, wenn Sie Perl nicht lesen:

  • @p=<>: Lesen Sie die gesamte Maschinenbeschreibung zu @p
  • /=/,$_{$`}=$' for split$",pop@p: Suchen Sie für jede ( for) Zuweisung ( split$") in der letzten Maschinenbeschreibungszeile ( @p) das Gleichheitszeichen ( /=/) und weisen Sie dann $'dem Hash- %_Schlüssel einen Wert zu$`
  • $o='\w+': Anfangszustand wäre der erste, der mit Perl-Regex "Wortzeichen" übereinstimmt
  • until/"/: Schleife, bis wir einen Beendigungsstatus erreichen:
    • map{($r,$o,$,,$b)=$'=~/".*?"|\S+/g if/^$o :/}@p: loop on machine description @p: Wenn wir in der Zeile sind, die dem aktuellen Status ( if/^$o :/) entspricht, tokenize ( /".*?"|\S+/g) den Rest der Zeile $'für Variablen ($r,$o,$,,$b). Trick: Dieselbe Variable, $owenn sie ursprünglich für den Markennamen und anschließend für den Operator verwendet wird. Sobald das Label übereinstimmt, überschreibt der Operator es und da ein Label (vernünftigerweise) nicht mit + oder - benannt werden kann, stimmt es nie wieder überein.
    • $_=$o=($_{$r}+=','cmp$o)<0?do{$_{$r}=0;$b}:$,:
      - Passen Sie das Zielregister nach $_{$r}oben oder unten an (ASCII-Magie: ','cmp'+'ist 1, während ','cmp'-'-1 ist);
      - wenn das Ergebnis negativ ist ( <0?kann nur passieren für -)
      - dann bleib bei 0 ( $_{$r}=0) und gib das zweite Etikett zurück $b;
      - Anderenfalls senden Sie das erste (möglicherweise einzige) Etikett zurück$,
    • Übrigens, es ist $,stattdessen $aso, dass es untilohne Leerzeichen dazwischen auf das nächste Token geklebt werden kann .
  • say for eval,%_: dump report ( eval) und Inhalt der Register in%_

Du brauchst den Doppelpunkt nicht wirklich /^$o :/. Das Caret allein reicht aus, um sicherzustellen, dass Sie nur Etiketten betrachten.
Lowjacker

@Lowjacker Ich brauche es nicht, um festzustellen, ob ich auf dem richtigen Etikett stehe, aber ich brauche es, um mich davor zu schützen $'. Es ist ein Charakter in der Regex, es wären drei $c,, die von außen zu berücksichtigen sind. Alternativ wechseln einige größere noch zum Tokenizing Regex.
JB

10

Python + C, 466 Zeichen

Nur zum Spaß, ein Python-Programm, das das RM-Programm nach C kompiliert und dann das C kompiliert und ausführt.

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
Dies funktioniert nicht, wenn Register Namen wie ' main', ' if' usw. haben.
Nabb

1
@Nabb: Buzzkill. Ich überlasse es dem Leser, an den richtigen Stellen Unterstrich-Präfixe hinzuzufügen.
Keith Randall

6

Haskell, 444 Zeichen

(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

Mann, das war schwer! Die ordnungsgemäße Bearbeitung von Nachrichten mit Leerzeichen kostet mehr als 70 Zeichen. Die Ausgabeformatierung, die für den Menschen besser lesbar ist und mit den Beispielen übereinstimmt, kostet weitere 25 Euro.


  • Edit: (498 -> 482) verschiedene kleine Inlinings und einige von @ FUZxxls Vorschlägen
  • Bearbeiten: (482 -> 453) Zurückschalten unter Verwendung der tatsächlichen Nummern für die Register; viele golf tricks angewendet
  • Bearbeiten: (453 -> 444) Inline-Ausgabeformatierung und Analyse der Anfangswerte

Ich kenne Haskell nicht, daher kann ich nicht die gesamte Syntax entschlüsseln, aber ich kann genug entschlüsseln, um festzustellen, dass Sie Listen für den Registerinhalt verwenden. Ich muss sagen, ich bin überrascht, dass das kürzer ist als die Verwendung von Ints.
Peter Taylor

Wenn Sie die lokalen Bindungen wherenacheinander in eine einzelne Zeile setzen, die durch Semikolons getrennt ist, können Sie 6 Zeichen sparen. Und ich vermute, Sie könnten ein paar Zeichen in der Definition von sparen, qindem Sie das ausführliche Wenn-Dann-Sonst in einen Pattern Guard ändern.
FUZxxl

Und außerdem: Nehmen Sie einfach blind an, dass der dritte Wert "-"in der Definition qeines Unterstrichs enthalten ist und verwenden Sie stattdessen einen Unterstrich.
FUZxxl

Ich denke, Sie könnten ein anderes Zeichen retten, indem Sie Zeile 8 auf ändern q[_,_,r,_,s,z]d|maybe t(==0)$lookup r d=n z d|t=n s$r%(-1)$d. Aber trotzdem ist dieses Programm extrem gut golfen.
FUZxxl

Sie können den Parsing-Code erheblich verkürzen, indem Sie lexdas Prelude nutzen. Zum Beispiel wird so etwas wie f[]=[];f s=lex s>>= \(t,r)->t:f reine Zeile in Token aufgeteilt, während die in Anführungszeichen gesetzten Zeichenfolgen korrekt behandelt werden.
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} /}

Ich würde erwarten, dass dies auf den Präfixen der Labels fehlschlägt. Gedanken?
JB

Ich kann es anscheinend mit keinem anderen Fall als den Beispielen klappen lassen. Was ist daran falsch ?
JB

Ich denke, es ist jetzt behoben.
Lowjacker

Ah, viel besser. Vielen Dank.
JB

3

Delphi, 646

Delphi bietet nicht viel in Bezug auf das Aufteilen von Strings und Sachen. Glücklicherweise haben wir generische Sammlungen, was ein bisschen hilft, aber dies ist immer noch eine ziemlich umfangreiche Lösung:

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.

Hier die eingerückte und kommentierte Version:

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 Zeichen

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

Änderungsprotokoll


446 -> 441 : Unterstützt Saiten für den ersten Zustand, und einige leichte Kompression
441 -> 402 : Compressed if / else und Zuweisungsanweisungen so viel wie möglich
402 -> 398 : Funktionsnamen können als Konstanten verwendet werden , die als Zeichenketten verwendet werden können ,
398 -> 395 : Verwendet Kurzschluss Operatoren
395 -> 389 : Keine Notwendigkeit für den anderen Teil
389 -> 371 : Keine Notwendigkeit zur Verwendung array_key_exists ()
371 -> 370 : entfernt nicht benötigter Raum
370 -> 366 : entfernt zwei nicht benötigte Räume in der 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
Ich habe das getestet, aber es scheint nichts zu stdout auszugeben . Was muss ich hinzufügen, um die Ergebnisse zu sehen? (PS die Spezifikation sagt, dass die Reihenfolge der Register in der Ausgabe irrelevant ist, so dass Sie 7 Zeichen sparen können .sort())
Peter Taylor

@ Peter danke für den Tipp - ich muss 8 Zeichen für hinzufügen - na ja println!
Armand

1

Clojure (344 Zeichen)

Mit ein paar Zeilenumbrüchen für "Lesbarkeit":

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

Für dieses Mal echt. Führt alle Testfälle aus. Es ist weiterhin erforderlich, dass das RM-Programm sofort im Programmstrom folgt.

Edit: Mehr Factoring, reduzierte Prozedurnamen.

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

Mit angefügtem Programm eingerückt und kommentiert.

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

Es ist schon eine Weile her, dass ich PostScript geschrieben habe, aber definieren Sie Funktionen mit Namen wie regline? Können Sie nicht viel sparen, indem Sie sie Dinge wie nennen R?
Peter Taylor

Ja definitiv. Es besteht jedoch auch ein potenzielles Problem, da all diese Definitionen mit den Status- und Registernamen im selben Wörterbuch koexistieren. Also habe ich versucht, Interpunktionszeichen mit einem mnemonischen Wert zu finden (also kann ich es immer noch lesen :). Ich hoffe auch, mehr algorithmische Verkleinerungen zu finden, also wollte ich nicht zu viel Energie ausgeben, bevor ich es mit neuen Augen betrachten konnte.
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]}

Dies ist die Ausgabe für den ersten Test:

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

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.