Recent Changes - Search:

My Projects

Writings

Source Code

Social Networks

Histoires

Live Traffic !


My Servers

Hosted and administered websites

My Friends

Old Website

Arbre syntaxique abstrait et Génération de code

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

<< Analyse sémantique | Arbre syntaxique abstrait et Génération de code | Évolution 1 : Opérateurs de comparaison >>

Si vous êtes en train de penser de ne pas voir le bout de ce cours et que vous en avez marre de ne toujours pas voir le langage Simple en action, j'ai alors le plaisir de vous annoncer que nous sommes à la dernière étape du développement de notre compilateur. Courage car vous avez franchi les parties les plus dures selon moi et que maintenant ce n'est plus que de l'amusement ! Donc ce serait très dommage d'abandonner maintenant et de louper le meilleur. Nous allons générer du simple code C. Le code C produit par notre compilateur sera ensuite lui même compilé par le compilateur C pour obtenir un exécutable. Il s'agit d'être très ordonné dans son code. On va utiliser un arbre n-aire (rassurez-vous on ne va pas la coder, on l'a déjà fait pour nous) toujours avec GLib. Ce sera notre arbre syntaxique abstrait (abrégé aussi AST pour Abstract Syntax Tree en anglais) et contiendra les séquences de code entrées par l'utilisateur. L'intérêt d'utiliser un arbre n-aire comme structure de données est multiple. On peut facilement faire de la récursivité, ce qui va être utile pour la génération. Et pour des questions d'optimisation de mémoire, on va stocker des entiers comme identifiants de ces séquences de code. Ce qui est beaucoup mieux que de stocker du texte (zone mémoire de char).

Nous allons faire propre. On va écrire un autre programme C chargé de faire la génération de code. On va toucher un peu au fichier de déclaration simple.h :

simple.h
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <stdbool.h>
  4. #include <string.h>
  5. #include <glib.h>
  6. #include "syntaxe_simple.tab.h"
  7. int yylex(void);
  8. void yyerror(char*);
  9. extern unsigned int lineno;
  10. extern bool error_lexical;
  11.  
  12. /* Le flux de notre fichier de sortie final */
  13. FILE* fichier;
  14.  
  15. /* Definition des methodes de generation de code C */
  16. extern void debut_code(void);
  17. extern void genere_code(GNode*);
  18. extern void fin_code(void);
  19.  
  20. /* Definition des sequences de code possibles pour l'AST (Arbre Syntaxique). Chaque sequence de code est associe a un numerique. */
  21. #define CODE_VIDE       0
  22. #define SEQUENCE        1
  23. #define VARIABLE        2
  24. #define AFFECTATION     3
  25. #define AFFECTATIONE    4
  26. #define AFFECTATIONB    5
  27. #define AFFICHAGEE      6
  28. #define AFFICHAGEB      7
  29. #define ENTIER          8
  30. #define ADDITION        9
  31. #define SOUSTRACTION    10
  32. #define MULTIPLICATION  11
  33. #define DIVISION        12
  34. #define ET              13
  35. #define OU              14
  36. #define NON             15
  37. #define VRAI            16
  38. #define FAUX            17
  39. #define EXPR_PAR        18

Nous allons modifier principalement le code l'analyseur syntaxique pour lui demander de traduire les instructions du langage Simple en C et de les écrire dans un fichier :

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. %right                  TOK_PARG        TOK_PARD        /* () */
  33.  
  34. /* Nous avons la liste de nos expressions (les non terminaux). Nous les typons tous en noeud de l'arbre syntaxique (GNode*) */
  35.  
  36. %type<noeud>            code
  37. %type<noeud>            instruction
  38. %type<noeud>            variable_arithmetique
  39. %type<noeud>            variable_booleenne
  40. %type<noeud>            affectation
  41. %type<noeud>            affichage
  42. %type<noeud>            expression_arithmetique
  43. %type<noeud>            expression_booleenne
  44. %type<noeud>            addition
  45. %type<noeud>            soustraction
  46. %type<noeud>            multiplication
  47. %type<noeud>            division
  48.  
  49. /* Nous avons la liste de nos tokens (les terminaux de notre grammaire) */
  50.  
  51. %token<nombre>          TOK_NOMBRE
  52. %token                  TOK_VRAI        /* true */
  53. %token                  TOK_FAUX        /* false */
  54. %token                  TOK_AFFECT      /* = */
  55. %token                  TOK_FINSTR      /* ; */
  56. %token                  TOK_AFFICHER    /* afficher */
  57. %token<texte>           TOK_VARB        /* variable booleenne */
  58. %token<texte>           TOK_VARE        /* variable arithmetique */
  59.  
  60. %%
  61.  
  62. /* 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 */
  63.  
  64. entree:         code{
  65.                         genere_code($1);
  66.                         g_node_destroy($1);
  67.                 };
  68.  
  69. code:           %empty{$$=g_node_new((gpointer)CODE_VIDE);}
  70.                 |
  71.                 code instruction{
  72.                         printf("Resultat : C'est une instruction valide !\n\n");
  73.                         $$=g_node_new((gpointer)SEQUENCE);
  74.                         g_node_append($$,$1);
  75.                         g_node_append($$,$2);
  76.                 }
  77.                 |
  78.                 code error{
  79.                         fprintf(stderr,"\tERREUR : Erreur de syntaxe a la ligne %d.\n",lineno);
  80.                         error_syntaxical=true;
  81.                 };
  82.  
  83. instruction:    affectation{
  84.                         printf("\tInstruction type Affectation\n");
  85.                         $$=$1;
  86.                 }
  87.                 |
  88.                 affichage{
  89.                         printf("\tInstruction type Affichage\n");
  90.                         $$=$1;
  91.                 };
  92.  
  93. variable_arithmetique:  TOK_VARE{
  94.                                 printf("\t\t\tVariable entiere %s\n",$1);
  95.                                 $$=g_node_new((gpointer)VARIABLE);
  96.                                 g_node_append_data($$,strdup($1));
  97.                         };
  98.  
  99. variable_booleenne:     TOK_VARB{
  100.                                 printf("\t\t\tVariable booleenne %s\n",$1);
  101.                                 $$=g_node_new((gpointer)VARIABLE);
  102.                                 g_node_append_data($$,strdup($1));
  103.                         };
  104.  
  105. affectation:    variable_arithmetique TOK_AFFECT expression_arithmetique TOK_FINSTR{
  106.                         /* $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. */
  107.                         printf("\t\tAffectation sur la variable\n");
  108.                         Variable* var=g_hash_table_lookup(table_variable,(char*)g_node_nth_child($1,0)->data);
  109.                         if(var==NULL){
  110.                                 /* On cree une Variable et on lui affecte le type que nous connaissons et la valeur */
  111.                                 var=malloc(sizeof(Variable));
  112.                                 if(var!=NULL){
  113.                                         var->type=strdup("entier");
  114.                                         var->value=$3;
  115.                                         /* On l'insere dans la table de hachage (cle: <nom_variable> / valeur: <(type,valeur)>) */
  116.                                         if(g_hash_table_insert(table_variable,g_node_nth_child($1,0)->data,var)){
  117.                                                 $$=g_node_new((gpointer)AFFECTATIONE);
  118.                                                 g_node_append($$,$1);
  119.                                                 g_node_append($$,$3);
  120.                                         }else{
  121.                                                 fprintf(stderr,"ERREUR - PROBLEME CREATION VARIABLE !\n");
  122.                                                 exit(-1);
  123.                                         }
  124.                                 }else{
  125.                                         fprintf(stderr,"ERREUR - PROBLEME ALLOCATION MEMOIRE VARIABLE !\n");
  126.                                         exit(-1);
  127.                                 }
  128.                         }else{
  129.                                 $$=g_node_new((gpointer)AFFECTATION);
  130.                                 g_node_append_data($$,$1);
  131.                                 g_node_append($$,$3);
  132.                         }
  133.                 }
  134.                 |
  135.                 variable_booleenne TOK_AFFECT expression_booleenne TOK_FINSTR{
  136.                         /* $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. */
  137.                         printf("\t\tAffectation sur la variable\n");
  138.                         Variable* var=g_hash_table_lookup(table_variable,(char*)g_node_nth_child($1,0)->data);
  139.                         if(var==NULL){
  140.                                 /* On cree une Variable et on lui affecte le type que nous connaissons et la valeur */
  141.                                 var=malloc(sizeof(Variable));
  142.                                 if(var!=NULL){
  143.                                         var->type=strdup("booleen");
  144.                                         var->value=$3;
  145.                                         /* On l'insere dans la table de hachage (cle: <nom_variable> / valeur: <(type,valeur)>) */
  146.                                         if(g_hash_table_insert(table_variable,g_node_nth_child($1,0)->data,var)){
  147.                                                 $$=g_node_new((gpointer)AFFECTATIONE);
  148.                                                 g_node_append($$,$1);
  149.                                                 g_node_append($$,$3);
  150.                                         }else{
  151.                                                 fprintf(stderr,"ERREUR - PROBLEME CREATION VARIABLE !\n");
  152.                                                 exit(-1);
  153.                                         }
  154.                                 }else{
  155.                                         fprintf(stderr,"ERREUR - PROBLEME ALLOCATION MEMOIRE VARIABLE !\n");
  156.                                         exit(-1);
  157.                                 }
  158.                         }else{
  159.                                 $$=g_node_new((gpointer)AFFECTATION);
  160.                                 g_node_append($$,$1);
  161.                                 g_node_append($$,$3);
  162.                         }
  163.                 };
  164.  
  165. affichage:      TOK_AFFICHER expression_arithmetique TOK_FINSTR{
  166.                         printf("\t\tAffichage de la valeur de l'expression arithmetique\n");
  167.                         $$=g_node_new((gpointer)AFFICHAGEE);
  168.                         g_node_append($$,$2);
  169.                 }
  170.                 |
  171.                 TOK_AFFICHER expression_booleenne TOK_FINSTR{
  172.                         printf("\t\tAffichage de la valeur de l'expression booleenne\n");
  173.                         $$=g_node_new((gpointer)AFFICHAGEB);
  174.                         g_node_append($$,$2);
  175.                 };
  176.  
  177.  
  178. expression_arithmetique:        TOK_NOMBRE{
  179.                                         printf("\t\t\tNombre : %ld\n",$1);
  180.                                         /* 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. */
  181.                                         int length=snprintf(NULL,0,"%ld",$1);
  182.                                         char* str=malloc(length+1);
  183.                                         snprintf(str,length+1,"%ld",$1);
  184.                                         $$=g_node_new((gpointer)ENTIER);
  185.                                         g_node_append_data($$,strdup(str));
  186.                                         free(str);
  187.                                 }
  188.                                 |
  189.                                 variable_arithmetique{
  190.                                         /* On recupere un pointeur vers la structure Variable */
  191.                                         Variable* var=g_hash_table_lookup(table_variable,(char*)g_node_nth_child($1,0)->data);
  192.                                         /* Si on a trouve un pointeur valable */
  193.                                         if(var!=NULL){
  194.                                                 /* On verifie que le type est bien un entier - Inutile car impose a l'analyse syntaxique */
  195.                                                 if(strcmp(var->type,"entier")==0){
  196.                                                         $$=$1;
  197.                                                 }else{
  198.                                                         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);
  199.                                                         error_semantical=true;
  200.                                                 }
  201.                                         /* Sinon on conclue que la variable n'a jamais ete declaree car absente de la table */
  202.                                         }else{
  203.                                                 fprintf(stderr,"\tERREUR : Erreur de semantique a la ligne %d. Variable %s jamais declaree !\n",lineno,(char*)g_node_nth_child($1,0)->data);
  204.                                                 error_semantical=true;
  205.                                         }
  206.                                 }
  207.                                 |
  208.                                 addition{
  209.                                         $$=$1;
  210.                                 }
  211.                                 |
  212.                                 soustraction{
  213.                                         $$=$1;
  214.                                 }
  215.                                 |
  216.                                 multiplication{
  217.                                         $$=$1;
  218.                                 }
  219.                                 |
  220.                                 division{
  221.                                         $$=$1;
  222.                                 }
  223.                                 |
  224.                                 TOK_PARG expression_arithmetique TOK_PARD{
  225.                                         printf("\t\t\tC'est une expression artihmetique entre parentheses\n");
  226.                                         $$=g_node_new((gpointer)EXPR_PAR);
  227.                                         g_node_append($$,$2);
  228.                                 };
  229.  
  230. expression_booleenne:           TOK_VRAI{
  231.                                         printf("\t\t\tBooleen Vrai\n");
  232.                                         $$=g_node_new((gpointer)VRAI);
  233.                                 }
  234.                                 |
  235.                                 TOK_FAUX{
  236.                                         printf("\t\t\tBooleen Faux\n");
  237.                                         $$=g_node_new((gpointer)FAUX);
  238.                                 }
  239.                                 |
  240.                                 variable_booleenne{
  241.                                         /* On recupere un pointeur vers la structure Variable */
  242.                                         Variable* var=g_hash_table_lookup(table_variable,(char*)g_node_nth_child($1,0)->data);
  243.                                         /* Si on a trouve un pointeur valable */
  244.                                         if(var!=NULL){
  245.                                                 /* On verifie que le type est bien un entier - Inutile car impose a l'analyse syntaxique */
  246.                                                 if(strcmp(var->type,"booleen")==0){
  247.                                                         $$=$1;
  248.                                                 }else{
  249.                                                         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);
  250.                                                         error_semantical=true;
  251.                                                 }
  252.                                         /* Sinon on conclue que la variable n'a jamais ete declaree car absente de la table */
  253.                                         }else{
  254.                                                 fprintf(stderr,"\tERREUR : Erreur de semantique a la ligne %d. Variable %s jamais declaree !\n",lineno,(char*)g_node_nth_child($1,0)->data);
  255.                                                 error_semantical=true;
  256.                                         }
  257.                                 }
  258.                                 |
  259.                                 TOK_NON expression_booleenne{
  260.                                         printf("\t\t\tOperation booleenne Non\n");
  261.                                         $$=g_node_new((gpointer)NON);
  262.                                         g_node_append($$,$2);
  263.                                 }
  264.                                 |
  265.                                 expression_booleenne TOK_ET expression_booleenne{
  266.                                         printf("\t\t\tOperation booleenne Et\n");
  267.                                         $$=g_node_new((gpointer)ET);
  268.                                         g_node_append($$,$1);
  269.                                         g_node_append($$,$3);
  270.                                 }
  271.                                 |
  272.                                 expression_booleenne TOK_OU expression_booleenne{
  273.                                         printf("\t\t\tOperation booleenne Ou\n");
  274.                                         $$=g_node_new((gpointer)OU);
  275.                                         g_node_append($$,$1);
  276.                                         g_node_append($$,$3);
  277.                                 }
  278.                                 |
  279.                                 TOK_PARG expression_booleenne TOK_PARD{
  280.                                         printf("\t\t\tC'est une expression booleenne entre parentheses\n");
  281.                                         $$=g_node_new((gpointer)EXPR_PAR);
  282.                                         g_node_append($$,$2);
  283.                                 };
  284.  
  285. addition:       expression_arithmetique TOK_PLUS expression_arithmetique{
  286.                         printf("\t\t\tAddition\n");
  287.                         $$=g_node_new((gpointer)ADDITION);
  288.                         g_node_append($$,$1);
  289.                         g_node_append($$,$3);
  290.                 };
  291.  
  292. soustraction:   expression_arithmetique TOK_MOINS expression_arithmetique{
  293.                         printf("\t\t\tSoustraction\n");
  294.                         $$=g_node_new((gpointer)SOUSTRACTION);
  295.                         g_node_append($$,$1);
  296.                         g_node_append($$,$3);
  297.                 };
  298.  
  299. multiplication: expression_arithmetique TOK_MUL expression_arithmetique{
  300.                         printf("\t\t\tMultiplication\n");
  301.                         $$=g_node_new((gpointer)MULTIPLICATION);
  302.                         g_node_append($$,$1);
  303.                         g_node_append($$,$3);
  304.                 };
  305.  
  306. division:       expression_arithmetique TOK_DIV expression_arithmetique{
  307.                         printf("\t\t\tDivision\n");
  308.                         $$=g_node_new((gpointer)DIVISION);
  309.                         g_node_append($$,$1);
  310.                         g_node_append($$,$3);
  311.                 };
  312.  
  313. %%
  314.  
  315. /* Dans la fonction main on appelle bien la routine yyparse() qui sera genere par Bison. Cette routine appellera yylex() de notre analyseur lexical. */
  316.  
  317. int main(int argc, char** argv){
  318.         /* recuperation du nom de fichier d'entree (langage Simple) donne en parametre */
  319.         char* fichier_entree=strdup(argv[1]);
  320.         /* ouverture du fichier en lecture dans le flux d'entree stdin */
  321.         stdin=fopen(fichier_entree,"r");
  322.         /* creation fichier de sortie (langage C) */
  323.         char* fichier_sortie=strdup(argv[1]);
  324.         /* remplace l'extension par .c */
  325.         strcpy(rindex(fichier_sortie, '.'), ".c");
  326.         /* ouvre le fichier cree en ecriture */
  327.         fichier=fopen(fichier_sortie, "w");
  328.         /* Creation de la table de hachage */
  329.         table_variable=g_hash_table_new_full(g_str_hash,g_str_equal,free,free);
  330.         printf("Debut de l'analyse syntaxique :\n");
  331.         debut_code();
  332.         yyparse();
  333.         fin_code();
  334.         printf("Fin de l'analyse !\n");
  335.         printf("Resultat :\n");
  336.         if(error_lexical){
  337.                 printf("\t-- Echec : Certains lexemes ne font pas partie du lexique du langage ! --\n");
  338.                 printf("\t-- Echec a l'analyse lexicale --\n");
  339.         }
  340.         else{
  341.                 printf("\t-- Succes a l'analyse lexicale ! --\n");
  342.         }
  343.         if(error_syntaxical){
  344.                 printf("\t-- Echec : Certaines phrases sont syntaxiquement incorrectes ! --\n");
  345.                 printf("\t-- Echec a l'analyse syntaxique --\n");
  346.         }
  347.         else{
  348.                 printf("\t-- Succes a l'analyse syntaxique ! --\n");
  349.                 if(error_semantical){
  350.                         printf("\t-- Echec : Certaines phrases sont semantiquement incorrectes ! --\n");
  351.                         printf("\t-- Echec a l'analyse semantique --\n");
  352.                 }
  353.                 else{
  354.                         printf("\t-- Succes a l'analyse semantique ! --\n");
  355.                 }
  356.         }
  357.         /* Suppression du fichier genere si erreurs analyse */
  358.         if(error_lexical||error_syntaxical||error_semantical){
  359.                 remove(fichier_sortie);
  360.                 printf("ECHEC GENERATION CODE !\n");
  361.         }
  362.         else{
  363.                 printf("Le fichier \"%s\" a ete genere !\n",fichier_sortie);
  364.         }
  365.         /* Fermeture des flux */
  366.         fclose(fichier);
  367.         fclose(stdin);
  368.         /* Liberation memoire */
  369.         free(fichier_entree);
  370.         free(fichier_sortie);
  371.         g_hash_table_destroy(table_variable);
  372.         return EXIT_SUCCESS;
  373. }
  374.  
  375. void yyerror(char *s) {
  376.         fprintf(stderr, "Erreur de syntaxe a la ligne %d: %s\n", lineno, s);
  377. }

Le programme de génération de code C :

generation_code.c
  1. #include "simple.h"
  2.  
  3. void debut_code(){
  4.         fprintf(fichier, "/* FICHIER GENERE PAR LE COMPILATEUR SIMPLE */\n\n");
  5.         fprintf(fichier, "#include<stdlib.h>\n#include<stdbool.h>\n#include<stdio.h>\n\n");
  6.         fprintf(fichier, "int main(void){\n");
  7. }
  8.  
  9. void fin_code(){
  10.         fprintf(fichier, "\treturn EXIT_SUCCESS;\n");
  11.         fprintf(fichier, "}\n");
  12. }
  13.  
  14. void genere_code(GNode* ast){
  15.         if(ast){
  16.                 switch((long)ast->data){
  17.                         case SEQUENCE:
  18.                                 genere_code(g_node_nth_child(ast,0));
  19.                                 genere_code(g_node_nth_child(ast,1));
  20.                                 break;
  21.                         case VARIABLE:
  22.                                 fprintf(fichier,"%s",(char*)g_node_nth_child(ast,0)->data);
  23.                                 break;
  24.                         case AFFECTATIONE:
  25.                                 fprintf(fichier,"\tlong ");
  26.                                 genere_code(g_node_nth_child(ast,0));
  27.                                 fprintf(fichier,"=");
  28.                                 genere_code(g_node_nth_child(ast,1));
  29.                                 fprintf(fichier,";\n");
  30.                                 break;
  31.                         case AFFECTATIONB:
  32.                                 fprintf(fichier,"\tbool ");
  33.                                 genere_code(g_node_nth_child(ast,0));
  34.                                 fprintf(fichier,"=");
  35.                                 genere_code(g_node_nth_child(ast,1));
  36.                                 fprintf(fichier,";\n");
  37.                                 break;
  38.                         case AFFECTATION:
  39.                                 fprintf(fichier,"\t");
  40.                                 genere_code(g_node_nth_child(ast,0));
  41.                                 fprintf(fichier,"=");
  42.                                 genere_code(g_node_nth_child(ast,1));
  43.                                 fprintf(fichier,";\n");
  44.                                 break;
  45.                         case AFFICHAGEE:
  46.                                 fprintf(fichier,"\tprintf(\"%%ld\\n\",");
  47.                                 genere_code(g_node_nth_child(ast,0));
  48.                                 fprintf(fichier,");\n");
  49.                                 break;
  50.                         case AFFICHAGEB:
  51.                                 fprintf(fichier,"\tprintf(\"%%s\\n\",");
  52.                                 genere_code(g_node_nth_child(ast,0));
  53.                                 fprintf(fichier,"?\"vrai\":\"faux\");\n");
  54.                                 break;
  55.                         case ENTIER:
  56.                                 fprintf(fichier,"%s",(char*)g_node_nth_child(ast,0)->data);
  57.                                 break;
  58.                         case ADDITION:
  59.                                 genere_code(g_node_nth_child(ast,0));
  60.                                 fprintf(fichier,"+");
  61.                                 genere_code(g_node_nth_child(ast,1));
  62.                                 break;
  63.                         case SOUSTRACTION:
  64.                                 genere_code(g_node_nth_child(ast,0));
  65.                                 fprintf(fichier,"-");
  66.                                 genere_code(g_node_nth_child(ast,1));
  67.                                 break;
  68.                         case MULTIPLICATION:
  69.                                 genere_code(g_node_nth_child(ast,0));
  70.                                 fprintf(fichier,"*");
  71.                                 genere_code(g_node_nth_child(ast,1));
  72.                                 break;
  73.                         case DIVISION:
  74.                                 genere_code(g_node_nth_child(ast,0));
  75.                                 fprintf(fichier,"/");
  76.                                 genere_code(g_node_nth_child(ast,1));
  77.                                 break;
  78.                         case VRAI:
  79.                                 fprintf(fichier,"true");
  80.                                 break;
  81.                         case FAUX:
  82.                                 fprintf(fichier,"false");
  83.                                 break;
  84.                         case ET:
  85.                                 genere_code(g_node_nth_child(ast,0));
  86.                                 fprintf(fichier,"&&");
  87.                                 genere_code(g_node_nth_child(ast,1));
  88.                                 break;
  89.                         case OU:
  90.                                 genere_code(g_node_nth_child(ast,0));
  91.                                 fprintf(fichier,"||");
  92.                                 genere_code(g_node_nth_child(ast,1));
  93.                                 break;
  94.                         case NON:
  95.                                 fprintf(fichier,"!");
  96.                                 genere_code(g_node_nth_child(ast,0));
  97.                                 break;
  98.                         case EXPR_PAR:
  99.                                 fprintf(fichier,"(");
  100.                                 genere_code(g_node_nth_child(ast,0));
  101.                                 fprintf(fichier,")");
  102.                                 break;
  103.                 }
  104.         }
  105. }

On compile :

flex -o lexique_simple.c lexique_simple.lex
bison -d syntaxe_simple.y
gcc lexique_simple.c syntaxe_simple.tab.c generation_code.c `pkg-config --cflags --libs glib-2.0` -o simple

Après compilation, on teste avec ce programme :

programme.simple
  1. entier = 2;
  2. afficher (3 * entier)+4;
  3. booleen = vrai et non faux;
  4. booleen = booleen et vrai;
  5. afficher booleen;
  6. booleen = non booleen;
  7. afficher booleen;
./simple programme.simple

Si vous avez regardé le code Bison, dans la fonction main, le programme prend le fichier en argument, donc faîtes attention de ne pas ajouter le '<' dans la commande shell, tel que c'est écrit au-dessus. Cela semble stupide de le dire mais je me suis quand même fait avoir dans mon propre piège. Je ne voudrais pas que vous ayez l'air aussi stupide que moi. On voit à l'emplacement du programme un fichier "programme.c" qui a été généré :

programme.c
  1. /* FICHIER GENERE PAR LE COMPILATEUR SIMPLE */
  2.  
  3. #include<stdlib.h>
  4. #include<stdbool.h>
  5. #include<stdio.h>
  6.  
  7. int main(void){
  8.         int entier=2;
  9.         printf("%i\n",(3*entier)+4);
  10.         bool booleen=true&&!false;
  11.         booleen=booleen&&true;
  12.         printf("%s\n",booleen?"vrai":"faux");
  13.         booleen=!booleen;
  14.         printf("%s\n",booleen?"vrai":"faux");
  15.         return EXIT_SUCCESS;
  16. }

On le compile avec gcc et on l'exécute :

gcc -o programme programme.c
./programme

La sortie du programme donne bien :

10
vrai
faux

Et voilà ! Elle est pas belle la vie ? Nous avons désormais fini le compilateur. Je vous propose à partir de maintenant que des évolutions sur ce langage Simple. La prochaine évolution est l'ajout des opérateurs de comparaisons. A bientôt pour l'évolution 1.

<< Analyse sémantique | Arbre syntaxique abstrait et Génération de code | Évolution 1 : Opérateurs de comparaison >>

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

Page last modified on August 11, 2016, at 10:20 AM EST

This page has been requested 844 times (Today : 2) - Total number of requests : 67748

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.