web-dev-qa-db-fra.com

Commencer un simple compilateur C (le plus simple peut-être)?

Je suis tombé sur ceci: Écriture d'un compilateur en utilisant Turbo Pascal

Je suis curieux de savoir s'il existe des tutoriels ou des références expliquant comment créer un compilateur C simple. Je veux dire, cela suffit si cela me permet de comprendre les opérations arithmétiques. Je suis devenu vraiment curieux après avoir lu cet article de Ken Thompson . L'idée d'écrire quelque chose qui se comprend semble passionnante.

Pourquoi ai-je posé cette question au lieu de la poser à Google? J'ai essayé Google et celui de Pascal était le premier lien. Le reste ne semblait pas pertinent et s'ajoutait à cela ... Je ne suis pas un majeur en CS (donc j'ai encore besoin d'apprendre ce que font tous ces outils comme yacc) et je veux apprendre cela en faisant et j'espère que les gens avec plus d'expérience sont toujours mieux dans ces domaines que Google. Je veux lire un article écrit dans le même esprit que celui que j'ai énuméré ci-dessus mais celui qui met en évidence au moins les phases d'amorçage de la construction d'un simple compilateur C.

De plus, je ne connais pas la meilleure façon d'apprendre. Dois-je commencer à construire un compilateur C en C ou dans un autre langage? Est-ce que j'écris un compilateur C ou un autre langage? Je pense que des questions comme celle-ci sont mieux répondues une fois que j'ai une direction à explorer. Aucune suggestion?

Aucune suggestion?

40
Legend

Un compilateur se compose de trois éléments:

  1. Un analyseur
  2. Un arbre de syntaxe abstraite (AST)
  3. Un générateur de code

Il existe de nombreux générateurs d'analyseurs Nice qui commencent par des grammaires linguistiques. Peut-être que ANTLR serait un bon point de départ. Si vous voulez vous en tenir aux racines C, essayez Lex/yacc ou bison.

Il existe des grammaires pour C, mais je pense que C dans son intégralité est complexe. Vous feriez bien de commencer avec un sous-ensemble de la langue et de progresser.

Une fois que vous avez un AST, vous l'utilisez pour générer le code machine que vous exécuterez.

C'est faisable, mais pas anodin.

Je vérifierais également Amazon pour des livres sur l'écriture de compilateurs. Le Dragon Book est le classique, mais il en existe des plus modernes.

MISE À JOUR: Il y a eu des questions similaires sur le débordement de pile, comme celui-ci . Consultez également ces ressources.

24
duffymo

Je vous conseille ce tutoriel:

C'est un petit exemple sur la façon d'implémenter un compilateur "petit langage". Le code source est très petit et est expliqué étape par étape.

Il existe également la bibliothèque frontale C pour la bibliothèque LLVM (Low Level Virtual Machine qui représente la structure interne d'un programme):

24
Phong

Pour ce que ça vaut, le Tiny C Compiler est un compilateur C assez complet dans un paquet source relativement petit. Vous pourriez bénéficier d'étudier cette source, car c'est probablement beaucoup plus facile à comprendre que d'essayer de comprendre toute la base de sources de GCC, par exemple.

15
Mark Rushakoff

C'est mon opinion (et conjecture) qu'il sera difficile d'écrire un compilateur sans comprendre les structures de données normalement couvertes dans les cours d'informatique de premier cycle (postsecondaire). Cela ne signifie pas que vous ne pouvez pas, mais vous aurez besoin de connaître les structures de données essentielles telles que les listes chaînées et les arbres.

Plutôt que d'écrire un compilateur de langage C complet ou conforme aux normes (au moins au début), je suggérerais de vous limiter à un sous-ensemble de base du langage, tel que les opérateurs communs, la prise en charge uniquement des entiers et les fonctions et pointeurs de base. Un exemple classique de cela est celui de Ron Cain Small-C , rendu populaire par une série d'articles écrits en Dr. Dobbs Journal dans les années 80, je crois. Ils publient un CD avec le livre épuisé de James Hendrix, A Small-C Compiler .

Ce que je suggérerais, c'est de suivre le didacticiel de Crenshaw, mais de l'écrire pour un compilateur de langage de type C, et quelle que soit la cible du processeur (Crenshaw cible le processeur Motorola 68000) que vous souhaitez cibler. Pour ce faire, vous aurez besoin de connaître l'assembly de base de la cible sur laquelle vous souhaitez exécuter les programmes compilés. Cela pourrait inclure un émulateur pour un 68000, ou MIPS qui sont sans doute plus gentils Ensembles d'instructions d'assemblage que le vénérable jeu d'instructions CISC de l'Intel x86 (16/32 bits).

Il existe de nombreux livres potentiels qui peuvent être utilisés comme points de départ pour apprendre la théorie (et la pratique) du compilateur/traducteur. Lisez la FAQ comp.compilers , et les critiques de divers vendeurs de livres en ligne. La plupart des livres d'introduction sont écrits comme des manuels pour les classes d'informatique de premier cycle à deuxième cycle, de sorte qu'ils peuvent être une lecture lente sans fond de CS. Un livre plus ancien qui pourrait être plus introductif, mais plus facile à lire que " The Dragon Book " est Introduction to Compiler Construction = par Thomas Parsons. Il est plus ancien, vous devriez donc être en mesure de trouver une copie d'occasion de votre choix de vendeurs de livres en ligne à un prix raisonnable.

Donc, je dirais, essayez de commencer par le tutoriel de Jack Crenshaw Construisons un compilateur , écrivez le vôtre, en suivant ses exemples comme guide, et construisez les bases d'un simple = compilateur. Une fois que cela fonctionne, vous pouvez mieux décider où vous souhaitez le prendre à partir de ce point.

Ajouté:

En ce qui concerne le processus d'amorçage. Puisqu'il existe des compilateurs C disponibles gratuitement, vous n'avez pas à vous soucier du bootstrap. Écrivez votre compilateur avec des outils existants distincts (GCC, Visual C++ Express, Mingw/djgpp, tcc), et vous pouvez vous soucier de l'auto-compilation de votre projet à un stade beaucoup plus tardif. J'ai été surpris par cette partie de la question jusqu'à ce que je réalise que vous avez eu l'idée d'écrire votre propre compilateur en lisant le discours du prix ACM Turing de Ken Thomas, Reflections on Trusting Trust , qui entre dans le processus de démarrage du compilateur. C'est un sujet avancé modéré, et c'est aussi tout simplement très compliqué. Je trouve même l'amorçage du compilateur GCC C sous les anciens systèmes Unix (Digital OSF/1 sur l'Alpha 64 bits) qui comprenait un compilateur C un processus lent et chronophage, sujet aux erreurs.

L'autre question était de savoir ce qu'un outil de compilation comme Yacc fait réellement. Yacc (Yet Another Compiler Compiler ou Bison de GNU) est un outil conçu pour faciliter l'écriture d'un analyseur de compilateur (ou traducteur). Basé sur la grammaire formelle pour votre langue cible que vous entrez dans yacc, il génère un parser, qui est une partie de la conception globale d'un compilateur. Vient ensuite Lex (ou flex de GNU) qui générait un analyseur lexical ou un scanner, qui est souvent utilisé en combinaison avec l'analyseur généré par yacc pour former le squelette du front-end d'un compilateur. Ces outils font de l'écrivain un frontal sans doute plus facile que d'écrire un analyseur lexical et un analyseur vous-même. Le didacticiel de Crenshaw n'utilise pas ces outils, et vous n'en avez pas besoin non plus, de nombreux rédacteurs de compilateurs ne les utilisent pas toujours. Bien sûr, Crenshaw admet que l'analyseur du didacticiel est assez basique.

Le didacticiel de Crenshaw ignore également la génération d'un AST (arbre de syntaxe abstraite), qui simplifie mais limite également le compilateur du didacticiel. Il manque la plupart sinon la totalité de l'optimisation et est très lié au langage de programmation spécifique et au langage d'assemblage particulier émis par le "back-end" du compilateur. Normalement, le AST est un élément central où une optimisation peut être effectuée, et sert à découpler le front-end du compilateur et Pour un débutant sans formation en informatique, je suggère de ne pas s'inquiéter de ne pas avoir un AST pour votre premier compilateur (ou du moins la première version de celui-ci). Je pense que le garder petit et simple vous aidera à terminer l'écriture d'un compilateur, dans sa première version, et vous pourrez décider à partir de là comment vous voulez procéder ensuite.

12
mctylr

Vous pourriez être intéressé par le livre/cours Les éléments des systèmes informatiques: construire un ordinateur moderne à partir des premiers principes.

Notez qu'il ne s'agit pas de construire un "pc" à partir de choses que vous avez achetées sur newegg. Il commence par une description des principes fondamentaux de la logique booléenne et construit un ordinateur virtuel des niveaux d'abstraction les plus bas aux niveaux d'abstraction progressivement plus élevés. Les supports de cours sont tous en ligne et le livre lui-même est assez bon marché d'Amazon.

Dans le cours, en plus de "construire le matériel", vous implémenterez également un assembleur, une machine virtuelle, un compilateur et un système d'exploitation rudimentaire, par étapes. Je pense que cela vous donnerait suffisamment de contexte pour approfondir le sujet avec certaines des ressources les plus couramment recommandées répertoriées dans les autres réponses.

6
Joe Internet

Comment [commencer à écrire] un simple compilateur C?

Il n'y a rien de simple à compiler C . Le meilleur compilateur C simple est lcc par Chris Fraser et David Hanson. Ils ont passé 10 ans à travailler sur la conception pour la rendre aussi simple que possible, tout en générant un code raisonnablement bon. Si vous avez accès à une bibliothèque universitaire, vous devriez pouvoir obtenir leur livre.

Dois-je commencer à construire un compilateur C en C ou dans un autre langage?

Une autre langue. Une fois, j'ai demandé à Hanson quelles leçons lui et Fraser avaient apprises en passant 10 ans sur le projet lcc. La principale chose que Hanson a dite était

C est un mauvais langage pour écrire un compilateur.

Vous feriez mieux d'utiliser Haskell ou un dialecte de ML. Les deux langages offrent des fonctions sur des types de données algébriques, ce qui correspond parfaitement aux problèmes rencontrés par le rédacteur du compilateur. Si vous voulez toujours poursuivre le C, vous pouvez commencer par CIL de George Necula, qui est un gros morceau d'un compilateur C écrit en ML.

Je veux lire un article écrit dans le même esprit que celui que j'ai listé ci-dessus mais celui qui met en évidence au moins les phases de bootstrapping ...

Vous ne trouverez pas un autre article comme celui de Ken. Mais Andrew Appel a écrit un article sympa appelé Axiomatic Bootstrapping: A Guide for Compiler Hackers Je n'ai pas pu trouver de version gratuite mais beaucoup de gens ont accès à la bibliothèque numérique ACM.

Aucune suggestion?

Si vous voulez écrire un compilateur,

  • Utilisez Haskell ou ML comme langage d'implémentation.

  • Pour votre premier compilateur, choisissez un langage très simple comme Oberon ou comme P0 du livre de Niklaus Wirth Algorithms + Data Structures = Programs. Wirth est célèbre pour la conception de langages faciles à compiler.

Vous pouvez écrire un compilateur C pour votre compilateur second.

5
Norman Ramsey

Dans L'environnement de programmation Unix , Kernighan et Pike parcourent 5 itérations de création d'une calculatrice fonctionnant depuis une simple analyse lexicale basée sur C et une exécution immédiate jusqu'à l'analyse yacc/Lex et la génération de code pour une machine abstraite. Parce qu'ils écrivent si merveilleusement, je ne peux pas suggérer une introduction plus fluide. Il est certainement plus petit que C, mais c'est probablement à votre avantage.

5
msw

Un compilateur est un sujet complexe qui couvre des aspects de

  • Traitement d'entrée impliquant Lexing, Parsing
  • Création d'un magasin de symboles de chaque variable utilisée, comme un arbre de syntaxe abstraite (AST)
  • À partir de l'arborescence AST, transposez et construisez un binaire de code machine basé sur la syntaxe

Ceci n'est en aucun cas exhaustif car il s'agit d'une vue abstraite à vol d'oiseau du sommet d'une montagne, cela se résume à obtenir la notation syntaxique correcte et à s'assurer que les entrées malformées ne la gâchent pas, en fait un bon traitement d'entrée ne devrait jamais tomber à genoux, peu importe à quel point les entrées mal formées, terribles et abusées lui sont lancées. Et, également pour décider et savoir quelle sortie va être, est-ce en code machine, ce qui impliquerait que vous deviez peut-être connaître intimement les instructions du processeur ... y compris l'adressage mémoire pour les variables et ainsi de suite ...

Voici quelques liens pour commencer:

  • Il y avait un Jack Crenshaw's port de son code pour C .... (je me souviens l'avoir téléchargé il y a des mois ...)
  • Voici un lien vers une question similaire ici sur SO.
  • Aussi, voici un autre petit tutoriel du compilateur pour le compilateur assembleur Basic à x86.
  • Tiny C compilateur
  • Petit compilateur C de Hendrix trouvé ici .
5
t0mm13b

Si vous voulez une expérience époustouflante qui vous apprend à écrire des compilateurs qui se compilent eux-mêmes, vous devez lire cet article de 1964 .

META II un langage d'écriture de compilateur orienté syntaxe par Val Schorre.

En 10 pages, il vous explique comment écrire des compilateurs, comment écrire des méta-compilateurs, fournit un jeu d'instructions de métacompilateur virtuel et un exemple de compilateur construit avec le métacompilateur.

J'ai appris à écrire des compilateurs à partir de cet article à la fin des années 60 et j'ai utilisé les idées pour construire des langages de type C pour plusieurs mini-ordinateurs et microprocesseurs.

Si le papier est trop volumineux (ce n'est pas le cas!), Il y a n tutoriel en ligne qui vous guidera à travers le tout.

Et si obtenir le papier à partir du lien d'origine est gênant parce que vous n'êtes pas membre d'ACM, vous constaterez que le didacticiel contient de toute façon tous les détails. (IMHO, pour le prix, le papier lui-même en vaut la peine).

10 pages!

3
Ira Baxter

Un compilateur est un très gros projet, même si je suppose que cela ne ferait pas de mal d'essayer.

Je connais au moins un compilateur C écrit en Pascal, donc ce n'est pas la la plupart chose insensée que vous pourriez faire. Personnellement, je choisirais un langage plus moderne dans lequel implémenter mon projet de compilateur C, à la fois pour la simplicité (il est facile de d/l des packages pour Python, Ruby, C, C++ ou Java) et car il sera meilleur sur votre CV.

Cependant, pour faire un compilateur en tant que projet débutant, vous devrez boire tous les Agile kool-aid . =

Faites toujours fonctionner quelque chose, même si cela ne fait rien. Ajoutez des éléments à votre compilateur uniquement par petites étapes. ("Versions fréquentes".) Choisissez un sous-ensemble vicieusement minuscule du langage et implémentez-le en premier. (Prise en charge uniquement i = 0; au début et développez les choses à partir de là.)

3
DigitalRoss

Il pourrait également être intéressant de se renseigner sur la programmation fonctionnelle. Les langages fonctionnels sont bien adaptés à l'écriture d'un compilateur à la fois in et for. La classe de compilateurs d'intro de mon école contenait une introduction aux langages fonctionnels et les devoirs étaient tous en OCaml.

C'est drôle que vous posiez cette question aujourd'hui, car il y a à peine quelques jours, j'ai écrit un interprète de calcul lambda. Le calcul Lambda est le grand-père de tous les langages fonctionnels. Il ne fait que 200 lignes (en C++, y compris les rapports d'erreurs, quelques jolies impressions, certains unicode) et a une structure en deux phases, avec un format intermédiaire qui pourrait être utilisé pour générer du code.

Non seulement commencer petit et développer l'approche la plus pratique des compilateurs, cela encourage également de bonnes pratiques organisationnelles modulaires.

3
Potatoswatter

Je ne recommanderais pas de commencer par C comme langage à implémenter, ni avec aucun des outils de générateur de compilateur ou de générateur d'analyseur. C est un langage très délicat, et c'est probablement une meilleure idée de créer votre propre langage. Cela peut être un peu C-like (par exemple, utilisez des backets bouclés si vous voulez indiquer le corps de la fonction, utilisez les mêmes noms de type, vous n'avez donc pas à vous souvenir de ce que vous avez tout appelé).

Les outils pour créer des compilateurs et des analyseurs sont excellents, mais ont le problème d'être vraiment une notation abrégée. Si vous ne savez pas comment créer un compilateur en longhand, le raccourci vous semblera cryptique, inutilement restrictif, etc. Alors écrivez d'abord votre propre compilateur simple, puis continuez à partir de là. Je vous recommande également de ne pas commencer à générer du code machine réel sauf si vous mangez et respirez l'assembleur. Créez votre propre interpréteur de bytecode avec une VM.

Quant au langage que vous devriez utiliser pour créer votre premier compilateur: cela n'a pas vraiment d'importance, tant que le langage est assez complet. Vous lirez le texte d'entrée, construirez des structures de données à partir d'eux et écrirez des données binaires. Donc, si une langue rend ces choses plus faciles de quelque manière que ce soit, c'est un point en sa faveur. Choisissez un langage que vous connaissez bien pour pouvoir vous concentrer sur la création du compilateur, et non sur l'apprentissage du langage. J'utilise généralement un langage OO, ce qui rend l'arborescence de syntaxe plus facile à écrire, un langage fonctionnel fonctionnerait probablement aussi si vous êtes familier avec cela.

J'ai beaucoup blogué sur les langages de programmation, vous pouvez donc trouver des articles utiles ici: http://orangejuiceliberationfront.com/category/language-design/

En particulier, http://orangejuiceliberationfront.com/how-to-write-a-compiler/ est un point de départ sur les particularités de l'analyse des constructions courantes et de la génération de quelque chose d'utile à partir de cela, ainsi que - http://orangejuiceliberationfront.com/generating-machine-code-at-runtime/ qui parle de cracher des instructions Intel qui font quelque chose.

Oh, en ce qui concerne le démarrage d'un compilateur: vous ne pourrez probablement pas le faire dès le début. Il y a pas mal de travail impliqué dans la création d'un compilateur. Ainsi, non seulement l'écriture d'un compilateur d'amorçage impliquerait d'écrire le compilateur (dans un autre langage), mais une fois que vous l'avez, vous devriez alors écrire une deuxième version du compilateur en utilisant lui-même. C'est deux fois le travail, plus le débogage nécessaire dans l'existant et le nouveau compilateur amorcé jusqu'à ce que tout fonctionne. Cela dit, une fois que vous avez un compilateur fonctionnel, c'est un bon moyen de tester son exhaustivité. OK, peut-être pas le double du travail, mais plus de travail. J'irais d'abord pour les succès faciles, puis passerais à partir de là.

Dans tous les cas, amusez-vous!

2
uliwitness