Simula una macchina registro Minsky (I)


26

Esistono molti formalismi, quindi mentre potresti trovare utili altre fonti, spero di specificarlo abbastanza chiaramente da non essere necessario.

Un RM è costituito da una macchina a stati finiti e da un numero finito di registri nominati, ognuno dei quali contiene un numero intero non negativo. Per semplicità di input testuale questa attività richiede che anche gli stati siano nominati.

Esistono tre tipi di stato: incremento e decremento, che fanno entrambi riferimento a un registro specifico; e terminare. Uno stato di incremento incrementa il suo registro e passa il controllo al suo unico successore. Uno stato di decremento ha due successori: se il suo registro è diverso da zero, lo decrementa e passa il controllo al primo successore; altrimenti (cioè il registro è zero) passa semplicemente il controllo al secondo successore.

Per "gentilezza" come linguaggio di programmazione, gli stati di terminazione richiedono una stringa codificata per la stampa (in modo da poter indicare una terminazione eccezionale).

L'input proviene da stdin. Il formato di input è costituito da una riga per stato, seguita dal contenuto del registro iniziale. La prima riga è lo stato iniziale. BNF per le linee di stato è:

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'è una certa flessibilità nella definizione di identificatore e messaggio. Il tuo programma deve accettare una stringa alfanumerica non vuota come identificatore, ma può accettare stringhe più generali se preferisci (ad es. Se la tua lingua supporta identificatori con caratteri di sottolineatura ed è più facile lavorare con te). Allo stesso modo, per il messaggio è necessario accettare una stringa non vuota di caratteri alfanumerici e spazi, ma è possibile accettare stringhe più complesse che consentono la fuga di nuove righe e caratteri di virgolette doppie se lo si desidera.

L'ultima riga di input, che fornisce i valori iniziali del registro, è un elenco separato da spazi di assegnazioni identificatore = int, che deve essere non vuoto. Non è necessario che inizializzi tutti i registri nominati nel programma: si presume che 0 non sia inizializzato.

Il tuo programma dovrebbe leggere l'input e simulare l'RM. Quando raggiunge uno stato di terminazione, dovrebbe emettere il messaggio, una nuova riga e quindi i valori di tutti i registri (in qualsiasi formato conveniente, leggibile dall'uomo, e in qualsiasi ordine).

Nota: formalmente i registri dovrebbero contenere numeri interi senza limiti. Tuttavia, è possibile, se lo si desidera, supporre che nessun valore del registro superi mai 2 ^ 30.

Alcuni semplici esempi

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

Risultati aspettati:

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

Risultati aspettati:

Ok
a=3 b=7 t=0
Casi di prova per macchine più complicate da analizzare
s0 : t - s0 s1
s1 : t + "t is 1"
t=17

Risultati aspettati:

t is 1
t=1

e

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

Risultati aspettati:

t is nonzero
t=0

Un esempio più complicato

Tratto dalla sfida del codice problema Josephus del DailyWTF. L'input è n (numero di soldati) e k (avanzamento) e l'output in r è la posizione (a zero) della persona che sopravvive.

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

Risultati aspettati:

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

Quel programma come immagine, per coloro che pensano visivamente e troverebbero utile capire la sintassi: Giuseppe Flavio problema RM

Se ti è piaciuto questo golf, dai un'occhiata al sequel .


L'input proviene da stdin, da un file o da qualche altro posto?
Kevin Brown,

@Bass, da stdin.
Peter Taylor,

Dovresti aggiungere alcuni casi di test con i seguenti problemi difficili da gestire: 1) messaggi con spazi, 2) messaggi con segni di uguale, 3) messaggi in inc_line, 4) messaggi nel primo stato di dec_line, 5) messaggi in spazi in casi 3 e 4.
MtnViewMark

La grammatica ha un errore: deve esserci uno spazio letterale tra le due voci state_name in dec_line. Non è anche chiaro se si intende richiedere alle persone di accettare più spazi tra i token nell'input.
MtnViewMark,

2
@Peter: +1 per un code-golf veramente carnoso con un buon equilibrio di specifiche e spazio di manovra! La maggior parte delle domande qui sono state troppo sottili.
MtnViewMark,

Risposte:


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

Corri con perl -M5.010 file.

È iniziato in modo completamente diverso, ma temo che convergesse con la soluzione Ruby in molte aree verso la fine. Sembra che il vantaggio di Ruby sia "nessun sigillo" e la "migliore integrazione regex" di Perl.

Un po 'di dettagli dalle viscere, se non leggi Perl:

  • @p=<>: leggi l'intera descrizione della macchina su @p
  • /=/,$_{$`}=$' for split$",pop@p: per ogni ( for) assegnazione ( split$") nell'ultima riga descrittiva della macchina ( @p), individuare il segno di uguale ( /=/) quindi assegnare il valore $'alla %_chiave hask$`
  • $o='\w+': lo stato iniziale sarebbe il primo a corrispondere al regex del Perl "caratteri di parole"
  • until/"/: loop fino a quando non raggiungiamo uno stato di terminazione:
    • map{($r,$o,$,,$b)=$'=~/".*?"|\S+/g if/^$o :/}@p: loop sulla descrizione della macchina @p: quando siamo sulla riga che corrisponde allo stato corrente ( if/^$o :/), tokenize ( /".*?"|\S+/g) il resto della linea $'alle variabili ($r,$o,$,,$b). Trucco: la stessa variabile $ose utilizzata inizialmente per il nome dell'etichetta e successivamente per l'operatore. Non appena l'etichetta corrisponde, l'operatore la sovrascrive e poiché un'etichetta non può (ragionevolmente) essere nominata + o -, non corrisponde più.
    • $_=$o=($_{$r}+=','cmp$o)<0?do{$_{$r}=0;$b}:$,:
      - regola il registro target $_{$r}su o giù (magia ASCII: ','cmp'+'è 1 mentre ','cmp'-'è -1);
      - se il risultato è negativo ( <0?, può succedere solo per -)
      - quindi rimanere su 0 ( $_{$r}=0) e restituire la seconda etichetta $b;
      - altrimenti restituisce la prima (possibilmente unica) etichetta$,
    • A proposito, è $,invece $ache può essere incollato al token successivo untilsenza spazi bianchi in mezzo.
  • say for eval,%_: dump report ( eval) e contenuto dei registri in%_

Non hai davvero bisogno dei due punti /^$o :/. Il solo cursore è sufficiente per assicurarti di guardare solo le etichette.
Lowjacker

@Lowjacker Non ne ho bisogno per determinare che sono sulla giusta etichetta, ma ne ho bisogno per essere tenuto fuori $'. È un personaggio nella regex, sarebbe tre $c,di cui tener conto dall'esterno. In alternativa alcuni più grandi cambiano ancora nella regex tokenizzante.
JB

10

Python + C, 466 caratteri

Solo per divertimento, un programma Python che compila il programma RM in C, quindi compila ed esegue il 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
Questo non funzionerà se i registri hanno nomi come ' main', ' if', ecc.
Nabb,

1
@Nabb: Buzzkill. Lascio al lettore l'aggiunta di prefissi di sottolineatura nei posti giusti.
Keith Randall,

6

Haskell, 444 personaggi

(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

Amico, è stato difficile! La corretta gestione dei messaggi con spazi in essi costa oltre 70 caratteri. La formattazione dell'output sarà più "leggibile dall'uomo" e corrisponderà agli esempi costandone altri 25.


  • Modifica: (498 -> 482) vari piccoli rivestimenti interni e alcuni dei suggerimenti di @ FUZxxl
  • Modifica: (482 -> 453) tornare indietro usando i numeri effettivi per i registri; molti trucchi da golf applicati
  • Modifica: (453 -> 444) formattazione dell'output in linea e analisi del valore iniziale

Non conosco Haskell, quindi non riesco a decifrare tutta la sintassi, ma posso decifrare abbastanza da vedere che stai usando le liste per il contenuto del registro. Devo dire che sono sorpreso del fatto che sia più breve dell'uso degli ints.
Peter Taylor,

Inserendo le associazioni locali wherein un'unica riga separate da punti e virgola è possibile salvare 6 caratteri. E immagino che potresti salvare alcuni caratteri nella definizione di qcambiando il prolisso if-then-else in un pattern guard.
FUZxxl,

E anche: supponiamo ciecamente che il terzo valore sia "-"nella definizione di qe usi invece un trattino basso.
FUZxxl,

Immagino che potresti salvare un altro carattere cambiando la riga 8 in q[_,_,r,_,s,z]d|maybe t(==0)$lookup r d=n z d|t=n s$r%(-1)$d. Ma comunque, questo programma è estremamente buono.
FUZxxl

È possibile abbreviare considerevolmente il codice di analisi sfruttando lexPreludio. Ad esempio, qualcosa come f[]=[];f s=lex s>>= \(t,r)->t:f rdividerà una linea in token durante la corretta gestione delle stringhe tra virgolette.
Hammar,

6

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

Mi aspetto che ciò fallisca sulle etichette dei prefissi l'una dell'altra. Pensieri?
JB

Non riesco a farlo funzionare con nessun altro caso oltre agli esempi. Cosa c'è di sbagliato in questo?
JB

Penso che sia stato risolto ora.
Lowjacker

Ah, molto meglio. Grazie.
JB

3

Delfi, 646

Delphi non offre molto riguardo alla suddivisione di stringhe e cose. Fortunatamente, abbiamo raccolte generiche, che aiutano un po ', ma questa è ancora una soluzione piuttosto ampia:

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.

Ecco la versione rientrata e commentata:

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 caratteri

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

changelog


446 -> 441 : supporta le stringhe per il primo stato e una leggera compressione
441 -> 402 : istruzioni if ​​/ else e assegnazione compresse il più possibile
402 -> 398 : i nomi delle funzioni possono essere usati come costanti che possono essere usate come stringhe
398 -> 395 : utilizza operatori di cortocircuito
395 -> 389 : non è necessario per l'altra parte
389 -> 371 : non è necessario utilizzare array_key_exists ()
371 -> 370 : spazio non necessario rimosso
370 -> 366 : rimossi due spazi non necessari in la 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
Ho provato questo ma non sembra produrre nulla su stdout . Cosa devo aggiungere per vedere i risultati? (PS la specifica dice che l'ordine dei registri nell'output è irrilevante, quindi puoi salvare 7 caratteri da .sort())
Peter Taylor

@Peter grazie per la punta - dovrò aggiungere 8 caratteri per println- ah bene!
Armand,

1

Clojure (344 caratteri)

Con alcune interruzioni di riga per "leggibilità":

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

Questa volta per davvero. Esegue tutti i casi di test. Richiede ancora che il programma RM segua immediatamente il flusso del programma.

Modifica: più factoring, nomi di procedure ridotti.

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

Rientrato e commentato con un programma allegato.

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

È da un po 'che non scrivo PostScript, ma stai definendo funzioni con nomi come regline? Non puoi risparmiare molto chiamandoli cose come R?
Peter Taylor,

Sì, sicuramente. Ma c'è anche un potenziale problema poiché tutte queste definizioni coesistono con lo stato e registrano i nomi nello stesso dizionario. Quindi ho cercato di trovare caratteri di punteggiatura con un valore mnemonico (così posso ancora leggerlo :). Spero anche di trovare ulteriori riduzioni algoritmiche, quindi non volevo spendere troppa energia prima di poterla guardare con occhi nuovi.
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]}

Questo è l'output per il primo test:

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

Esegui ed esegui il debug

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.