Simulieren Sie eine Minsky-Registermaschine (II)

11

Dies ist eine Erweiterung von Simulate a Minsky Register Machine (I) . Ich werde dort nicht die gesamte Beschreibung wiederholen. Bitte lesen Sie zuerst diese Problembeschreibung.

Die Grammatik in Teil (I) war so einfach wie möglich, führt aber zu ziemlich langen Programmen. Da dies eine Code-Golf-Site ist, hätten wir lieber eine Golf-Grammatik, nicht wahr?

Auf hohem Niveau sind die Änderungen gegenüber der ursprünglichen Grammatik wie folgt:

  • Die Beschriftung in der ersten Zeile ist optional
  • Leerzeichen sind optional, es sei denn, dies ist erforderlich, um zwei benachbarte Bezeichner zu trennen
  • Zustände können eingefügt werden. Um eine nicht mehrdeutige Analyse zu gewährleisten, muss der erste Zustand einer Dekrementierungsoperation, wenn er ein Inline-Zustand ist, in Klammern eingeschlossen werden. Dies bedeutet, dass jedes Programm zu einem Einzeiler zusammengefasst werden kann.

Zum Beispiel hatten wir in den ursprünglichen Testfällen:

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

In der Golfgrammatik könnte dies verkürzt werden auf:

init:t-init d
d:a-(b+t+d)a
a:t-(a+a)"Ok"
a=3 b=4

oder auch:

init:t-init d:a-(b+t+d)a:t-(a+a)"Ok"
a=3 b=4

Die neue BNF für die "Programm" -Zeilen (im Gegensatz zur letzten Zeile, bei der es sich um Daten handelt) lautet:

program    ::= first_line (newline line)*
first_line ::= cmd
line       ::= named_cmd
state      ::= state_name
             | cmd
             | '"' message '"'
delim_state::= '(' cmd ')'
             | '"' message '"'
cmd        ::= raw_cmd
             | named_cmd
named_cmd  ::= state_name ' '* ':' ' '* raw_cmd
raw_cmd    ::= inc_cmd
             | dec_cmd
inc_cmd    ::= reg_name ' '* '+' ' '* state
dec_cmd    ::= reg_name ' '* '-' ' '* delim_state ' '* state
             | reg_name ' '* '-' ' '* state_name ' '* delim_state
             | reg_name ' '* '-' ' '* state_name ' '+ state
state_name ::= identifier
reg_name   ::= identifier

Kennungen und Nachrichten sind wie bei der vorherigen Herausforderung flexibel.


Alle Testfälle aus der vorherigen Herausforderung sind weiterhin anwendbar. Darüber hinaus sollte die folgende Golf-Josephus-Lösung den größten Teil der Grammatik ausüben:

in:k-(r+t+in)in2:t-(k+in2)r-(i+n-0"ERROR n is 0")"ERROR k is 0"
0:n-(i+2:k-(r+t+2)5:t-(k+5)7:i-(r-(t+7)c:t-(i+r+c)i+0)a:t-(i+a)7)"Ok"
n=40 k=3

Erwartete Ausgabe:

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

Und ich denke, dies deckt den verbleibenden Fall ab:

k+k-"nop""assert false"
k=3

Erwartete Ausgabe:

nop
k=3

Sie können davon ausgehen, dass alle Programme eine sinnvolle Semantik haben. Insbesondere haben sie mindestens einen Zustand und definieren einen Zustand nicht neu. Nach wie vor kann ein Zustand jedoch verwendet werden, bevor er definiert wird.

Die Wertung ist eine Variante des Code-Golfs. Sie können ein in sich geschlossenes Programm schreiben, das nach der UTF-8-Codierung die Länge des Programms in Byte angibt. Da die Wiederverwendung von Code eine gute Sache ist, können Sie alternativ, wenn Sie Teil (I) in n1Bytes implementiert haben , ein Programm schreiben, das aus einem Teil (II) -Programm ein Teil (I) -Programm macht, das zum Weiterleiten an das Original bereit ist. Ihre Punktzahl entspricht dann der Länge Ihres Transformationsprogramms plus ceil(n1 / 2).

NB Wenn Sie sich für die Umwandlung entscheiden, müssen Sie Namen für die anonymen Zustände so generieren, dass Sie sicherstellen, dass sie nicht mit benannten Zuständen in Konflikt geraten.

Peter Taylor
quelle

Antworten:

6

Haskell, 552 499 493 Zeichen

import Control.Monad.RWS
import Data.Map
main=interact$z.lines
z x=let(s:_,w)=evalRWS(mapM(q.t)x)w[]in s.f.i.t$last x 
p=get>>=q
q(l:":":x)=x%do a<-p;tell$f[(l,a)];r a
q(v:"+":x)=x%fmap(.a v 1)p
q(v:"-":x)=x%liftM2(d v)p p
q(('"':s):x)=x%r(\w->unlines[init s,do(v,x)<-assocs w;v++'=':show x++" "])
q(n:x)|n<"*"=x%p|1<3=x%asks(!n)
d v p n w|member v w&&w!v>0=p$a v(-1)w|1<3=n w
t[]=[];t x=lex x>>= \(y,x)->y:t x
i(v:_:x:t)=(v,read x):i t;i[]=[]
x%m=put x>>m;r=return;a=insertWith(+);f=fromList

Habe mehr oder weniger komplett umgeschrieben. Ersetzte CPS durch eine RWS-Monade, die ihre eigene Ausgabe liest, um nach Status zu suchen, die noch nicht analysiert wurde (yay for faul!), Sowie einige andere Verbesserungen.

Hammar
quelle