Nada mal para um tarpit de Turing bastante detalhado ...
N
Count i while _%128-9 {
Count x while _/128%2 {
Write 40
_+128
}
Write _%128
_+128-_%128+N
}
Count j while _/256-j {
Write 41
}
(Sim, todo esse espaço em branco é obrigatório.)
Nota: devido às limitações de entrada do Acc !! , é impossível ler uma sequência arbitrária de caracteres sem um delimitador final. Portanto, este programa espera entrada (no stdin) como uma sequência seguida por um caractere de tabulação.
Acc !! ?
É uma linguagem que criei que parece apenas inutilizável . O único tipo de dados são números inteiros, a única construção de fluxo de controle é o Count x while y
loop, e a única maneira de armazenar dados é um único acumulador _
. A entrada e a saída são executadas um caractere de cada vez, usando o valor especial N
e a Write
instrução Apesar dessas limitações, tenho certeza de que Acc !! é Turing completo.
Explicação
A estratégia básica em Acc !! A programação é usar a %
divisão mod e número inteiro /
para particionar conceitualmente o acumulador, permitindo que ele armazene vários valores ao mesmo tempo. Neste programa, usamos três seções: os sete bits de ordem mais baixa ( _%128
) armazenam um código ASCII da entrada; o próximo bit ( _/128%2
) armazena um valor de flag; e os bits restantes ( _/256
) contam o número de parênteses necessárias.
Entrada em Acc !! vem do valor especial N
, que lê um único caractere e avalia seu código ASCII. Qualquer declaração que consiste apenas em uma expressão atribui o resultado dessa expressão ao acumulador. Então, começamos armazenando o código do primeiro caractere no acumulador.
_%128
irá armazenar o caractere lido mais recentemente. Portanto, o primeiro loop é executado enquanto _%128-9
é diferente de zero - ou seja, até o caractere atual ser uma guia.
Dentro do loop, queremos imprimir, a (
menos que estejamos na primeira iteração. Desde Acc !! não tem declaração if, temos que usar loops para condicionais. Usamos o bit 128 do acumulador _/128%2
, como valor de flag. Na primeira passagem, a única coisa no acumulador é um valor ASCII <128, portanto, o sinalizador é 0 e o loop é ignorado. Em cada passe subsequente, garantiremos que a bandeira seja 1.
Dentro do Count x
loop (sempre que o sinalizador é 1), escrevemos um paren aberto (ASCII 40
) e adicionamos 128 ao acumulador, configurando o sinalizador para 0 e saindo do loop. Isso também aumenta o valor de _/256
, que usaremos como registro de proximidade a ser produzido.
Independentemente do valor da flag, escrevemos o char de entrada mais recente, que é simplesmente _%128
.
A próxima tarefa ( _+128-_%128+N
) faz duas coisas. Primeiro, adicionando 128, ele define o sinalizador para a próxima vez no loop. Segundo, zera o _%128
slot, lê outro caractere e o armazena lá. Então nós fazemos um loop.
Quando o Count i
loop termina, acabamos de ler um caractere de tabulação, e o valor do acumulador se divide assim:
_%128
: 9
(o caractere de tabulação)
_/128%2
: 1
(a bandeira)
_/256
: número de caracteres lidos, menos 1
(O menos 1 é porque nós adicionamos 128 ao acumulador apenas uma vez durante a primeira passagem pelo loop principal.) Tudo o que precisamos agora são os parênteses. Count j while _/256-j
loops _/256
vezes, escrevendo um parêntese (ASCII 41
) a cada vez. Voila!