L'écriture d'un compilateur dans sa propre langue
Intuitivement, il semble qu'un compilateur pour le langage Foo
ne peut pas être lui-même écrit dans Foo. Plus précisément, le première compilateur pour le langage Foo
ne peut pas être écrit dans Foo, mais tout ultérieure compilateur pourrait être écrit pour Foo
.
Mais est-ce réellement vrai? J'ai quelques très vague souvenir de la lecture d'une langue dont le premier compilateur a été écrit dans "elle-même". Est-ce possible, et si oui, comment?
- Double Possible de Amorçage nécessite encore d'un soutien extérieur
- C'est une très vieille question, mais disons que j'ai écrit un interprète pour la langue Foo en Java. Puis avec la langue foo, j'ai écrit son propre interprète. Foo nécessiterait encore la JRE droit?
Vous devez vous connecter pour publier un commentaire.
Cela s'appelle le "bootstrapping". Vous devez d'abord construire un compilateur (ou interprète) pour votre langue, dans un autre langage (Java ou C). Une fois que c'est fait, vous pouvez écrire une nouvelle version du compilateur de langage de Foo. Vous utilisez la première bootstrap compilateur pour compiler le compilateur, et ensuite utiliser cette compilé compilateur pour compiler tout le reste (y compris les futures versions de lui-même).
La plupart des langues sont en effet créés de cette manière, en partie parce que la langue designers aiment à utiliser la langue qu'ils sont en train de créer, et aussi parce qu'un non-trivial compilateur sert souvent comme un outil de référence utile pour comment "remplir" la langue peut être.
Un exemple de ceci serait Scala. Son premier compilateur a été créé dans les Pizzas, une expérience de la langue par Martin Odersky. À partir de la version 2.0, le compilateur a été complètement ré-écrit en Scala. À partir de ce moment, la vieille Pizza compilateur peut être complètement écartée, en raison du fait que le nouveau compilateur Scala pourrait être utilisé pour compiler lui-même pour les futures itérations.
Je me souviens de l'écoute d'un Génie logiciel podcast Radio où Dick Gabriel a parlé de démarrage de l'original interpréteur LISP par la rédaction d'un bare-bones version en LISP sur papier et de la main de l'assemblage en code machine. À partir de là, le reste du LISP caractéristiques étaient à la fois écrit et interprété avec LISP.
L'ajout d'une curiosité pour les réponses précédentes.
Voici une citation de la Linux From Scratch manuel, à l'étape où l'on commence à construire le compilateur GCC à partir de sa source. (Linux from Scratch est un moyen d'installer Linux qui est radicalement différent de l'installation d'une distribution, vous devez compiler vraiment chaque binaire du système cible.)
Que l'utilisation de la 'bootstrap' objectif est motivé par le fait que le compilateur l'on utilise pour construire le système cible de la chaîne ne peut pas avoir la même version de la cible du compilateur. Procédant de la sorte, on est sûr d'obtenir, dans le système cible, un compilateur qui permet de compiler lui-même.
Lorsque vous écrivez votre premier compilateur pour C, vous l'écrire dans une autre langue. Maintenant, vous avez un compilateur de C dans, disons, de l'assembleur. Finalement, vous arriverez à l'endroit où vous avez à analyser des chaînes, plus précisément des séquences d'échappement. Vous allez écrire le code pour convertir
\n
pour le personnage avec le code décimal 10 (et\r
à 13, etc).Après que le compilateur est prêt, vous allez commencer à ré-écrire en C. Ce processus est appelé "l'amorçage".
La chaîne d'analyse de code sera le suivant:
Lors de cette compile, vous disposez d'un binaire qui comprend le '\n'. Cela signifie que vous pouvez modifier le code source:
Alors, où est l'information que "\n " est le code pour 13? C'est dans le binaire! C'est comme de l'ADN: la Compilation de code source C avec ce binaire hériteront de cette information. Si le compilateur compile lui-même, il va transmettre cette connaissance à sa progéniture. À partir de ce point, il n'y a pas moyen de voir à partir de la source de ce que le compilateur ne.
Si vous voulez cacher un virus dans le source d'un programme, vous pouvez le faire comme ceci: Obtenir le code source d'un compilateur, trouver la fonction qui compile les fonctions et le remplacer par celui-ci:
Les parties intéressantes sont A et B. A est le code source pour
compileFunction
y compris les virus, probablement cryptée, d'une certaine façon il n'est donc pas évident de la recherche sur le binaire résultant. Cela permet de s'assurer que la compilation le compilateur avec lui-même permettra de préserver le virus de l'injection de code.B est le même pour la fonction que nous voulons remplacer notre virus. Par exemple, il pourrait être la fonction "login" dans le source du fichier "login.c" est probablement à partir du noyau Linux. On pourrait le remplacer par une version qui accepte le mot de passe "joshua" pour le compte root en plus du mot de passe.
Si vous compiler et diffuser comme un fichier binaire, il n'y aura pas moyen de trouver le virus en regardant le source.
La source d'origine de l'idée: http://cm.bell-labs.com/who/ken/trust.html
Vous ne pouvez pas écrire un compilateur en lui-même parce que vous n'avez rien à compiler votre départ code source avec. Il existe deux approches pour la résolution de ce.
Les moins favorisés est la suivante. Vous écrivez un minimum de compilateur assembleur (beurk) pour un ensemble minimal de la langue, et ensuite utiliser le compilateur de mettre en œuvre des fonctionnalités supplémentaires de la langue. La construction de votre façon jusqu'à ce que vous avez un compilateur avec toutes les fonctionnalités de langage pour lui-même. Un processus douloureux qui est habituellement fait seulement lorsque vous n'avez pas d'autres choix.
L'approche privilégiée consiste à utiliser un compilateur croisé. Vous modifier l'arrière d'un compilateur sur une machine différente pour créer une sortie qui s'exécute sur la machine cible. Ensuite, vous avez une belle compilateur complet et fonctionne sur la machine cible. Le plus populaire pour ce qui est du langage C, car il ya beaucoup de compilateurs existants qui ont enfichable à l'arrière extrémités qui peuvent être permutées.
Un fait peu connu est que le compilateur GNU C++ est une application qui utilise uniquement le sous-ensemble C. La raison d'être, il est généralement facile de trouver un compilateur C pour une nouvelle machine cible qui vous permet ensuite de construire le plein compilateur GNU C++ à partir d'elle. Vous avez maintenant de démarrage attaché-vous d'avoir un compilateur C++ sur la machine cible.
Généralement, vous avez besoin d'avoir un travail (si primative) coupe du compilateur travaille d'abord - ensuite, vous pouvez commencer à penser à l'auto-hébergement. C'est en fait considéré comme un jalon important dans certaines langues.
De ce que je me souviens de "mono", il est probable qu'ils auront besoin d'ajouter quelques choses à la réflexion pour le faire fonctionner: l'équipe de mono garder soulignant que certaines choses ne sont tout simplement pas possible avec
Reflection.Emit
; bien sûr, les états membres de l'équipe peuvent prouver qu'ils ont tort.Ce qui a un peu de réel avantages: c'est un assez bon test de l'unité, pour les débutants! Et vous n'avez qu'une seule langue à s'inquiéter (c'est à dire qu'il est possible en C# expert pourriez ne pas savoir beaucoup de C++; mais maintenant, ton peut fixer le compilateur C#). Mais je me demande si il n'y a pas un montant de fierté professionnelle ici à l'œuvre: ils ont simplement voulez auto-hébergement.
Pas tout à fait un compilateur, mais j'ai récemment travaillé sur un système d'auto hébergement; le générateur de code est utilisé pour générer le générateur de code... donc, si les modifications de schéma, j'ai simplement l'exécuter sur elle-même : la nouvelle version. Si il y a un bug, je viens de revenir à une version antérieure et essayez de nouveau. Très pratique et très facile à entretenir.
Mise à jour de 1
J'ai juste regardé cette vidéo de Anders au PDC, et (environ une heure), il donne beaucoup plus de raisons valables - tout sur le compilateur comme un service. Juste pour le record.
Voici un dump (sujet difficile à rechercher, en fait):
Smalltalk
C
C'est aussi l'idée de PyPy et Rubinius:
(Je pense que cela pourrait également s'appliquer à Suite, mais je ne sais rien à propos de Suite.)
GNAT, le compilateur GNU Ada, nécessite un compilateur Ada pour être pleinement intégré. Cela peut être une douleur lorsque le portage vers une plate-forme où il n'y a pas de GNAT binaire facilement disponibles.
En fait, la plupart des compilateurs sont écrits dans la langue de leur compilation, pour les raisons indiquées ci-dessus.
La première bootstrap compilateur est généralement écrites en C, C++ ou de l'Assemblée.
Le Mono projet compilateur C# a été "auto-organisé" pour un long moment maintenant, ce que cela signifie, c'est qu'il a été écrit en C# elle-même.
Ce que je sais, c'est que le compilateur a commencé comme pur code en C, mais une fois que la "base" caractéristiques de l'ECMA ont été mis en œuvre, ils ont commencé à réécrire le compilateur en C#.
Je ne suis pas au courant des avantages de l'écriture du compilateur dans la même langue, mais je suis sûr qu'il a à faire, au moins, avec les caractéristiques que le langage lui-même peut offrir (C, par exemple, ne prend pas en charge la programmation orientée objet).
Vous pouvez trouver plus d'informations ici.
Peut-être que vous pouvez écrire un BNF décrivant la BNF.