Interprete seu idioma, mas não você mesmo?

21

Existem muitos desafios que dizem "interpretar X", onde X é uma linguagem simples. Na minha opinião, isso é muito chato. Para dar a todas as pessoas que procrastinam na internet algo interessante para fazer, você pode tentar fazer este desafio:

Desafio

Escolha um idioma $LANG. $LANGpode ser qualquer linguagem de programação completa ou um subconjunto completo de uma linguagem de programação. Lembre-se de que, se você omitir um recurso do seu idioma $LANGpara interpretação, também não deve usá-lo em seu próprio programa, pois sua submissão também deve ser escrita $LANG.

Escreva um compilador / intérprete para $LANGescrever em $LANG. Você pode usar todos os recursos (inclusive evale amigos) do seu idioma disponíveis para escrever este compilador. Para tornar a tarefa mais desafiadora, há uma restrição: O programa deve ser capaz de interpretar / compilar todos os programas válidos, $LANGexceto o próprio intérprete / compilador. Se ocorrer que o programa a ser interpretado / compilado é seu próprio intérprete ou compilador (independentemente do nome do arquivo), seu programa deve fazer algo completamente não relacionado à funcionalidade de um intérprete ou compilador (como vomitar ou imprimir Hello, world!).

Para tornar essa tarefa ainda mais complexa, seu programa não deve ler sua própria fonte ao compilar ou interpretar.

Especificações

  • Esta tarefa é código de golfe. A submissão com menos caracteres corretos vence. Em caso de empate, a solução enviada primeiro vence.
  • Seu programa / script deve ler o programa a ser interpretado de um arquivo. Você pode codificar seu caminho e nome. Quando o arquivo é lido, você pode compilar o arquivo para outro arquivo (deve ser executável no seu sistema) ou executá-lo diretamente. Se $LANGnão houver recursos de leitura de arquivos, você poderá escolher outra maneira de ler o código adequado $LANG. Você não pode escolher $LANGcomo um subconjunto de outro idioma, mas com os recursos de leitura de arquivos removidos.
  • Aplicam-se regras usuais de código-golfe. Ou seja: é proibido o seu idioma de estimação pessoal que você criou para solucionar esse desafio, se a solução se tornar trivial (como definir um programa de caractere único que implemente exatamente a solução). O abuso de regras é incentivado.
FUZxxl
fonte
Podemos definir um idioma para isso, desde que esteja completo?
triturador
@ Cruncher Sim, você é. Consulte o último marcador das especificações para obter mais detalhes.
FUZxxl

Respostas:

8

Ruby, 63

b=$<.read
t="b=$<.read\nt=%p\nb!=t%%t&&eval(b)"
b!=t%t&&eval(b)
Lowjacker
fonte
Resposta aceita desde que não exista uma solução menor.
FUZxxl
11

Perl, 89 caracteres, sem trapaça

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

Observe que esse código é extremamente exigente quanto ao que conta como "em si". Em particular, ele não se reconhecerá se houver novas linhas à direita ou outro espaço em branco extra na entrada. Para testá-lo, salve-o em um arquivo chamado (por exemplo) unquine.ple faça o seguinte:

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

Lembre-se de que o unquine.plarquivo deve ter exatamente 89 bytes, nem mais nem menos. A execução com outro script Perl como entrada apenas executa o outro script, como deveria:

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

Como o nome pode sugerir, a implementação é baseada em uma solução - especificamente, esta:

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

Esse código é $_igual a ele mesmo; o restante do programa (que, é claro, deve ser duplicado por dentro $_) apenas se compara $_à entrada, morre se corresponder e avalia a entrada de outra forma.

Ilmari Karonen
fonte
Você pode substituir esse &&/ ;par por um ternário (um caractere desligado, dobrado por quining). Ótima idéia e implementação!
JB
@JB: Boa captura! Até 89 caracteres agora.
Ilmari Karonen
5

GolfScript, 30 caracteres

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

Este programa lê o conteúdo de um arquivo nomeado na linha de comando e, se não for exatamente igual ao código acima, o interpreta como GolfScript. Se a entrada for exatamente igual ao código acima, ela simplesmente será impressa inalterada (exceto por uma nova linha anexada ao final).

Essa é uma adaptação bastante direta desse programa de identificação automática . Especificamente:

  • { } é um literal de bloco de código no GolfScript.
  • .~, aplicado a um bloco de código, duplica o bloco e executa a cópia.

Dentro do bloco de código:

  • ` especifica a cópia do bloco de código.
  • ".~"+acrescenta os caracteres .~a ele, produzindo uma string contendo o código fonte do programa.
  • "#{$<.read}"é um hack documentado que permite a execução de código Ruby no GolfScript. Nesse caso, ele executa a instrução Ruby $<.read(roubada descaradamente da solução Ruby do Lowjacker ), que lê e retorna o conteúdo de qualquer arquivo especificado na linha de comando. Esse hack é necessário porque o próprio GolfScript não fornece recursos explícitos de E / S de arquivo.
  • .@ duplica e embaralha os elementos na parte superior da pilha para que a pilha contenha duas cópias do conteúdo do arquivo, seguidas pelo código fonte deste programa.
  • =! compara os dois principais itens da pilha (ou seja, o conteúdo do arquivo e a fonte), retornando 1 se forem diferentes e 0 se forem iguais.
  • {~}*avalia a cópia restante do conteúdo do arquivo como código GolfScript, mas apenas se o resultado da comparação for 1. (Tecnicamente, ele executa o bloco de código {~}quantas vezes for fornecido pelo número na pilha, ou seja, 0 ou 1 vezes. o bloco, ~é o operador de avaliação GolfScript.)

Ps. Se a leitura do código a ser executado a partir do stdin for permitida, esse desafio poderá ser resolvido em 21 caracteres, sem a necessidade de desembolsar para o Ruby:

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

Este programa lerá uma string de entrada do stdin e, se não corresponder à sua própria fonte, a executará (com uma entrada vazia). Como no programa acima, a entrada que corresponde à fonte é simplesmente retornada.

Ilmari Karonen
fonte
Parece bom, mas não parece que você leia a entrada de um arquivo.
FUZxxl
Corrigido, agora ele lê de um arquivo (exatamente) como a solução Lowjacker.
Ilmari Karonen
5

Python, 167 130 118 bytes

Esta é a minha primeira tentativa de jogar golfe, então aqui vai! Ele interpreta qualquer programa, exceto ele próprio

Versão melhorada:

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)

Se obtém a si próprio, vomita com:

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

Acho que essa solução funciona da mesma maneira que a de Ilmari Karonen, a idéia básica é algo como:

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

A solução que usei foi baseada nesta:

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

Mas desde então percebi que uma solução muito mais curta é:

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

E isso pode ser ainda mais curto se você permitir o shell interativo do python; nesse caso, você pode fazer:

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

Como o python não tem um caminho curto para obter argumentos de linha de comando, fui com raw_input () (que ainda é bastante longo, mas não enquanto

import sys;sys.argv[1]

O uso é:

echo "foobar.py" | python quinterpretter.py

ou

python quinterpretter.py
<type filename and hit enter>

Encontrei um quine mais curto para usar, mas aqui está minha versão antiga (para a posteridade):

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)
Gordon Bailey
fonte
Substitua% s por% re remova a repr. % r significa cru e é basicamente a mesma coisa.
Loovjo 6/06
4

Não consigo ler exatamente de um arquivo usando Javascript (ok, eu poderia, usando a coisa HTML5 FileReader, mas isso torna as coisas muito mais complicadas do que eu preciso). Portanto, essa é uma função que aceita um programa Javascript como uma string e o executa.

Provavelmente isso não é tão complicado quanto poderia ser, mas aqui está:

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)}

Deixe-me saber se alguém conhece uma técnica melhor para formar uma solução em Javascript.

Peter Olson
fonte
11
Postei uma solução JS de 135 caracteres abaixo, com base no seu código e na minha solução Perl. +1 para a inspiração!
Ilmari Karonen
2
read p<p;read c<c;[ "$p" = "$c" ]||. ./c

45 caracteres de sh (shell POSIX). O código a ser executado deve estar no arquivo ./c.

O código para o intérprete em si deve estar no arquivo ./p, então eu acho que meio que trapaceou, embora o desafio não pareça proibi-lo. Ou isso desqualificaria minha "linguagem" de ser uma "linguagem de programação completa"?

Usando uma ferramenta que normalmente é um executável externo, mas que teoricamente pode ser incorporada ao shell, o código pode ser reduzido:

cmp -s p c||. ./c

São 18 caracteres, e o -sbit é apenas para suprimir uma linha que, de outra forma, sempre seria impressa para programas válidos (não próprios).

E então você sempre pode criar uma versão da linguagem shell que faz o acima com sintaxe mais concisa.

E então você sempre pode criar um programa que, quando a entrada consiste em um único '.' - ou, inferno, a string vazia-- avalia o conteúdo de outro arquivo como código normal e chama isso de linguagem de programação. Portanto, a string vazia seria sua solução para o desafio, no idioma que você criou. De fato, aqui está um intérprete para esse idioma:

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

Usando o idioma interpretado pelo script acima, a solução é a string vazia. E a localização do código não precisa mais ser codificada.

Problema?

TaylanUB
fonte
2
O desafio diz que "o seu programa não deve ler sua própria fonte".
Ilmari Karonen
Darnit, perdeu algum tempo então. E eu vejo que até diz que você não deve usar recursos que você omitirá. Isso iria contra o recurso de cadeia vazia. Por outro lado, o intérprete deve estar omitindo / alterando a funcionalidade se o código do compilador / intérprete causar um comportamento diferente no novo idioma. De qualquer forma, eu me diverti escrevendo falácias.
TaylanUB
@ TaylanUB Bem, você realmente tem que interpretar todos os programas $ lang válidos, exceto o próprio intérprete.
FUZxxl
@FUZxxl Sim, a linguagem "sh + cadeia vazia" é equivalente a sh (se o código não for a cadeia vazia), e o programa de cadeia vazia escrito nele também interpreta o código sh (que deve ser inserido ./othercode) e nada quando o código é a string vazia. Eu não deveria ter chamado o arquivo ./othercode, é enganoso; é apenas o código que o intérprete escrito no idioma da string vazia interpretará.
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()}

A solução JavaScript de Peter Olson me inspirou a tentar portar minha solução Perl para JS. Como sua solução, esse código define uma função cque aceita uma string e a avalia se não for igual ao código acima.

Levei um tempo para descobrir uma boa maneira de lidar com a ausência de delimitadores de cordas equilibradas em JavaScript, até que eu encontrei o que em retrospectiva é a solução óbvia: unescape().

Convenientemente, meu código não contém barras invertidas ou aspas duplas; portanto, ele pode ser armazenado com segurança em seqüências de caracteres com aspas duplas. Isso facilita o teste:

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
Ilmari Karonen
fonte
Você pode substituir alert()por 0para não fazer nada em vez de alertar undefinede salvar 13 caracteres.
Peter Olson
@ PeterOlson: Sim, mas a tarefa diz que "o seu programa deve fazer algo completamente não relacionado" se ele se detectar. Eu interpreto isso como significando que deve fazer algo - de preferência algo visível para o usuário, eu presumo. Além disso, eu gosto mais dessa maneira. :) (.! Ps Yay, está nevando lá fora inverno é finalmente aqui!)
Ilmari Karonen
11
@ Ilmari Não fazer nada não está relacionado à interpretação do Javascript IMHO.
FUZxxl
Você poderia ir em p=>...vez defunction c(p)
FireCubez 07/10
2

Lisp comum, 59

#+~ #.(#:a)(defun L(p)(compile-file p))(push :~ *features*)
  • Em um novo Lisp REPL, compile seu arquivo (por exemplo sbcl --load)
  • Agora você tem uma função Lque pode compilar arquivos Common Lisp
  • No entanto, se você ligar (L <your file>), um erro será sinalizado durante a leitura do arquivo.

Por quê?

Porque na primeira vez, você inseriu a :~palavra-chave *features*. Agora, seu ambiente conhece o ~recurso, e a macro do leitor #+, ao avaliar a ~ expressão do recurso , será bem-sucedida e lerá o seguinte formulário, em vez de ignorá-lo como na primeira vez. No seu arquivo, é o seguinte formulário #.(#:a), que pede para avaliar (#:a)em tempo de leitura e usar o valor resultante como o código que está sendo lido. Mas (#:a)chama a função associada ao símbolo não interno #:a. Como não #:aé interno, é um novo símbolo que não está vinculado a nenhuma função (ou seja, não fboundp). Erro.

coredump
fonte
1

Esquema, 48 ou 51 caracteres

Scheme é uma linguagem com muitas implementações diferentes. Apesar das implementações terem que estar em conformidade com o RnRS mais recente, o mais recente padrão de trabalho (R6RS) tem sido impopular devido à sua falta de minimalismo. O R7RS será lançado em breve como um remédio, dividindo o idioma em 2. O primeiro idioma é poderoso e minimalista e o segundo, um superconjunto do primeiro destinado a fornecer extensões de recursos para interoperabilidade entre implementações. Até então, contamos com SRFIs (solicitações de esquema para implementação), que fornecem (se implementadas na implementação do host ou manualmente (como é comum no esquema)) um meio de realizar tarefas comuns de maneira portável. Tudo isso para dizer que o primeiro trecho de código (51 caracteres), apesar de permanecer o mais portátil possível, depende do SRFI-22 (executando scripts de esquema no UNIX) para acessar os argumentos da linha de comando:

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

ou mais facilmente:

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

O segundo (48 caracteres) é um meio de interpretação sem arquivo que não pode se avaliar (em um ambiente nulo):

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

ou mais facilmente:

(define (interpret)
  (write (eval (read) null-environment))
  (interpret))
Samuel Duclos
fonte
Seu código não funcionará se você copiar seu intérprete.
FUZxxl
11
Deixe que uma resposta do esquema contenha parênteses aninhados em sua prosa.
Cyoce
1

Groovy, 13 bytes

{Eval.me(it)}

Isso deve interpretar um subconjunto do Groovy.

casos de teste:

p={Eval.me(it)}

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

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

Infelizmente, embora certamente vomite, o faz de uma maneira completamente semelhante a intérprete, e o faz para bastante entrada.

Armand
fonte
Em qual linha você lê o programa a ser interpretado? Seu código é interessante, embora não seja um envio válido para esta tarefa.
FUZxxl
Presumo que o erro seja algo como "limite de recursão excedido"?
Ilmari Karonen