Comment le premier compilateur C ++ pourrait-il être écrit en C ++?

48

Stroustrup affirme que Cfront, le premier compilateur C ++, a été écrit en C ++ ( FAQ Stroustrup ).

Cependant, comment est-il possible que le premier compilateur C ++ soit écrit en C ++?

Le code qui compose le compilateur doit également être compilé et le premier compilateur C ++ n'aurait donc pas pu être écrit en C ++, n'est-ce pas?

Pacerier
la source

Réponses:

57

La clé est ici:

Le premier compilateur C ++ (Cfront) a été écrit en C ++. Pour construire cela, j'ai d'abord utilisé C pour écrire un préprocesseur "C with Classes"-to-C. "C with Classes" était un dialecte C qui devint l'ancêtre immédiat du C ++. Ce préprocesseur a traduit les constructions "C avec classes" (telles que les classes et les constructeurs) en C. Il s'agissait d'un préprocesseur traditionnel qui ne comprenait pas tout le langage, laissait la plupart des vérifications de type au compilateur C et traduisait individuellement construit sans connaissance complète. J'ai ensuite écrit la première version de Cfront dans "C with Classes".

La première version de Cfront n'a donc pas été écrite en C ++, mais plutôt dans le langage intermédiaire. La possibilité de créer des compilateurs C et des pré-processeurs directement en C a entraîné de nombreuses innovations (et d’ énormes lacunes en matière de sécurité ) en C. Vous écrivez donc votre nouveau préprocesseur qui transforme votre code "C avec classes" en C (car C peut faire quoi que ce soit) et ensuite vous utilisez "C with Classes" pour écrire un compilateur C ++ (non pas que vous ne puissiez pas le faire en C, cela prendrait un moment) puis vous utilisez ce compilateur C ++ pour écrire un compilateur plus efficace / complet en C ++. Je l'ai?

Christopher Bibbs
la source
5
+1 pour l'inclusion d'un lien vers l'une de mes histoires préférées de choses qui peuvent être faites (et ne devraient pas).
Jwernerny
3
Le compilateur a été écrit en code C ++ valide, mais n’a utilisé que quelques-unes des fonctionnalités complètes de C ++, celles qui étaient prises en charge par le préprocesseur "C with Classes". Il utilisait un sous-ensemble du langage complet, il était donc également compilé sur le résultat (la première version de travail de Cfront). Après avoir effectué cette étape de "démarrage", il n’a probablement jamais eu besoin de réutiliser le préprocesseur.
joeytwiddle
2
@ Jwernerny - J'ai toujours trouvé cet article insatisfaisant. Il passe sous silence la partie la plus difficile et non triviale: "Le bogue correspond au code de la commande 'login' UNIX. Le code de remplacement falsifiera la commande de connexion de manière à accepter soit le mot de passe crypté prévu, soit un mot de passe connu particulier. " Mais comment cela serait-il fait? At-il déjà été démontré?
Détly
3
"C a été à l'origine de nombreuses innovations (et d'énormes failles de sécurité) en C": Autant que je sache, ces astuces peuvent être utilisées dans n'importe quelle langue, pas seulement en C. Toute autre langue peut donc avoir les mêmes failles de sécurité.
Giorgio
2
@detly: Cela semble anodin maintenant, mais en 1983, il s'agissait d'une nouvelle attaque rendue viable par un manque de diversité dans la mise en œuvre. Nous faisions davantage confiance aux fichiers binaires à l'époque, en partie parce que tout compiler à partir de la source était une épreuve beaucoup plus grande qu'aujourd'hui.
Blrfl
17

C'était bootstrapped. Dès qu'une fonctionnalité C ++ a été ajoutée à cfront, cfront peut également utiliser cette fonctionnalité à partir de ce moment (mais pas pour implémenter cette fonctionnalité). Cela a fonctionné car cfront avait la possibilité de convertir le code C ++ en code C. Ainsi, si une nouvelle plate-forme venait à apparaître, vous pourriez utiliser cfront sur une autre plate-forme pour convertir cfront de C ++ en C, puis utiliser le compilateur C de la nouvelle plate-forme pour terminer la compilation de C en code objet.

David Schwartz
la source
9

Je pense que BS répond à cette question:

Le premier compilateur C ++ (Cfront) a été écrit en C ++. Pour construire cela, j'ai d'abord utilisé C pour écrire un préprocesseur "C with Classes"-to-C. "C with Classes" était un dialecte C qui devint l'ancêtre immédiat du C ++. Ce préprocesseur a traduit les constructions "C avec classes" (telles que les classes et les constructeurs) en C. Il s'agissait d'un préprocesseur traditionnel qui ne comprenait pas tout le langage, laissait la plupart des vérifications de type au compilateur C et traduisait individuellement construit sans connaissance complète.

J'ai ensuite écrit la première version de Cfront dans "C with Classes". Cfront était un compilateur traditionnel qui effectuait la vérification syntaxique et sémantique complète de la source C ++. Pour cela, il disposait d'un analyseur complet, de tables de symboles et d'une arborescence interne complète de chaque classe, fonction, etc. C généré, n’a utilisé C pour aucune vérification de type. Il utilisait simplement C en tant qu'assembleur. Le code résultant était d'une rapidité sans compromis.

Il a d'abord créé quelque chose qu'il a appelé "C avec classes", implémenté par un simple préprocesseur en C. Il s'agissait essentiellement de C ++, mais le préprocesseur n'a fait que peu ou pas de vérification. Il a ensuite utilisé cela pour écrire Cfront, la version plus puissante du traducteur de C ++ en C, avec vérification de type, tables de symboles, etc.

Mike Dunlavey
la source
1
Donc, fondamentalement, lorsque nous compilons un programme C ++, il est converti en C, puis une fois converti en C, il est compilé à nouveau en code machine?
Pacerier le
@Pacerier: À l'origine, oui, mais pas maintenant, je pense.
Mike Dunlavey le
Je ne comprends pas très bien ton commentaire. voulez-vous dire maintenant qu'il existe des compilateurs qui sautent la deuxième étape et prennent simplement la source C ++ et la compilent en code machine?
Pacerier
7
@ Pacerier: Eh bien, ils ne vont pas directement au langage d'assemblage ou au code machine. Habituellement, ils vont d'abord dans une représentation intermédiaire indépendante de la machine (triples ou quadruples) et analysent cela pour l'optimisation. À partir de cela, ils génèrent un code d'assemblage ou un code machine. Si vous prenez un livre sur la conception du compilateur (Aho & Ullman), je suis sûr que vous le trouverez intéressant.
Mike Dunlavey
1
Il est important de noter que le C ++ qu'il était en train de construire était également une fraction du langage qui existe actuellement. Il n'avait pas de modèles, pas de nouvelles bibliothèques, utilisait uniquement le casting en C et si je me souviens bien, il n'y avait pas d'exception.
Gort le robot
2

J'ajouterai cette réponse car aucune réponse ne couvrait cet aspect.

Techniquement, vous n'avez pas besoin d'un logiciel pour compiler du code. Tant que vous avez les spécifications du compilateur nécessaires, vous pouvez effectuer la compilation proprement dite manuellement. Ce n'est pas ainsi que le premier compilateur C ++ a été compilé. Je dis juste que c'est possible.

Comparez avec le langage d'assemblage. Quand ils ont été utilisés dans les premiers jours, il n'existait aucun logiciel d'assemblage permettant de convertir le code d'assemblage en code machine. Cela a été fait à la main, mais le langage d'assemblage a donné aux programmeurs une meilleure vue d'ensemble.

Klutt
la source