Recent Changes - Search:

My Projects

Courses

Writings

Source Code

Social Networks

Histoires

Live Traffic !

Évolution 3 : Les commentaires

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

<< Évolution 2 : If/Else | Évolution 3 : Les commentaires | Évolution 4 : Les raccourcis syntaxiques >>

Commenter son code est devenu essentiel. Rappelons-nous qu'un langage de programmation n'est pas tout à fait le langage des humains. Les habitués peuvent très vite comprendre ce que fait un bout de code, mais les débutants vont mettre un peu plus de temps. Les commentaires ne sont pas qu'utiles aux autres mais aussi pour le développeur. Il peut facilement revenir sur son code si il l'a bien commenté. Parfois les commentaires ne servent pas seulement à décrire le fonctionnement mais également à marquer des choses qui seraient à revoir ou à faire. On peut aussi y mettre des renseignements utiles comme la date de création, l'auteur, la licence... Bref il est appréciable dans tout langage de programmation de pouvoir écrire du texte librement.

Évolution 3 du langage :

  1. <code > ::= <code > | <code > commentaire

commentaire est un terminal. En fait c'est une expression régulière au même titre que variable_booleenne et variable_arithmetique. Voici la regex pour ce terminal :

  1. ((\/\/|#).*)

Bien donc si vous avez compris, on aura juste un lexème à rajouter dans l'analyseur lexical. Mais on voudrait aussi faire des commentaires sur plusieurs lignes. On aura un marqueur de début et un marqueur de fin. Ce sera toujours un lexème (pouvant être sur plusieurs lignes) qui devra être reconnu par l'analyseur lexical. On aura deux types de marqueurs de début et de fin donc deux lexèmes différents. Au total cela fait trois lexèmes pour un même token :

Exemples de 1er lexème :

  1. //blablabla
  2. #blablabla

Exemple de 2nd lexème (marqueurs "/*" et "*/") :

  1. /*
  2. il fait chaud cet ete !!
  3. */

Exemple de 3ème lexème (marqueurs " " et " ") :

  1. <!--
  2. c'est pas que un commentaire en XML ou HTML, c'est aussi un commentaire en Simple !!
  3. -->

Pour ces trois lexèmes que l'analyseur lexical devra reconnaître, il enverra le même token à l'analyseur syntaxique. Pour ceux qui ne voyaient pas la différence entre lexème et token, ici elle est plutôt flagrante. Un token est un "code" associé à un ou plusieurs lexèmes.

lexique_simple.lex
  1. %{
  2.  
  3. #include "simple.h"
  4. unsigned int lineno=1;
  5. bool error_lexical=false;
  6.  
  7. %}
  8.  
  9. %option noyywrap
  10.  
  11. nombre 0|[1-9][[:digit:]]*
  12. variable_booleenne b(_|[[:alnum:]])*
  13. variable_arithmetique e(_|[[:alnum:]])*
  14.  
  15. /* regex de commentaire d'une seule ligne */
  16. commentaire ((\/\/|#).*)
  17.  
  18. /* pour les commentaires de plusieurs lignes, on declare nos deux lexemes en tant que conditions de demarrage exclusives (%x) dans Flex */
  19. %x  commentaire_1
  20. %x  commentaire_2
  21.  
  22. %%
  23.  
  24. "/*"    {
  25.             /* un marqueur de debut de commentaire trouve -> on lui dit que le lexeme commentaire_1 commence */
  26.             BEGIN(commentaire_1);
  27.             printf("Commentaire detecte en ligne %i\n",lineno);
  28.         }
  29.  
  30. <commentaire_1>"\n"     {
  31.                             /* si on trouve des retours chariots et que la condition de demarrage est commentaire_1, alors on incremente la variable lineno. sans cela, on serait en decalage pour la suite de l'analyse */
  32.                             lineno++;
  33.                         }
  34.  
  35. <commentaire_1>"*"+"/"      {
  36.                                 /* si on au moins une fois "*" suivi de "/" et que la condition de demarrage est commentaire_1, alors on lui dit que le lexeme commentaire_1 est fini */
  37.                                 BEGIN(INITIAL);
  38.                                 printf("Fin du commentaire en ligne %i\n",lineno);
  39.                                 return TOK_COMMENT;
  40.                             }
  41.  
  42. <commentaire_1>.    {/* les autres caracteres suivants la conditions de demarrage sont absorbes par l'analyse est donc ingores */}
  43.  
  44. "<!--"      {
  45.                 BEGIN(commentaire_2);
  46.                 printf("Commentaire detecte en ligne %i\n",lineno);
  47.             }
  48. <commentaire_2>"\n"         {lineno++;}
  49. <commentaire_2>"-"+"-"+">"  {
  50.                                 BEGIN(INITIAL);
  51.                                 printf("Fin du commentaire en ligne %i\n",lineno);
  52.                                 return TOK_COMMENT;
  53.                             }
  54. <commentaire_2>.            {}
  55.  
  56. {nombre} {
  57.     sscanf(yytext, "%ld", &yylval.nombre);
  58.     return TOK_NOMBRE;
  59. }
  60.  
  61. "si"    {return TOK_SI;}
  62.  
  63. "alors" {return TOK_ALORS;}
  64.  
  65. "sinon" {return TOK_SINON;}
  66.  
  67. "egal a"|"equivalent a"|"=="        {return TOK_EQU;}
  68.  
  69. "different de"|"!="|"<>"            {return TOK_DIFF;}
  70.  
  71. "superieur a"|"plus grand que"|">"  {return TOK_SUP;}
  72.  
  73. "inferieur a"|"plus petit que"|"<"  {return TOK_INF;}
  74.  
  75. "superieur ou egal a"|">="          {return TOK_SUPEQU;}
  76.  
  77. "inferieur ou egal a"|"<="          {return TOK_INFEQU;}
  78.  
  79. "compris dans"|"dans"               {return TOK_IN;}
  80.  
  81. "afficher"      {return TOK_AFFICHER;}
  82.  
  83. "="             {return TOK_AFFECT;}
  84.  
  85. "+"             {return TOK_PLUS;}
  86.  
  87. "-"             {return TOK_MOINS;}
  88.  
  89. "*"             {return TOK_MUL;}
  90.  
  91. "/"             {return TOK_DIV;}
  92.  
  93. "("             {return TOK_PARG;}
  94.  
  95. ")"             {return TOK_PARD;}
  96.  
  97. "["             {return TOK_CROG;}
  98.  
  99. "]"             {return TOK_CROD;}
  100.  
  101. "et"            {return TOK_ET;}
  102.  
  103. "ou"            {return TOK_OU;}
  104.  
  105. "non"           {return TOK_NON;}
  106.  
  107. ";"             {return TOK_FINSTR;}
  108.  
  109. "vrai"          {return TOK_VRAI;}
  110.  
  111. "faux"          {return TOK_FAUX;}
  112.  
  113. "\n"            {lineno++;}
  114.  
  115. {variable_booleenne} {
  116.     yylval.texte = yytext;
  117.     return TOK_VARB;
  118. }
  119.  
  120.  
  121. {variable_arithmetique} {
  122.     yylval.texte = yytext;
  123.     return TOK_VARE;
  124. }
  125.  
  126. {commentaire}   {
  127.     printf("Commentaire detecte en ligne %i\n",lineno);
  128.     printf("Fin du commentaire en ligne %i\n",lineno);
  129.     return TOK_COMMENT;
  130. }
  131.  
  132. " "|"\t" {}
  133.  
  134. . {
  135.     fprintf(stderr,"\tERREUR : Lexeme inconnu a la ligne %d. Il s'agit de %s et comporte %d lettre(s)\n",lineno,yytext,yyleng);
  136.     error_lexical=true;
  137.     return yytext[0];
  138. }
  139.  
  140. %%

Pour l'analyseur syntaxique, voici ce qu'on a :

syntaxe_simple.y
  1. %{
  2.  
  3. #include "simple.h"
  4. bool error_syntaxical=false;
  5. bool error_semantical=false;
  6. /* Notre table de hachage */
  7. GHashTable* table_variable;
  8.  
  9. /* Fonction de suppression des variables declarees a l'interieur d'un arbre syntaxique */
  10. void supprime_variable(GNode*);
  11.  
  12. /* Notre structure Variable qui a comme membre le type et un pointeur generique vers la valeur */
  13. typedef struct Variable Variable;
  14.  
  15. struct Variable{
  16.         char* type;
  17.         GNode* value;
  18. };
  19.  
  20. %}
  21.  
  22. /* L'union dans Bison est utilisee pour typer nos tokens ainsi que nos non terminaux. Ici nous avons declare une union avec trois types : nombre de type int, texte de type pointeur de char (char*) et noeud d'arbre syntaxique (AST) de type (GNode*) */
  23.  
  24. %union {
  25.         long nombre;
  26.         char* texte;
  27.         GNode*  noeud;
  28. }
  29.  
  30. /* Nous avons ici les operateurs, ils sont definis par leur ordre de priorite. Si je definis par exemple la multiplication en premier et l'addition apres, le + l'emportera alors sur le * dans le langage. Les parenthese sont prioritaires avec %right */
  31.  
  32. %left                   TOK_PLUS        TOK_MOINS       /* +- */
  33. %left                   TOK_MUL         TOK_DIV         /* /* */
  34. %left                   TOK_ET          TOK_OU          TOK_NON         /* et ou non */
  35. %left                   TOK_EQU         TOK_DIFF        TOK_SUP         TOK_INF         TOK_SUPEQU      TOK_INFEQU      /* comparaisons */
  36. %right                  TOK_PARG        TOK_PARD        /* () */
  37.  
  38. /* Nous avons la liste de nos expressions (les non terminaux). Nous les typons tous en noeud de l'arbre syntaxique (GNode*) */
  39.  
  40. %type<noeud>            code
  41. %type<noeud>            bloc_code
  42. %type<noeud>            commentaire
  43. %type<noeud>            instruction
  44. %type<noeud>            condition
  45. %type<noeud>            condition_si
  46. %type<noeud>            condition_sinon
  47. %type<noeud>            variable_arithmetique
  48. %type<noeud>            variable_booleenne
  49. %type<noeud>            affectation
  50. %type<noeud>            affichage
  51. %type<noeud>            expression_arithmetique
  52. %type<noeud>            expression_booleenne
  53. %type<noeud>            addition
  54. %type<noeud>            soustraction
  55. %type<noeud>            multiplication
  56. %type<noeud>            division
  57.  
  58. /* Nous avons la liste de nos tokens (les terminaux de notre grammaire) */
  59.  
  60. %token<nombre>          TOK_NOMBRE
  61. %token                  TOK_VRAI        /* true */
  62. %token                  TOK_FAUX        /* false */
  63. %token                  TOK_AFFECT      /* = */
  64. %token                  TOK_FINSTR      /* ; */
  65. %token                  TOK_IN          /* dans */
  66. %token                  TOK_CROG    TOK_CROD    /* [] */
  67. %token                  TOK_AFFICHER    /* afficher */
  68. %token<texte>           TOK_VARB        /* variable booleenne */
  69. %token<texte>           TOK_VARE        /* variable arithmetique */
  70. %token                  TOK_SI          /* si */
  71. %token                  TOK_ALORS       /* alors */
  72. %token                  TOK_SINON       /* sinon */
  73. %token                  TOK_COMMENT             /* commentaire */
  74.  
  75. %%
  76.  
  77. /* Nous definissons toutes les regles grammaticales de chaque non terminal de notre langage. Par defaut on commence a definir l'axiome, c'est a dire ici le non terminal code. Si nous le definissons pas en premier nous devons le specifier en option dans Bison avec %start */
  78.  
  79. entree:         code{
  80.                         genere_code($1);
  81.                         g_node_destroy($1);
  82.                 };
  83.  
  84. code:           %empty{$$=g_node_new((gpointer)CODE_VIDE);}
  85.                 |
  86.                 code commentaire{
  87.                         $$=g_node_new((gpointer)SEQUENCE);
  88.                         g_node_append($$,$1);
  89.                         g_node_append($$,$2);
  90.                 }
  91.                 |
  92.                 code instruction{
  93.                         printf("Resultat : C'est une instruction valide !\n\n");
  94.                         $$=g_node_new((gpointer)SEQUENCE);
  95.                         g_node_append($$,$1);
  96.                         g_node_append($$,$2);
  97.                 }
  98.                 |
  99.                 code error{
  100.                         fprintf(stderr,"\tERREUR : Erreur de syntaxe a la ligne %d.\n",lineno);
  101.                         error_syntaxical=true;
  102.                 };
  103.  
  104. commentaire:    TOK_COMMENT{
  105.                                         $$=g_node_new((gpointer)CODE_VIDE);
  106.                                 };
  107. bloc_code:      code{
  108.                         $$=g_node_new((gpointer)BLOC_CODE);
  109.                         g_node_append($$,$1);
  110.                         /* on efface toutes les variables declarees de la table de hachage a la sortie du bloc de code */
  111.                         supprime_variable($1);
  112.                 };
  113.  
  114. instruction:    affectation{
  115.                         printf("\tInstruction type Affectation\n");
  116.                         $$=$1;
  117.                 }
  118.                 |
  119.                 affichage{
  120.                         printf("\tInstruction type Affichage\n");
  121.                         $$=$1;
  122.                 }
  123.                 |
  124.                 condition{
  125.                     printf("Condition si/sinon\n");
  126.                     $$=$1;
  127.                 };
  128.  
  129. variable_arithmetique:  TOK_VARE{
  130.                                 printf("\t\t\tVariable entiere %s\n",$1);
  131.                                 $$=g_node_new((gpointer)VARIABLE);
  132.                                 g_node_append_data($$,strdup($1));
  133.                         };
  134.  
  135. variable_booleenne:     TOK_VARB{
  136.                                 printf("\t\t\tVariable booleenne %s\n",$1);
  137.                                 $$=g_node_new((gpointer)VARIABLE);
  138.                                 g_node_append_data($$,strdup($1));
  139.                         };
  140.  
  141. condition:      condition_si TOK_FINSTR{
  142.                     printf("\tCondition si\n");
  143.                     $$=g_node_new((gpointer)CONDITION_SI);
  144.                     g_node_append($$,$1);
  145.                 }
  146.                 |
  147.                 condition_si condition_sinon TOK_FINSTR{
  148.                     printf("\tCondition si/sinon\n");
  149.                     $$=g_node_new((gpointer)CONDITION_SI_SINON);
  150.                     g_node_append($$,$1);
  151.                     g_node_append($$,$2);
  152.                 };
  153.  
  154. condition_si:   TOK_SI expression_booleenne TOK_ALORS bloc_code{
  155.                     $$=g_node_new((gpointer)SI);
  156.                     g_node_append($$,$2);
  157.                     g_node_append($$,$4);
  158.                 };
  159.  
  160. condition_sinon:   TOK_SINON bloc_code{
  161.                         $$=g_node_new((gpointer)SINON);
  162.                         g_node_append($$,$2);
  163.                     };
  164.  
  165. affectation:    variable_arithmetique TOK_AFFECT expression_arithmetique TOK_FINSTR{
  166.                         /* $1 est la valeur du premier non terminal. Ici c'est la valeur du non terminal variable. $3 est la valeur du 2nd non terminal. */
  167.                         printf("\t\tAffectation sur la variable\n");
  168.                         Variable* var=g_hash_table_lookup(table_variable,(char*)g_node_nth_child($1,0)->data);
  169.                         if(var==NULL){
  170.                                 /* On cree une Variable et on lui affecte le type que nous connaissons et la valeur */
  171.                                 var=malloc(sizeof(Variable));
  172.                                 if(var!=NULL){
  173.                                         var->type=strdup("entier");
  174.                                         var->value=$3;
  175.                                         /* On l'insere dans la table de hachage (cle: <nom_variable> / valeur: <(type,valeur)>) */
  176.                                         if(g_hash_table_insert(table_variable,g_node_nth_child($1,0)->data,var)){
  177.                                         $$=g_node_new((gpointer)AFFECTATIONE);
  178.                                         g_node_append($$,$1);
  179.                                         g_node_append($$,$3);
  180.                                         }else{
  181.                                             fprintf(stderr,"ERREUR - PROBLEME CREATION VARIABLE !\n");
  182.                                             exit(-1);
  183.                                         }
  184.                                 }else{
  185.                                         fprintf(stderr,"ERREUR - PROBLEME ALLOCATION MEMOIRE VARIABLE !\n");
  186.                                         exit(-1);
  187.                                 }
  188.                         }else{
  189.                                 $$=g_node_new((gpointer)AFFECTATION);
  190.                                 g_node_append($$,$1);
  191.                                 g_node_append($$,$3);
  192.                         }
  193.                 }
  194.                 |
  195.                 variable_booleenne TOK_AFFECT expression_booleenne TOK_FINSTR{
  196.                         /* $1 est la valeur du premier non terminal. Ici c'est la valeur du non terminal variable. $3 est la valeur du 2nd non terminal. */
  197.                         printf("\t\tAffectation sur la variable\n");
  198.                         Variable* var=g_hash_table_lookup(table_variable,(char*)g_node_nth_child($1,0)->data);
  199.                         if(var==NULL){
  200.                                 /* On cree une Variable et on lui affecte le type que nous connaissons et la valeur */
  201.                                 var=malloc(sizeof(Variable));
  202.                                 if(var!=NULL){
  203.                                         var->type=strdup("booleen");
  204.                                         var->value=$3;
  205.                                         /* On l'insere dans la table de hachage (cle: <nom_variable> / valeur: <(type,valeur)>) */
  206.                                         if(g_hash_table_insert(table_variable,g_node_nth_child($1,0)->data,var)){
  207.                                         $$=g_node_new((gpointer)AFFECTATIONB);
  208.                                         g_node_append($$,$1);
  209.                                         g_node_append($$,$3);
  210.                                         }else{
  211.                                             fprintf(stderr,"ERREUR - PROBLEME CREATION VARIABLE !\n");
  212.                                             exit(-1);
  213.                                         }
  214.                                 }else{
  215.                                         fprintf(stderr,"ERREUR - PROBLEME ALLOCATION MEMOIRE VARIABLE !\n");
  216.                                         exit(-1);
  217.                                 }
  218.                         }else{
  219.                                 $$=g_node_new((gpointer)AFFECTATION);
  220.                                 g_node_append($$,$1);
  221.                                 g_node_append($$,$3);
  222.                         }
  223.                 };
  224.  
  225. affichage:      TOK_AFFICHER expression_arithmetique TOK_FINSTR{
  226.                         printf("\t\tAffichage de la valeur de l'expression arithmetique\n");
  227.                         $$=g_node_new((gpointer)AFFICHAGEE);
  228.                         g_node_append($$,$2);
  229.                 }
  230.                 |
  231.                 TOK_AFFICHER expression_booleenne TOK_FINSTR{
  232.                         printf("\t\tAffichage de la valeur de l'expression booleenne\n");
  233.                         $$=g_node_new((gpointer)AFFICHAGEB);
  234.                         g_node_append($$,$2);
  235.                 };
  236.  
  237.  
  238. expression_arithmetique:        TOK_NOMBRE{
  239.                                         printf("\t\t\tNombre : %ld\n",$1);
  240.                                         /* Comme le token TOK_NOMBRE est de type entier et que on a type expression_arithmetique comme du texte, il nous faut convertir la valeur en texte. */
  241.                                         int length=snprintf(NULL,0,"%ld",$1);
  242.                                         char* str=malloc(length+1);
  243.                                         snprintf(str,length+1,"%ld",$1);
  244.                                         $$=g_node_new((gpointer)ENTIER);
  245.                                         g_node_append_data($$,strdup(str));
  246.                                         free(str);
  247.                                 }
  248.                                 |
  249.                                 variable_arithmetique{
  250.                                         /* On recupere un pointeur vers la structure Variable */
  251.                                         Variable* var=g_hash_table_lookup(table_variable,(char*)g_node_nth_child($1,0)->data);
  252.                                         /* Si on a trouve un pointeur valable */
  253.                                         if(var!=NULL){
  254.                                                 /* On verifie que le type est bien un entier - Inutile car impose a l'analyse syntaxique */
  255.                                                 if(strcmp(var->type,"entier")==0){
  256.                                                         $$=$1;
  257.                                                 }else{
  258.                                                         fprintf(stderr,"\tERREUR : Erreur de semantique a la ligne %d. Type incompatible (entier attendu - valeur : %s) !\n",lineno,(char*)g_node_nth_child($1,0)->data);
  259.                                                         error_semantical=true;
  260.                                                 }
  261.                                         /* Sinon on conclue que la variable n'a jamais ete declaree car absente de la table */
  262.                                         }else{
  263.                                                 fprintf(stderr,"\tERREUR : Erreur de semantique a la ligne %d. Variable %s jamais declaree !\n",lineno,(char*)g_node_nth_child($1,0)->data);
  264.                                                 error_semantical=true;
  265.                                         }
  266.                                 }
  267.                                 |
  268.                                 addition{
  269.                                         $$=$1;
  270.                                 }
  271.                                 |
  272.                                 soustraction{
  273.                                         $$=$1;
  274.                                 }
  275.                                 |
  276.                                 multiplication{
  277.                                         $$=$1;
  278.                                 }
  279.                                 |
  280.                                 division{
  281.                                         $$=$1;
  282.                                 }
  283.                                 |
  284.                                 TOK_PLUS expression_arithmetique{
  285.                                     $$=$2;
  286.                                 }
  287.                                 |
  288.                                 TOK_MOINS expression_arithmetique{
  289.                                     printf("\t\t\tOperation unaire negation\n");
  290.                                     $$=g_node_new((gpointer)NEGATIF);
  291.                                         g_node_append($$,$2);
  292.                                 }
  293.                                 |
  294.                                 TOK_PARG expression_arithmetique TOK_PARD{
  295.                                         printf("\t\t\tC'est une expression artihmetique entre parentheses\n");
  296.                                         $$=g_node_new((gpointer)EXPR_PAR);
  297.                                         g_node_append($$,$2);
  298.                                 };
  299.  
  300. expression_booleenne:           TOK_VRAI{
  301.                                         printf("\t\t\tBooleen Vrai\n");
  302.                                         $$=g_node_new((gpointer)VRAI);
  303.                                 }
  304.                                 |
  305.                                 TOK_FAUX{
  306.                                         printf("\t\t\tBooleen Faux\n");
  307.                                         $$=g_node_new((gpointer)FAUX);
  308.                                 }
  309.                                 |
  310.                                 variable_booleenne{
  311.                                         /* On recupere un pointeur vers la structure Variable */
  312.                                         Variable* var=g_hash_table_lookup(table_variable,(char*)g_node_nth_child($1,0)->data);
  313.                                         /* Si on a trouve un pointeur valable */
  314.                                         if(var!=NULL){
  315.                                                 /* On verifie que le type est bien un entier - Inutile car impose a l'analyse syntaxique */
  316.                                                 if(strcmp(var->type,"booleen")==0){
  317.                                                         $$=$1;
  318.                                                 }else{
  319.                                                         fprintf(stderr,"\tERREUR : Erreur de semantique a la ligne %d. Type incompatible (booleen attendu - valeur : %s) !\n",lineno,(char*)g_node_nth_child($1,0)->data);
  320.                                                         error_semantical=true;
  321.                                                 }
  322.                                         /* Sinon on conclue que la variable n'a jamais ete declaree car absente de la table */
  323.                                         }else{
  324.                                                 fprintf(stderr,"\tERREUR : Erreur de semantique a la ligne %d. Variable %s jamais declaree !\n",lineno,(char*)g_node_nth_child($1,0)->data);
  325.                                                 error_semantical=true;
  326.                                         }
  327.                                 }
  328.                                 |
  329.                                 TOK_NON expression_booleenne{
  330.                                         printf("\t\t\tOperation booleenne Non\n");
  331.                                         $$=g_node_new((gpointer)NON);
  332.                                         g_node_append($$,$2);
  333.                                 }
  334.                                 |
  335.                                 expression_booleenne TOK_ET expression_booleenne{
  336.                                         printf("\t\t\tOperation booleenne Et\n");
  337.                                         $$=g_node_new((gpointer)ET);
  338.                                         g_node_append($$,$1);
  339.                                         g_node_append($$,$3);
  340.                                 }
  341.                                 |
  342.                                 expression_booleenne TOK_OU expression_booleenne{
  343.                                         printf("\t\t\tOperation booleenne Ou\n");
  344.                                         $$=g_node_new((gpointer)OU);
  345.                                         g_node_append($$,$1);
  346.                                         g_node_append($$,$3);
  347.                                 }
  348.                                 |
  349.                                 TOK_PARG expression_booleenne TOK_PARD{
  350.                                         printf("\t\t\tC'est une expression booleenne entre parentheses\n");
  351.                                         $$=g_node_new((gpointer)EXPR_PAR);
  352.                                         g_node_append($$,$2);
  353.                                 }
  354.                                 |
  355.                                 expression_booleenne TOK_EQU expression_booleenne{
  356.                                         printf("\t\t\tOperateur d'egalite ==\n");
  357.                                         $$=g_node_new((gpointer)EGALITE);
  358.                                         g_node_append($$,$1);
  359.                                         g_node_append($$,$3);
  360.                                 }
  361.                                 |
  362.                                 expression_booleenne TOK_DIFF expression_booleenne{
  363.                                         printf("\t\t\tOperateur d'inegalite !=\n");
  364.                                         $$=g_node_new((gpointer)DIFFERENT);
  365.                                         g_node_append($$,$1);
  366.                                         g_node_append($$,$3);
  367.                                 }
  368.                                 |
  369.                                 expression_arithmetique TOK_EQU expression_arithmetique{
  370.                                         printf("\t\t\tOperateur d'egalite ==\n");
  371.                                         $$=g_node_new((gpointer)EGALITE);
  372.                                         g_node_append($$,$1);
  373.                                         g_node_append($$,$3);
  374.                                 }
  375.                                 |
  376.                                 expression_arithmetique TOK_DIFF expression_arithmetique{
  377.                                         printf("\t\t\tOperateur d'inegalite !=\n");
  378.                                         $$=g_node_new((gpointer)DIFFERENT);
  379.                                         g_node_append($$,$1);
  380.                                         g_node_append($$,$3);
  381.                                 }
  382.                                 |
  383.                                 expression_arithmetique TOK_SUP expression_arithmetique{
  384.                                         printf("\t\t\tOperateur de superiorite >\n");
  385.                                         $$=g_node_new((gpointer)SUPERIEUR);
  386.                                         g_node_append($$,$1);
  387.                                         g_node_append($$,$3);
  388.                                 }
  389.                                 |
  390.                                 expression_arithmetique TOK_INF expression_arithmetique{
  391.                                         printf("\t\t\tOperateur d'inferiorite <\n");
  392.                                         $$=g_node_new((gpointer)INFERIEUR);
  393.                                         g_node_append($$,$1);
  394.                                         g_node_append($$,$3);
  395.                                 }
  396.                                 |
  397.                                 expression_arithmetique TOK_SUPEQU expression_arithmetique{
  398.                                         printf("\t\t\tOperateur >=\n");
  399.                                         $$=g_node_new((gpointer)SUPEGAL);
  400.                                         g_node_append($$,$1);
  401.                                         g_node_append($$,$3);
  402.                                 }
  403.                                 |
  404.                                 expression_arithmetique TOK_INFEQU expression_arithmetique{
  405.                                         printf("\t\t\tOperateur <=\n");
  406.                                         $$=g_node_new((gpointer)INFEGAL);
  407.                                         g_node_append($$,$1);
  408.                                         g_node_append($$,$3);
  409.                                 }
  410.                                 |
  411.                                 expression_arithmetique TOK_IN TOK_CROG expression_arithmetique TOK_FINSTR expression_arithmetique TOK_CROD{
  412.                                         printf("\t\t\tOperateur dans\n");
  413.                                         $$=g_node_new((gpointer)DANSII);
  414.                                         g_node_append($$,$1);
  415.                                         g_node_append($$,$4);
  416.                                         g_node_append($$,$6);
  417.                                 }
  418.                                 |
  419.                                 expression_arithmetique TOK_IN TOK_CROD expression_arithmetique TOK_FINSTR expression_arithmetique TOK_CROD{
  420.                                         printf("\t\t\tOperateur dans\n");
  421.                                         $$=g_node_new((gpointer)DANSEI);
  422.                                         g_node_append($$,$1);
  423.                                         g_node_append($$,$4);
  424.                                         g_node_append($$,$6);
  425.                                 }
  426.                                 |
  427.                                 expression_arithmetique TOK_IN TOK_CROG expression_arithmetique TOK_FINSTR expression_arithmetique TOK_CROG{
  428.                                         printf("\t\t\tOperateur dans\n");
  429.                                         $$=g_node_new((gpointer)DANSIE);
  430.                                         g_node_append($$,$1);
  431.                                         g_node_append($$,$4);
  432.                                         g_node_append($$,$6);
  433.                                 }
  434.                                 |
  435.                                 expression_arithmetique TOK_IN TOK_CROD expression_arithmetique TOK_FINSTR expression_arithmetique TOK_CROG{
  436.                                         printf("\t\t\tOperateur dans\n");
  437.                                         $$=g_node_new((gpointer)DANSEE);
  438.                                         g_node_append($$,$1);
  439.                                         g_node_append($$,$4);
  440.                                         g_node_append($$,$6);
  441.                                 };
  442.  
  443. addition:       expression_arithmetique TOK_PLUS expression_arithmetique{
  444.                         printf("\t\t\tAddition\n");
  445.                         $$=g_node_new((gpointer)ADDITION);
  446.                         g_node_append($$,$1);
  447.                         g_node_append($$,$3);
  448.                 };
  449.  
  450. soustraction:   expression_arithmetique TOK_MOINS expression_arithmetique{
  451.                                 printf("\t\t\tSoustraction\n");
  452.                                 $$=g_node_new((gpointer)SOUSTRACTION);
  453.                                 g_node_append($$,$1);
  454.                                 g_node_append($$,$3);
  455.                         };
  456.  
  457. multiplication: expression_arithmetique TOK_MUL expression_arithmetique{
  458.                         printf("\t\t\tMultiplication\n");
  459.                         $$=g_node_new((gpointer)MULTIPLICATION);
  460.                         g_node_append($$,$1);
  461.                         g_node_append($$,$3);
  462.                 };
  463.  
  464. division:       expression_arithmetique TOK_DIV expression_arithmetique{
  465.                         printf("\t\t\tDivision\n");
  466.                         $$=g_node_new((gpointer)DIVISION);
  467.                         g_node_append($$,$1);
  468.                         g_node_append($$,$3);
  469.                 };
  470.  
  471. %%
  472.  
  473. /* Dans la fonction main on appelle bien la routine yyparse() qui sera genere par Bison. Cette routine appellera yylex() de notre analyseur lexical. */
  474.  
  475. int main(int argc, char** argv){
  476.         /* recuperation du nom de fichier d'entree (langage Simple) donne en parametre */
  477.         char* fichier_entree=strdup(argv[1]);
  478.         /* ouverture du fichier en lecture dans le flux d'entree stdin */
  479.         stdin=fopen(fichier_entree,"r");
  480.         /* creation fichier de sortie (langage C) */
  481.         char* fichier_sortie=strdup(argv[1]);
  482.         /* remplace l'extension par .c */
  483.         strcpy(rindex(fichier_sortie, '.'), ".c");
  484.         /* ouvre le fichier cree en ecriture */
  485.         fichier=fopen(fichier_sortie, "w");
  486.         /* Creation de la table de hachage */
  487.         table_variable=g_hash_table_new_full(g_str_hash,g_str_equal,free,free);
  488.         printf("Debut de l'analyse syntaxique :\n");
  489.         debut_code();
  490.         yyparse();
  491.         fin_code();
  492.         printf("Fin de l'analyse !\n");
  493.         printf("Resultat :\n");
  494.         if(error_lexical){
  495.                 printf("\t-- Echec : Certains lexemes ne font pas partie du lexique du langage ! --\n");
  496.                 printf("\t-- Echec a l'analyse lexicale --\n");
  497.         }
  498.         else{
  499.                 printf("\t-- Succes a l'analyse lexicale ! --\n");
  500.         }
  501.         if(error_syntaxical){
  502.                 printf("\t-- Echec : Certaines phrases sont syntaxiquement incorrectes ! --\n");
  503.                 printf("\t-- Echec a l'analyse syntaxique --\n");
  504.         }
  505.         else{
  506.                 printf("\t-- Succes a l'analyse syntaxique ! --\n");
  507.                 if(error_semantical){
  508.                         printf("\t-- Echec : Certaines phrases sont semantiquement incorrectes ! --\n");
  509.                         printf("\t-- Echec a l'analyse semantique --\n");
  510.                 }
  511.                 else{
  512.                         printf("\t-- Succes a l'analyse semantique ! --\n");
  513.                 }
  514.         }
  515.         /* Suppression du fichier genere si erreurs analyse */
  516.         if(error_lexical||error_syntaxical||error_semantical){
  517.                 remove(fichier_sortie);
  518.                 printf("ECHEC GENERATION CODE !\n");
  519.         }
  520.         else{
  521.                 printf("Le fichier \"%s\" a ete genere !\n",fichier_sortie);
  522.         }
  523.         /* Fermeture des flux */
  524.         fclose(fichier);
  525.         fclose(stdin);
  526.         /* Liberation memoire */
  527.         free(fichier_entree);
  528.         free(fichier_sortie);
  529.         g_hash_table_destroy(table_variable);
  530.         return EXIT_SUCCESS;
  531. }
  532.  
  533. void yyerror(char *s) {
  534.         fprintf(stderr, "Erreur de syntaxe a la ligne %d: %s\n", lineno, s);
  535. }
  536.  
  537. /* Cette fonction supprime dans la table de hachage toutes les variables declarees pour la premiere fois dans l'arbre syntaxique donne en parametre */
  538.  
  539. void supprime_variable(GNode* ast){
  540.     /* si l'element est n'est pas NULL et que ce n'est pas une feuille et que ce n'est pas un noeud d'arbre type bloc_code (pour eviter de supprimer des variables deja supprimees dans le cas ou on aurait des blocs de code dans des blocs de code */*/
  541.     if(ast&&!G_NODE_IS_LEAF(ast)&&(long)ast->data!=BLOC_CODE){
  542.         /* si le noeud est de type declaration */
  543.         if((long)ast->data==AFFECTATIONB||(long)ast->data==AFFECTATIONE){
  544.             /* suppression de la variable dans la table de hachage */
  545.             if(g_hash_table_remove(table_variable,(char*)g_node_nth_child(g_node_nth_child(ast,0),0)->data)){
  546.                 printf("Variable supprimee !\n");
  547.             }else{
  548.                 fprintf(stderr,"ERREUR - PROBLEME DE SUPPRESSION VARIABLE !\n");
  549.                 exit(-1);
  550.             }
  551.         /* sinon on continue de parcourir l'arbre */
  552.         }else{
  553.             int nb_enfant;
  554.             for(nb_enfant=0;nb_enfant<=g_node_n_children(ast);nb_enfant++){
  555.                 supprime_variable(g_node_nth_child(ast,nb_enfant));
  556.             }
  557.         }
  558.     }
  559. }

Et... c'est tout ! Si vous êtes des chefs, vous savez qu'on n'a besoin de toucher au générateur de code ni au fichier d'entête. On compile et on teste avec un programme contenant des commentaires :

programme.simple
  1. /*
  2.  
  3. Les commentaires peuvent etre sur une ou plusieurs lignes entre "%comment% " et " %%"
  4.  
  5. */
  6.  
  7. <!------------------------------------<
  8.  
  9. Fichier : programme.simple
  10. Date : 19 juillet 2016
  11.  
  12. Auteur : Thomas Tributsch (totodunet)
  13.  
  14. Lieu : Business & Decision - Niort
  15.  
  16. >!------------------------------------>
  17.  
  18. # DECLARATION DES VARIABLES #
  19. entier = 10;
  20. booleen = vrai ou faux;
  21.  
  22. // CONDIION //
  23.  
  24. #si booleen est faux, on affiche la variable entier
  25. si non booleen alors
  26.     afficher entier;
  27. //sinon on affiche la valeur + 1 de la variable entier
  28. sinon
  29.     afficher entier+1;
  30. ;
  31.  
  32. <!--
  33.  
  34. Les commentaires peuvent etre sur une ou plusieurs lignes entre "/*" et "*/"
  35.  
  36. -->

La sortie du compilateur affiche :

Debut de l'analyse syntaxique :
Commentaire detecte en ligne 1
Fin du commentaire en ligne 5
Commentaire detecte en ligne 7
Fin du commentaire en ligne 16
Commentaire detecte en ligne 18
Fin du commentaire en ligne 18
                        Variable entiere entier
                        Nombre : 10
                Affectation sur la variable
        Instruction type Affectation
Resultat : C'est une instruction valide !

                        Variable booleenne booleen
                        Booleen Vrai
                        Booleen Faux
                        Operation booleenne Ou
                Affectation sur la variable
        Instruction type Affectation
Resultat : C'est une instruction valide !

Commentaire detecte en ligne 22
Fin du commentaire en ligne 22
Commentaire detecte en ligne 24
Fin du commentaire en ligne 24
                        Variable booleenne booleen
                        Operation booleenne Non
                        Variable entiere entier
                Affichage de la valeur de l'expression arithmetique
        Instruction type Affichage
Resultat : C'est une instruction valide !

Commentaire detecte en ligne 27
Fin du commentaire en ligne 27
                        Variable entiere entier
                        Nombre : 1
                        Addition
                Affichage de la valeur de l'expression arithmetique
        Instruction type Affichage
Resultat : C'est une instruction valide !

        Condition si/sinon
Condition si/sinon
Resultat : C'est une instruction valide !

Commentaire detecte en ligne 32
Fin du commentaire en ligne 36
Fin de l'analyse !
Resultat :
        -- Succes a l'analyse lexicale ! --
        -- Succes a l'analyse syntaxique ! --
        -- Succes a l'analyse semantique ! --
Le fichier "programme.c" a ete genere !

On peut compiler le programme C généré et l'exécuter :

Bon je vous dis à la prochaine évolution !! Ce sera une petite évolution. On implémentera quelques syntaxes utiles à savoir les affectations rapides sur une variable entière et booléeenne : ("++","+=","--","-=","/=,"*=","|=","&=") et l'opérateur arithmétique modulo. Je profiterai pour rajouter le lexème "!" pour le token TOK_NON utilisé dans la syntaxe de l'opération booléenne unaire non.

<< Évolution 2 : If/Else | Évolution 3 : Les commentaires | Évolution 4 : Les raccourcis syntaxiques >>

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

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

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

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.