Recent Changes - Search:

My Projects

Writings

Source Code

Social Networks

Histoires

Live Traffic !

Introduction

Créer son propre langage de programmation de A à Z

<< Sommaire | Introduction | Notion de grammaire et langage formel >>

Il n'est pas difficile de créer un langage de programmation. Tout dépend en réalité de sa complexité grammaticale. Aussi créer un langage ne nécessite aucune connaissance technique en programmation. Il faut surtout être logique et très rigoureux. La grammaire d'un langage de programmation peut être enrichie au fil du temps. On peut commencer par créer quelque chose de simple puis faire évoluer notre langage en implémentant des mécanismes de fonctions par exemples, de classes... etc. Beaucoup de langages informatiques évoluent encore aujourd'hui comme le Java, le C++, le PHP ou encore le HTML. Il fut une époque où PHP et Python n'étaient pas des langages orientés objets ! Développer un compilateur nécessite bien évidemment une connaissance dans le langage dans lequel on va l'écrire ainsi que le langage cible. Dans ce cours, nous allons apprendre à écrire un compilateur en C. Il nécessite donc quelques pré-requis en programmation C. Afin de ne pas cumuler d'autres pré-requis, j'ai décidé que le langage cible du compilateur sera aussi du C.

Quel est l'intérêt de créer un langage de programmation ?

Il existe plusieurs raisons de vouloir créer un langage de programmation. La première est de s'amuser tout simplement. Ensuite, parce qu'on a en tête une syntaxe que l'on souhaite utiliser dans nos programmes. On ne veut pas être soumis à la syntaxe des autres langages et utiliser un vocabulaire qui nous est propre. Une autre raison que je vois aussi, c'est la volonté de cacher son code. Un langage que l'on ne comprend pas est synonyme de code secret. Si une seule personne s'invente un langage et qui l'utilise, personne dans son entourage le comprendra. Imaginez une organisation sensible qui souhaiterait protéger ses algorithmes. Elle a à mon avis tout intérêt à développer son propre langage et ne le dévoiler à personne. Ainsi seulement les personnes connaissant le langage comprendront ce qu'ils écrivent. Et leur code marchera comme n'importe quel autre code parce qu'ils auront le compilateur spécifique au langage. A l'inverse, cela peut être une stratégie purement commerciale. Les langages propriétaires obligent aux utilisateurs d'être dépendants des outils payants pouvant exécuter les programmes. Une autre raison que j'ai trouvée est que l'on pense pouvoir améliorer, ou en tout cas apporter des modifications sur la syntaxe d'un langage déjà existant pour le rendre généralement plus simple à écrire.

Mais qu'est-ce que réellement un compilateur ?

Le processeur ne comprend en fait qu'un seul langage qui est le langage binaire appelé aussi le langage machine. Ce langage a la particularité d'avoir un alphabet extrêmement faible, le plus faible qu'il puisse y avoir. Il ne contient en effet que 2 lettres : le '1' et le '0'. Tout ce qui se trouve sur votre ordinateur est traduit en 1 et 0. Ainsi quand un processeur exécute un programme, il traite une série plus ou moins immense de 1 et de 0. Il est évident que programmer en binaire est une tâche assez compliquée. D'une part parce qu'il nécessite de recopier pour une instruction, son code binaire associé. Ensuite le langage machine est différent d'une famille de processeur à l'autre sans parler de l'architecture. D'autre part, écrire en binaire est très long et source évidente d'erreurs. Car oui l'Homme commet des erreurs. Pour pallier à ce problème, des informaticiens ont inventé un langage qui s'appelle assembleur ou ASM et qui en bref associe des symboles aux combinaisons de bits. La traduction du langage assembleur vers le langage machine est effectuée par un Assembleur. Le langage assembleur est aussi spécifique à l'architecture du processeur sur lequel on souhaite exécuter le programme mais il a l'avantage d'être largement plus facile à lire et à écrire que le binaire.

Pour répondre précisément à la question du sous-titre, un compilateur est un traducteur d'un langage source vers un langage cible. Le processus de traduction appelé compilation se fait théoriquement en plusieurs phases :

  • Une phase d'analyse lexicale, il identifie les mots et s'assure qu'ils sont compris dans le vocabulaire du langage
  • Une phase d'analyse syntaxique, il s'assure que la syntaxe est correcte autrement dit si la suite de mots écrite est dans le bon ordre
  • Une phase d'analyse sémantique, il s'assure du sens des phrases. Par exemple si je dis "Je suis plus vieux que mon père.", syntaxiquement c'est correcte, ma phrase ne comprend aucune erreur grammaticale mais sémantiquement parlant elle n'a aucun sens
  • Optimisation éventuelle
  • Génération du code dans le langage cible

Si vous voulez des exemples de compilateurs populaires et très utilisés, je peux citer gcc, javac, tcc ou encore g++.

Tout les langages sont donc compilés alors ?

Non pas tous. On exclut les langages scripts qui sont des langages interprétés. PHP, Python, JavaScript, SQL et j'en passe sont des langages qui sont compris par des interpréteurs ou interprètes. Le processus de traduction est toutefois le même, seulement dans ce cas là la compilation est faîte dynamiquement. Je m'explique : l'interpréteur analyse, traduit et exécute aussitôt l'instruction. Et il fait ceci instruction par instruction. Ainsi on peut dire que la compilation et l'exécution sont faîtes simultanément. C'est la différence avec les langages compilés, où le programme peut être exécuté une fois seulement que la totalité du code a été compilé. L'avantage des langages scripts est la portabilité des programmes car ils s'exécuteront tant que la machine possède les interpréteurs spécifiques à son architecture. Alors qu'un programme écrit en C par exemple, nécessite d'être recompilé si on change de machine ayant une architecture différente.

Les shell Unix (sh, bash, csh...) sont de très bons exemples d'interpréteurs. Ils interprètent des commandes systèmes généralement depuis un terminal.

On exclut aussi généralement tout les autres langages informatiques qui ne sont pas des langages de programmation. Nous avons notamment les langages de description des données, de représentation des données comme le XML, SVG, MathML, XSL, DTD, Relax NG, HTML, JSON et j'en passe... Ce sont pour la plupart des standards définis, des formats de données facilitant l'échange et l'interopérabilité. Nous avons aussi des langages de modélisation comme UML qui a la particularité d'être graphique. Néanmoins, ce n'est pas parce que ce ne sont pas des langages que l'on compile qui ne sont pas compilables. On peut tout à fait imaginer écrire des instructions de programmation en XML puis ensuite créer un compilateur qui va lire le fichier XML et produire un fichier exécutable. D'ailleurs la page que vous êtes en train de visualiser en ce moment est écrite en HTML. Et si votre navigateur favori a réussi à mettre en forme la page, c'est qu'avant de vous l'afficher, un moteur de rendu a du analyser et traduire le code HTML. Tout langage informatique est en fait analysable si il repose sur une grammaire bien définie. Vous comprendrez mieux au chapitre suivant.

Le cas Java

Le langage Java est assez particulier. C'est un langage compilé qui, à la compilation, donne un fichier exécutable sur n'importe quelle machine. La compilation d'un programme écrit en Java par javac (compilateur Java) donne du bytecode java (une sorte de langage assembleur Java on va dire). Et on n'a plus besoin de recompiler le code à chaque fois qu'on change d'architecture à la différence du C ou du C++. Seulement s'il est si portable que cela, c'est que derrière il y a en fait une machine qui lit ce bytecode java généré par le compilateur Java. Cette machine est la machine virtuelle Java, souvent abrégé JVM. En fait on compile du Java en une sorte de langage assembleur (bytecode Java) par javac pour que ce soit ensuite interprété par la JVM. JVM, qui elle est bien spécifique à l'architecture de la machine sur laquelle elle se trouve. Java est ainsi cross-platform (indépendant de la machine).

Bas niveau et haut niveau

Plus le langage de programmation est proche du langage machine, plus il est bas niveau. L'assembleur est donc un langage très bas niveau car c'est le langage machine avec les instructions binaires qui sont substituées par des symboles. Le langage C est un langage bas niveau mais plus haut que l'assembleur. Le langage Simple sera quant à lui un langage de plus haut niveau que le langage C. Pourquoi ? Le code généré par notre futur compilateur sera du C qui lui même devra être compilé pour obtenir au final un exécutable. L'exécutable produit sera donc finalement un exécutable provenant du langage C et non pas du langage Simple. Mais le langage Simple sera plus facile à écrire pour nous que le C. En revanche, je n'ai pas prévu le fait d'avoir accès à toutes les fonctionnalités du langage C telles que les pointeurs. Mais c'est tout à fait volontaire. Tout comme le C ne donne pas accès à toutes les fonctionnalités de l'assembleur telle que la manipulation de registres par exemple (il est vrai qu'on trouve maintenant des librairies pour le faire). On retiendra que les langages de haut niveau sont faits pour faciliter le développement en rendant transparent des mécanismes plus ou moins complexes comme la gestion de la mémoire, les registres, les pointeurs, les entrées et sorties que le développeur n'a plus à se soucier. Cependant un langage de haut niveau gagne en productivité mais pas forcément en performance. Tout dépend en fait de la qualité du code généré par le compilateur.

Compilateur de compilateur

Oui ça existe, car un compilateur n'est rien d'autre qu'un programme. Et comme tout programme qui n'est pas écrit en langage machine... il faut le compiler ! Il existe plusieurs outils. Nous n'en verrons que deux dans ce tutoriel : Flex et Bison. Flex génère un analyseur lexical et Bison un analyseur syntaxique. Le couple Flex et Bison sont les versions libres respectives de Lex et Yacc. Mais nous aurons le temps d'y revenir après. Bref on va faire du C !! Et dans le but de faire après du Simple !! Je vous dis tout ça maintenant car je compte sur vous pour installer ces deux outils comme des grands. Installez aussi la librairie GLib, nous l'utiliserons pour l'analyse sémantique. Bien sûr, installez gcc si vous ne l'avez pas, sinon on ne pourra pas compiler notre compilateur. Aussi, je vous conseille d'être comme moi sous un environnement Unix. Dans ce cours, je vais en effet développer sous Linux et je ne donnerai pas de solutions alternatives pour Windows. Si vous avez des soucis d'installation ou que vous reculez à installer Linux sur votre machine, vous pouvez créer un nouveau projet sur la plateforme en ligne Cloud9. C'est gratuit et tout les outils dont on a besoin sont déjà installés. Cela vous permet d'avoir une mini machine virtuelle UNIX toute prête pour ce que l'on va faire.

<< Sommaire | Introduction | Notion de grammaire et langage formel >>

Thomas - (CC BY-NC-SA 3.0 FR)

Page last modified on July 09, 2017, at 07:32 PM EST

This page has been requested 2503 times (Today : 1) - Total number of requests : 72611

Edit - History - Statistics - Print - Recent Changes - Search

Clin d'oeil aux victimes des attentats survenus dans la soirée du 13 novembre 2015. La nouvelle version du site a été installée quelques heures avant.