Remarques
――Veuillez le considérer comme une sorte de jeu. -Ce n'est pas l'histoire de Gauche's Are. ――L'auteur n'est pas très familier avec le langage C. Veuillez signaler tout point étrange.
Récemment, j'ai joué avec la création de Lisp avec Python.
C'était amusant avec ça, mais je n'étais pas motivé parce que ce n'était pas pratique, à part l'utiliser et ne pas l'utiliser, et je me demandais à quoi jouer ensuite. À ce moment-là, je me souviens avoir lu un article quelque part qui semble venir avec un transpilateur de langage S-type → C, et cela me paraissait intéressant, alors j'ai complètement détourné la partie lecteur de mon propre Lisp. Je l'ai implémenté en Python. L'original s'appelle CiSE (C dans S-Expression), mais celui implémenté cette fois est ** complètement différent **. Au fait, il a une saveur plutôt Common Lisp.
Publié sous le nom CLOP, donc si vous êtes intéressé, s'il vous plaît. Au fait, c'est un nom que je n'aime pas vraiment, alors je pourrais le changer si j'y pense. CiSE peut être cool.
Le flux de génération du langage C à partir de l'expression S est le suivant.
Une * fonction prédéfinie * est, par exemple:
def aref(array, subscript):
return f"{array}[{subscript}]"
Par exemple, (aref hoge fuga)
est converti en["aref", "hoge", "fuga"]
(1), puis" hoge [fuga] "" est généré (2). est. A ce moment, si le premier élément de la liste n'est pas recherché, il est traité en fonction de c. Par exemple,
(printf" bonjour ")produit
" printf (\ "bonjour ") "` (3).
De plus, «+ hoge +» est converti en «HOGE», et «hoge-hoge» est converti en «hoge_hoge».
J'ai utilisé l'expression ** function ** telle que définie à l'avance, mais le fait est que c'est comme une macro. Les macros suivantes sont définies à l'avance dans CLOP.
* + - / 1+ 1- < > and aref ash break cast cond continue
decf declare defconstant defenum defstruct defsyntax
defun defunion defvar eq for if incf include let logand
logior logxor mod not or progn return setf when while
La plupart des noms sont tirés de Common Lisp ou C. C'est juste cela, donc vous pouvez presque imaginer ce que cela fait.
Si vous ne l'oubliez pas, vous devriez être capable de gérer presque toutes les fonctions du langage C.
Hello, world!
hello.clop
(include stdio)
(defun int:main (void)
(printf "Hello, world!\n")
(return 0))
Je pense que je ne l'ai pas vu. Le type est déclaré avec des spécificateurs séparés par des deux-points, tels que ʻunsigned: int: hoge`. Vous pouvez convertir en langage C avec la commande suivante.
$ clop translate hello.clop --out hello.c
hello.c
#include <stdio.h>
int main (void)
{
printf("Hello, world!\n");
return 0;
}
Vous pouvez utiliser des macros pour le moment. Cependant, CLOP n'est rien de plus qu'un ** list → convertisseur de chaînes ** après tout, il n'y a donc pas de fonction d'opération de liste. Par conséquent, vous ne pouvez pas utiliser de macros puissantes comme Common Lisp, mais vous pouvez écrire de manière plus flexible que les fonctions macro en langage C. Par exemple.
python
(defsyntax null (ptr)
(eq ,ptr +null+))
Ceci est développé comme suit.
hoge == NULL // (null hoge)
Il est vraiment désagréable d'avoir des guillemets arrière même s'il n'y a pas de guillemets, mais si vous ajoutez des guillemets arrière, la valeur sera insérée à partir de l'argument donné au moment de l'expansion de la macro. C'est la même chose que la macro CPP, voici donc un exemple plus compliqué. Dans CLOP, vous pouvez utiliser des arguments d'option de type Common Lisp, des arguments de mot-clé et des arguments de longueur variable.
with-open-file.clop
(include stdio)
(defsyntax null (ptr)
(eq ,ptr +null+))
(defsyntax with-open-file ((stream filespec &optional (mode "w")) &body body)
(let ((FILE*:,stream (fopen ,filespec ,mode)))
(if (null ,stream)
(perror "Failed to open file")
(progn
,@body
(fclose ,stream)))))
Si vous faites , @ hoge
, le contenu de l'argument sera développé tel quel. (Une parenthèse peut être prise)
Vous pouvez écrire la définition de la macro dans un seul code source, mais vous pouvez également la extraire d'un autre fichier avec require
. A ce moment, le fichier d'en-tête qui est ʻincludeest également extrait en même temps s'il n'est pas déjà inclus. De plus, à l'exception de la définition de macro et de l'inclusion, elle sera ignorée. Voici un exemple de
require the previous
with-open-file.clop avec
main.clop`.
main.clop
(include stdio)
(require with-open-file)
(defun int:main (void)
(with-open-file (fd "hello.txt")
(fprintf fd "Hello, world!\n"))
(return 0))
$ clop translate main.clop --out main.c
main.c
#include <stdio.h>
int main (void)
{
({
FILE* fd = fopen("hello.txt", "w");
fd == NULL? (perror("Failed to open file")) : (({
fprintf(fd, "Hello, world!\n");
fclose(fd);
}));
});
return 0;
}
C'est un code effrayant, mais cela fonctionne bien. CLOP fait un usage intensif des expressions composées (comme ({hoge; fuge; ...})
), ce qui peut la rendre terrible dans certains cas.
Pensons aux avantages.
Sauf pour le troisième, c'est subtil.
J'ai senti que la syntaxe du langage C était compliquée. Je ne pense pas à l'écriture de C brut, mais lors de la génération à partir d'une expression S, j'étais assez inquiet de savoir où mettre les parenthèses et où appuyer sur le point-virgule. Compte tenu de cela, je pense que le pouvoir expressif de la formule S est incroyable.
Implémentation d'Oreore CiSE en Python. Je pense qu'il y a un désir universel d'écrire des choses non-S dans le style S (par exemple, Hy). Et le langage C? Je voudrais toucher CiSE du chef de famille gauche, mais c'est dommage qu'il n'y ait pas beaucoup d'informations. (Peut-être que vous ne pouvez tout simplement pas le trouver. S'il vous plaît laissez-moi savoir si vous avez un bon document)
** Addenda ** Il y avait une telle chose. https://github.com/burtonsamograd/sxc
Recommended Posts