Intérprete auto interpretado


25

Con base en un comentario de George Edison a esta pregunta , escriba el intérprete de interpretación más pequeño.

  • Puede usar el idioma que elija.
  • Los idiomas vacíos no cuentan. Su programa debe tener al menos dos caracteres de longitud.
  • El programa no necesita interpretar todo el idioma, solo un subconjunto completo de características de lenguaje de Turing (que contiene el intérprete).
  • Las quines no cuentan.
  • No utilice la evalfunción integrada de su idioma o equivalente. Lo mismo vale para apply, etc.

1
(Hmm ... debería hacer algo con /usr/bin/cat) ¿qué pasa con la integridad de Turing?
Ming-Tang

@ SHiNKiROU: Gracias, no pensé en eso como una prueba. Actualizado.
Hoa Long Tam

Relacionado: Lenguaje con el intérprete más pequeño escrito en sí mismo en Stack Overflow, aunque hay pocas (¿solo una?) Respuestas que realmente cumplan con las reglas que se dan aquí.
dmckee

1
¿Tenemos que reescribir ese analizador de Schep sexp, o podemos considerar que el idioma del host está bien?
JB

@JB: Las utilidades de procesamiento de cadenas del lenguaje están bien, incluido el sexpanalizador.
Hoa Long Tam

Respuestas:


19

CI - 260

,(1p0(2d())(41(2d())('#((1p0()(10()(1d,1p$)=)<)$2d,1p$)(40(1d,1c$^)(''(1d,^)('0
'9('0-(,'0'9('0-2p10*+1p$)(!1d)~)$^)(0($)'$(^)'^(&)'&(c)'c(p)'p(d)'d(=)'=(<)'<(
>)'>(~)'~(.)'.(,)',(!)'!(+)'+(-)'-(*)'*(/)'/(%)'%()38p(1p3p0(3d)((2)(3)=p1d1p$)
=)$)~)=)=,2p$&)=)=)<)$$

320 → 260: empuje asignaciones simples de caracteres a instrucciones, luego dóblelas sobre ellas. Esto reduce a la mitad el tamaño del código por caso (hay 18 casos), pero cuesta 30 caracteres hacer el plegado.

Este es otro de mis lenguajes construidos (intérprete base alojado en Gist ). Es único en que el lenguaje reifica fragmentos de código. Es decir, las cadenas de instrucciones en este lenguaje basado en la pila se usan con el mismo efecto que las estructuras de datos o los cierres en otros idiomas:

1^      # Push a 1, and "lift" it to be a code literal.
(5 +)   # Define a code literal.
&       # Join the two code literals, forming (1 5 +)
$       # Execute the code literal.

El intérprete crea un fragmento de código de todo el programa antes de ejecutarlo, por lo que también puede considerarse un compilador. Debido a esto, apilar el intérprete no da como resultado una sobrecarga de tiempo de ejecución exponencial.

El intérprete deriva todos sus operadores directamente del intérprete anfitrión. Sin embargo, realiza el análisis por sí mismo, por lo que la mayoría del código son solo secuencias que traducen caracteres a sus respectivos literales de código. Esto no es lo mismo que usar eval, pero revela cuán dependiente es la implementación de cualquier lenguaje de programación de la semántica de su lenguaje / arquitectura host.


Referencia idiomática:

Consigue el intérprete aquí

Bloques

  • ( ... )

    Cree un "bloque", que es efectivamente una lista de instrucciones sin contexto. Internamente, incluso podría ser código de máquina.

  • bloquear $

    Llamar a un bloque. El destinatario recibe la pila global, que incluye el bloque que se llama.

  • valor ^

    Levantar un valor. Es decir, conviértalo en un bloque que empuje ese valor.

    Ejemplo :

       1 ^
    == (1)
    
  • bloque1 bloque2 &

    Une dos bloques, formando uno que corra ambos en secuencia.

    Ejemplo :

       (1) (2) &
    == (1 2)
    

Manipulación de la pila

  • norte c

    Copie el enésimo valor de la pila.

    Ejemplo :

       5 4 3 2 1 0 3c
    == 5 4 3 2 1 0 3
    
  • norte p

    Arranque el enésimo valor de la pila (quítelo y tráigalo al frente).

    Ejemplo :

       5 4 3 2 1 0 3p
    == 5 4 2 1 0 3
    
  • norte d

    Descarte n valores de la pila. 0des un no-op.

    Ejemplo :

       5 4 3 2 1 0 3d
    == 5 4 3
    

Operadores relacionales

  • ab (en_verdadero) (en_falso) =

    Prueba si a es igual a b. Consume todo excepto el primer argumento y llama a on_true o on_false. Si un argumento es cero y el otro es de cualquier otro tipo, el resultado será falso. De lo contrario, ayb deben ser enteros.

    Ejemplo :

       3 3 ('0+ .) (1d) =
    == 3 '0+ .
    
  • ab (en_verdadero) (en_falso) <

    Pruebe si a es menor que b. ayb deben ser enteros.

    Ejemplo :

       3 5 (1d 5) () <
    == 3 1d 5
    == 5
    
  • ab (en_verdadero) (en_falso) >

    Pruebe si a es mayor que b. ayb deben ser enteros.

    Ejemplo :

       3 5 (1d 5) () >
    == 3
    
  • a lo hi (on_true) (on_false) ~

    Probar si lo <= a <= hi. a, lo y hi deben ser enteros.

    Ejemplo :

       3 0 10 ('0+ .) (1d) ~
    == 3 '0+ .
    

I / O

  • do .

    Pon el carácter c (consumiéndolo de la pila).

  • ,

    Consigue un personaje y empújalo a la pila. Si se alcanza el final del archivo, se empuja -1.

  • do !

    Desbloquea un personaje. Al igual que ungetc en C, solo se permite un retroceso.

Literales enteros

  • 'c

    Empuja el personaje c.

  • [0-9] +

    Empuje un entero decimal.

Aritmética

  • ab +
  • ab -
  • ab *

    Sumar / restar / multiplicar dos números.

    Ejemplo :

       3 5 + 7 3 + *
    == 80
    
  • ab /

  • ab %

    División y módulo. A diferencia de C, estos redondean hacia el infinito negativo.

Diverso

  • #comentario de código

    El #personaje comenta todo al final de la línea.

  • )

    Se usa para terminar bloques. También se puede usar para finalizar todo el programa.

  • Todos los demás personajes son ignorados.


24

Cálculo binario de Lambda, 232 bits (29 bytes)

0101000110100000000101011000000000011110000101111110011110000101110011110000001111000010110110111001111100001111100001011110100111010010110011100001101100001011111000011111000011100110111101111100111101110110000110010001101000011010

Ver http://en.wikipedia.org/wiki/Binary_lambda_calculus#Lambda_encoding para más detalles


2
¿Por qué no es esta la respuesta aceptada D: BLC es increíble!
gato

¿Puedes explicarlo?
PyRulez

1
Desafortunadamente, Wikipedia eliminó la página Binary Lambda Calculus. Mi página tromp.github.io/cl/cl.html enlaza a una copia preservada y a un documento que escribí explicando el funcionamiento del intérprete.
John Tromp

13

No puedo tomar el crédito por este , pero pensé que compartiría este increíble:

Cerebro *** (423)

>>>+[[-]>>[-]++>+>+++++++[<++++>>++<-]++>>+>+>+++++[>++>++++++<<-]+>>>,<++[[>[
->>]<[>>]<<-]<[<]<+>>[>]>[<+>-[[<+>-]>]<[[[-]<]++<-[<+++++++++>[<->-]>>]>>]]<<
]<]<[[<]>[[>]>>[>>]+[<<]<[<]<+>>-]>[>]+[->>]<<<<[[<<]<[<]+<<[+>+<<-[>-->+<<-[>
+<[>>+<<-]]]>[<+>-]<]++>>-->[>]>>[>>]]<<[>>+<[[<]<]>[[<<]<[<]+[-<+>>-[<<+>++>-
[<->[<<+>>-]]]<[>+<-]>]>[>]>]>[>>]>>]<<[>>+>>+>>]<<[->>>>>>>>]<<[>.>>>>>>>]<<[
>->>>>>]<<[>,>>>]<<[>+>]<<[+<<]<]

10

BlockScript - 535

{[B':=?0:B';=?0:B'}=?0:B'{=?,A!,A!d1c&:B'?=?,A!,A!2e&:B''=?,,A!d3c&:B{[B'0<?0:B
'9>?0:1}!?B'0-{[,g!?c'0-B10*d+A!:Bd]A!d3c&}!:B'#=?{[,10=?,]A!:A!}!:,A!Bb&}{[AC[
B]DB?[AB{[Bh&hbhn!}{[B[AB]C?1-eA!:b}&[C1=?E[C]FHc&B!:C2=?{G?D:E[C}!FHcI!:C3=?E[
C]B!:C'!=?G[ABC]Hc&dbh&D?b@I!B!:b@I!:C'&=?HB!:C'@=?FGDI!:C'[=?GF&HDI!:C']=?F[A]
HDI!:C',=?,B!:C'.=?G.FHDI!:C'a'z{[DC<?0:DB>?0:1}!?Ce-HA!B!:C'A'Ze!?F[B]Cg-dA!B!
:{C'+=?{[CB+}:C'-=?{[CB-}:C'*=?{[CB*}:C'/=?{[CB/}:C'%=?{[CB%}:C'<=?{[CB<}:C'>=?
{[CB>}:C'==?{[CB=}:0}!?H[A][B]Ge!B!:FHDI!:c},c!0ac&0&0&0bho!;

BlockScript es un lenguaje trivial basado en la pila de espagueti que creé específicamente para este desafío. El intérprete base es blockscript.c .

Programa de muestra (imprime los primeros 15 números de Fibonacci):

{[B?B10/A!B10%d&:0}
{[B0<?'-.0B-A!:{B?Bh!{[B?B[A]A!B[B]'0+.:}!:'0.}!10.}
{[B?Dd!DC+B1-CecA!:}
0 1 15d!
;

El intérprete lee el código fuente y la entrada del programa desde la entrada estándar, en ese orden. Esto significa que para ejecutar un intérprete dentro de un intérprete dentro de un intérprete, simplemente copie y pegue:

# Level 1
{[B':=?0:B';=?0:B'}=?0:B'{=?,A!,A!d1c&:B'?=?,A!,A!2e&:B''=?,,A!d3c&:B{[B'0<?0:B
'9>?0:1}!?B'0-{[,g!?c'0-B10*d+A!:Bd]A!d3c&}!:B'#=?{[,10=?,]A!:A!}!:,A!Bb&}{[AC[
B]DB?[AB{[Bh&hbhn!}{[B[AB]C?1-eA!:b}&[C1=?E[C]FHc&B!:C2=?{G?D:E[C}!FHcI!:C3=?E[
C]B!:C'!=?G[ABC]Hc&dbh&D?b@I!B!:b@I!:C'&=?HB!:C'@=?FGDI!:C'[=?GF&HDI!:C']=?F[A]
HDI!:C',=?,B!:C'.=?G.FHDI!:C'a'z{[DC<?0:DB>?0:1}!?Ce-HA!B!:C'A'Ze!?F[B]Cg-dA!B!
:{C'+=?{[CB+}:C'-=?{[CB-}:C'*=?{[CB*}:C'/=?{[CB/}:C'%=?{[CB%}:C'<=?{[CB<}:C'>=?
{[CB>}:C'==?{[CB=}:0}!?H[A][B]Ge!B!:FHDI!:c},c!0ac&0&0&0bho!;

# Level 2
{[B':=?0:B';=?0:B'}=?0:B'{=?,A!,A!d1c&:B'?=?,A!,A!2e&:B''=?,,A!d3c&:B{[B'0<?0:B
'9>?0:1}!?B'0-{[,g!?c'0-B10*d+A!:Bd]A!d3c&}!:B'#=?{[,10=?,]A!:A!}!:,A!Bb&}{[AC[
B]DB?[AB{[Bh&hbhn!}{[B[AB]C?1-eA!:b}&[C1=?E[C]FHc&B!:C2=?{G?D:E[C}!FHcI!:C3=?E[
C]B!:C'!=?G[ABC]Hc&dbh&D?b@I!B!:b@I!:C'&=?HB!:C'@=?FGDI!:C'[=?GF&HDI!:C']=?F[A]
HDI!:C',=?,B!:C'.=?G.FHDI!:C'a'z{[DC<?0:DB>?0:1}!?Ce-HA!B!:C'A'Ze!?F[B]Cg-dA!B!
:{C'+=?{[CB+}:C'-=?{[CB-}:C'*=?{[CB*}:C'/=?{[CB/}:C'%=?{[CB%}:C'<=?{[CB<}:C'>=?
{[CB>}:C'==?{[CB=}:0}!?H[A][B]Ge!B!:FHDI!:c},c!0ac&0&0&0bho!;

# Level 3
{[B?B10/A!B10%d&:0}
{[B0<?'-.0B-A!:{B?Bh!{[B?B[A]A!B[B]'0+.:}!:'0.}!10.}
{[B?Dd!DC+B1-CecA!:}
0 1 15d!
;

Al igual que la película Inception , prácticamente no puedes ir más allá de los tres niveles. No es cuestión de tiempo, sino de espacio. BlockScript pierde profusamente la memoria, y esto tiene que ver con cómo está diseñado el lenguaje en sí.


Referencia idiomática:

Consigue el intérprete aquí

En BlockScript, la "pila" no es una matriz que se sobrescribe por operaciones posteriores como está acostumbrado. En realidad, se implementa como una lista vinculada inmutable, y una pila persiste durante la duración del programa. Además, ningún operador (excepto @) elimina valores de la pila. Sin embargo, las modificaciones de la pila solo afectan el bloque en el que ocurren.

Selección de valor

  • a mediante z

    Obtenga el elemento 0-25o de la pila y empújelo hacia la pila. ase refiere a la cabeza, o al elemento empujado más recientemente, de la pila.

  • A mediante Z

    Obtenga el elemento 0-25 del marco actual y empújelo a la pila.

  • [

    Abra un "marco" para seleccionar elementos de la referencia de la pila (ver más abajo) en el encabezado de la pila. [no requiere una coincidencia ], pero los marcos tienen un alcance léxico. En BlockScript, el "alcance" está determinado por llaves ( {... }) que forman bloques. Por lo tanto, abrir un marco dentro de un bloque no tendrá ningún efecto en el código fuera del bloque.

  • ]

    Cierre el marco actual, volviendo al marco anterior (si lo hay).

Bloques

  • { ... }

    Crea un "bloque" y empújalo a la pila. Dentro de un bloque, la pila comenzará en lo que era antes del bloque, excepto que la pila de la persona que llama será empujada hacia arriba. Las pilas son persistentes e inmutables en BlockScript, por lo que los bloques son cierres. El modismo {[significa abrir un bloque, luego abrir un marco para comenzar a seleccionar argumentos (usando a Através de Z). El valor de retorno de un bloque es la cabeza de la pila cuando }se alcanza.

    Ejemplo:

    '3 '2 '1 {[ b. d. f. B. C. D. A! } 'D 'C 'B d!;
    

    Esto imprime 123BCD123DCB123BCD123DCB…. Las letras minúsculas se refieren a los valores de la pila, mientras que las letras mayúsculas se refieren a los argumentos (porque el marco se establece en la pila de la persona que llama). A!toma la cabeza de la persona que llama (que se garantiza que es el bloque que se llama) y lo llama. Si se pregunta por qué se invierte BCDcada dos veces, es porque B. C. D.empuja esos argumentos en orden inverso justo antes de que el bloque se llame a sí mismo.

  • !

    Llamar a un bloque. Empuje el valor de retorno a la pila.

Referencias de pila

  • &

    Cree una referencia de pila y empújela a la pila. Piense en esto como "super-contras", ya que efectivamente toma cada elemento en la pila y forma una "tupla". La expresión &[significa que cualquier cosa a, b, chace referencia ahora se puede acceder antes con A, B, C(para el resto del bloque o hasta que ]se encuentra).

    En parte porque &captura más valores de los que generalmente necesita, BlockScript pierde memoria por diseño.

  • @

    Cambie a la pila a la que apunta la referencia de la pila a. Este operador es bastante extraño, pero el autointerpretador BlockScript lo usa un par de veces para evitar tener que empujar los mismos argumentos dos veces. Los efectos de @(o cualquier operación de pila, para el caso) se limitan al bloque en el que se invoca. Además, el marco no se ve afectado @, por lo que se puede usar para tomar los valores que necesita después de cambiar las pilas.

Expresión condicional

  • ? <en verdadero> : <en falso>

    Expresión condicional, al igual que el operador ternario en C. Es decir, si aes "verdadero" (es decir, no es igual al entero cero), entonces haga <en verdadero> , de lo contrario haga <en falso> .

I / O

Nota: La entrada y salida se realizan en UTF-8. Un "carácter" es un número entero que corresponde a un índice Unicode.

  • ,

    Obtenga el siguiente carácter de entrada y empújelo a la pila. Si se alcanza el final de la entrada, presione -1 en su lugar.

  • .

    Salida del personaje en la cabeza de la pila.

Enteros / literales de caracteres

Nota: Los enteros y los caracteres son lo mismo en BlockScript.

  • 'c

    Empuja el personaje c.

  • [0-9] +

    Empuje un entero decimal.

Aritmética

Estos operadores solo funcionan con valores enteros.

  • +Compute b+ a(empujando el resultado, pero sin descartar ninguno de los valores).
  • -Calcular b- a.
  • *Calcular b* a.
  • /Calcular b/ a(división entera; se redondea hacia el infinito negativo).
  • %Calcular b% a(módulo entero; se redondea hacia el infinito negativo).

Operadores relacionales

Estos operadores solo funcionan con valores enteros.

  • <Si bes menor que a, presione 1, de lo contrario presione 0.
  • >
  • =

Diverso

  • # Comentario al final de la línea
  • El programa debe terminar con ;
  • Todos los demás personajes son ignorados.

2
Cristo. ¿Te gustaría compartir las especificaciones como lo hiciste para CI?
Casey

@Casey: se agregó una referencia.
Joey Adams

1
¿Te interesaría saber que estás soñando? ... En el nivel 4.
Mateen Ulhaq

3

Zozotez LISP : 414

los avances de línea agregados para obtener un buen bloque no son necesarios y no se cuentan.

((\(E V A L)(E(r)'(())))(\(x e)(?(s x)(V x e)((\(b j)(?(= b ")(a j)(?(= b \)x
(?(= b ?)(?(E(a j)e)(E(a(d j))e)(E(a(d(d j)))e))(?(s b)(A b(E(a j)e)(E(a(d j)
)e))(E(a(d(d b)))(L(a(d b))j e)))))))(E(a x)e)(d x))))(\(x g)(? g(?(= x(a(a
g)))(d(a g))(V x(d g)))x))(\(f h v)(?(= f r)(r)(?(= f p)(p h)(?(= f s)(s h)(?
(= f a)(a h)(?(= f d)(d h)(?(= f =)(= h v)(c h v))))))))(\(k v i)(? k(L(d k)(
d v)(c(c(a k)(E(a v)i))i))i)))

En teoría, debería poder ejecutarse solo, pero dado que el intérprete original es un binario BrainFuck y en sí mismo un intérprete, solo he podido probar cada parte. Cuando se da solo y una expresión simple (p p), creo que necesita más tiempo que los 40 minutos que he esperado hasta ahora y estoy usando mi ayuno jitbfpara ejecutarlo que (mal) usa Perl Inline-C para ejecutar el código C sobre la marcha.

Es imposible implementar todo el Zozotez en Zozotez ya que no tiene medios para mutar contras y : (setq / define) lo necesita para actualizar los enlaces. Tampoco implementé argumentos explícitos de inicio / progreso o descanso, macros y argumentos especiales de impresión ya que no lo usé en el intérprete. Incluí p(imprimir) aunque no lo uso, por lo que los programas necesitan imprimir explícitamente sus cálculos al igual que el intérprete original.

Lo mismo sin golf:

;; A stand alone Zozotez script need to be
;; contained in one expression, here with
;; all functions provided as arguments to
;; get them bound in the dynamic environment
((\ (E V A L)
  (E(r)'(())))
 ;; E (EVAL)
 (\ (x e)
   (? (s x)
      (V x e)
      ((\ (b j)
         (? (= b ") (a j)
         (? (= b \) x
         (? (= b ?) (? (E(a j)e) (E(a(d j))e) (E(a(d(d j)))e))
         (? (s b)
            (A b (E(a j)e) (E (a(d j))e))
            (E (a(d(d b))) (L(a(d b))j e)))))))
       (E (a x) e)(d x))))
 ;; V (VALUE / symbol->value)
 (\ (x g)
   (? g
      (? (= x (a (a g)))
         (d (a g))
         (V x (d g)))
      x))
 ;; A (APPLY) but just for primitives
 (\ (f h v)
   (? (= f r) (r)
   (? (= f p) (p h)
   (? (= f s) (s h)
   (? (= f a) (a h)
   (? (= f d) (d h)
   (? (= f =)
      (= h v)
      (c h v))))))))
 ;; L ( joint evLis / extend-env)
 (\ (k v i)
   (? k
      (L (d k) 
         (d v)
     (c (c (a k) 
           (E (a v) i)) 
        i))
      i)))

0

CHIQRSX9 + (probablemente no competidor), 2 bytes

+I

No hay forma de escribir un intérprete de autointerpretación en este lenguaje basado en HQ9 + sin usar I, que ejecuta un intérprete incorporado que procesa STDIN.


1
En ninguna parte de las reglas dice que no se permiten intérpretes incorporados. Dice for eval, que es para expresiones, no para programas.
Erik the Outgolfer

¿Cómo se calculan los números primos en este idioma?
pppery

XSe supone que @ppperry hace que el lenguaje Turing sea completo (por lo tanto, capaz de calcular números primos) de una manera dependiente de la implementación.
user8397947

Según la página de Esolang, el Xcomando del intérprete de Perl perturba aleatoriamente el programa y lo ejecuta, lo que significa que no se puede usar el comando para calcular primitivamente determinísticamente. ¿Me puede dar un intérprete de ejemplo que le permita usar Xde la manera que especificó?
pppery

@ppperry Aparentemente, el intérprete escrito en Perl es el único intérprete, así que no. Además, ¿qué pasa si hay un programa que calcula números primos cuando se "aleatoriza" con un valor específico?
user8397947

0

Sistema de archivos concurrente Befunge 98 - 53 \ 18 bytes (casi seguro trampa)

Intérprete completo de 53 bytes sin restricciones (aunque no he probado interacciones de tiempo complicadas que involucran división y ajuste de IP):

v ;;;;;;;;
>]390'ai@
 t;;;;;;;;
;>zzzzz#;

Lee la entrada de un archivo llamado ay lo ejecuta. No se especifica en las reglas que no podemos usar código auto modificable.

Intérprete de 18 bytes que no permite el ajuste (la IP se mueve de un borde del código y comienza en el borde opuesto):

]210'ai@
t
><
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.