Interpretar Volátil

11

Interpretar Volátil

Volatile é um esolang baseado em pilha feito por A_ / a '_' / A que possui apenas 8 instruções e está completo. No entanto, também não é determinístico ... o que significa que os programas nem sempre dão a mesma saída. Sua tarefa é interpretar esse idioma.

Especificações de idioma

Retirado da página esolangs:

~: Push a random integer in any range of integers. Minimum range of 0 through 32768

+: Pop 2 values and push the sum of the 2 values

-: Like +, but subtracts

*: Multiply

/: Divide. 0-division will result in an error.

:: Duplicate the top of the stack

.: Output the top of the stack without popping it


(...): Execute ... inside a while loop when the top of the stack is not 0

Tudo o mais é desconsiderado

Entrada

Observe que esses programas podem falhar aleatoriamente

~:/::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.~:/:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.~:/::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.~:/::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.~:/:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.~:/::::::::::::::::::::::::::::::::::::::::::::++++++++++++++++++++++++++++++++++++++++++++.~:/::::::::::::::::::::::::::::::::++++++++++++++++++++++++++++++++.~:/:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.~:/:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.~:/::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.~:/::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.~:/::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.~:/:::::::::::::::::::::::::::::::::+++++++++++++++++++++++++++++++++.~:/::::::::::++++++++++.

~:-.~:/+.(~:/+.)

~:-:/

Resultado

73 102 109 109 112 45 33 120 112 115 109 101 34 11

0 1 2 3 4 5 6 7 8 9 ...

<Any Error Message>

Mais exemplos, bem como uma implementação de referência (use o segundo, encontrado em (Outro) intérprete python 3 ) podem ser encontrados em https://esolangs.org/wiki/Volatile

Pontuação

Isso é código-golfe, então a resposta mais curta em bytes ganha

Classificação

Aqui está um snippet de pilha para gerar uma classificação regular e uma visão geral dos vencedores por idioma.

Para garantir que sua resposta seja exibida, inicie-a com um título, usando o seguinte modelo de remarcação:

# Language Name, N bytes

onde Nestá o tamanho do seu envio. Se você melhorar sua pontuação, poderá manter as pontuações antigas no título, identificando-as. Por exemplo:

# Ruby, <s>104</s> <s>101</s> 96 bytes

Se você quiser incluir vários números no cabeçalho (por exemplo, porque sua pontuação é a soma de dois arquivos ou você deseja listar as penalidades do sinalizador de intérpretes separadamente), verifique se a pontuação real é o último número no cabeçalho:

# Perl, 43 + 2 (-p flag) = 45 bytes

Você também pode transformar o nome do idioma em um link que será exibido no snippet do placar de líderes:

# [><>](http://esolangs.org/wiki/Fish), 121 bytes

Lyxal
fonte
2
A divisão deve arredondar para 0?
Grimmy
Empurra ~um número inteiro ou qualquer número?
mbomb007
1
Além disso, dependendo da implementação, isso pode não ser realmente não determinístico. Claro, a página esolang afirma que é, mas isso é apenas devido à maneira listada para envio 1, que pode ser dividida por zero. ~deve poder pressionar zero, caso contrário, é determinístico. Além disso, o RNG sempre deve poder retornar zero após qualquer número de zeros consecutivos.
mbomb007
2
Essa segunda entrada não deve ~:-.~:/+.(~:/+.)começar em 0 1 2 ...vez de 1 2 3 ...? A ~:-.resultaria em 0 que ele gera. Os intérpretes da página Esolang parecem confirmar isso ( aqui o segundo ).
Kevin Cruijssen 10/09/19
2
Sugestão para adicionar um caso de teste:~:-.(~:/+.)
Night2 11/11/19

Respostas:

6

05AB1E , 35 bytes

"~:/.()"”žGÝΩ DŠéõq}÷ = [D_# }”#‡.V

Experimente online!

Transpila o código volátil para 05AB1E e o avalia. *, +E -pode ser deixado como está. :,, .e )possui um byte equivalente direto. Os outros comandos levam alguns bytes cada. Infelizmente, 05AB1E não falha na divisão por 0, então isso é implementado por uma condição "encerre se o topo da pilha == 0".

Grimmy
fonte
1
Isso funciona corretamente para o loop. Se eu inserir o segundo caso de teste parece ouput 0e 1corretamente antes do loop, mas, em seguida, ele começa a produzir o programa volátil (a entrada implícita) em si. Eu gosto dessa D Doingõqstring de dicionário para a instrução if, btw! :)
Kevin Cruijssen 10/09/19
1
@KevinCruijssen o exemplo parece assumir que o loop é a while peek, mas no intérprete de referência é a while pop. O exemplo pode ser corrigido adicionando alguns :( TIO ). Como alternativa, meu código pode ser alterado para a while peekadicionando a D.
Grimmy
1
Ambos os intérpretes de referência do Esolang ainda emitem 0 1 2 3 ..., no entanto. Eu não olhei para o código fonte deles, mas tentei os dois.
Kevin Cruijssen 10/09/19
1
@KevinCruijssen Oh, a função é chamada pop, mas na verdade é uma espiada. Maximamente confuso. Eu adicionei o Dno meu código.
Grimmy
Lol .. Nomes internos confusos me lembram os replacevs do Java replaceAll(que substituem todas as ocorrências, mas replaceAllusam expressões regulares e a outra não). xD
Kevin Cruijssen
4

Julia 1.0 , 334 bytes

a\b=push!(a,b)
a=pop!(a)
v(q,s=[],l=0)=(i=1;
for c in q
!r=c==r
i+=1
!')' ? (l<1 && break;l-=1) :
!'(' ? (while s[end]!=0 v(q[i:end],s) end;l+=1) :
l>0 ? continue :
!'~' ? s\rand(Int) : 
!'+' ? s\(s+√s) :
!'-' ? s\(s-√s) :
!'*' ? s\(s*√s) :
!'/' ? s\(s÷√s) :
!':' ? s\s[end] :
!'.' ? print(s[end]," ") : 0
end)

Meu primeiro "intérprete" de qualquer tipo, foi mais fácil do que eu esperava. Eu pratiquei golfe básico, mas provavelmente há espaço para mais. Eu fiz imprimir um espaço após a saída para. mach para exemplo de saída. A versão ungolfed está no cabeçalho no link TIO. Exemplo de uso v("~:-:/").

+41 bytes para corrigir o erro Night2 indicado adicionando um contador de loop. Agora vejo por que transpilar é uma boa opção. Um bom caso de teste é ~:-.(~:/+.)(~:/+.())~:-.com a saída esperada0 0

Experimente online!

gggg
fonte
3

Encantos Rúnicos , 266 264 bytes

DS͗{r;'ui[0[0y̤<<<<<?+f2,;$"!0/"?*7≠0:S͗\
RS͗}:'~=?!\:':=?!\:'+=?!\:'-=?!\:'/=?!/:'.=?!\:'*=?!\:';=?!;:')≠3*?04B͍:'(=?!S͗
U/lA`R耀`S͗/?7  :S͗/?+f1+S͗/?3  -S͗/?3     $ '$:S͗/?7  *S͗/
U\m(d*?"SO!"$;
{:'(=?!\:')=?!\R
~/?)0l{͗/?8 {͗l}͗/U
 \}͗21B͍

Experimente online!

Devido às limitações embutidas no Runic, ele suporta apenas comprimentos de programa (e tamanho da pilha) de ~ 50 1 . Programas grandes demais simplesmente falham. Se a pilha crescer muito, ocorrerá um erro SO!(não foi necessário, mas foi melhor que a finalização silenciosa; custou 24 bytes). Se o programa tentar dividir por 0, será impresso /0!.

Os erros são anexados ao final da saída padrão, pois o Runic não tem como gravar em STDERR.

Esta versão suporta programas arbitrariamente longos, mas ainda está limitada a uma pilha de ~ 90 (e, portanto, erros no segundo resultado do primeiro programa de teste) e não foi muito bem-sucedida (o aumento no comprimento do comando entre S͗}:e S͗}͍:0%:exigia alguns espaçamento adicional para alinhar as seções, mas esse espaço extra também permitiu mais< para um tamanho máximo de pilha maior).

Como alternativa, este programa evitará ~gerar um zero e o programa será encerrado após 1 milhão de etapas de execução (uma proteção contra loops infinitos incorporados ao intérprete Runic). Também inclui alguns bytes para pular o excesso de espaço NOP e executar um pouco mais.

  1. Ocorre uma falha de tamanho excessivo da pilha em (IP mana + 10) e o check-in que fiz para a pilha do Volatile é sizeof(stack) < manae há 5 IPs que mesclam e combinam sua mana (50 inicial). Aumentar esse valor para o limite verdadeiro (o +10) custaria mais 2 bytes e eu deixei a lógica de golfe em vez de precisa.

Explicação

Fluxo volátil

  1. O programa começa na área azul do centro superior ao longo <<<<<dos cinco IPs e se fundem noy
  2. O IP se move para a esquerda, configurando as pilhas e lendo a entrada e se move para a seção ciano
  3. O IP se move para a direita nessa linha, verificando o caractere superior na pilha para saber qual é o comando. Essa linha continua à direita além do visível. quando a instrução correta é encontrada, ele executa o código na linha abaixo à esquerda (pulando outras seções para retornar ao ciano pelo azul).
  4. A seção magenta é executada durante ~ou: comandos para erro no estouro da pilha; a seção amarela é pulada se a pilha não estiver cheia demais e retorna via azulejo para o azul escuro.
  5. Distante à direita, quando )encontrado, o programa ramifica para a seção vermelha e move-se para a direita.
  6. Esta seção gira a pilha de comandos para a direita até que a (seja encontrada (continue em verde).
  7. Para cada adicional )é encontrado (continue em laranja), a pilha de profundidade da pilha é aumentada e, quando (for encontrado, a pilha de profundidade da pilha é exibida uma vez (prossiga na reentrada em verde escuro e laranja)
  8. Se a pilha de profundidade estiver vazia, continue seguindo o verde até o Bretorno e retorne para ciano no loop de análise principal; caso contrário, enrole em laranja-> amarelo-> vermelho (reinsira o loop de redefinição do loop).
  9. O roxo no canto superior direito lida com a divisão. Se o valor a ser dividido é 0, a seção marrom lida com o erro e a finalização. Re-entra no loop de análise principal pulando a seção ciano.
Draco18s não confia mais no SE
fonte
2

PHP , 196 bytes

eval(strtr($argn,[':'=>($v='$a[]=').$e='end($a);','~'=>$v.'rand();','+'=>($q=$v.$p='array_pop($a)')."+$p;",'-'=>"$q-$p;",'*'=>"$q*$p;",'/'=>"$q/$p;",'.'=>"echo' ',$e",'('=>"for(;$e){",')'=>'}']));

Entrada 1: Experimente online!

Entrada 2 (0, 1, 2, ...): Experimente online!

Entrada 3 (erro de divisão por zero): Experimente online!

Apenas traduz o código para PHP e o avalia!

Night2
fonte
2

JavaScript (V8) ,  178 172  171 bytes

Transpiles para JS. Pode lançar um Z is not definedou x is not definedse o código tentar fazer algo ruim.

s=>eval(s.replace(/./g,c=>`S.push(${c>'}'?'x=Math.random()*1e5|0':c>'9'?'x':c=='.'?');print(x':c<')'?');while(x){(0':c<'*'?')}(0':`1/(x${c}=S.pop(S.pop()))?x:Z`});`,S=[]))

Experimente o 1º programa online!

Experimente o 2º programa online!

Experimente o terceiro programa online!

Quão?

Cada instrução é transpilada para S.push(, seguida por um padrão específico, seguido por );.

Temos que testar a divisão por zero explicitamente, porque JS não dá a mínima para uma operação tão inofensiva. :-p

Caracteres. | Código JS
------- + --------------------------------------
   ~ S.push ( x = Math.random () * 1e5 | 0 );
   + | S.push ( 1 / (x + = S.pop (S.pop ()))? X: Z );
   - | S.push ( 1 / (x- = S.pop (S.pop ()))? X: Z );
   * S.push ( 1 / (x * = S.pop (S.pop ()))? X: Z );
   / | S.push ( 1 / (x / = S.pop (S.pop ()))? X: Z );
   : | S.push ( x );
   . | S.push ( ); impressão (x );
   (| S.push ( ); while (x) {(0 );
   ) S.push ( )} (0 );
Arnauld
fonte
2

Java 8, 420 418 402 373 359 357 341 bytes

import java.util.*;s->f(s,new Stack());void f(String s,Stack<Integer>S){for(int i=0,c,t,u;i++<s.length();){if((c=s.charAt(i-1))<42&&S.peek()!=0)f(s.substring(40/c*i),S);if(c==46)System.out.println(S.peek());if(c>57)S.add(c>99?new Random().nextInt():S.peek());if(c<44|c==45|c==47){t=S.pop();u=S.pop();S.add(c<43?u*t:c<45?u+t:c<46?u-t:u/t);}}}

-2 bytes graças a @Grimy .
-16 bytes graças a @ceilingcat .

Experimente online.

Explicação:

import java.util.*;       // Required import for 2x Stack and Random

s->                       // Method with String parameter and no return-type
  f(s,new Stack())        //  Call the recursive function, with a new Stack

// Separated recursive method with String and Stack parameters
void f(String s,Stack<Integer>S){
  int i=0,                //  Index integer
      c,                  //  Temp integer used for the current character
      t,u;                //  Temp integers used for the peeked/popped top of the stack
  for(;i++<s.length();){  //  Loop `i` in the range [0, String-length):
    if((c=s.charAt(i-1))  //   Set `c` to the current character
        <42               //   If the character is either '(' or ')',
        &&S.peek()!=0)    //   and the top of the stack is not 0:
         f(s.substring(   //    Take the substring, either removing everything before and
            40/c*i),      //    including the "(", or keeping the string as is for ")"
           S);            //    And do a recursive call with this String
    if(c==46)             //    If the character is '.'
      System.out.println( //     Print with trailing newline:
       S.peek());         //      The peeked top of the stack
    if(c>57)              //    If the character is ':' or '~':
      S.add(c>99?         //     If the character is '~':
        new Random().nextInt()
                          //      Add a random [0,2147483647) integer to the stack
       :                  //     Else (the character is ':')
        S.peek());        //      Add the peeked top to the stack
    if(c<44|c==45|c==47)  //    If the character is '*', '+', '-', or '/':
      t=S.pop();u=S.pop();//    Pop and set the top two values to `t` and `u`
      S.add(c<43?         //     If the character is '*':
        u*t               //      Add the product of the two values to the stack
       :c<44?             //     Else-if the character is '+':
        u+t               //      Add the sum of the two values to the stack
       :c<46?             //     Else-if the character is '-':
        u-t               //      Subtract the top two values, and add it to the stack
       :                  //     Else (the character is '/'):
        u/t;}}}           //      Divide the top two values, and add it to the stack
Kevin Cruijssen
fonte
1
new Random().nextInt()é 2 menor que (int)(Math.random()*1e5).
Grimmy
@ Grimy Ah, esqueci que eu tinha essa java.util.*importação para o Stack. Obrigado! :)
Kevin Cruijssen
@ceilingcat Obrigado por -16!
Kevin Cruijssen 17/09/19
Provavelmente isso vai contra uma ou mais regras de decoro, mas se você substituir new Random().nextInt()por 5todas as caixas de teste, ainda será aprovado.
ceilingcat
@ceilingcat Sim, mas 5não é exatamente aleatório ;) xkcd relevante
Kevin Cruijssen
2

C (gcc) para Linux x86_64, 675643621211313773404040 bytes

printf();*z;*mmap();(*p)();*j(char*a){char*t=a,*n,c;for(p=0;read(0,&c,!p);t=!~c?n=j(t+9),z=mempcpy(t,L"\xf00f883Ƅ",5),*z=n-t-9,n:!c?p=*t++=233,z=t,*z=a-13-t,z+1:stpcpy(t,c-85?c-2?c-4?c-1?c-6?c-17?"PAPTYh%ld T_P^1\xc0QH\x83\xcc\bQA\xff\xd0\\AXX":"P":L"\xfef7995e":"[\xf7\xeb":"[)\xd8":"[\1\xd8":L"\xf0c70f50"))c-=41;return t;}main(){p=mmap(0,1<<20,6,34,0,0);p(strcpy(j(p),"j<X\xf\5"),0,0,0,printf);}

Experimente online!

Este é um JIT que converte diretamente as instruções voláteis no idioma da máquina x86_64 e executa o código. Se a sua máquina não tiver as rdrandinstruções, você poderá substituirL"\xf0c70f50" -lo "Pj*X"por um " PRNG menos uniforme ". Para a porta para algo diferente de Linux, substitua as syscalls nos printf()e exit()blobs e ajustar parâmetros para mmap().

EDIT: Esta versão chama em printf()vez de implementar um subconjunto do zero.

EDIT2: números inteiros suportados agora são 32 bits em vez de 64.

Um pouco menos jogado ...

printf();*z;*mmap();(*p)();
// recursive function translates Volatile commands to x86_64 instructions
*j(char*a){
  char*t=a,*n,c;
  for(p=0;read(0,&c,!p);)
    c-=41,
    t=c=='('+41?
      // cmp eax,0
      // je n-t-9
      n=j(t+9),
      z=mempcpy(t,"\x83\xf8\x00\x0f\x84",5),
      *z=n-t-9,
      n
    :
      c==')'+41?
        // jmp a-13-t
        p=*t++=233,
        z=t,
        *z=a-13-t,
        z+1
      :
        stpcpy(t,c-'~'+41?
                   c-'+'+41?
                     c-'-'+41?
                       c-'*'+41?
                         c-'/'+41?
                           c-':'+41?
                             // ; This calls printf("%ld ",%rax)
                             // push rax
                             // push r8
                             // push rsp
                             // pop  rcx
                             // push 0x20646c25
                             // push rsp
                             // pop  rdi
                             // push rax
                             // pop  rsi
                             // xor  eax, eax
                             // push rcx
                             // or   rsp, 8
                             // push rcx
                             // call r8
                             // pop  rsp
                             // pop  r8
                             // pop  rax
                             "\x50\x41\x50\x54\x59\x68\x25\x6c\x64\x20\x54\x5f\x50\x5e\x31\xc0\x51\x48\x83\xcc\x08\x51\x41\xff\xd0\x5c\x41\x58\x58"
                           :
                             // push rax
                             "\x50"
                         :
                           // pop rsi
                           // cdq  
                           // idiv esi
                           "\x5e\x99\xf7\xfe"
                       :
                         // pop rbx
                         // imul ebx
                         "\x5b\xf7\xeb"
                     :
                       // pop rbx
                       // sub eax, ebx
                       "\x5b\x29\xd8"
                   :
                     // pop rbx
                     // add eax, ebx
                     "\x5b\x01\xd8"
                 :
                   // push rax
                   // rdrand eax
                   "\x50\x0f\xc7\xf0");
  return t;
}
main(){
  p=mmap(0,1<<20,6,34,0,0);
  p(strcpy(j(p),"\x6a\x3c\x58\x0f\x05"),0,0,0,printf);
}
teto
fonte
1

Kotlin , 412 bytes

Infelizmente, perdi para o Java, mas não queria import java.util.Stack(e não tenho certeza se isso diminuiria a diferença).

{p->var i=0
var s=List(0){0}
var c=List(0){0}
while(i<p.length){when(val o=p[i]){'~'->s+=(0..32768).random()
in "+-*/"->{val(a,b)=s.takeLast(2)
s=s.dropLast(2)+when(o){'+'->a+b
'-'->a-b
'*'->a*b
'/'->a/b
else->0}}
':'->s+=s.last()
'.'->println(s.last())
'('->{if(s.last()!=0)c+=i else{var z=0
do{if(p[i]=='(')z++else if(p[i]==')')z--
i++}while(z>0)
i--}}
')'->if(s.last()!=0)i=c.last()else c=c.dropLast(1)}
i++}}

Ungolfed

{ p ->                  // open lambda: p is the code string
    var i = 0           // program counter
    var s = List(0){0}  // data stack
    var c = List(0){0}  // jump stack

    // main loop
    while(i<p.length) {
        // match on the current character
        when(val o = p[i]) {
            // add random number to end of stack
            '~' -> s += (0..32768).random()
            // if a math op...
            in "+-*/" -> {
                // pick top stack items
                val (a, b) = s.takeLast(2)
                // pop two items and then push based on op
                s = s.dropLast(2) + when(o) {
                    '+' -> a+b
                    '-' -> a-b
                    '*' -> a*b
                    '/' -> a/b
                    else -> 0  // else is required here
                }
            }
            // duplicate top stack item
            ':' -> s += s.last()
            // print top stack item
            '.' -> println(s.last())
            // open loop
            '(' -> {
                if(s.last()!=0)
                    // push to jump stack if top of data stack is nonzero
                    c+=i
                else {
                    // skip ahead
                    var z=0
                    do {
                        // seek to matching brace
                        if(p[i]=='(') z++ else if(p[i]==')') z--
                        i++
                    } while(z>0)
                    // ensure program counter doesn't go too far
                    i--
                }
            }
            // close loop
            ')' -> if(s.last()!=0) i=c.last() else c=c.dropLast(1)
        }
        // next character
        i++
    }
}

Experimente online!

Caracol_
fonte