Interpreta la tua lingua, ma non te stesso?


21

Ci sono molte sfide che dicono "interpretare X", dove X è un linguaggio semplice. Secondo me, è troppo noioso. Per dare a tutte le persone procrastinate su Internet qualcosa di interessante da fare, puoi provare a fare questa sfida:

Sfida

Scegliere una lingua $LANG. $LANGpuò essere qualsiasi linguaggio di programmazione completo turing o un sottoinsieme completo di turing di un linguaggio di programmazione. Fai attenzione che se ometti una caratteristica della tua lingua $LANGper l'interpretazione, non devi usarla anche per il tuo programma, poiché anche la tua presentazione deve essere scritta $LANG.

Scrivi un compilatore / interprete per la $LANGscrittura $LANG. Puoi usare tutte le strutture (inclusi evale amici) della tua lingua disponibili per scrivere questo compilatore. Per rendere l'attività più impegnativa, esiste una restrizione: il programma dovrebbe essere in grado di interpretare / compilare tutti i programmi validi $LANGtranne l'interprete / compilatore stesso. Se si verifica che il programma da interpretare / compilare è il tuo stesso interprete o compilatore (indipendentemente dal nome del file), il tuo programma dovrebbe fare qualcosa di completamente estraneo alla funzionalità di un interprete o di un compilatore (come barfing o stampa Hello, world!).

Per rendere questa attività ancora più complessa, il programma non deve leggere la propria fonte durante la compilazione o l'interpretazione.

specificazioni

  • Questo compito è il golf del codice. Vince l'invio con il minor numero di caratteri corretti. In caso di pareggio, vince la soluzione presentata per prima.
  • Il tuo programma / script dovrebbe leggere il programma da interpretare da un file. È possibile codificare il percorso e il nome. Quando il file viene letto, è possibile compilare il file in un altro file (che deve essere eseguibile sul proprio sistema) o eseguirlo direttamente. Se $LANGmanca di capacità di lettura dei file, puoi scegliere un altro modo di leggere il codice adatto $LANG. Non è possibile scegliere $LANGcome sottoinsieme di un'altra lingua ma con capacità di lettura dei file rimosse.
  • Si applicano le normali regole del code-golf. Cioè: il tuo linguaggio personale personale che hai inventato solo per risolvere questa sfida è proibito, se la soluzione diventa banale usandola (come la definizione di un programma a carattere singolo che implementa esattamente la soluzione). L'abuso di regole è incoraggiato.

Ci è permesso di definire una lingua per questo, purché sia ​​completa?
Cruncher,

@Cruncher Sì, lo sei. Vedere l'ultimo punto elenco delle specifiche per maggiori dettagli.
FUZxxl

Risposte:


8

Ruby, 63 anni

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

Risposta accettata fino a quando non esiste una soluzione più piccola.
FUZxxl,

11

Perl, 89 caratteri, nessun imbroglio

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

Si noti che questo codice è estremamente esigente su ciò che conta come "se stesso". In particolare, non si riconoscerà se nell'input sono presenti nuove righe finali o altri spazi bianchi extra. Per provarlo, salvalo in un file chiamato (ad esempio) unquine.ple fai questo:

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

Ricorda, il unquine.plfile dovrebbe essere lungo esattamente 89 byte, né più né meno. Eseguendolo con qualche altro script Perl come input, esegue solo l'altro script, come dovrebbe:

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

Come potrebbe suggerire il nome, l'implementazione si basa su un quine - in particolare, questo:

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

Questo codice è $_uguale a se stesso; il resto del programma (che, ovviamente, deve essere duplicato all'interno $_) confronta solo $_l'input, muore se corrispondono e valuta l'input in caso contrario.


È possibile sostituire quella &&/ ;coppia con un ternario (un carattere spento, raddoppiato quining). Ottima idea e realizzazione!
JB,

@JB: buona cattura! Fino a 89 caratteri ora.
Ilmari Karonen,

5

GolfScript, 30 caratteri

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

Questo programma legge il contenuto di un file chiamato nella riga di comando e, se non corrisponde esattamente al codice sopra, lo interpreta come GolfScript. Se l'input è esattamente uguale al codice sopra, verrà semplicemente stampato invariato (ad eccezione di una nuova riga aggiunta alla fine).

Questo è un adattamento abbastanza semplice di questo programma di autoidentificazione . In particolare:

  • { } è un blocco di codice letterale in GolfScript.
  • .~, applicato a un blocco di codice, duplica il blocco ed esegue la copia.

All'interno del blocco di codice:

  • ` restringe la copia del blocco di codice.
  • ".~"+aggiunge i caratteri .~ad esso, producendo una stringa contenente il codice sorgente del programma.
  • "#{$<.read}"è un hack documentato che consente l'esecuzione del codice Ruby all'interno di GolfScript. In questo caso, esegue l'istruzione Ruby $<.read(rubata spudoratamente dalla soluzione Ruby di Lowjacker ), che legge e restituisce il contenuto di tutti i file specificati sulla riga di comando. Questo hack è necessario perché GolfScript stesso non offre funzionalità di I / O di file esplicite.
  • .@ duplica e mescola gli elementi in cima allo stack in modo che lo stack contenga due copie del contenuto del file seguito dal codice sorgente di questo programma.
  • =! confronta i primi due elementi nello stack (ovvero il contenuto del file e l'origine), restituendo 1 se sono diversi e 0 se sono uguali.
  • {~}*valuta la copia rimanente del contenuto del file come codice GolfScript, ma solo se il risultato del confronto è 1. (Tecnicamente, esegue il blocco di codice {~}tutte le volte dato dal numero nello stack, ovvero 0 o 1 volte. il blocco, ~è l'operatore eval GolfScript.)

Ps. Se la lettura del codice da eseguire da stdin è consentita, questa sfida può essere risolta in 21 caratteri senza dover sborsare su Ruby:

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

Questo programma leggerà una stringa di input da stdin e, se non corrisponde alla propria sorgente, la esegue (con un input vuoto). Come il programma precedente, l'input che corrisponde alla sorgente viene semplicemente ripetuto.


Sembra carino, ma non sembra che tu abbia letto l'input da un file.
FUZxxl,

Risolto, ora legge da un file (esattamente) come la soluzione di Lowjacker.
Ilmari Karonen,

5

Python, 167 130 118 byte

Questo è il mio primo tentativo di giocare a golf, quindi ecco qui! Interpreta qualsiasi programma tranne se stesso

Versione migliorata:

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 si ottiene, quindi barfs 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

Penso che questa soluzione funzioni più o meno allo stesso modo di Ilmari Karonen, l'idea di base è qualcosa di simile:

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

Il quine che ho usato era basato su questo:

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

Ma da allora ho capito che un quine molto più breve è:

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

E ciò può essere ancora più breve se consenti la shell interattiva in Python, nel qual caso puoi fare:

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

Dal momento che python non ha un modo breve per ottenere args da riga di comando, sono andato con raw_input () (che è ancora piuttosto lungo, ma non fino a quando

import sys;sys.argv[1]

L'utilizzo è:

echo "foobar.py" | python quinterpretter.py

o

python quinterpretter.py
<type filename and hit enter>

Ho trovato un quine più corto da usare, ma ecco la mia vecchia versione (per i posteri):

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)

Sostituisci% s con% r e rimuovi il repr. % r significa crudo ed è sostanzialmente la stessa cosa.
Loovjo,

4

Non riesco a leggere esattamente da un file usando Javascript (ok, potrei, usando la cosa FileReader HTML5, ma questo rende le cose molto più complicate di quelle di cui ho bisogno). Quindi, questa è una funzione che accetta un programma Javascript come stringa e lo esegue.

Questo probabilmente non è così facile come potrebbe essere, ma eccolo qui:

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

Fammi sapere se qualcuno conosce una tecnica migliore per formare un quine in Javascript.


1
Di seguito ho pubblicato una soluzione JS a 135 caratteri, basata sul tuo codice e sulla mia soluzione Perl. +1 per l'ispirazione!
Ilmari Karonen,

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

45 caratteri di sh (shell POSIX). Il codice da eseguire deve essere nel file ./c.

Il codice per l'interprete stesso deve essere nel file ./p, quindi immagino di aver barato, anche se la sfida non sembra proibirlo. O questo escluderebbe il mio "linguaggio" dall'essere un "linguaggio di programmazione completo"?

Utilizzando uno strumento che è normalmente un eseguibile esterno, ma potrebbe teoricamente essere integrato nella shell, il codice può essere abbreviato:

cmp -s p c||. ./c

Sono 18 caratteri e il -sbit è solo quello di sopprimere una riga che altrimenti verrebbe sempre stampata per programmi validi (non autonomi).

E poi puoi sempre costruire una versione del linguaggio shell che fa quanto sopra con una sintassi più concisa.

E poi puoi sempre creare un programma che, quando l'input è costituito da un singolo '.' - o diavolo, la stringa vuota - valuta il contenuto di un altro file come codice normale e lo chiama un linguaggio di programmazione. Quindi la stringa vuota sarebbe la tua soluzione alla sfida, nella lingua che hai creato. In effetti, ecco un interprete per una tale lingua:

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

Utilizzando la lingua interpretata dallo script sopra, la soluzione è la stringa vuota. E la posizione del codice non deve più essere codificata.

Problema?


2
La sfida dice che "il tuo programma non deve leggere la propria fonte".
Ilmari Karonen,

Accidenti, ho perso un po 'di tempo allora. E vedo che dice anche che non devi usare funzionalità che ometterai. Ciò andrebbe contro la funzione stringa vuota. Inoltre, l'interprete deve omettere / modificare la funzionalità se il codice per il compilatore / interprete stesso provoca un comportamento diverso nella nuova lingua. In ogni caso, mi sono divertito a scrivere errori.
TaylanUB,

@TaylanUB Beh, devi effettivamente interpretare tutti i programmi $ lang validi tranne l'interprete stesso.
FUZxxl

@FUZxxl Sì, il linguaggio "sh + stringa vuota" è altrimenti equivalente a sh (se il codice non è la stringa vuota), e il programma di stringa vuota scritto in esso interpreta anche il codice sh (che deve essere inserito ./othercode), e lo fa niente quando il codice è la stringa vuota. Non avrei dovuto chiamare il file ./othercode, è fuorviante; è solo il codice che interpreterà l'interprete scritto nel linguaggio stringa vuoto.
TaylanUB,

2

JavaScript, 135 caratteri

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 soluzione JavaScript di Peter Olson mi ha ispirato a provare il porting della mia soluzione Perl su JS. Come la sua soluzione, questo codice definisce una funzione cche accetta una stringa e la elimina se non è uguale al codice sopra.

Mi c'è voluto un po 'per capire un buon modo per affrontare con l'assenza di delimitatori di stringa equilibrati in JavaScript, fino a quando ho trovato quello che col senno di poi è la soluzione più ovvia: unescape().

Convenientemente, il mio codice non contiene barre rovesciate o virgolette doppie, quindi può essere tranquillamente memorizzato in stringhe tra virgolette doppie. Ciò semplifica il test:

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

È possibile sostituire alert()con 0per fare in modo che non faccia nulla invece di avvisare undefinede salvare 13 caratteri.
Peter Olson,

@PeterOlson: Sì, ma l'attività dice che "il tuo programma dovrebbe fare qualcosa di completamente indipendente" se rileva se stesso. Lo interpreto nel senso che dovrebbe fare qualcosa , preferibilmente qualcosa di visibile all'utente, presumo. Inoltre, mi piace solo così. :) (Sal. Yay, fuori nevica! Finalmente l'inverno è qui!)
Ilmari Karonen,

1
@Ilmari Non fare nulla è estraneo all'interpretazione di Javascript IMHO.
FUZxxl,

Potresti andare p=>...invece difunction c(p)
FireCubez il

2

Lisp comune, 59

#+~ #.(#:a)(defun L(p)(compile-file p))(push :~ *features*)
  • In un nuovo REPL Lisp, compila il tuo file (ad es. sbcl --load)
  • Ora hai una funzione L, che può compilare file Common Lisp
  • Tuttavia, se si chiama (L <your file>), viene segnalato un errore durante la lettura del file.

Perché?

Perché la prima volta, hai inserito la :~parola chiave *features*. Ora, il tuo ambiente è a conoscenza della ~funzione e la macro del lettore #+, dopo aver valutato l' ~ espressione della funzione , avrà esito positivo e leggerà il modulo seguente invece di saltarlo come faceva la prima volta. Nel tuo file, è il seguente modulo #.(#:a), che chiede di valutare (#:a)al momento della lettura e di utilizzare il valore risultante come codice da leggere. Ma (#:a)chiama la funzione associata al simbolo non interessato #:a. Poiché non #:aè interessato, è un nuovo simbolo che non è associato a nessuna funzione (cioè no fboundp). Errore.


1

Schema, 48 o 51 caratteri

Lo schema è un linguaggio con molte implementazioni diverse. Nonostante le implementazioni debbano essere conformi all'ultimo RnRS, l'ultimo standard di lavoro (R6RS) è stato impopolare a causa della sua mancanza di minimalismo. L'R7RS verrà presto rilasciato come rimedio, dividendo la lingua in 2. La prima lingua è potente e minimalista e la seconda, un superset della prima destinata a fornire estensioni di funzionalità per l'interoperabilità tra le implementazioni. Fino ad allora, ci affidiamo a SRFI (richieste di schema per l'implementazione), che forniscono (se implementato nell'implementazione dell'host o manualmente (come è comune nello schema)) un mezzo per eseguire in modo portabile attività comuni. Tutto ciò per dire che il primo frammento di codice (51 caratteri), pur rimanendo il più portatile possibile, si affida a SRFI-22 (esecuzione di script di schema in UNIX) per l'accesso agli argomenti della riga di comando:

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

o più facilmente:

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

Il secondo (48 caratteri) è un mezzo di interpretazione senza file che non può valutarsi (in un ambiente nullo):

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

o più facilmente:

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

Il codice non funziona se si copia l'interprete.
FUZxxl,

1
Lascialo a una risposta dello schema per contenere parentesi annidate nella sua prosa.
Cyoce,

1

Groovy, 13 byte

{Eval.me(it)}

Questo dovrebbe interpretare un sottoinsieme di Groovy.

casi test:

p={Eval.me(it)}

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

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

Sfortunatamente, sebbene certamente offra, lo fa in un modo completamente da interprete e lo fa per un bel po 'di input.


In quale riga leggi il programma da interpretare? Il tuo codice è interessante anche se non è un invio valido per questa attività.
FUZxxl,

Presumo che l'errore sia qualcosa come "limite di ricorsione superato"?
Ilmari Karonen,

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.