Pourquoi C ++ pour écrire un compilateur?

14

Je me demandais pourquoi C ++ est un bon choix pour écrire un compilateur. Bien sûr, C est également utile à cet effet, car de nombreux compilateurs sont écrits en C ou en C ++, mais je suis plus intéressé par C ++ cette fois. Des bonnes raisons? Je cherchais cela sur Internet, mais je ne trouve aucune bonne raison.

Kobra
la source
3
"De nombreux compilateurs sont écrits [...] en C ++" - des références? Lesquels? Qu'est-ce qui vous fait penser que C ++ est plus souvent utilisé pour la construction de compilateurs que d'autres langages populaires?
Doc Brown
6
@DocBrown Eh bien, Clang et MSVC sont écrits principalement en C ++, gcc contient maintenant un peu de C ++, Java JVM est écrit en C ++ stackoverflow.com/questions/410320/what-is-java-written-in et aussi superutilisateur. com / questions / 136136 /…
Klaim
@DocBrown DMD le compilateur de référence pour D est écrit en C ++
ratchet freak
3
Qui a dit que c'était un bon choix ??
Phil
1
@Phil Pensez-vous qu'ils ont fait ce choix sans aucune considération d'alternatives? Ce n'est pas un "bon" choix, c'est un choix "efficace".
Klaim

Réponses:

25

C ++ a deux faces. Il a un côté de développement de bas niveau qui le fait ressembler à un langage naturel pour faire des choses de bas niveau comme la génération de code. Il a également un côté de haut niveau (ce que C ne fait pas) qui vous permet de structurer une application complexe (comme un compilateur) de manière logique, orientée objet, tout en conservant les performances. Parce qu'il a à la fois des aspects de bas et de haut niveau, c'est un bon choix pour les grandes applications qui nécessitent des fonctionnalités ou des performances de bas niveau.

Oleksi
la source
10
Pour autant que je sache, une grande partie de la logique à l'intérieur d'un compilateur est de nature fonctionnelle (transformant des structures de données complexes en d'autres structures de données), donc je ne suis pas sûr si les installations orientées objet (qui sont plus ciblées sur la programmation à grande échelle) , aspects architecturaux) apportent un réel avantage à la construction du compilateur par rapport à un style de programmation procédurale. Juste mes 2 cents.
Giorgio
5
@Giorgio Le fait d'avoir des objets aide dans beaucoup d'autres aspects de l'écriture du compilateur. Par exemple, il y a beaucoup d'état qu'un compilateur doit gérer lors de l'optimisation et ce genre de choses se prête bien à la POO. De plus, la programmation orientée objet et fonctionnelle peut être assez complémentaire, donc le simple fait que les algorithmes soient principalement fonctionnels ne signifie pas que les objets n'aideront pas.
Oleksi
3
@Giorgio et Oleksi: Je peux vous confirmer tous les deux. J'ai écrit un compilateur avec Haskell pour une langue du monde réel. C'était vraiment un bon ajustement. Mais parfois, je manquais des OO autour. Si je devais écrire un autre compilateur, je choisirais certainement Haskell, mais c'est vraiment un cas particulier. Je ne choisirais pas Haskell sans hésiter pour d'autres types de projets.
scarfridge
27
Pourquoi avez-vous besoin d'un langage avec un "côté bas niveau" pour faire de la génération de code? Je ne peux pas voir comment ces deux sont connectés de quelque façon.
phant0m
5
Vous n'avez pas besoin d'un "côté bas niveau" pour faire de la génération de code pas plus que vous n'avez besoin d' identifiants Unicode pour pouvoir écrire du texte japonais dans un fichier.
dan04
16

Mon expérience ne correspond pas à votre prémisse ici. En fait, pour les langages généraux de haut niveau, il est très courant d'écrire le compilateur dans la même langue que la langue source (la langue en cours de compilation). Par exemple:

  • Le compilateur Java de Sun est écrit en Java
  • Le compilateur Scala est écrit en Scala
  • Le compilateur C # de Mono est écrit en C #
  • Le compilateur Smalltalk de Squick est écrit en Smalltalk
  • ... et beaucoup plus

Une exception est les frontaux du compilateur écrits pour les frameworks de compilateur existants, tels que GCC, LLVM ou Polyglot, qui sont ensuite écrits dans le langage du framework, ou les compilateurs qui s'appuient sur des générateurs d'analyseurs existants tels que Yacc. Étant donné que GCC, LLVM et Yacc sont des outils communs établis établis en C et C ++, cela incite les rédacteurs de compilateurs à les utiliser, ce qui pourrait conduire C et C ++ à obtenir une large part de la distribution du langage d'implémentation du compilateur.

Chêne
la source
2
Je pense que cela a beaucoup plus à voir avec le fait que les gens qui écrivent le compilateur connaissent bien et aiment beaucoup le langage pour lequel ils écrivent un compilateur que pour des raisons techniques objectives.
Thomas Bonini
1
@Krelp Je suis d'accord qu'il ne s'agit pas d'une raison technique objective, mais ce n'est pas vraiment "aimer" non plus - c'est juste considéré comme un rite de passage pour une langue - "est-il suffisamment mûr pour pouvoir servir de langage d'implémentation propre compilateur".
Oak
1
Le compilateur Java de Sun est écrit en C ++: stackoverflow.com/questions/410320/what-is-java-written-in
Klaim
12
@Klaim, vous confondez deux produits ici. L'un est le compilateur Java de Sun ( javacligne de commande), qui compile Java en Java Bytecode. Il est écrit en Java - je l'ai moi-même modifié plusieurs fois et vous pouvez parcourir ses sources Java en ligne . L'autre est le compilateur juste à temps incorporé dans la machine virtuelle Java Hotspot, qui compile Java Bytecode en code machine natif. Comme la plupart des JVM, il est écrit en C ++, mais ce n'est pas un compilateur Java - en fait, il ne sait rien du langage Java.
Oak
@Oak, absolument correct! En d'autres termes, JVM! = Javac
Paul Draper
6

Pour compiler quoi à quoi? Un compilateur transforme un code source d'une langue ( langue source) en une autre (langue de destination), ce qui n'indique rien sur le faible niveau de la langue de destination.

  • CoffeeScript compile en JavaScript, le compilateur étant écrit en CoffeeScript.
  • Script # compile C # en JavaScript, le compilateur étant écrit, si je me souviens bien, C #.
  • etc.

La langue que vous choisissez pour écrire un compilateur dépend du contexte. Par exemple, en travaillant sur un projet qui compile un langage dérivé de PHP vers un code PHP natif, j'ai utilisé un mélange de PHP et C # pour écrire le compilateur, car cela avait le plus de sens pour moi étant donné mes compétences. Une autre personne choisirait Python, ou Java et PHP, ou C ++ avec un peu de JavaScript, ou quoi que ce soit.

C ou C ++ est un choix populaire en raison de la prise en charge des outils liés au compilateur (voir la réponse de Telastyn), et parce que ces deux langues vous permettent de devenir vraiment natif. Mais il n'y a rien de mal à choisir une autre langue.

Notez que pour être plus geek , vous pouvez choisir la langue source pour écrire le compilateur lui-même. C'est ce qui s'est produit pour le compilateur CoffeeScript et de nombreux autres compilateurs. Il est également populaire auprès des IDE: l'un des premiers Visual Studio a été construit en utilisant le même Visual Studio.

Arseni Mourzenko
la source
5
L'auto-hébergement n'est pas geek, c'est une propriété importante pour le portage d'un compilateur.
5
La raison en est qu'il permet immédiatement au compilateur lui-même d'être un programme de test. Ce sera probablement aussi le plus gros programme de ce compilateur pendant un bon moment.
6

J'ai tendance à remettre en question la prémisse de base ici. Alors que C et C ++ fonctionnent parfaitement bien pour l'écriture de compilateurs, un certain nombre d'autres langages semblent également parfaitement fonctionner pour la tâche.

Cela dépend cependant un peu de la langue que vous compilez. Pour les petits langages simples, C et Pascal fonctionnent très bien. Si vous allez compiler quelque chose de gros et de complexe, votre compilateur devient aussi gros et complexe - dans ce cas, les fonctionnalités supplémentaires de C ++ pour organiser et travailler avec des programmes plus grands sont évidemment utiles. Ce n'est pas vraiment très spécifique à la compilation, juste des fonctionnalités utiles pour les programmes plus grands en général.

Je pense qu'il vaut également la peine de mentionner un autre point. Les débutants (semblent) penser que les compilateurs font principalement de la manipulation de texte, ils pensent donc que quelque chose comme Perl sera d'une aide considérable pour écrire des compilateurs. En réalité, la plupart des parties intéressantes de la compilation ne commencent vraiment qu'après avoir construit votre AST. Bien que je sois sûr que Perl puisse parfaitement faire le travail, sa capacité de manipulation de texte ne lui donne pas vraiment un énorme avantage non plus (la manipulation de texte est principalement dans le lexer, et les générateurs de lexer pour des choses comme C supportent tous les RE de toute façon).

Jerry Coffin
la source
2
AST = arbre de syntaxe abstraite, RE = expressions régulières
chaotic3quilibrium
5

Les compilateurs peuvent être implémentés dans n'importe quel langage moderne. Cependant, l'une des exigences les plus importantes d'un compilateur est d'être rapide.

C ++ a un net avantage ici. L'optimisation en C ++ n'est pas bon marché. Cependant, en raison de la nature de bas niveau de ce langage, il est possible d'optimiser manuellement le code C ++ plus que dans tout autre langage (sauf Assembly qui n'est pas portable).

Lior Kogan
la source
11
Une autre exigence importante est que le code généré soit correct - je préfère avoir un compilateur lent en lequel je peux avoir confiance qu'un rapide qui génère du code incorrect.
2
Bien qu'il soit certainement possible d'optimiser C ++ très fortement, il y a beaucoup de… plutôt… du code C ++ moins qu'optimal.
Donal Fellows
2
@DonalFellows Inversez le sens: il est possible d'écrire du code moins qu'optimal dans n'importe quel langage, mais il y a des optimisations qui sont impossibles à activer dans d'autres langages que C ++ (autre que l'assembleur. Je n'inclus pas C à cause du manque de structures de haut niveau permettant une inlining plus forte).
Klaim
3

Je soupçonne que le principal facteur de motivation pour leur utilisation est que la sortie Lex / Yacc / Bison est (principalement) en C.Comme cela a été la norme depuis si longtemps, elle a un élan.

Ce ne sont pas des raisons particulièrement bonnes ...

Telastyn
la source
En fait, cela ne me satisfait pas, mais merci d'essayer.
Kobra
Cela ne répond pas à la question "pourquoi choisir C ++ plutôt que C pour la construction du compilateur".
Doc Brown
3
Ce n'est pas du tout une bonne raison. Des outils analogues à Lex et Yacc existent pour de nombreuses plateformes. PLY et ANTLR, par exemple.
user16764
De plus, les compilateurs du monde réel les plus populaires (je suis à peu près certain qu'abuot Clang et GCC, par exemple) utilisent des analyseurs manuscrits.
@delnan: Oui, mais ils ont probablement commencé à en utiliser un généré pour faire décoller les choses. La génération manuelle de l'analyseur est une étape d'optimisation que vous ne voulez pas vraiment faire tant que vous ne pouvez pas prouver que d'autres choses fonctionnent.
Martin York
1

J'ai de l'expérience avec cette affaire. J'ai écrit des compilateurs en C et C ++. La principale différence entre C et C ++ est que C n'a pas de gestion dynamique de la mémoire de manière automatique. Toute la gestion de la mémoire en C doit être effectuée explicitement. L'écriture d'un compilateur traite beaucoup du traitement des chaînes et de la gestion des tableaux. En C, vous êtes obligé de penser à la taille de chaque chaîne et de chaque tableau que vous déclarez et vérifiez également les index lorsque vous accédez à ces objets (si vous voulez que votre code soit sûr et stable). En C, vous pouvez avoir une gestion dynamique de la mémoire, bien sûr, mais rien n'est automatique. Vous devez explicitement allouer et libérer de la mémoire en utilisant malloc () et free (), conserver la taille de vos objets dynamiques dans des variables séparées afin d'être sûr de ne pas y accéder hors des limites.

En C ++, vous pouvez avoir les mêmes mécanismes mais c'est vraiment un temps de développement efficace car toute votre gestion de la mémoire peut être encapsulée dans des constructeurs et des destructeurs que vous n'avez pas à appeler explicitement. Ainsi, le compilateur alloue et libère des ressources pour vous. La taille de vos objets dynamiques peut également être encapsulée si vous créez vos propres classes, et les index peuvent être vérifiés pour l'accès aux limites par l'opérateur de surcharge []. Ces abstractions aident à rendre votre code plus propre, plus facile à comprendre et à déboguer et accélèrent définitivement le développement.

Si vous créez un compilateur en C, cela vous prendra certainement plus de temps. C ++ vous fera terminer votre projet en moins de temps. C et C ++ ont les mêmes performances mais C ++ a beaucoup d'avantages que C n'a pas.

Diego Marin
la source
0

Le projet CompCert est un compilateur C de recherche qui n'est pas écrit en C ou en C ++, mais plus en Ocaml et Coq.

Remarquez que C ++ était auparavant traduit en C (dans Cfront ). Vous pouvez maintenant utiliser l' interface GCC vers Gimple , puis vider le Gimple dans une base de données, puis écrire un Gimple dans votre traducteur d'assembleur. Mais pour des raisons juridiques (l' exception de la bibliothèque d'exécution GCC ), un tel compilateur doit être open source. Demandez des précisions à votre avocat, je ne suis pas avocat. Les anciennes variantes de GCC ont été écrites en C (+ plusieurs langages spécifiques au domaine) avec un front-end pour une variante de C ++. OpenWatcom pourrait être un compilateur C ++ écrit en C (je vous laisse le vérifier).

La source de Compcert est disponible gratuitement à des fins académiques et de recherche. Si vous souhaitez l'utiliser industriellement (et légalement), vous devez obtenir une licence d'Absint.

Voir aussi ceci et cela qui répond à deux questions connexes.

Si j'ai été chargé en 2020 d'écrire un compilateur C (ou C ++) à partir de zéro (fonctionnant sous Linux, peut-être un compilateur croisé ), je ne l'écrirai probablement pas en C ++. J'envisagerais de l' écrire en utilisant Ocaml , Go ou Rust . Et je pourrais le baser sur Frama-C si cela était permis. Si je devais coder en C ou C ++, je coderais d'abord une bibliothèque de garbage collector pour cela, probablement une couche de persistance - très utile pour l'optimisation de programme entier - et ensuite je considérerais une approche de métaprogrammation (générant la plupart du code C ou C ++ du compilateur avec mes outils ad-hoc, peut-être Bismon ou RefPerSys si cela est autorisé).

Vous pouvez trouver des compilateurs C (plus ou moins open source) codés en Common Lisp ou en Python (par exemple ShivyC ou nqcc ). Regardez également dans ZetaC .

Notez que les versions récentes de GCC ne sont pas techniquement codées en C ++ pur, elles sont une douzaine de langages spécifiques à un domaine impliqués dans GCC (plusieurs d'entre eux étant Turing-complete ). Voir aussi mon ancien projet GCC MELT .

Je ne serai pas surpris si, dans les futures versions de GCC, un interpréteur Python ou Guile serait intégré à l'intérieur (par exemple, en remplacement du gestionnaire de passes de GCC).

Consultez également le projet MILEPOST GCC .

Basile Starynkevitch
la source