Interprete o Kipple!

12

Introdução

Kipple é uma linguagem de programação esotérica baseada em pilha inventada por Rune Berg em março de 2003.

O Kipple possui 27 pilhas, 4 operadores e uma estrutura de controle.

Pilhas

As pilhas são nomeadas a- ze contêm números inteiros assinados de 32 bits. Há também uma pilha especial @, para tornar os números de saída mais convenientes. Quando um número é pressionado @, os valores ASCII dos dígitos desse número são pressionados. (Por exemplo, se você pressionar 12 para @, ele pressionará 49 e depois 50 para @).

A entrada é pressionada na pilha de entrada iantes da execução do programa. O intérprete solicitará valores para armazenar iantes da execução. Após a conclusão da execução, qualquer coisa na pilha de saída oé exibida como caracteres ASCII. Como esse é o único mecanismo de E / S do Kipple, é impossível interagir com um programa Kipple.

Operadores

Um operando é um identificador de pilha ou um inteiro assinado de 32 bits.

Push: >ou<

Sintaxe: Operand>StackIndentifierouStackIndentifier<Operand

O operador Push leva o operando para a esquerda e o empurra para a pilha especificada. Por exemplo, 12>acolocará o valor 12 na pilha a. a>birá exibir o valor mais alto da pilha ae empurrá-lo para a pilha b. O surgimento de uma pilha vazia sempre retorna 0. a<bé equivalente a b>a. a<b>caparece o valor mais alto de be empurra para ambos ce a.

Adicionar: +

Sintaxe: StackIndentifier+Operand

O operador Adicionar coloca a soma do item mais alto na pilha e o operando na pilha. Se o operando for uma pilha, o valor será exibido nela. Por exemplo, se o valor mais alto da pilha afor 1, ele a+2empurrará 3 para ela. Se aestiver vazio, a+2pressione 2 nele. Se os valores mais altos da pilha ae bsão 1 e 2, em seguida, a+birá aparecer o valor 2 de pilha be empurrar 3 na pilha a.

Subtrair: -

Sintaxe: StackIndentifier-Operand

O operador Subtrair funciona exatamente como o operador Adicionar, exceto que subtrai em vez de adicionar.

Claro: ?

Sintaxe: StackIndentifier?

O operador Clear esvazia a pilha se o item mais alto for 0.

O intérprete irá ignorar qualquer coisa que não está ao lado de um operador, então o seguinte programa funcionaria: a+2 this will be ignored c<i. No entanto, a maneira correta de adicionar comentários é usando o #caractere. Qualquer coisa entre um #e um caractere de fim de linha é removida antes da execução. O caractere ASCII # 10 é definido como final de linha no Kipple.

Operandos podem ser compartilhados por dois operadores, por exemplo, a>b c>b c?podem ser escritos como a>b<c?.

O programa 1>a<2 a+aresultará em aconter os valores [1 4](de baixo para cima) e não [1 3]. Da mesma forma para o -operador.

A estrutura de controle

Existe apenas uma estrutura de controle no Kipple: o loop.

Sintaxe: (StackIndentifier code )

Enquanto a pilha especificada não estiver vazia, o código entre parênteses será repetido. Loops podem conter outros loops. Por exemplo, (a a>b)moverá todos os valores da pilha apara a pilha b, embora a ordem seja revertida . Uma maneira funcionalmente idêntica, mas mais elegante de fazer isso é (a>b).

Exemplos

100>@ (@>o)

Isso produzirá 100

33>o 100>o 108>o 114>o 111>o 87>o 32>o 111>o 108>o 108>o 101>o 72>o

Isso será impresso "Hello World!". Quando a opilha está sendo impressa, ela começa a exibir caracteres de cima para baixo.

#prime.k by Jannis Harder
u<200
#change 200


k<2>m
u-2
(u-1 u>t u>z u<t
  (k>e e+0 e>r)
  (e>k)
  m+1
  m>t
  m>z
  m<t
  t<0>z? t?
  1>g
  (r>b
    m+0 m>a
    b+0 b>w
    (a-1 
      b+0 b>j
      j?
      1>s
      (j<0>s j?)
      s?
      (s<0 w+0 w>b s?)
      a>t
      a>z
      t>a
      b-1
      b>t
      b>z
      t>b
      z<0>t? z?
    a?)
    b?
    1>p
    (b<0 b? 0>p)
    p?
    (p 0>r? 0>p? 0>g)
  )
  g?
  (g m+0 m>k 0>g?)
u?)
(k>@
  10>o
  (@>o)
)

Este é um gerador de números primos, mas não tenho certeza de como funciona.

Regras

  • Você deve escrever um programa / função que interprete o Kipple. Este programa / função pode obter um programa Kipple através de um arquivo de origem ou via STDIN diretamente do usuário. Se STDIN não estiver disponível, ele deve ser obtido da entrada do teclado e continuar recebendo até que um caractere não imprimível específico seja inserido. Por exemplo, se o seu intérprete for escrito em código de máquina x86, ele obterá o caractere do programa Kipple por caractere do teclado e continuará a fazê-lo até que esc(ou qualquer outra tecla que não emita um caractere imprimível) seja pressionada.

  • Se houver um erro, por exemplo, um erro de sintaxe ou estouro de pilha, ele deverá reconhecê-lo de alguma forma, por exemplo, retornando 10 em vez de 0 ou mensagens de erro produzidas pelo intérprete / compilador, MAS NÃO IMPRIME MENSAGENS DE ERRO .

  • Quaisquer outras regras regulares para o código de golfe se aplicam a esse desafio.

  • Seu código será testado com alguns dos exemplos no arquivo de amostras do Kipple

Este é um . O código mais curto em bytes vencerá. Boa sorte!


Observe que existe um operador opcional no Kipple, "mas ele não faz parte da especificação e é apenas um recurso extra no intérprete oficial. Eu não o mencionei aqui, portanto, ele não precisa ser suportado em seu envio.

Se você tiver alguma dúvida sobre qualquer parte da especificação, poderá examiná-la com intérprete oficial escrito em Java . Isso fará o download de um arquivo zip contendo o programa compilado e o código fonte. É licenciado sob a GPL.


fonte
1
Temos que usar números inteiros assinados de 32 bits ou podemos usar o tipo inteiro natural da implementação do host? (A maioria dos casos importantes são provavelmente unsigned inteiros de 32 bits, assinado ou não assinado números inteiros de 8 bits e inteiros de precisão arbitrária.)
Martin Ender
Bem, foi o que eu encontrei no wiki esotric. sim, porque o seu intérprete pode ser incompatível com outros programas entulho que seu mecanismo são baseadas neste recurso
Você pode ser mais específico sobre o comportamento no caso de erros? Para que possamos retornar uma resposta incorreta ou emitir um erro, mas não podemos imprimir o erro?
Alex A.
@Alex A. Sim, porque pode ser considerado como saída do programa e você pode criar um programa kipple que pode ter a mesma saída que a mensagem de erro. Também é "mais barato" (usa menos caracteres) não ter uma função / instrução que imprima uma mensagem de erro.
3
Que espaço em branco pode ocorrer em um programa de origem? Como pedir informações ise eu pegar o programa de origem do stdin?
orlp

Respostas:

6

C, 709 702 bytes

A pontuação de bytes é com as novas linhas (que podem ser removidas) removidas, mas, para facilitar a leitura, eu as publico aqui com novas linhas:

#define R return
#define C ;break;case
c[999]={};*P=c;*S[28];M[99999]={};t;*T;
u(s,v){S[s]+=28;*S[s]=v;
if(s>26){for(t=v/10;t;t/=10)S[s]+=28;T=S[s];do{*T=48+v%10;T-=28;}while(v/=10);}}
o(s){t=S[s]-M>27;S[s]-=28*t;R S[s][28]*t;}
I(s){R s<65?27:s-97;}
O(int*p){if(!isdigit(*p))R o(I(*p));
for(;isdigit(p[-1]);--p);for(t=0;isdigit(*p);t*=10,t+=*p++-48);R t;}

main(i,a){for(i=0;i<28;++i)S[i]=M+i;
for(;~(*++P=getchar()););P=c+1;
for(;;){i=I(P[-1]);switch(*P++){
case 35:for(;*P++!=10;)
C'<':u(i,O(P))
C'>':u(I(*P),O(P-2))
C'+':u(i,*S[i]+O(P))
C'-':u(i,*S[i]-O(P))
C'?':if(!*S[i])S[i]=M+i
C'(':for(i=1,T=P;i;++T)i+=(*T==40)-(*T==41);if(S[I(*P)]-M<28)P=T;else u(26,P-c)
C')':P=c+o(26)-1
C-1:for(;i=o(14);)putchar(i); R 0;}}}

Compile com gcc -w golf.c( -wsilencia avisos para sua sanidade).

Suporta tudo, exceto a ientrada, pois o solicitante ainda não respondeu à minha pergunta sobre como fazê-lo se você pegar o código do stdin. Não relata erros de sintaxe.

orlp
fonte
Eu respondi sua pergunta sobre a pilha "i" nos comentários da postagem principal.
btw como ele lê programas kipple? via argumentos de comando? como devo usá-lo?
@GLASSIC Espera o programa em stdin.
orlp
Até quando ? Como iniciar a extrusão?
@GLASSIC Basta passar o programa em stdin. Por exemplo ./a.out < prime.k.
orlp 9/07/16
3

Ruby, 718 bytes (atualmente não competitivo)

Eu estou muito cansado

O arquivo é carregado como um argumento de linha de comando e a entrada é enviada por meio de STDIN. Como alternativa, canalize o arquivo no STDIN se você não precisar inserir dados no seu iregistro.

Por causa de alguma confusão em relação às especificações, a versão atual não está sendo gerenciada a<b>ccorretamente e, portanto, não é competitiva até que seja corrigida.

a<b>cestá consertado agora. No entanto, ele ainda retorna o resultado errado ao executar a função de números primos, portanto, permanece como uma resposta não-competitiva.

(f=$<.read.gsub(/#.*?\n|\s[^+-<>#()?]*\s/m,' ').tr ?@,?`
t=Array.new(27){[]}
t[9]=STDIN.read.bytes
k=s=2**32-1
r=->c{c=c[0];c[0]==?(?(s[c[1..-2]]while[]!=t[c[1].ord-96]):(c=c.sub(/^(.)<(\D)>(.)/){$1+"<#{t[$2.ord-96].pop||0}>"+$3}.sub(/(\d+|.)(\W)(\d+|.)?/){_,x,y,z=*$~
a=x.ord-96
b=(z||?|).ord-96
q=->i,j=z{j[/\d/]?j.to_i: (t[i]||[]).pop||0}
l=t[a]
y<?-?(x==z ?l[-1]*=2:l<<(l.pop||0)+q[b]
l[-1]-=k while l[-1]>k/2):y<?.?(x==z ?l[-1]=0:l<<(l.pop||0)-q[b]
l[-1]+=k while l[-1]<-k/2-1):y<?>?t[a]+=a<1?q[b].to_s.bytes: [q[b]]:y<???
(t[b]+=b<1?q[a,x].to_s.bytes: [q[a,x]]): l[-1]==0?t[a]=[]:0
z||x}while c !~/^(\d+|.)$/)}
s=->c{(z=c.scan(/(\((\g<1>|\s)+\)|[^()\s]+)/m)).map &r}
s[f]
$><<t[15].reverse.map(&:chr)*'')rescue 0
Value Ink
fonte
+1 de qualquer maneira. Você tentou o programa fibonacci?
Edc65
@ edc65 O programa de sequência de Fibbonacci também imprime a coisa errada: 0 1 1 2 4 8 16...Gostaria de saber se é um erro de especificação.
Value Ink
Não, o programa de Fibonacci é uma porcaria, por exemplo, a linha a+0é um absurdo
edc65
Eu acho que o problema dos números primos é que ele não lida com estruturas de controle aninhadas, mas eu não sei muito sobre ruby, duvido que meu palpite esteja correto.
Este programa deve manipular conjuntos de parênteses aninhados corretamente devido à correspondência regex recursiva /(\((\g<1>|\s)+\)|[^()\s]+)/musada para dividir em tokens e grupos de tokens. ( Teste-o no regex101 ). Provavelmente é um erro no restante da análise, mas não sei onde.
Value Ink