Interpreta tu lenguaje, pero no a ti mismo.


21

Hay muchos desafíos que dicen "interpretar X", donde X es un lenguaje simple. En mi opinión, eso es demasiado aburrido. Para darle a todas las personas que postergan las cosas en Internet algo interesante que hacer, puede intentar hacer este desafío:

Reto

Elige un idioma $LANG. $LANGpuede ser cualquier lenguaje de programación completo o un subconjunto completo de un lenguaje de programación. Tenga en cuenta que si omite una característica de su idioma $LANGpara la interpretación, no debe usarla para su propio programa, ya que su presentación también debe estar escrita $LANG.

Escriba un compilador / intérprete para $LANGescrito $LANG. Puede utilizar todas las facilidades (incluidos evaly amigos) de su idioma que están disponibles para escribir este compilador. Para hacer la tarea más desafiante, hay una restricción: su programa debe ser capaz de interpretar / compilar todos los programas válidos, $LANGexcepto su propio intérprete / compilador. Si ocurre que el programa a interpretar / compilar es su propio intérprete o compilador (independientemente del nombre del archivo), su programa debe hacer algo completamente ajeno a la funcionalidad de un intérprete o compilador (como barfing o impresión Hello, world!).

Para hacer esta tarea aún más compleja, su programa no debe leer su propia fuente al compilar o interpretar.

Presupuesto

  • Esta tarea es el código de golf. La presentación con la menor cantidad de caracteres que es correcta gana. En caso de empate, la solución que se presentó primero gana.
  • Su programa / script debe leer el programa para ser interpretado desde un archivo. Puede codificar su ruta y nombre. Cuando se lee el archivo, puede compilar el archivo en otro archivo (que debe ser ejecutable en su sistema) o ejecutarlo directamente. Si $LANGcarece de capacidades de lectura de archivos, puede elegir otra forma de leer el código que se ajuste $LANG. No puede elegir $LANGcomo un subconjunto de otro idioma pero con las capacidades de lectura de archivos eliminadas.
  • Se aplican las reglas habituales de código de golf. Es decir: su lenguaje personal de mascotas que creó solo para resolver este desafío está prohibido, si la solución se vuelve trivial al usarlo (como definir un programa de un solo carácter que implemente exactamente la solución). Se alienta el abuso de las reglas.

¿Se nos permite definir un lenguaje para esto, siempre que esté completo?
Cruncher

@Cruncher Sí, lo eres. Vea la última viñeta de las especificaciones para más detalles.
FUZxxl

Respuestas:


8

Rubí, 63

b=$<.read
t="b=$<.read\nt=%p\nb!=t%%t&&eval(b)"
b!=t%t&&eval(b)

Respuesta aceptada siempre que no haya una solución menor.
FUZxxl

11

Perl, 89 caracteres, sin trampas

$_=q($_=q(Q);s/Q/$_/;($q=join"",<>)eq$_?die:eval$q);s/Q/$_/;($q=join"",<>)eq$_?die:eval$q

Tenga en cuenta que este código es extremadamente exigente con lo que cuenta como "en sí mismo". En particular, no se reconocerá si hay líneas nuevas u otros espacios en blanco adicionales en la entrada. Para probarlo, guárdelo en un archivo llamado (por ejemplo) unquine.ply haga esto:

$ perl unquine.pl unquine.pl
Died at unquine.pl line 1, <> line 1.

Recuerde, el unquine.plarchivo debe tener exactamente 89 bytes de longitud, ni más ni menos. Ejecutarlo con algún otro script Perl como entrada solo ejecuta el otro script, como debería:

$ perl unquine.pl hello.pl
Hello, world!

Como su nombre podría sugerir, la implementación se basa en una quine, específicamente, esta:

$_=q($_=q(Q);s/Q/$_/);s/Q/$_/

Este código se establece $_igual a sí mismo; el resto del programa (que, por supuesto, debe duplicarse en el interior $_) simplemente se compara $_con la entrada, muere si coinciden y evalúa la entrada de otra manera.


Puede reemplazar ese &&/ ;par con un ternario (un carácter apagado, duplicado por comillas). ¡Gran idea e implementación!
JB

@JB: ¡Buena captura! Hasta 89 caracteres ahora.
Ilmari Karonen

5

GolfScript, 30 caracteres

{`".~"+"#{$<.read}".@=!{~}*}.~

Este programa lee el contenido de un archivo nombrado en la línea de comando y, si no coincide exactamente con el código anterior, lo interpreta como GolfScript. Si la entrada es exactamente igual al código anterior, simplemente se imprimirá sin cambios (excepto por una nueva línea adjunta al final).

Esta es una adaptación bastante sencilla de este programa de autoidentificación . Específicamente:

  • { } es un literal de bloque de código en GolfScript.
  • .~, aplicado a un bloque de código, duplica el bloque y ejecuta la copia.

Dentro del bloque de código:

  • ` stringifica la copia del bloque de código.
  • ".~"+le agrega los caracteres .~, produciendo una cadena que contiene el código fuente del programa.
  • "#{$<.read}"es un hack documentado que permite la ejecución de código Ruby dentro de GolfScript. En este caso, ejecuta la instrucción Ruby $<.read(robada descaradamente de la solución Ruby de Lowjacker ), que lee y devuelve el contenido de cualquier archivo especificado en la línea de comando. Este truco es necesario porque GolfScript en sí no proporciona capacidades explícitas de E / S de archivos.
  • .@ duplica y baraja los elementos en la parte superior de la pila para que la pila contenga dos copias del contenido del archivo seguido del código fuente de este programa.
  • =! compara los dos primeros elementos de la pila (es decir, el contenido del archivo y la fuente), devolviendo 1 si son diferentes y 0 si son iguales.
  • {~}*evalúa la copia restante del contenido del archivo como código GolfScript, pero solo si el resultado de la comparación es 1. (Técnicamente, ejecuta el bloque de código {~}tantas veces como lo indica el número en la pila, es decir, 0 o 1 veces. el bloque, ~es el operador eval de GolfScript).

PD. Si se permite leer el código para ejecutar desde stdin, este desafío se puede resolver en 21 caracteres sin tener que pagarle a Ruby:

{`".~"+1$=!{""\~}*}.~

Este programa leerá una cadena de entrada de stdin y, si no coincide con su propia fuente, la ejecuta (con una entrada vacía). Al igual que el programa anterior, la entrada que coincide con la fuente simplemente se repite.


Se ve bien, pero no parece que haya leído la entrada de un archivo.
FUZxxl

Solucionado, ahora se lee desde un archivo (exactamente) como la solución de Lowjacker.
Ilmari Karonen

5

Python, 167 130 118 bytes

Este es mi primer intento de jugar golf, así que aquí va! Interpreta cualquier programa excepto él mismo

Versión mejorada:

i=open(raw_input()).read();q='i=open(raw_input()).read();q=%s;i==q%%repr(q)and a;exec(i)\n';i==q%repr(q)and a;exec(i)

Si se pone a sí mismo, entonces vomita con:

Traceback (most recent call last):
  File "pygolf.py", line 1, in <module>
    i=open(raw_input()).read();q='i=open(raw_input()).read();q=%s;i==q%%repr(q)and a;exec(i)\n';i==q%repr(q)and a;exec(i)
NameError: name 'a' is not defined

Creo que esta solución funciona casi de la misma manera que la de Ilmari Karonen, la idea básica es algo así como:

input = read_some_file()
if input == some_quine()
    barf()
interpret(input)

La quine que utilicé se basó en esta:

(lambda x: x + repr((x,)))('(lambda x: x + repr((x,)))',)

Pero desde entonces me di cuenta de que una quine mucho más corta es:

q='q=%s;q%%repr(q)';q%repr(q)

Y eso puede ser aún más corto si permite el shell interactivo de Python, en cuyo caso puede hacer:

'%s;_%%repr(_)';_%repr(_)

Como Python no tiene una forma corta de obtener argumentos de línea de comando, utilicé raw_input () (que todavía es bastante largo, pero no tanto como

import sys;sys.argv[1]

El uso es:

echo "foobar.py" | python quinterpretter.py

o

python quinterpretter.py
<type filename and hit enter>

Encontré una quine más corta para usar, pero aquí está mi versión anterior (para la posteridad):

i=open(raw_input()).read();a if i==(lambda x,y:x+repr((x,y))+y)('i=open(raw_input()).read();a if i==(lambda x,y:x+repr((x,y))+y)', ' else 1;exec(i)\n') else 1;exec(i)

Reemplace% s con% r y elimine la repr. % r significa crudo y es básicamente lo mismo.
Loovjo

4

No puedo leer exactamente de un archivo usando Javascript (ok, podría hacerlo, usando el archivo HTML5 FileReader, pero eso hace las cosas mucho más complicadas de lo que necesito). Entonces, esta es una función que acepta un programa Javascript como una cadena y lo ejecuta.

Esto probablemente no sea tan golfístico como podría ser, pero aquí está de todos modos:

Javascript, 252

function c(p){q='\"';s='\\';a="function c(p){q='\"';s='\\';a=%;a=a.slice(0,17)+s+a.slice(17,24)+a[23]+a.slice(24);a=q+a.replace('%',q+a+q)+q;alert(a);}";a=a.slice(0,17)+s+a.slice(17,24)+a[23]+a.slice(24);a=a.replace('%',q+a+q);alert(a);if(p!=a)eval(p)}

Avíseme si alguien conoce una mejor técnica para formar una quina en Javascript.


1
Publiqué una solución JS de 135 caracteres a continuación, basada en su código y mi solución Perl. +1 por la inspiración!
Ilmari Karonen

2
read p<p;read c<c;[ "$p" = "$c" ]||. ./c

45 caracteres de sh (shell POSIX). El código a ejecutar debe estar en el archivo ./c.

El código para el propio intérprete debe estar en el archivo ./p, así que supongo que hice trampa, aunque el desafío no parece prohibirlo. ¿O esto descalificaría mi "lenguaje" de ser un "lenguaje de programación completo"?

Usando una herramienta que normalmente es un ejecutable externo, pero que en teoría podría integrarse en el shell, el código se puede acortar:

cmp -s p c||. ./c

Son 18 caracteres, y el -sbit es solo para suprimir una línea que de otra manera siempre se imprimiría para programas válidos (no propios).

Y luego siempre puede construir una versión del lenguaje de shell que haga lo anterior con una sintaxis más concisa.

Y luego siempre puedes construir un programa que, cuando la entrada consiste en un solo '.' --o demonios, la cadena vacía-- evalúa el contenido de otro archivo como código normal, y llama a esto un lenguaje de programación. Entonces, la cadena vacía sería su solución al desafío, en el lenguaje que creó. De hecho, aquí hay un intérprete para tal lenguaje:

read code; if [ "$code" ]; then eval "$code"; else . ./othercode; fi

Usando el lenguaje que interpreta el script anterior, la solución es la cadena vacía. Y la ubicación del código ya no necesita ser codificada.

¿Problema?


2
El desafío dice que "su programa no debe leer su propia fuente".
Ilmari Karonen

Darnit, perdió algo de tiempo entonces. Y veo que incluso dice que no debes usar funciones que vas a omitir. Esto iría en contra de la función de cadena vacía. Por otra parte, el intérprete debe omitir / cambiar la funcionalidad si el código para el compilador / intérprete en sí causa un comportamiento diferente en el nuevo lenguaje. En cualquier caso, me divertí escribiendo falacias.
TaylanUB

@TaylanUB Bueno, en realidad tienes que interpretar todos los programas válidos de $ lang excepto el propio intérprete.
FUZxxl

@FUZxxl Sí, el lenguaje "sh + cadena vacía" es equivalente a sh (si el código no es la cadena vacía), y el programa de cadena vacía escrito en él también interpreta el código sh (que debe introducirse ./othercode), y lo hace nada cuando el código es la cadena vacía. No debería haber llamado al archivo ./othercode, es engañoso; es solo el código que interpretará el intérprete escrito en el lenguaje de cadena vacío.
TaylanUB

2

JavaScript, 135 caracteres

function c(p){q='function c(p){q=%27Q%27;p!=unescape(q).replace(/Q/,q)?eval(p):alert()}';p!=unescape(q).replace(/Q/,q)?eval(p):alert()}

La solución JavaScript de Peter Olson me inspiró a intentar portar mi solución Perl a JS. Al igual que su solución, este código define una función cque acepta una cadena y la evalúa si no es igual al código anterior.

Me tomó un tiempo para averiguar una manera buena para hacer frente a la ausencia de delimitadores de cadenas equilibradas en JavaScript, hasta que encontré lo que en retrospectiva es la solución obvia: unescape().

Convenientemente, mi código no contiene barras invertidas ni comillas dobles, por lo que puede almacenarse de manera segura en cadenas de comillas dobles. Esto facilita la prueba:

e = "function c(p){q='function c(p){q=%27Q%27;p!=unescape(q).replace(/Q/,q)?eval(p):alert()}';p!=unescape(q).replace(/Q/,q)?eval(p):alert()}"
h = "alert('Hello, world!')"

eval(e)  // defines the function c()

c(h)     // evaluates h
c(e)     // does not evaluate e, alerts "undefined" instead

Puede reemplazar alert()con 0para que no haga nada en lugar de alertar undefinedy guardar 13 caracteres.
Peter Olson

@PeterOlson: Sí, pero la tarea dice que "su programa debería hacer algo completamente ajeno" si se detecta a sí mismo. Interpreto que significa que debería hacer algo , preferiblemente algo visible para el usuario, supongo. Además, me gusta más de esta manera. :) (Ps. ¡Sí, está nevando afuera! ¡El invierno finalmente está aquí!)
Ilmari Karonen

1
@Ilmari No hacer nada no está relacionado con la interpretación de Javascript en mi humilde opinión.
FUZxxl

Podrías ir en p=>...lugar defunction c(p)
FireCubez

2

Lisp común, 59

#+~ #.(#:a)(defun L(p)(compile-file p))(push :~ *features*)
  • En un nuevo Lisp REPL, compile su archivo (por ejemplo sbcl --load)
  • Ahora tiene una función L, que puede compilar archivos Common Lisp
  • Sin embargo, si llama (L <your file>), se señala un error mientras lee el archivo.

¿Por qué?

Porque la primera vez, introdujo la :~palabra clave *features*. Ahora, su entorno conoce la ~característica, y la macro del lector #+, al evaluar la ~ expresión de la característica , tendrá éxito y leerá el siguiente formulario en lugar de omitirlo como lo hizo la primera vez. En su archivo, el siguiente formulario es #.(#:a), que pide evaluar (#:a)en tiempo de lectura y usar el valor resultante como el código que se está leyendo. Pero (#:a)llama a la función asociada con el símbolo no interno #:a. Como no #:aestá conectado, es un símbolo nuevo que no está vinculado a ninguna función (es decir, no fboundp). Error.


1

Esquema, 48 o 51 caracteres.

Scheme es un lenguaje con muchas implementaciones diferentes. A pesar de que las implementaciones tienen que ajustarse al último RnRS, el último estándar de trabajo (R6RS) ha sido impopular debido a su falta de minimalismo. El R7RS pronto se lanzará como un remedio, mientras divide el lenguaje en 2. El primer lenguaje es potente y minimalista y el segundo, un superconjunto del primero destinado a proporcionar extensiones de características para la interoperabilidad entre implementaciones. Hasta entonces, confiamos en los SRFI (Solicitudes de esquema para la implementación), que proporcionan (si se implementa en la implementación del host o manualmente (como es común en el esquema)) un medio para llevar a cabo tareas comunes de manera portátil. Todo esto para decir que el primer fragmento de código (51 caracteres), aunque sigue siendo lo más portátil posible, se basa en SRFI-22 (ejecución de scripts de esquema en UNIX) para acceder a los argumentos de la línea de comandos:

(define(main x y)(case y(x => error)(else => load)))

o más legible:

(define (main current-file arg)
  (case arg
    [current-file => error]
    [else => load]))

El segundo (48 caracteres) es un medio de interpretación sin archivo que no puede evaluarse a sí mismo (en un entorno nulo):

(define(e)(write(eval(read)null-environment))(e))

o más legible:

(define (interpret)
  (write (eval (read) null-environment))
  (interpret))

Su código no funciona si copia su intérprete.
FUZxxl

1
Déjelo en una respuesta de esquema para contener paréntesis anidados en su prosa.
Cyoce

1

Groovy, 13 bytes

{Eval.me(it)}

Esto debería interpretar un subconjunto de Groovy.

Casos de prueba:

p={Eval.me(it)}

p'''
    (0..37).each{println"1234567890JIHGFEDCBAKLMNOPQRST!?,.ZYXWVU"[it..it+2]}
'''

p'''
    {Eval.me(it)}
'''

Desafortunadamente, aunque ciertamente irrita, lo hace de una manera completamente similar a la de un intérprete, y lo hace por una gran cantidad de información.


¿En qué línea lees el programa a interpretar? Su código es interesante, aunque no es un envío válido para esta tarea.
FUZxxl

¿Asumo que el error es algo como "límite de recursión excedido"?
Ilmari Karonen

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.