Clem è un linguaggio di programmazione basato su stack minimo con funzioni di prima classe. Il tuo obiettivo è quello di scrivere un interprete per il linguaggio Clem. Dovrebbe eseguire correttamente tutti gli esempi inclusi nell'implementazione di riferimento, disponibile qui .
- Come al solito, si applicano scappatoie standard .
- Vince la voce più piccola per numero di byte.
La lingua clem
Clem è un linguaggio di programmazione basato su stack con funzioni di prima classe. Il modo migliore per imparare Clem è eseguire l' clem
interprete senza argomenti. Si avvierà in modalità interattiva, permettendoti di giocare con i comandi disponibili. Per eseguire i programmi di esempio, digitare clem example.clm
dove esempio è il nome del programma. Questo breve tutorial dovrebbe essere sufficiente per iniziare.
Esistono due classi principali di funzioni. Funzioni atomiche e funzioni composte. Le funzioni composte sono elenchi composti da altre funzioni composte e funzioni atomiche. Si noti che una funzione composta non può contenere se stessa.
Funzioni atomiche
Il primo tipo di funzione atomica è la costante . Una costante è semplicemente un valore intero. Ad esempio, -10. Quando l'interprete incontra una costante , la spinge in pila. Corri clem
adesso. Digitare -10
al prompt. Tu dovresti vedere
> -10
001: (-10)
>
Il valore 001
descrive la posizione della funzione nello stack ed (-10)
è la costante appena inserita. Ora inserisci +11
al prompt. Tu dovresti vedere
> +11
002: (-10)
001: (11)
>
Si noti che (-10)
è passato alla seconda posizione nella pila e (11)
ora occupa la prima. Questa è la natura di uno stack! Noterai che -
è anche il comando di decremento. Ogni volta -
che +
precedono un numero, indicano il segno di quel numero e non il comando corrispondente. Tutte le altre funzioni atomiche sono comandi . Ce ne sono 14 in totale:
@ Rotate the top three functions on the stack
# Pop the function on top of the stack and push it twice
$ Swap the top two functions on top of the stack
% Pop the function on top of the stack and throw it away
/ Pop a compound function. Split off the first function, push what's left,
then push the first function.
. Pop two functions, concatenate them and push the result
+ Pop a function. If its a constant then increment it. Push it
- Pop a function. If its a constant then decrement it. Push it
< Get a character from STDIN and push it to the stack. Pushes -1 on EOF.
> Pop a function and print its ASCII character if its a constant
c Pop a function and print its value if its a constant
w Pop a function from the stack. Peek at the top of the stack. While it is
a non-zero constant, execute the function.
Digitando un comando al prompt verrà eseguito il comando. Digitare #
al prompt (il comando duplicato). Tu dovresti vedere
> #
003: (-10)
002: (11)
001: (11)
>
Si noti che il (11) è stato duplicato. Ora digita %
al prompt (il comando drop). Tu dovresti vedere
> %
002: (-10)
001: (11)
>
Per inviare un comando allo stack, racchiuderlo semplicemente tra parentesi. Digitare (-)
al prompt. Ciò spingerà l'operatore di decremento nello stack. Tu dovresti vedere
> (-)
003: (-10)
002: (11)
001: (-)
>
Funzioni composte
È inoltre possibile racchiudere tra parentesi più funzioni atomiche per formare una funzione composta. Quando si inserisce una funzione composta al prompt, viene inserita nello stack. Digitare ($+$)
al prompt. Tu dovresti vedere
> ($+$)
004: (-10)
003: (11)
002: (-)
001: ($ + $)
>
Tecnicamente, tutto nello stack è una funzione composta. Tuttavia, alcune delle funzioni composte nello stack sono costituite da un'unica funzione atomica (nel qual caso, le considereremo come funzioni atomiche per motivi di praticità). Quando si manipolano le funzioni composte nello stack, il .
comando (concatenazione) è spesso utile. Digita .
ora. Tu dovresti vedere
> .
003: (-10)
002: (11)
001: (- $ + $)
>
Si noti che la prima e la seconda funzione nello stack sono state concatenate e che la seconda funzione nello stack viene prima nell'elenco risultante. Per eseguire una funzione che si trova nello stack (sia esso atomico o composto), è necessario emettere il w
comando (while). Il w
comando farà apparire la prima funzione nello stack ed eseguirla ripetutamente finché la seconda funzione nello stack è una costante diversa da zero. Prova a prevedere cosa accadrà se digitiamo w
. Ora digita w
. Tu dovresti vedere
> w
002: (1)
001: (0)
>
È quello che ti aspettavi? Sono stati aggiunti i due numeri in cima alla pila e la loro somma rimane. Proviamo di nuovo. Per prima cosa lasciamo cadere lo zero e spingiamo un 10 digitando %10
. Tu dovresti vedere
> %10
002: (1)
001: (10)
>
Ora digiteremo l'intera funzione in un colpo solo, ma aggiungeremo un extra %
alla fine per sbarazzarci dello zero. Digitare (-$+$)w%
al prompt. Tu dovresti vedere
> (-$+$)w%
001: (11)
>
(Nota che questo algoritmo funziona solo se la prima costante nello stack è positiva).
stringhe
Sono anche presenti stringhe. Sono principalmente zucchero sintattico, ma possono essere abbastanza utili. Quando l'interprete incontra una stringa, spinge ogni personaggio dall'ultimo al primo nella pila. Digitare %
per eliminare l'11 dall'esempio precedente. Ora digita 0 10 "Hi!"
il prompt. Il 0
inserirà un terminatore NULL e la 10
inserirà un carattere di nuova linea. Tu dovresti vedere
> 0 10 "Hi!"
005: (0)
004: (10)
003: (33)
002: (105)
001: (72)
>
Digitare (>)w
per stampare i caratteri dalla pila fino a quando non si incontra il terminatore NULL. Tu dovresti vedere
> (>)w
Hi!
001: (0)
>
conclusioni
Speriamo che questo sia sufficiente per iniziare con l'interprete. Il design del linguaggio dovrebbe essere relativamente semplice. Fammi sapere se qualcosa è terribilmente poco chiaro :) Alcune cose sono state lasciate intenzionalmente vaghe: i valori devono essere firmati e almeno 16 bit, lo stack deve essere abbastanza grande per eseguire tutti i programmi di riferimento, ecc. Molti dettagli non sono stati scolpiti qui fuori perché una specifica del linguaggio completo sarebbe proibizionalmente grande da pubblicare (e non ne ho ancora scritto uno: P). In caso di dubbio, imitare l'implementazione di riferimento.