Je recherche CoffeeScript sur le site Web http://coffeescript.org/ , et il contient le texte
Le compilateur CoffeeScript est lui-même écrit en CoffeeScript
Comment un compilateur peut-il se compiler, ou que signifie cette déclaration?
compilation
AlexanderRD
la source
la source
self-hosting
compilateur. Voir programmers.stackexchange.com/q/263651/6221Réponses:
La première édition d'un compilateur ne peut pas être générée automatiquement à partir d'un langage de programmation qui lui est spécifique; votre confusion est compréhensible. Une version ultérieure du compilateur avec plus de fonctionnalités de langage (avec la source réécrite dans la première version du nouveau langage) pourrait être construite par le premier compilateur. Cette version pourrait alors compiler le prochain compilateur, et ainsi de suite. Voici un exemple:
Remarque: je ne sais pas exactement comment les versions de CoffeeScript sont numérotées, ce n'était qu'un exemple.
Ce processus est généralement appelé bootstrapping . Un autre exemple de compilateur d'amorçage est
rustc
le compilateur du langage Rust .la source
Dans l'article Reflections on Trusting Trust , Ken Thompson, l'un des initiateurs d'Unix, écrit un aperçu fascinant (et facilement lisible) de la façon dont le compilateur C se compile. Des concepts similaires peuvent être appliqués à CoffeeScript ou à tout autre langage.
L'idée d'un compilateur qui compile son propre code est vaguement similaire à un quine : code source qui, lorsqu'il est exécuté, produit en sortie le code source d'origine. Voici un exemple de quine CoffeeScript. Thompson a donné cet exemple de C quine:
Ensuite, vous pourriez vous demander comment le compilateur apprend qu'une séquence d'échappement comme
'\n'
représente le code ASCII 10. La réponse est que quelque part dans le compilateur C, il existe une routine qui interprète les caractères littéraux, contenant certaines conditions comme celle-ci pour reconnaître les séquences de barres obliques inverses:Nous pouvons donc ajouter une condition au code ci-dessus…
… Pour produire un compilateur qui sait que
'\n'
représente ASCII 10. Fait intéressant, ce compilateur, et tous les compilateurs suivants compilés par lui , "connaissent" ce mappage, donc dans la prochaine génération du code source, vous pouvez changer cette dernière ligne en… Et il fera la bonne chose! Le
10
provient du compilateur et n'a plus besoin d'être explicitement défini dans le code source du compilateur. 1C'est un exemple d'une fonctionnalité de langage C qui a été implémentée dans du code C. Maintenant, répétez ce processus pour chaque fonctionnalité du langage, et vous avez un compilateur "auto-hébergé": un compilateur C qui est écrit en C.
1 La torsion de l'intrigue décrite dans l'article est que puisque le compilateur peut être "enseigné" des faits comme celui-ci, il peut également être mal appris pour générer des exécutables de chevaux de Troie d'une manière qui est difficile à détecter, et un tel acte de sabotage peut persister dans tous les compilateurs produits par le compilateur corrompu.
la source
Vous avez déjà obtenu une très bonne réponse, mais je veux vous offrir une perspective différente, qui, espérons-le, vous éclairera. Établissons d'abord deux faits sur lesquels nous pouvons tous deux nous entendre:
Je suis sûr que vous pouvez convenir que les deux numéros 1 et 2 sont vrais. Maintenant, regardez les deux déclarations. Voyez-vous maintenant qu'il est tout à fait normal que le compilateur CoffeeScript puisse compiler le compilateur CoffeeScript?
Le compilateur ne se soucie pas de ce qu'il compile. Tant qu'il s'agit d'un programme écrit en CoffeeScript, il peut le compiler. Et le compilateur CoffeeScript lui-même se trouve être un tel programme. Le compilateur CoffeeScript ne se soucie pas que ce soit le compilateur CoffeeScript lui-même qu'il compile. Tout ce qu'il voit, c'est du code CoffeeScript. Période.
Oui, c'est exactement ce que signifie cette déclaration, et j'espère que vous pouvez voir maintenant comment cette déclaration est vraie.
la source
Cela signifie exactement cela. Tout d'abord, certaines choses à considérer. Il y a quatre objets que nous devons examiner:
Maintenant, il devrait être évident que vous pouvez utiliser l'assembly généré - l'exécutable - du compilateur CoffeScript pour compiler n'importe quel programme CoffeScript arbitraire et générer l'assembly pour ce programme.
Maintenant, le compilateur CoffeScript lui-même n'est qu'un programme CoffeScript arbitraire, et donc, il peut être compilé par le compilateur CoffeScript.
Il semble que votre confusion provient du fait que lorsque vous créez votre propre nouvelle langue, vous n'avez un compilateur mais vous pouvez utiliser pour compiler votre compilateur. Cela ressemble sûrement à un problème d'oeuf de poule , non?
Présentez le processus appelé bootstrapping .
Vous devez maintenant ajouter de nouvelles fonctionnalités. Supposons que vous
while
n'ayez implémenté que -loops, mais quefor
vous vouliez également -loops. Ce n'est pas un problème, puisque vous pouvez réécrire n'importe quellefor
-loop de telle sorte que ce soit unewhile
-loop. Cela signifie que vous ne pouvez utiliserwhile
-loops que dans le code source de votre compilateur, puisque l'assembly que vous avez sous la main ne peut les compiler. Mais vous pouvez créer des fonctions dans votre compilateur qui peuvent passer et compilerfor
-loops avec lui. Ensuite, vous utilisez l'assembly que vous avez déjà et compilez la nouvelle version du compilateur. Et maintenant, vous avez un assembly d'un compilateur qui peut également analyser et compilerfor
-loops! Vous pouvez maintenant revenir au fichier source de votre compilateur et réécrire toutes leswhile
boucles que vous ne voulez pas dansfor
-loops.Rincez et répétez jusqu'à ce que toutes les fonctionnalités du langage souhaitées puissent être compilées avec le compilateur.
while
etfor
n'étaient évidemment que des exemples, mais cela fonctionne pour toute nouvelle fonctionnalité de langage que vous souhaitez. Et puis vous êtes dans la situation dans laquelle CoffeScript est maintenant: Le compilateur se compile.Il y a beaucoup de littérature là-bas. Reflections on Trusting Trust est un classique que tous ceux qui s'intéressent à ce sujet devraient lire au moins une fois.
la source
Une petite mais importante clarification
Ici, le terme compilateur passe sous silence le fait qu'il y a deux fichiers impliqués. L'un est un exécutable qui prend comme fichiers d'entrée écrits en CoffeScript et produit comme fichier de sortie un autre exécutable, un fichier objet pouvant être lié ou une bibliothèque partagée. L'autre est un fichier source CoffeeScript qui se trouve juste pour décrire la procédure de compilation de CoffeeScript.
Vous appliquez le premier fichier au second, produisant un troisième qui est capable d'effectuer le même acte de compilation que le premier (éventuellement plus, si le second fichier définit des fonctionnalités non implémentées par le premier), et peut donc remplacer le premier si vous alors le désir.
la source
Comme la version Ruby du compilateur CoffeeScript existait déjà, elle a été utilisée pour créer la version CoffeeScript du compilateur CoffeeScript.
C'est ce qu'on appelle un compilateur auto-hébergé .
C'est extrêmement courant et résulte généralement du désir d'un auteur d'utiliser sa propre langue pour maintenir la croissance de cette langue.
la source
Ce n'est pas une question de compilateurs ici, mais une question d'expressivité du langage, puisqu'un compilateur n'est qu'un programme écrit dans un langage.
Quand nous disons qu '"un langage est écrit / implémenté", nous voulons dire en fait qu'un compilateur ou un interpréteur pour ce langage est implémenté. Il existe des langages de programmation dans lesquels vous pouvez écrire des programmes qui implémentent le langage (il s'agit de compilateurs / interprètes pour le même langage). Ces langues sont appelées langues universelles .
Pour pouvoir comprendre cela, pensez à un tour à métaux. C'est un outil utilisé pour façonner le métal. Il est possible, en utilisant uniquement cet outil, de créer un autre outil identique, en créant ses pièces. Ainsi, cet outil est une machine universelle. Bien sûr, le premier a été créé en utilisant d'autres moyens (d'autres outils), et était probablement de qualité inférieure. Mais le premier a été utilisé pour en construire de nouveaux avec une plus grande précision.
Une imprimante 3D est presque une machine universelle. Vous pouvez imprimer toute l'imprimante 3D à l'aide d'une imprimante 3D (vous ne pouvez pas construire la pointe qui fait fondre le plastique).
la source
Preuve par induction
Étape inductive
La version n + 1e du compilateur est écrite en X.
Ainsi, il peut être compilé par la nième version du compilateur (également écrite en X).
Cas de base
Mais la première version du compilateur écrite en X doit être compilée par un compilateur pour X qui est écrit dans un langage autre que X. Cette étape est appelée amorçage du compilateur.
la source
Les compilateurs prennent une spécification de haut niveau et la transforment en une implémentation de bas niveau, telle qu'elle peut être exécutée sur du matériel. Il n'y a donc pas de relation entre le format de la spécification et l'exécution réelle en dehors de la sémantique du langage ciblé.
Les compilateurs croisés passent d'un système à un autre, les compilateurs multilingues compilent une spécification de langage dans une autre spécification de langage.
Fondamentalement, la compilation est une traduction juste, et le niveau est généralement du niveau supérieur de la langue au niveau inférieur de la langue, mais il existe de nombreuses variantes.
Les compilateurs d'amorçage sont les plus déroutants, bien sûr, car ils compilent le langage dans lequel ils sont écrits. N'oubliez pas l'étape initiale du bootstrap qui nécessite au moins une version minimale existante exécutable. De nombreux compilateurs bootstrap travaillent d'abord sur les fonctionnalités minimales d'un langage de programmation et ajoutent des fonctionnalités de langage complexes supplémentaires à l'avenir tant que la nouvelle fonctionnalité peut être exprimée en utilisant les fonctionnalités précédentes. Si ce n'était pas le cas, il faudrait que cette partie du "compilateur" soit développée au préalable dans un autre langage.
la source