{"id":127,"date":"2021-07-02T22:05:13","date_gmt":"2021-07-02T22:05:13","guid":{"rendered":"https:\/\/www.louismarchand.me\/?p=127"},"modified":"2021-07-02T22:05:13","modified_gmt":"2021-07-02T22:05:13","slug":"la-creation-dun-langage-de-programmation-analyseur-lexical","status":"publish","type":"post","link":"https:\/\/www.louismarchand.me\/index.php\/2021\/07\/02\/la-creation-dun-langage-de-programmation-analyseur-lexical\/","title":{"rendered":"La cr\u00e9ation d\u2019un langage de programmation &#8211; Analyseur lexical"},"content":{"rendered":"<p>Cet article est le second d&rsquo;une s\u00e9rie d&rsquo;articles pr\u00e9sentant les \u00e9tapes de d\u00e9veloppement d&rsquo;un langage de programmation. La s\u00e9rie d&rsquo;articles d\u00e9bute <a href=\"https:\/\/www.louismarchand.me\/index.php\/2021\/06\/25\/la-creation-dun-langage-de-programmation\/\">ici<\/a>.<\/p>\n<p>La premi\u00e8re \u00e9tape effectu\u00e9e par un compilateur (ou un interpr\u00e9teur) est l&rsquo;analyse lexicale (ou \u00ab\u00a0scanner\u00a0\u00bb ou \u00ab\u00a0lexer\u00a0\u00bb) d&rsquo;un code source. L&rsquo;analyseur lexical permet de transformer les informations du code source (mots cl\u00e9s, identificateurs, constantes, etc.), nomm\u00e9es lex\u00e8me, en jeton (\u00ab\u00a0token\u00a0\u00bb). Un jeton est un type d&rsquo;information qui sera plus facile \u00e0 travailler et \u00e0 manipuler que du texte dans les autres \u00e9tapes de la compilation.<\/p>\n<p>Par exemple, le programme Java suivant:<\/p>\n<div class=\"highlight\">\n<pre><span class=\"cm\">\/**<\/span>\r\n<span class=\"cm\"> * Programme exemple<\/span>\r\n<span class=\"cm\"> * <\/span>\r\n<span class=\"cm\"> * @author Louis Marchand (prog@tioui.com)<\/span>\r\n<span class=\"cm\"> * @version 0.1, vendredi jui 02, 2021 16:57:14 EDT<\/span>\r\n<span class=\"cm\"> * <\/span>\r\n<span class=\"cm\"> * Distribu\u00e9 sous licence MIT.<\/span>\r\n<span class=\"cm\"> *\/<\/span>\r\n\r\n<span class=\"kd\">public<\/span> <span class=\"kd\">class<\/span> <span class=\"nc\">Test<\/span> <span class=\"o\">{<\/span>\r\n    <span class=\"cm\">\/**<\/span>\r\n<span class=\"cm\">     * Ex\u00e9cution du programme.<\/span>\r\n<span class=\"cm\">     *<\/span>\r\n<span class=\"cm\">     * @param aArguments Les param\u00eatres du programme.<\/span>\r\n<span class=\"cm\">     *\/<\/span>\r\n    <span class=\"kd\">public<\/span> <span class=\"kd\">static<\/span> <span class=\"kt\">void<\/span> <span class=\"nf\">main<\/span><span class=\"o\">(<\/span><span class=\"n\">String<\/span><span class=\"o\">[]<\/span> <span class=\"n\">aArguments<\/span><span class=\"o\">)<\/span> <span class=\"o\">{<\/span>\r\n        <span class=\"n\">System<\/span><span class=\"o\">.<\/span><span class=\"na\">out<\/span><span class=\"o\">.<\/span><span class=\"na\">println<\/span><span class=\"o\">(<\/span><span class=\"s\">\"Bonjour \u00e0 tous\"<\/span><span class=\"o\">);<\/span>        \r\n    <span class=\"o\">}<\/span>\t\r\n<span class=\"o\">}<\/span>\r\n<\/pre>\n<\/div>\n<p>sera convertie en la suite de jeton suivant:<\/p>\n<div class=\"highlight\">\n<pre>COMMENTAIRE PUBLIC CLASS IDENTIFICATEUR ACCOLADE_OUVRANTE COMMENTAIRE\r\nPUBLIC STATIC VOID IDENTIFICATEUR PARENTHESE_OUVRANTE IDENTIFICATEUR\r\nCROCHET_OUVRANT CROCHET_FERMANT IDENTIFICATEUR PARENTHESE_FERMANTE\r\nACCOLADE_OUVRANTE IDENTIFICATEUR POINT IDENTIFICATEUR POINT IDENTIFICATEUR\r\nPARENTHESE_OUVRANTE CHAINE PARENTHESE_FERMANTE POINT_VIRGULE ACCOLADE_FERMANTE\r\nACCOLADE_FERMANTE\r\n<\/pre>\n<\/div>\n<p>Ici, bien entendu, c&rsquo;est une repr\u00e9sentation imag\u00e9e en texte de ce qui est stock\u00e9 par l&rsquo;analyseur lexical. En r\u00e9alit\u00e9, il s&rsquo;agit d&rsquo;une instance propre au langage qui sera utilis\u00e9 pour cr\u00e9er le compilateur (par exemple, une structure si le compilateur est cr\u00e9\u00e9 en C ou une classe si le compilateur est cr\u00e9\u00e9 en C++). Minimalement, un jeton peut \u00eatre tout simplement un index (entier) unique par type de lex\u00e8me diff\u00e9rent. Par contre, en g\u00e9n\u00e9ral, on garde dans le jeton certaines informations qui pourront aider les prochaines \u00e9tapes de la compilation \u00e0 s&rsquo;ex\u00e9cuter comme ils se doivent. Par exemple, on peut stocker dans le jeton, le nom du fichier source, la ligne et la colonne (qui pourront \u00eatre utilis\u00e9s pour donner des messages d&rsquo;erreur plus efficace lors de la compilation) ou le texte d&rsquo;origine du jeton (qui pourra \u00eatre utilis\u00e9 pour interpr\u00e9ter les constantes ou les identificateurs par exemple).<\/p>\n<p>La cr\u00e9ation d&rsquo;un analyseur lexical se fait en sp\u00e9cifiant un fichier de descriptions \u00e0 un g\u00e9n\u00e9rateur d&rsquo;analyseur lexical. Un fichier de description contient une s\u00e9rie d&rsquo;expression r\u00e9guli\u00e8re qui permettra de reconna\u00eetre les lex\u00e8mes du langage. Une fois ex\u00e9cuter, le g\u00e9n\u00e9rateur d&rsquo;analyseur lexical cr\u00e9era du code source qui pourra \u00eatre int\u00e9gr\u00e9 dans le code source du compilateur afin d&rsquo;effectuer sa t\u00e2che.<\/p>\n<p>Il existe une grande quantit\u00e9 de g\u00e9n\u00e9rateurs d&rsquo;analyseur lexical qui peuvent cr\u00e9er du code source dans diff\u00e9rents langages de programmation. Par exemple, \u00ab\u00a0Lex\u00a0\u00bb g\u00e9n\u00e8re en C, \u00ab\u00a0Flex\u00a0\u00bb g\u00e9n\u00e8re en C ou C++, \u00ab\u00a0C# Lex\u00a0\u00bb g\u00e9n\u00e8re en C#, \u00ab\u00a0JLex\u00a0\u00bb g\u00e9n\u00e8re en Java, etc. Dans le cas du langage Triumph qui est pr\u00e9sentement en cours de d\u00e9veloppement, le compilateur sera cr\u00e9\u00e9 dans le langage de programmation Eiffel. Le g\u00e9n\u00e9rateur d&rsquo;analyseur lexical qui sera utilis\u00e9 devra donc \u00eatre capable de g\u00e9n\u00e9rer du code source Eiffel. C&rsquo;est pour cette raison que j&rsquo;utiliserai le g\u00e9n\u00e9rateur \u00ab\u00a0<a href=\"http:\/\/www.gobosoft.com\/eiffel\/gobo\/gelex\/index.html\">gelex<\/a>\u00a0\u00bb de la s\u00e9rie d&rsquo;outils <a href=\"https:\/\/gitlab.com\/tioui\/triumph-programming-language\/-\/blob\/b77868139758f3eb2df2788e870fb9e77a477861\/project\/parser\/triumph_scanner.l\">Gobo<\/a>.<\/p>\n<p>Voici un lien vers le fichier de description que j&rsquo;ai cr\u00e9\u00e9 pour le langage de programmation Triumph: <a href=\"https:\/\/gitlab.com\/tioui\/triumph-programming-language\/-\/blob\/b77868139758f3eb2df2788e870fb9e77a477861\/project\/parser\/triumph_scanner.l\">ici<\/a>. Il s&rsquo;agit ici d&rsquo;une version initiale qui pourrait changer en cours de d\u00e9veloppement.<\/p>\n<p>Voici les diff\u00e9rentes sections du fichier de description:<\/p>\n<ul>\n<li>Les commentaires sont d\u00e9butent par des \u00ab\u00a0&#8211;\u00ab\u00a0;<\/li>\n<li>Les lignes <a href=\"https:\/\/gitlab.com\/tioui\/triumph-programming-language\/-\/blob\/b77868139758f3eb2df2788e870fb9e77a477861\/project\/parser\/triumph_scanner.l#L1\">1<\/a> \u00e0 <a href=\"https:\/\/gitlab.com\/tioui\/triumph-programming-language\/-\/blob\/b77868139758f3eb2df2788e870fb9e77a477861\/project\/parser\/triumph_scanner.l#L19\">19<\/a> repr\u00e9sentent l&rsquo;ent\u00eate de la classe Eiffel qui sera g\u00e9n\u00e9r\u00e9 par le g\u00e9n\u00e9rateur d&rsquo;analyseur lexical \u00ab\u00a0Gelex\u00a0\u00bb;<\/li>\n<li>La ligne <a href=\"https:\/\/gitlab.com\/tioui\/triumph-programming-language\/-\/blob\/b77868139758f3eb2df2788e870fb9e77a477861\/project\/parser\/triumph_scanner.l#L21\">21<\/a> repr\u00e9sente des options de g\u00e9n\u00e9ration. En gros, j&rsquo;indique \u00e0 Gelex de g\u00e9n\u00e9rer un analyseur lexical qui g\u00e8re la position des lex\u00e8mes dans le fichier source, qui ne poss\u00e8de aucune r\u00e8gle par d\u00e9faut dans le cas o\u00f9 aucun lex\u00e8me ne serait trouv\u00e9 pour une s\u00e9quence donn\u00e9e (je n&rsquo;en ai pas besoin) et qui devra cr\u00e9er le fichier source Eiffel \u00ab\u00a0triumph_scanner.e\u00a0\u00bb;<\/li>\n<li>Les lignes <a href=\"https:\/\/gitlab.com\/tioui\/triumph-programming-language\/-\/blob\/b77868139758f3eb2df2788e870fb9e77a477861\/project\/parser\/triumph_scanner.l#L23\">23<\/a> \u00e0 <a href=\"https:\/\/gitlab.com\/tioui\/triumph-programming-language\/-\/blob\/b77868139758f3eb2df2788e870fb9e77a477861\/project\/parser\/triumph_scanner.l#L49\">49<\/a> d\u00e9clarent des expressions r\u00e9guli\u00e8res que je pourrai me servir dans le reste du fichier;<\/li>\n<li>La ligne <a href=\"https:\/\/gitlab.com\/tioui\/triumph-programming-language\/-\/blob\/b77868139758f3eb2df2788e870fb9e77a477861\/project\/parser\/triumph_scanner.l#L47\">47<\/a> indique \u00e0 Gelex qu&rsquo;il s&rsquo;agit du d\u00e9but des descriptions des lex\u00e8mes;<\/li>\n<li>Les lignes <a href=\"https:\/\/gitlab.com\/tioui\/triumph-programming-language\/-\/blob\/b77868139758f3eb2df2788e870fb9e77a477861\/project\/parser\/triumph_scanner.l#L49\">49<\/a> \u00e0 <a href=\"https:\/\/gitlab.com\/tioui\/triumph-programming-language\/-\/blob\/b77868139758f3eb2df2788e870fb9e77a477861\/project\/parser\/triumph_scanner.l#L55\">55<\/a> correspondent aux expressions r\u00e9guli\u00e8res qui repr\u00e9sentent les s\u00e9parateurs de lex\u00e8me dans le langage (ces caract\u00e8res sont compl\u00e8tement ignor\u00e9s puisqu&rsquo;ils ne g\u00e9n\u00e8rent pas de jeton);<\/li>\n<li>Les lignes <a href=\"https:\/\/gitlab.com\/tioui\/triumph-programming-language\/-\/blob\/b77868139758f3eb2df2788e870fb9e77a477861\/project\/parser\/triumph_scanner.l#L58\">58<\/a> \u00e0 <a href=\"https:\/\/gitlab.com\/tioui\/triumph-programming-language\/-\/blob\/b77868139758f3eb2df2788e870fb9e77a477861\/project\/parser\/triumph_scanner.l#L150\">150<\/a> repr\u00e9sentent tous les op\u00e9rateurs du langage Triumph (on voit que plusieurs op\u00e9rateurs peuvent g\u00e9n\u00e9rer le m\u00eame jeton, comme \u00ab\u00a0&gt;\u00a0\u00bb ou \u00ab\u00a0&lt;\u00ab\u00a0);<\/li>\n<li>Les lignes <a href=\"https:\/\/gitlab.com\/tioui\/triumph-programming-language\/-\/blob\/b77868139758f3eb2df2788e870fb9e77a477861\/project\/parser\/triumph_scanner.l#L155\">155<\/a> \u00e0 <a href=\"https:\/\/gitlab.com\/tioui\/triumph-programming-language\/-\/blob\/b77868139758f3eb2df2788e870fb9e77a477861\/project\/parser\/triumph_scanner.l#L310\">310<\/a> repr\u00e9sentent tous les mots-cl\u00e9s du langage Triumph (encore une fois, on voit que plusieurs op\u00e9rateurs peuvent g\u00e9n\u00e9rer le m\u00eame jeton, comme \u00ab\u00a0or\u00a0\u00bb ou \u00ab\u00a0and\u00a0\u00bb);<\/li>\n<li>La ligne <a href=\"https:\/\/gitlab.com\/tioui\/triumph-programming-language\/-\/blob\/b77868139758f3eb2df2788e870fb9e77a477861\/project\/parser\/triumph_scanner.l#L317\">317<\/a> repr\u00e9sente les identificateurs (Nom de classes, attributs, m\u00e9thodes, variables, argument, etc.),<\/li>\n<li>Les lignes <a href=\"https:\/\/gitlab.com\/tioui\/triumph-programming-language\/-\/blob\/b77868139758f3eb2df2788e870fb9e77a477861\/project\/parser\/triumph_scanner.l#L323\">323<\/a> \u00e0 <a href=\"https:\/\/gitlab.com\/tioui\/triumph-programming-language\/-\/blob\/b77868139758f3eb2df2788e870fb9e77a477861\/project\/parser\/triumph_scanner.l#L337\">337<\/a> repr\u00e9sentent les constantes enti\u00e8res en version d\u00e9cimale, hexad\u00e9cimale, octale ou binaire;<\/li>\n<li>Les lignes <a href=\"https:\/\/gitlab.com\/tioui\/triumph-programming-language\/-\/blob\/b77868139758f3eb2df2788e870fb9e77a477861\/project\/parser\/triumph_scanner.l#L339\">339<\/a> \u00e0 <a href=\"https:\/\/gitlab.com\/tioui\/triumph-programming-language\/-\/blob\/b77868139758f3eb2df2788e870fb9e77a477861\/project\/parser\/triumph_scanner.l#L342\">342<\/a> permettent de repr\u00e9senter une erreur plus int\u00e9ressante qu&rsquo;un simple \u00ab\u00a0syntaxe error\u00a0\u00bb lorsque le code source pr\u00e9sente une mauvaise repr\u00e9sentation de nombre octal ou binaire (cette description aurait pu ne pas \u00eatre d\u00e9clar\u00e9e et le langage aurait fonctionn\u00e9 quand m\u00eame);<\/li>\n<li>Les lignes <a href=\"https:\/\/gitlab.com\/tioui\/triumph-programming-language\/-\/blob\/b77868139758f3eb2df2788e870fb9e77a477861\/project\/parser\/triumph_scanner.l#L347\">347<\/a> \u00e0 <a href=\"https:\/\/gitlab.com\/tioui\/triumph-programming-language\/-\/blob\/b77868139758f3eb2df2788e870fb9e77a477861\/project\/parser\/triumph_scanner.l#L349\">349<\/a> repr\u00e9sentent les constantes en virgule flottante;<\/li>\n<li>Les lignes <a href=\"https:\/\/gitlab.com\/tioui\/triumph-programming-language\/-\/blob\/b77868139758f3eb2df2788e870fb9e77a477861\/project\/parser\/triumph_scanner.l#L354\">354<\/a> \u00e0 <a href=\"https:\/\/gitlab.com\/tioui\/triumph-programming-language\/-\/blob\/b77868139758f3eb2df2788e870fb9e77a477861\/project\/parser\/triumph_scanner.l#L368\">368<\/a> repr\u00e9sentent les constantes caract\u00e8res et cha\u00eenes de caract\u00e8res;<\/li>\n<li>La ligne <a href=\"https:\/\/gitlab.com\/tioui\/triumph-programming-language\/-\/blob\/b77868139758f3eb2df2788e870fb9e77a477861\/project\/parser\/triumph_scanner.l#L374\">374<\/a> repr\u00e9sente les commentaires dans le langage Triumph;<\/li>\n<li>La description \u00e0 la ligne <a href=\"https:\/\/gitlab.com\/tioui\/triumph-programming-language\/-\/blob\/b77868139758f3eb2df2788e870fb9e77a477861\/project\/parser\/triumph_scanner.l#L378\">378<\/a> d\u00e9tecte la fin du fichier source et arr\u00eate l&rsquo;analyseur lexical;<\/li>\n<li>Puisque, pour chaque lex\u00e8me, les descriptions sont test\u00e9es en ordre de leurs apparitions dans le fichier de description, la description \u00e0 la ligne <a href=\"https:\/\/gitlab.com\/tioui\/triumph-programming-language\/-\/blob\/b77868139758f3eb2df2788e870fb9e77a477861\/project\/parser\/triumph_scanner.l#L380\">380<\/a> permet de donner une erreur dans le cas ou un lex\u00e8me n&rsquo;aurait pas \u00e9t\u00e9 d\u00e9tect\u00e9 par l&rsquo;analyseur;<\/li>\n<li>La ligne <a href=\"https:\/\/gitlab.com\/tioui\/triumph-programming-language\/-\/blob\/b77868139758f3eb2df2788e870fb9e77a477861\/project\/parser\/triumph_scanner.l#L386\">386<\/a> indique \u00e0 Gelex qu&rsquo;il s&rsquo;agit de la fin des descriptions du fichier<\/li>\n<li>Le reste du fichier repr\u00e9sente le pied de classe de la classe Eiffel qui sera g\u00e9n\u00e9r\u00e9 par Gelex.<\/li>\n<\/ul>\n<p>Malgr\u00e9 qu&rsquo;il y a quelques possibilit\u00e9s d&rsquo;erreur g\u00e9r\u00e9e par l&rsquo;analyseur lexical, on peut facilement voir que cet outil ne v\u00e9rifie pas que le code source analys\u00e9 respecte le langage cible. Tout ce que cette \u00e9tape a fait, c&rsquo;est de valider que les lex\u00e8mes sont valident et ensuite transformer ces derniers en jeton. Par exemple, malgr\u00e9 que le code Java suivant ne fasse aucun sens:<\/p>\n<div class=\"highlight\">\n<pre><span class=\"kd\">static<\/span> <span class=\"s\">\"Coucou\"<\/span> <span class=\"o\">[<\/span> <span class=\"n\">System<\/span> <span class=\"kd\">class<\/span> \r\n<span class=\"err\">} <\/span><span class=\"nc\">variable<\/span> <span class=\"k\">if<\/span>\r\n<\/pre>\n<\/div>\n<p>un analyseur lexical Java pourrait tout de m\u00eame faire l&rsquo;enti\u00e8ret\u00e9 de sont travail puisque tous les lex\u00e8mes sont valident en Java.<\/p>\n<p>Afin de v\u00e9rifier que les jetons g\u00e9n\u00e9r\u00e9s respectent r\u00e9ellement le langage, le compilateur devra faire une analyse plus en d\u00e9tail de ces jetons. La prochaine \u00e9tape d&rsquo;analyse se nomme l&rsquo;analyseur syntaxique et sera le contenu du prochain article.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Cet article est le second d&rsquo;une s\u00e9rie d&rsquo;articles pr\u00e9sentant les \u00e9tapes de d\u00e9veloppement d&rsquo;un langage de programmation. La s\u00e9rie d&rsquo;articles d\u00e9bute ici. La premi\u00e8re \u00e9tape effectu\u00e9e par un compilateur (ou un interpr\u00e9teur) est l&rsquo;analyse lexicale (ou \u00ab\u00a0scanner\u00a0\u00bb ou \u00ab\u00a0lexer\u00a0\u00bb) d&rsquo;un code source. L&rsquo;analyseur lexical permet de transformer les informations du code source (mots cl\u00e9s, identificateurs,&hellip; <a class=\"more-link\" href=\"https:\/\/www.louismarchand.me\/index.php\/2021\/07\/02\/la-creation-dun-langage-de-programmation-analyseur-lexical\/\">Continue reading <span class=\"screen-reader-text\">La cr\u00e9ation d\u2019un langage de programmation &#8211; Analyseur lexical<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-127","post","type-post","status-publish","format-standard","hentry","category-non-classe","entry"],"_links":{"self":[{"href":"https:\/\/www.louismarchand.me\/index.php\/wp-json\/wp\/v2\/posts\/127","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.louismarchand.me\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.louismarchand.me\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.louismarchand.me\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.louismarchand.me\/index.php\/wp-json\/wp\/v2\/comments?post=127"}],"version-history":[{"count":11,"href":"https:\/\/www.louismarchand.me\/index.php\/wp-json\/wp\/v2\/posts\/127\/revisions"}],"predecessor-version":[{"id":138,"href":"https:\/\/www.louismarchand.me\/index.php\/wp-json\/wp\/v2\/posts\/127\/revisions\/138"}],"wp:attachment":[{"href":"https:\/\/www.louismarchand.me\/index.php\/wp-json\/wp\/v2\/media?parent=127"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.louismarchand.me\/index.php\/wp-json\/wp\/v2\/categories?post=127"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.louismarchand.me\/index.php\/wp-json\/wp\/v2\/tags?post=127"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}