Simular uma máquina Minsky Register (II)

11

Esta é uma extensão do Simulate a Minsky Register Machine (I) . Não vou repetir toda a descrição lá, então leia essa descrição do problema primeiro.

A gramática na parte (I) era a mais simples possível, mas resulta em programas bastante longos. Como este é um site de código de golfe, preferimos ter uma gramática do golfe, não é?

Em um nível alto, as alterações da gramática original são as seguintes:

  • A etiqueta na primeira linha é opcional
  • Espaço em branco é opcional, exceto quando necessário para separar dois identificadores adjacentes
  • Os estados podem ser incorporados. Para garantir a análise não ambígua, se o primeiro estado de uma operação de decremento for um estado embutido, ele deverá estar entre parênteses. Isso significa que qualquer programa pode ser jogado em uma única linha.

Por exemplo, nos casos de teste originais, tivemos:

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

Na gramática do golfe, isso pode ser reduzido para:

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

ou até:

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

O novo BNF para as linhas do "programa" (ao contrário da linha final, que são dados) é:

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

Identificadores e mensagens são flexíveis, como no desafio anterior.


Todos os casos de teste do desafio anterior ainda são aplicáveis. Além disso, a seguinte solução Josephus para golfe deve exercer a maior parte da gramática:

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

Saída esperada:

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

E acho que isso cobre o restante do caso:

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

Saída esperada:

nop
k=3

Você pode assumir que todos os programas terão semântica sensata. Em particular, eles terão pelo menos um estado e não redefinirão um estado. No entanto, como antes, um estado pode ser usado antes de ser definido.

A pontuação é uma variante do código-golfe. Você pode escrever um programa independente e ele pontuará como o tamanho do programa em bytes após a codificação UTF-8. Como alternativa, como a reutilização de código é uma Coisa Boa, se você implementou a parte (I) em n1bytes, é possível escrever um programa que transforma um programa de parte (II) em um programa de parte (I), pronto para ser canalizado para o original. Sua pontuação será a duração do seu programa de transformação plus ceil(n1 / 2).

NB Se você optar pela transformação, precisará gerar nomes para os estados anônimos de forma a garantir que eles não entrem em conflito com os estados nomeados.

Peter Taylor
fonte

Respostas:

6

Haskell, 552 499 493 caracteres

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

Reescreveu mais ou menos completamente. Substituiu o CPS por uma mônada do RWS que lê sua própria saída para procurar estados que ainda não foram analisados ​​(sim, por preguiça!), Além de outros ajustes.

hammar
fonte