Recent Changes - Search:

My Projects

Courses

Writings

Source Code

Social Networks

Histoires

Live Traffic !

Évolution 2 : If/Else

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

<< Évolution 1 : Opérateurs de comparaison | Évolution 2 : If/Else | Évolution 3 : Les commentaires >>

Il est temps d'implémenter les conditions. Comme tout langage de programmation qui se respecte, le développeur doit pouvoir exécuter des instructions sous certaines conditions. Je vais profiter de cette évolution pour ajouter l'opérateur unaire "-" que j'ai complètement zappé. Il y a le "-" de la soustraction, la différence entre deux nombres, mais aussi le "-" comme opérateur unaire, qui indique le caractère négatif du nombre. Et celui-là je ne l'ai jusqu'ici pas encore mis.

Évolution 2 du langage :

  1. <condition_si> ::= "si" <expression_booleenne> "alors" <code >
  2.  
  3. <condition_sinon> ::= "sinon" <code >
  4.  
  5. <condition> ::= <condition_si> [<condition_sinon>] ";"
  6.  
  7. <code > ::= <code > | <condition>
  8.  
  9. <expression_arithmetique> ::= <expression_arithmetique> | "-" <expression_arithmetique>

On ajoute les nouveaux lexèmes à l'analyseur lexical :

lexique_simple.lex
  1. "si"    {return TOK_SI;}
  2.  
  3. "alors" {return TOK_ALORS;}
  4.  
  5. "sinon" {return TOK_SINON;}

On met à jour l'analyseur syntaxique :

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

On oublie pas d'ajouter les nouvelles sequences de code dans le fichier d'entête :

simple.h
  1. #define CONDITION_SI    29
  2. #define CONDITION_SI_SINON 30
  3. #define SI          31
  4. #define SINON       32
  5. #define NEGATIF     33

Et bien sûr éditer le générateur de code :

generation_code.c
  1. case NEGATIF:
  2.         fprintf(fichier,"-");
  3.         genere_code(g_node_nth_child(ast,0));
  4.         break;
  5. case CONDITION_SI:
  6.         genere_code(g_node_nth_child(ast,0));
  7.         fprintf(fichier,"\n");
  8.         break;
  9. case CONDITION_SI_SINON:
  10.         genere_code(g_node_nth_child(ast,0));
  11.         genere_code(g_node_nth_child(ast,1));
  12.         break;
  13. case SI:
  14.         fprintf(fichier,"\tif(");
  15.         genere_code(g_node_nth_child(ast,0));
  16.         fprintf(fichier,"){\n");
  17.         genere_code(g_node_nth_child(ast,1));
  18.         fprintf(fichier,"\t}");
  19.         break;
  20. case SINON:
  21.         fprintf(fichier,"else{\n");
  22.         genere_code(g_node_nth_child(ast,0));
  23.         fprintf(fichier,"\t}\n");
  24.         break;

On compile et maintenant on teste !! Je vous propose ce programme de test :

programme.simple
  1. entier = 8;
  2. si entier > 5 alors
  3.     booleen = faux;
  4.     afficher booleen;
  5. sinon
  6.     afficher entier;
  7. ;
  8. afficher booleen;

On compile le fichier généré :

gcc programme.c

Et on obtient l'erreur suivante (en tout cas moi oui) :

programme.c: In function ‘main’:
programme.c:15:16: error: ‘booleen’ undeclared (first use in this function)
  printf("%s\n",booleen?"vrai":"faux");
                ^
programme.c:15:16: note: each undeclared identifier is reported only once for each function it appears in

Arf ! On a un gros problème sur la portée de nos variables en fait. Le langage Simple donne la possibilité de déclarer une variable dans un bloc d'instruction et de la réutiliser à l'extérieur. A la ligne 3 du programme, j'ai déclaré une variable booleenne que j'initialise à faux et je réutilise cette même variable en ligne 8 à l'extérieur du "si". En C, cela n'est pas possible. Il faut donc adapter l'analyse sémantique pour prévenir l'erreur au développeur. Rappelez-vous, on stocke toutes les variables dans une table de hachage. Lorsqu'on rencontre une variable, si elle n'existe pas dans la table, on l'ajoute et le générateur de code la déclare. Mais si elle existe déjà, le générateur ne fait pas de déclaration. L'idée est de supprimer toutes les variables déclarées dans un bloc d'instruction, une fois sorti de ce bloc. On va ajouter une fonction qui supprime dans la table des variables toutes les variables nouvellement déclarées à l'intérieur d'un noeud d'arbre syntaxique. On va pour faire bien, déclarer un nouveau non terminal dans Bison, que l'on va appeler bloc_code.

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

On réedite le fichier d'entête et le générateur de code :

simple.h
  1. #define BLOC_CODE     34
generation_code.c
  1. case BLOC_CODE:
  2.         genere_code(g_node_nth_child(ast,0));
  3.         break;

Si on recompile tout et qu'on reteste avec le même programme, on a la log suivante :

Debut de l'analyse syntaxique :
                        Variable entiere entier
                        Nombre : 8
                Affectation sur la variable
        Instruction type Affectation
Resultat : C'est une instruction valide !

                        Variable entiere entier
                        Nombre : 5
                        Operateur de superiorite >
                        Variable booleenne booleen
                        Booleen Faux
                Affectation sur la variable
        Instruction type Affectation
Resultat : C'est une instruction valide !

                        Variable booleenne booleen
                Affichage de la valeur de l'expression booleenne
        Instruction type Affichage
Resultat : C'est une instruction valide !

Variable booleen supprimee !
                        Variable entiere entier
                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 !

                        Variable booleenne booleen
        ERREUR : Erreur de semantique a la ligne 8. Variable booleen jamais declaree !
                Affichage de la valeur de l'expression booleenne
        Instruction type Affichage
Resultat : C'est une instruction valide !

Fin de l'analyse !
Resultat :
        -- Succes a l'analyse lexicale ! --
        -- Succes a l'analyse syntaxique ! --
        -- Echec : Certaines phrases sont semantiquement incorrectes ! --
        -- Echec a l'analyse semantique --
ECHEC GENERATION CODE !

Il est dit que la variable booleen a été supprimée tout de suite à la sortie du "si". Ce qui a provoqué fatalement une erreur sémantique quand on la réutilise après. Changeons donc le programme pour que cela puisse correctement passer à la compilation :

programme.simple
  1. entier = 8;
  2. si entier > 5 alors
  3.     booleen = faux;
  4.     afficher booleen;
  5. sinon
  6.     afficher entier;
  7. ;
  8. booleen = vrai;
  9. afficher booleen;

La compilation se passe cette fois-ci bien.

gcc -o programme programme.c
./programme
faux
vrai

La prochaine évolution sera consacrée aux commentaires. A l'heure actuelle, il nous est impossible de commenter notre code. Les commentaires dans ce langage passent par l'analyseur syntaxique. Il faut dire à ce dernier qu'il s'agit de commentaires et qu'il doit les ignorer.

<< Évolution 1 : Opérateurs de comparaison | Évolution 2 : If/Else | Évolution 3 : Les commentaires >>

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

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

This page has been requested 1057 times (Today : 3) - Total number of requests : 95323

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.