Simular uma máquina Minsky Register (I)


26

Existem muitos formalismos, portanto, embora você possa encontrar outras fontes úteis, espero especificar isso com clareza suficiente para que não sejam necessárias.

Um RM consiste em uma máquina de estados finitos e um número finito de registros nomeados, cada um dos quais contém um número inteiro não negativo. Para facilitar a entrada de texto, esta tarefa requer que os estados também sejam nomeados.

Existem três tipos de estado: incremento e decremento, que referenciam um registro específico; e terminar. Um estado de incremento incrementa seu registro e passa o controle para seu sucessor. Um estado de decréscimo possui dois sucessores: se seu registro é diferente de zero, ele o diminui e passa o controle para o primeiro sucessor; caso contrário (ou seja, o registro é zero), ele simplesmente passa o controle para o segundo sucessor.

Para "gentileza" como linguagem de programação, os estados de terminação levam uma string codificada para imprimir (para que você possa indicar uma terminação excepcional).

A entrada é de stdin. O formato de entrada consiste em uma linha por estado, seguida pelo conteúdo inicial do registro. A primeira linha é o estado inicial. O BNF para as linhas de estado é:

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

Há alguma flexibilidade na definição de identificador e mensagem. Seu programa deve aceitar uma sequência alfanumérica não vazia como identificador, mas pode aceitar sequências mais genéricas, se você preferir (por exemplo, se o seu idioma suportar identificadores com sublinhados e for mais fácil trabalhar com ele). Da mesma forma, para a mensagem, você deve aceitar uma sequência não-vazia de alfanuméricos e espaços, mas pode aceitar sequências mais complexas que permitam novas linhas de escape e aspas duplas, se desejar.

A linha final de entrada, que fornece os valores iniciais do registro, é uma lista separada por espaços das atribuições identifier = int, que devem estar não vazias. Não é necessário que ele inicialize todos os registros nomeados no programa: qualquer um que não seja inicializado será assumido como 0.

Seu programa deve ler a entrada e simular o RM. Quando atingir um estado final, deve emitir a mensagem, uma nova linha e, em seguida, os valores de todos os registros (em qualquer formato conveniente, legível por humanos, e em qualquer ordem).

Nota: formalmente os registradores devem conter números inteiros ilimitados. No entanto, você pode, se desejar, assumir que o valor de nenhum registro excederá 2 ^ 30.

Alguns exemplos simples

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

Resultados esperados:

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

Resultados esperados:

Ok
a=3 b=7 t=0
Casos de teste para máquinas mais difíceis de analisar
s0 : t - s0 s1
s1 : t + "t is 1"
t=17

Resultados esperados:

t is 1
t=1

e

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

Resultados esperados:

t is nonzero
t=0

Um exemplo mais complicado

Retirado do desafio de código de problema Josephus do DailyWTF. A entrada é n (número de soldados) ek (avanço) e a saída em r é a posição (indexada a zero) da pessoa que sobrevive.

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

Resultados esperados:

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

Esse programa como uma imagem, para aqueles que pensam visualmente e acham útil entender a sintaxe: Josephus problem RM

Se você gostou deste golfe, dê uma olhada na sequência .


A entrada vem do stdin, de um arquivo ou de algum outro lugar?
Kevin Brown

@ Bass, de stdin.
Peter Taylor

Você deve adicionar alguns casos de teste com os seguintes problemas difíceis de tratar: 1) mensagens com espaços, 2) mensagens com sinais de igual, 3) mensagens em inc_line, 4) mensagens no primeiro estado de um dec_line, 5) mensagens em espaços em casos 3 e 4.
MtnViewMark 28/03

A gramática possui um erro: precisa haver um espaço literal entre as duas entradas state_name em dec_line. Também não está claro se você deseja exigir que as pessoas aceitem vários espaços entre os tokens na entrada.
MtnViewMark

2
@ Peter: +1 para um código de golfe realmente bastante equilibrado, com bom equilíbrio de especificações e espaço para manobras! A maioria das perguntas aqui são muito finas.
MtnViewMark

Respostas:


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

Corra com perl -M5.010 file.

Tudo começou muito diferente, mas receio que tenha convergido com a solução Ruby em muitas áreas no final. Parece que a vantagem de Ruby é "sem sigilos" e "melhor integração de expressões regulares" de Perl.

Um pouco de detalhes das entranhas, se você não lê Perl:

  • @p=<>: leia a descrição completa da máquina para @p
  • /=/,$_{$`}=$' for split$",pop@p: para cada ( for) atribuição ( split$") na última linha de descrição da máquina ( @p), localize o sinal de igual ( /=/) e atribua valor $'à %_chave de hask$`
  • $o='\w+': o estado inicial seria o primeiro a corresponder à expressão regular do Perl "caracteres da palavra"
  • until/"/: loop até atingirmos um estado de término:
    • map{($r,$o,$,,$b)=$'=~/".*?"|\S+/g if/^$o :/}@p: loop na descrição da máquina @p: quando estamos na linha que corresponde ao estado atual ( if/^$o :/), tokenize ( /".*?"|\S+/g) o resto da linha $'com variáveis ($r,$o,$,,$b). Truque: a mesma variável $ose usada inicialmente para o nome do rótulo e posteriormente para o operador. Assim que o rótulo corresponde, o operador o substitui e, como um rótulo não pode (razoavelmente) ser nomeado + ou -, nunca corresponde novamente.
    • $_=$o=($_{$r}+=','cmp$o)<0?do{$_{$r}=0;$b}:$,:
      - ajuste o registro de destino para $_{$r}cima ou para baixo (ASCII magic: ','cmp'+'é 1 ','cmp'-'e -1);
      - se o resultado for negativo ( <0?, só pode acontecer para -)
      - permaneça em 0 ( $_{$r}=0) e retorne o segundo rótulo $b;
      - caso contrário, retorne o primeiro rótulo (possivelmente único)$,
    • BTW, é em $,vez de, $aportanto, pode ser colado no próximo token untilsem espaço em branco no meio.
  • say for eval,%_: relatório de despejo ( eval) e conteúdo dos registros em%_

Você realmente não precisa de dois pontos /^$o :/. Somente o sinal de intercalação é suficiente para garantir que você esteja apenas visualizando rótulos.
Lowjacker 30/03/11

@ Lowjacker Não preciso disso para determinar que estou no rótulo certo, mas preciso que seja mantido fora $'. É um caractere no regex, seriam três $c,para contabilizar de fora. Como alternativa, alguns maiores ainda mudam para a regex de tokenização.
JB

10

Python + C, 466 caracteres

Apenas por diversão, um programa python que compila o programa RM para C, compila e executa o 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
Isso não funcionará se os registradores tiverem nomes como ' main', ' if' etc.
Nabb 30/03/11

1
@Nabb: Buzzkill. Deixo ao leitor a adição de prefixos sublinhados nos lugares certos.
Keith Randall

6

Haskell, 444 caracteres

(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

Cara, isso foi difícil! O manuseio adequado das mensagens com espaços custa mais de 70 caracteres. A formatação de saída para ser mais "legível por humanos" e corresponder aos exemplos custa outros 25.


  • Edit: (498 -> 482) vários pequenos revestimentos e algumas das sugestões de @ FUZxxl
  • Edit: (482 -> 453) volte usando números reais para os registros; muitos truques de golfe aplicados
  • Editar: (453 -> 444) formatação de saída embutida e análise de valor inicial

Como não conheço Haskell, não posso decifrar toda a sintaxe, mas posso decifrar o suficiente para ver que você está usando listas para o conteúdo do registro. Devo dizer que estou surpreso que seja mais curto do que usar ints.
Peter Taylor

Colocar as ligações locais depois whereem uma única linha separada por ponto e vírgula pode economizar 6 caracteres. E eu acho que você pode salvar alguns caracteres na definição de q, alterando o detalhado if-then-else para um protetor de padrão.
FUZxxl 28/03

E também: suponha cegamente que o terceiro valor está "-"na definição de qe use um sublinhado.
FUZxxl 28/03

Eu acho que você pode salvar outro caractere alterando a linha 8 para q[_,_,r,_,s,z]d|maybe t(==0)$lookup r d=n z d|t=n s$r%(-1)$d. Mas de qualquer maneira, este programa é extremamente bom.
FUZxxl 29/03

Você pode reduzir consideravelmente o código de análise aproveitando lexo Prelude. Por exemplo, algo como f[]=[];f s=lex s>>= \(t,r)->t:f rdividirá uma linha em tokens enquanto manipula as strings entre aspas corretamente.
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} /}

Eu esperaria que isso falhasse nos prefixos de etiquetas um do outro. Pensamentos?
JB

Não consigo fazê-lo funcionar com nenhum outro caso além dos exemplos. O que há de errado nisso?
JB

Eu acho que está consertado agora.
Lowjacker

Ah, muito melhor. Obrigado.
JB

3

Delphi, 646

O Delphi não oferece muito em relação à divisão de strings e outras coisas. Felizmente, temos coleções genéricas, o que ajuda um pouco, mas ainda é uma solução bastante ampla:

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.

Aqui a versão recuada e comentada:

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 caracteres

<?$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 : Suporta seqüências de caracteres para o primeiro estado e alguma leve compressão
441 -> 402 : Instruções if / else e de atribuição compactadas, tanto quanto possível
402 -> 398 : Os nomes das funções podem ser usados ​​como constantes e podem ser usados ​​como strings
398 -> 395 : Utiliza operadores de curto-circuito
395 -> 389 : Não há necessidade da outra parte
389 -> 371 : Não há necessidade de usar array_key_exists ()
371 -> 370 : Espaço desnecessário removido
370 -> 366 : Removidos dois espaços desnecessários o 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
Eu testei isso, mas ele não parece produzir nada para o stdout . O que preciso adicionar para ver os resultados? (PS a especificação diz que a ordem dos registros na saída é irrelevante, assim você pode economizar 7 caracteres a partir de .sort())
Peter Taylor

@ Peter obrigado pela dica - eu vou ter que adicionar 8 caracteres para println- ah bem!
Armand

1

Clojure (344 caracteres)

Com algumas quebras de linha para "legibilidade":

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

Para reais desta vez. Executa todos os casos de teste. Ele ainda exige que o programa RM siga imediatamente no fluxo do programa.

Edit: Mais fatoração, nomes de procedimentos reduzidos.

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

Recuado e comentado com o programa anexado.

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

Faz um tempo desde que escrevi algum PostScript, mas você está definindo funções com nomes como regline? Você não pode economizar muito chamando-as de coisas assim R?
Peter Taylor

Sim definitivamente. Mas também há um problema em potencial, pois todas essas definições coexistem com o estado e registram nomes no mesmo dicionário. Então, eu tenho tentado encontrar caracteres de pontuação com algum valor mnemônico (para que eu ainda possa lê-lo :). Também espero encontrar mais reduções algorítmicas, por isso não queria gastar muita energia antes que pudesse olhar com novos olhos.
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]}

Esta é a saída para o primeiro teste:

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

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

Execute e depure

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.