Créer son propre langage de programmation de A à Z
<< Évolution 8 : Autres boucles for | Évolution 9 : Les nombres décimaux | Évolution 10 : Les entrées clavier >>
Nous allons mettre en place un tout nouveau type de variable : les nombres décimaux ! Les noms des variables devront commencer par un 'd' minuscule. Le lexème decimal sera de la forme nombre.nombre.
Évolution 9 du langage :
⚠ (:source lang=bnf linenum:)
<affectation> ::= <affectation> | variable_decimale "=" <expression_arithmetique> ";"
<:vspace>
<expression_arithmetique> ::= <expression_arithmetique> | variable_decimale | decimal
(:sourcend:)
Nous allons mettre à jour l'analyseur lexical pour intégrer les deux nouveaux lexèmes (variable_decimale et decimal) :
⚠ (:source lang=c header="lexique_simple.lex" linenum:)
%{
<:vspace>
#include "simple.h"
unsigned int lineno=1;
bool error_lexical=false;
<:vspace>
/* definition de la fonction de concatenation pour les chaines de texte */
void* concat(char*,char*);
<:vspace>
%}
<:vspace>
%option noyywrap
<:vspace>
entier 0|[1-9][[:digit:]]*
decimal {entier}\.{entier}
variable_booleenne b(_|[[:alnum:]])*
variable_entiere e(_|[[:alnum:]])*
variable_decimale d(_|[[:alnum:]])*
variable_texte t(_|[[:alnum:]])*
<:vspace>
/* regex de commentaire d'une seule ligne */
commentaire ((\/\/|#).*)
<:vspace>
/* pour les commentaires de plusieurs lignes, on declare nos deux lexemes en tant que conditions de demarrage exclusives (%x) dans Flex */
%x commentaire_1
%x commentaire_2
<:vspace>
/* chaine de caractere */
%x chaine
<:vspace>
%%
<:vspace>
"/*" {
/* un marqueur de debut de commentaire trouve -> on lui dit que le lexeme commentaire_1 commence */
BEGIN(commentaire_1);
printf("Commentaire detecte en ligne %i\n",lineno);
}
<:vspace>
<commentaire_1>"\n" {
/* si on trouve des retours chariots et que la condition de demarrage est commentaire_1, alors on incremente la variable lineno. sans cela, on serait en decalage pour la suite de l'analyse */
lineno++;
}
<:vspace>
<commentaire_1>"*"+"/" {
/* si on au moins une fois "*" suivi de "/" et que la condition de demarrage est commentaire_1, alors on lui dit que le lexeme commentaire_1 est fini */
BEGIN(INITIAL);
printf("Fin du commentaire en ligne %i\n",lineno);
return TOK_COMMENT;
}
<:vspace>
<commentaire_1>. {/* les autres caracteres suivants la conditions de demarrage sont absorbes par l'analyse est donc ingores */}
<:vspace>
"<!--" {
BEGIN(commentaire_2);
printf("Commentaire detecte en ligne %i\n",lineno);
}
<commentaire_2>"\n" {lineno++;}
<commentaire_2>"-"+"-"+">" {
BEGIN(INITIAL);
printf("Fin du commentaire en ligne %i\n",lineno);
return TOK_COMMENT;
}
<commentaire_2>. {}
<:vspace>
"\"" {
/* debut de la chaine de texte (premier guillemet) */
BEGIN(chaine);
yylval.texte=malloc(sizeof(char)*strlen(yytext));
if(yylval.texte==NULL){
fprintf(stderr,"\tERREUR : Probleme de memoire sur une chaine texte a la ligne %i !\n",lineno);
exit(-1);
}
yylval.texte=strdup(yytext);
printf("Chaine de texte detectee en ligne %i\n",lineno);
}
<:vspace>
<chaine>"\n" {
/* on prend en compte les sauts de ligne que l'on traduira par "\n" */
lineno++;
yylval.texte=(char*)concat(yylval.texte,"\\n");
if(yylval.texte==NULL){
fprintf(stderr,"\tERREUR : Probleme de memoire sur une chaine texte a la ligne %i !\n",lineno);
exit(-1);
}
}
<:vspace>
<chaine>"\t" {
/* on prend en compte les tabulations que l'on traduira par "\t" */
yylval.texte=(char*)concat(yylval.texte,"\\t");
if(yylval.texte==NULL){
fprintf(stderr,"\tERREUR : Probleme de memoire sur une chaine texte a la ligne %i !\n",lineno);
exit(-1);
}
}
<:vspace>
<chaine>"\\\"" {
/* pour echapper le guillemet dans la chaine \" */
yylval.texte=(char*)concat(yylval.texte,yytext);
if(yylval.texte==NULL){
fprintf(stderr,"\tERREUR : Probleme de memoire sur une chaine texte a la ligne %i !\n",lineno);
exit(-1);
}
}
<:vspace>
<chaine>"\"" {
/* fin de la chaine (deuxieme guillemet non echappe) */
BEGIN(INITIAL);
yylval.texte=(char*)concat(yylval.texte,yytext);
if(yylval.texte==NULL){
fprintf(stderr,"\tERREUR : Probleme de memoire sur une chaine texte a la ligne %i !\n",lineno);
exit(-1);
}
printf("Fin de la chaine en ligne %i\n",lineno);
return TOK_TEXTE;
}
<:vspace>
<chaine>. {
/* les caracteres de la chaine */
yylval.texte=(char*)concat(yylval.texte,yytext);
if(yylval.texte==NULL){
fprintf(stderr,"\tERREUR : Probleme de memoire sur une chaine texte a la ligne %i !\n",lineno);
exit(-1);
}
}
<:vspace>
{decimal} {
sscanf(yytext, "%lf", &yylval.decimal);
return TOK_DECIMAL;
}
<:vspace>
{entier} {
sscanf(yytext, "%ld", &yylval.entier);
return TOK_ENTIER;
}
<:vspace>
"si" {return TOK_SI;}
<:vspace>
"alors" {return TOK_ALORS;}
<:vspace>
"sinon" {return TOK_SINON;}
<:vspace>
"++" {return TOK_INCREMENTATION;}
<:vspace>
"--" {return TOK_DECREMENTATION;}
<:vspace>
"+=" {return TOK_AFFECT_PLUS;}
<:vspace>
"-=" {return TOK_AFFECT_MOINS;}
<:vspace>
"*=" {return TOK_AFFECT_MUL;}
<:vspace>
"/=" {return TOK_AFFECT_DIV;}
<:vspace>
"%=" {return TOK_AFFECT_MOD;}
<:vspace>
"&=" {return TOK_AFFECT_ET;}
<:vspace>
"|=" {return TOK_AFFECT_OU;}
<:vspace>
"egal a"|"equivalent a"|"==" {return TOK_EQU;}
<:vspace>
"different de"|"!="|"<>" {return TOK_DIFF;}
<:vspace>
"superieur a"|"plus grand que"|">" {return TOK_SUP;}
<:vspace>
"inferieur a"|"plus petit que"|"<" {return TOK_INF;}
<:vspace>
"superieur ou egal a"|">=" {return TOK_SUPEQU;}
<:vspace>
"inferieur ou egal a"|"<=" {return TOK_INFEQU;}
<:vspace>
"compris dans"|"dans" {return TOK_IN;}
<:vspace>
"afficher" {return TOK_AFFICHER;}
<:vspace>
"supprimer" {return TOK_SUPPR;}
<:vspace>
"faire" {return TOK_FAIRE;}
<:vspace>
"x" {return TOK_CROIX;}
<:vspace>
"=" {return TOK_AFFECT;}
<:vspace>
"+" {return TOK_PLUS;}
<:vspace>
"-" {return TOK_MOINS;}
<:vspace>
"*" {return TOK_MUL;}
<:vspace>
"/" {return TOK_DIV;}
<:vspace>
"%" {return TOK_MOD;}
<:vspace>
"^" {return TOK_PUISSANCE;}
<:vspace>
"(" {return TOK_PARG;}
<:vspace>
")" {return TOK_PARD;}
<:vspace>
"[" {return TOK_CROG;}
<:vspace>
"]" {return TOK_CROD;}
<:vspace>
"?" {return TOK_POINT_INTERROGATION;}
<:vspace>
":" {return TOK_DOUBLE_POINT;}
<:vspace>
"et" {return TOK_ET;}
<:vspace>
"ou" {return TOK_OU;}
<:vspace>
"non"|"!" {return TOK_NON;}
<:vspace>
";" {return TOK_FINSTR;}
<:vspace>
"vrai" {return TOK_VRAI;}
<:vspace>
"faux" {return TOK_FAUX;}
<:vspace>
"\n" {lineno++;}
<:vspace>
{variable_booleenne} {
yylval.texte = yytext;
return TOK_VARB;
}
<:vspace>
<:vspace>
{variable_entiere} {
yylval.texte = yytext;
return TOK_VARE;
}
<:vspace>
{variable_decimale} {
yylval.texte = yytext;
return TOK_VARD;
}
<:vspace>
{variable_texte} {
yylval.texte = yytext;
return TOK_VART;
}
<:vspace>
{commentaire} {
printf("Commentaire detecte en ligne %i\n",lineno);
printf("Fin du commentaire en ligne %i\n",lineno);
return TOK_COMMENT;
}
<:vspace>
" "|"\t" {}
<:vspace>
. {
fprintf(stderr,"\tERREUR : Lexeme inconnu a la ligne %d. Il s'agit de %s et comporte %d lettre(s)\n",lineno,yytext,yyleng);
error_lexical=true;
return yytext[0];
}
<:vspace>
%%
<:vspace>
/* fonction de concatenation - realloue la memoire a la variable texte dimensionne a la taille memoire du tableau de char ajout puis concatene */
<:vspace>
void* concat(char* texte, char* ajout){
void* p=NULL;
/* realloue la memoire -> taille de texte + taille de ajout + 1 (caractere de fin \0) */
if((p=realloc(texte,sizeof(char)*(strlen(texte)+strlen(ajout)+1)))){
texte=p;
return strcat(texte,ajout);
}else{
/* appel de la macro FREE pour liberer correctement la memoire */
FREE(texte);
return NULL;
}
}
(:sourcend:)
On met à jour le fichier d'entête. L'affichage d'un double en C est différent que celui d'un long. Il faut donc prendre en compte cette différence. De même dans l'affectation.
⚠ (:source lang=c header="simple.h" linestart=80 linenum:)
#define DECIMAL 56
#define AFFECTATIOND 57
#define AFFICHAGED 58
(:sourcend:)
Maintenant on passe à l'analyseur syntaxique. Il faudra être très vigilant au niveau de l'analyse sémantique. En effet un nombre décimal est une expression arithmétique et un nombre entier est aussi une expression arithmétique. Donc si on demande d'afficher une expression arithmétique, il faut que le langage sache si l'expression contient un nombre décimal et donc par conséquent fait l'affichage d'un double classique en C ou ne contient pas de décimaux et affiche donc un entier. Nous allons créer une fonction qui prend en argument un noeud d'arbre (l'expression arithmetique) et renvoie true ou false selon la nature de l'expression.
⚠ (:source lang=c header="syntaxe_bison.y" linenum:)
%{
<:vspace>
#include "simple.h"
bool error_syntaxical=false;
bool error_semantical=false;
/* Notre table de hachage */
GHashTable* table_variable;
<:vspace>
/* Fonction de suppression des variables declarees a l'interieur d'un arbre syntaxique */
void supprime_variable(GNode*);
<:vspace>
/* Fonction permettant de dire si un noeud d'arbre contient un decimal ou non */
bool decimal(GNode*);
<:vspace>
/* Notre structure Variable qui a comme membre le type et un pointeur generique vers la valeur */
typedef struct Variable Variable;
<:vspace>
struct Variable{
char* type;
GNode* value;
};
<:vspace>
%}
<:vspace>
/* 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*) */
<:vspace>
%union {
long entier;
double decimal;
char* texte;
GNode* noeud;
}
<:vspace>
/* 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 */
<:vspace>
%left TOK_INCREMENTATION TOK_DECREMENTATION /* ++ -- */
%left TOK_PLUS TOK_MOINS /* +- */
%left TOK_MUL TOK_DIV TOK_MOD /* /*% */
%left TOK_PUISSANCE /* ^ */
%left TOK_ET TOK_OU TOK_NON /* et ou non */
%left TOK_EQU TOK_DIFF TOK_SUP TOK_INF TOK_SUPEQU TOK_INFEQU /* comparaisons */
%right TOK_PARG TOK_PARD /* () */
<:vspace>
/* Nous avons la liste de nos expressions (les non terminaux). Nous les typons tous en noeud de l'arbre syntaxique (GNode*) */
<:vspace>
%type<noeud> code
%type<noeud> bloc_code
%type<noeud> commentaire
%type<noeud> instruction
%type<noeud> condition
%type<noeud> condition_si
%type<noeud> condition_sinon
%type<noeud> boucle_for
%type<noeud> boucle_while
%type<noeud> boucle_do_while
%type<noeud> variable_entiere
%type<noeud> variable_decimale
%type<noeud> variable_booleenne
%type<noeud> variable_texte
%type<noeud> affectation
%type<noeud> affichage
%type<noeud> suppression
%type<noeud> expression_arithmetique
%type<noeud> expression_booleenne
%type<noeud> expression_texte
%type<noeud> addition
%type<noeud> soustraction
%type<noeud> multiplication
%type<noeud> division
%type<noeud> modulo
<:vspace>
/* Nous avons la liste de nos tokens (les terminaux de notre grammaire) */
<:vspace>
%token<entier> TOK_ENTIER
%token<decimal> TOK_DECIMAL
%token TOK_VRAI /* true */
%token TOK_FAUX /* false */
%token TOK_AFFECT /* = */
%token TOK_FINSTR /* ; */
%token TOK_IN /* dans */
%token TOK_CROG TOK_CROD /* [] */
%token TOK_AFFICHER /* afficher */
%token<texte> TOK_VARB /* variable booleenne */
%token<texte> TOK_VARE /* variable entiere */
%token<texte> TOK_VARD /* variable decimale */
%token<texte> TOK_VART
%token TOK_SI /* si */
%token TOK_ALORS /* alors */
%token TOK_SINON /* sinon */
%token TOK_COMMENT /* commentaire */
%token TOK_AFFECT_PLUS TOK_AFFECT_MOINS TOK_AFFECT_MUL TOK_AFFECT_DIV TOK_AFFECT_MOD /* += -= *= /= %= */
%token TOK_AFFECT_ET TOK_AFFECT_OU /* &= |= */
%token TOK_POINT_INTERROGATION /* ? */
%token TOK_DOUBLE_POINT /* : */
%token TOK_FAIRE /* faire */
%token TOK_CROIX /* x */
%token<texte> TOK_TEXTE /* texte libre */
%token TOK_SUPPR /* supprimer */
<:vspace>
%%
<:vspace>
/* 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 */
<:vspace>
entree: code{
genere_code($1);
g_node_destroy($1);
};
<:vspace>
bloc_code: code{
$$=g_node_new((gpointer)BLOC_CODE);
g_node_append($$,$1);
supprime_variable($1);
}
<:vspace>
code: %empty{$$=g_node_new((gpointer)CODE_VIDE);}
|
code commentaire{
$$=g_node_new((gpointer)SEQUENCE);
g_node_append($$,$1);
g_node_append($$,$2);
}
|
code instruction{
printf("Resultat : C'est une instruction valide !\n\n");
$$=g_node_new((gpointer)SEQUENCE);
g_node_append($$,$1);
g_node_append($$,$2);
}
|
code error{
fprintf(stderr,"\tERREUR : Erreur de syntaxe a la ligne %d.\n",lineno);
error_syntaxical=true;
};
<:vspace>
commentaire: TOK_COMMENT{
$$=g_node_new((gpointer)CODE_VIDE);
};
<:vspace>
instruction: affectation{
printf("\tInstruction type Affectation\n");
$$=$1;
}
|
affichage{
printf("\tInstruction type Affichage\n");
$$=$1;
}
|
condition{
printf("Condition si/sinon\n");
$$=$1;
}
|
boucle_for{
printf("Boucle repetee\n");
$$=$1;
}
|
boucle_while{
printf("Boucle tant que\n");
$$=$1;
}
|
boucle_do_while{
printf("Boucle faire tant que\n");
$$=$1;
}
|
suppression{
printf("\tInstruction type Suppression\n");
$$=$1;
};
<:vspace>
variable_entiere: TOK_VARE{
printf("\t\t\tVariable entiere %s\n",$1);
$$=g_node_new((gpointer)VARIABLE);
g_node_append_data($$,strdup($1));
};
<:vspace>
variable_decimale: TOK_VARD{
printf("\t\t\tVariable decimale %s\n",$1);
$$=g_node_new((gpointer)VARIABLE);
g_node_append_data($$,strdup($1));
};
<:vspace>
variable_booleenne: TOK_VARB{
printf("\t\t\tVariable booleenne %s\n",$1);
$$=g_node_new((gpointer)VARIABLE);
g_node_append_data($$,strdup($1));
};
<:vspace>
variable_texte: TOK_VART{
printf("\t\t\tVariable texte %s\n",$1);
$$=g_node_new((gpointer)VARIABLE);
g_node_append_data($$,strdup($1));
};
<:vspace>
condition: condition_si TOK_FINSTR{
printf("\tCondition si\n");
$$=g_node_new((gpointer)CONDITION_SI);
g_node_append($$,$1);
}
|
condition_si condition_sinon TOK_FINSTR{
printf("\tCondition si/sinon\n");
$$=g_node_new((gpointer)CONDITION_SI_SINON);
g_node_append($$,$1);
g_node_append($$,$2);
}
|
TOK_PARG expression_booleenne TOK_PARD TOK_POINT_INTERROGATION bloc_code TOK_DOUBLE_POINT bloc_code TOK_FINSTR{
printf("\tCondition si/sinon\n");
$$=g_node_new((gpointer)CONDITION_SI_SINON);
g_node_append($$,g_node_new((gpointer)SI));
g_node_append(g_node_nth_child($$,0),$2);
g_node_append(g_node_nth_child($$,0),$5);
g_node_append($$,g_node_new((gpointer)SINON));
g_node_append(g_node_nth_child($$,1),$7);
<:vspace>
};
<:vspace>
condition_si: TOK_SI expression_booleenne TOK_ALORS bloc_code{
$$=g_node_new((gpointer)SI);
g_node_append($$,$2);
g_node_append($$,$4);
};
<:vspace>
condition_sinon: TOK_SINON bloc_code{
$$=g_node_new((gpointer)SINON);
g_node_append($$,$2);
};
<:vspace>
boucle_for: TOK_PARG expression_arithmetique TOK_PARD TOK_CROIX bloc_code TOK_FINSTR{
$$=g_node_new((gpointer)BOUCLE_FOR);
g_node_append($$,g_node_new((gpointer)ENTIER));
g_node_append_data(g_node_nth_child($$,0),strdup("0"));
g_node_append($$,g_node_new((gpointer)ENTIER));
g_node_append_data(g_node_nth_child($$,1),strdup("1"));
g_node_append($$,$2);
g_node_append($$,$5);
}
|
TOK_PARG expression_arithmetique TOK_DOUBLE_POINT expression_arithmetique TOK_PARD bloc_code TOK_FINSTR{
$$=g_node_new((gpointer)BOUCLE_FOR);
g_node_append($$,$2);
g_node_append($$,g_node_new((gpointer)ENTIER));
g_node_append_data(g_node_nth_child($$,1),strdup("1"));
g_node_append($$,$4);
g_node_append($$,$6);
}
|
TOK_PARG expression_arithmetique TOK_DOUBLE_POINT expression_arithmetique TOK_DOUBLE_POINT expression_arithmetique TOK_PARD bloc_code TOK_FINSTR{
$$=g_node_new((gpointer)BOUCLE_FOR);
g_node_append($$,$2);
g_node_append($$,$4);
g_node_append($$,$6);
g_node_append($$,$8);
};
<:vspace>
boucle_while: TOK_PARG expression_booleenne TOK_PARD TOK_POINT_INTERROGATION bloc_code TOK_FINSTR{
$$=g_node_new((gpointer)BOUCLE_WHILE);
g_node_append($$,$2);
g_node_append($$,$5);
};
<:vspace>
boucle_do_while: TOK_FAIRE bloc_code TOK_POINT_INTERROGATION TOK_PARG expression_booleenne TOK_PARD TOK_FINSTR{
$$=g_node_new((gpointer)BOUCLE_DO_WHILE);
g_node_append($$,$2);
g_node_append($$,$5);
};
<:vspace>
affectation: variable_entiere TOK_AFFECT expression_arithmetique TOK_FINSTR{
/* $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. */
printf("\t\tAffectation sur la variable\n");
Variable* var=g_hash_table_lookup(table_variable,(char*)g_node_nth_child($1,0)->data);
if(var==NULL){
/* On cree une Variable et on lui affecte le type que nous connaissons et la valeur */
var=malloc(sizeof(Variable));
if(var!=NULL){
var->type=strdup("entier");
var->value=$3;
/* On l'insere dans la table de hachage (cle: <nom_variable> / valeur: <(type,valeur)>) */
if(g_hash_table_insert(table_variable,g_node_nth_child($1,0)->data,var)){
$$=g_node_new((gpointer)AFFECTATIONE);
g_node_append($$,$1);
g_node_append($$,$3);
}else{
fprintf(stderr,"ERREUR - PROBLEME CREATION VARIABLE !\n");
exit(-1);
}
}else{
fprintf(stderr,"ERREUR - PROBLEME ALLOCATION MEMOIRE VARIABLE !\n");
exit(-1);
}
}else{
$$=g_node_new((gpointer)AFFECTATION);
g_node_append($$,$1);
g_node_append($$,$3);
}
}
|
variable_entiere TOK_AFFECT_PLUS expression_arithmetique TOK_FINSTR{
Variable* var=g_hash_table_lookup(table_variable,(char*)g_node_nth_child($1,0)->data);
if(var==NULL){
fprintf(stderr,"\tERREUR : Erreur de semantique a la ligne %d. Variable %s jamais declaree !\n",lineno,(char*)g_node_nth_child($1,0)->data);
error_semantical=true;
}else{
$$=g_node_new((gpointer)AFFECTATION_PLUS);
g_node_append($$,$1);
g_node_append($$,$3);
}
}
|
variable_entiere TOK_AFFECT_MOINS expression_arithmetique TOK_FINSTR{
Variable* var=g_hash_table_lookup(table_variable,(char*)g_node_nth_child($1,0)->data);
if(var==NULL){
fprintf(stderr,"\tERREUR : Erreur de semantique a la ligne %d. Variable %s jamais declaree !\n",lineno,(char*)g_node_nth_child($1,0)->data);
error_semantical=true;
}else{
$$=g_node_new((gpointer)AFFECTATION_MOINS);
g_node_append($$,$1);
g_node_append($$,$3);
}
}
|
variable_entiere TOK_AFFECT_MUL expression_arithmetique TOK_FINSTR{
Variable* var=g_hash_table_lookup(table_variable,(char*)g_node_nth_child($1,0)->data);
if(var==NULL){
fprintf(stderr,"\tERREUR : Erreur de semantique a la ligne %d. Variable %s jamais declaree !\n",lineno,(char*)g_node_nth_child($1,0)->data);
error_semantical=true;
}else{
$$=g_node_new((gpointer)AFFECTATION_MUL);
g_node_append($$,$1);
g_node_append($$,$3);
}
}
|
variable_entiere TOK_AFFECT_DIV expression_arithmetique TOK_FINSTR{
Variable* var=g_hash_table_lookup(table_variable,(char*)g_node_nth_child($1,0)->data);
if(var==NULL){
fprintf(stderr,"\tERREUR : Erreur de semantique a la ligne %d. Variable %s jamais declaree !\n",lineno,(char*)g_node_nth_child($1,0)->data);
error_semantical=true;
}else{
$$=g_node_new((gpointer)AFFECTATION_DIV);
g_node_append($$,$1);
g_node_append($$,$3);
}
}
|
variable_entiere TOK_AFFECT_MOD expression_arithmetique TOK_FINSTR{
Variable* var=g_hash_table_lookup(table_variable,(char*)g_node_nth_child($1,0)->data);
if(var==NULL){
fprintf(stderr,"\tERREUR : Erreur de semantique a la ligne %d. Variable %s jamais declaree !\n",lineno,(char*)g_node_nth_child($1,0)->data);
error_semantical=true;
}else{
$$=g_node_new((gpointer)AFFECTATION_MOD);
g_node_append($$,$1);
g_node_append($$,$3);
}
}
|
variable_entiere TOK_INCREMENTATION TOK_FINSTR{
printf("\t\t\tIncrementation de +1 sur la variable\n");
$$=g_node_new((gpointer)AFFECTATION_INCR);
g_node_append($$,$1);
}
|
variable_entiere TOK_DECREMENTATION TOK_FINSTR{
printf("\t\t\tDecrementation de -1 sur la variable\n");
$$=g_node_new((gpointer)AFFECTATION_DECR);
g_node_append($$,$1);
}
|
variable_decimale TOK_AFFECT expression_arithmetique TOK_FINSTR{
/* $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. */
printf("\t\tAffectation sur la variable\n");
Variable* var=g_hash_table_lookup(table_variable,(char*)g_node_nth_child($1,0)->data);
if(var==NULL){
/* On cree une Variable et on lui affecte le type que nous connaissons et la valeur */
var=malloc(sizeof(Variable));
if(var!=NULL){
var->type=strdup("decimal");
var->value=$3;
/* On l'insere dans la table de hachage (cle: <nom_variable> / valeur: <(type,valeur)>) */
if(g_hash_table_insert(table_variable,g_node_nth_child($1,0)->data,var)){
$$=g_node_new((gpointer)AFFECTATIOND);
g_node_append($$,$1);
g_node_append($$,$3);
}else{
fprintf(stderr,"ERREUR - PROBLEME CREATION VARIABLE !\n");
exit(-1);
}
}else{
fprintf(stderr,"ERREUR - PROBLEME ALLOCATION MEMOIRE VARIABLE !\n");
exit(-1);
}
}else{
$$=g_node_new((gpointer)AFFECTATION);
g_node_append($$,$1);
g_node_append($$,$3);
}
}
|
variable_decimale TOK_AFFECT_PLUS expression_arithmetique TOK_FINSTR{
Variable* var=g_hash_table_lookup(table_variable,(char*)g_node_nth_child($1,0)->data);
if(var==NULL){
fprintf(stderr,"\tERREUR : Erreur de semantique a la ligne %d. Variable %s jamais declaree !\n",lineno,(char*)g_node_nth_child($1,0)->data);
error_semantical=true;
}else{
$$=g_node_new((gpointer)AFFECTATION_PLUS);
g_node_append($$,$1);
g_node_append($$,$3);
}
}
|
variable_decimale TOK_AFFECT_MOINS expression_arithmetique TOK_FINSTR{
Variable* var=g_hash_table_lookup(table_variable,(char*)g_node_nth_child($1,0)->data);
if(var==NULL){
fprintf(stderr,"\tERREUR : Erreur de semantique a la ligne %d. Variable %s jamais declaree !\n",lineno,(char*)g_node_nth_child($1,0)->data);
error_semantical=true;
}else{
$$=g_node_new((gpointer)AFFECTATION_MOINS);
g_node_append($$,$1);
g_node_append($$,$3);
}
}
|
variable_decimale TOK_AFFECT_MUL expression_arithmetique TOK_FINSTR{
Variable* var=g_hash_table_lookup(table_variable,(char*)g_node_nth_child($1,0)->data);
if(var==NULL){
fprintf(stderr,"\tERREUR : Erreur de semantique a la ligne %d. Variable %s jamais declaree !\n",lineno,(char*)g_node_nth_child($1,0)->data);
error_semantical=true;
}else{
$$=g_node_new((gpointer)AFFECTATION_MUL);
g_node_append($$,$1);
g_node_append($$,$3);
}
}
|
variable_decimale TOK_AFFECT_DIV expression_arithmetique TOK_FINSTR{
Variable* var=g_hash_table_lookup(table_variable,(char*)g_node_nth_child($1,0)->data);
if(var==NULL){
fprintf(stderr,"\tERREUR : Erreur de semantique a la ligne %d. Variable %s jamais declaree !\n",lineno,(char*)g_node_nth_child($1,0)->data);
error_semantical=true;
}else{
$$=g_node_new((gpointer)AFFECTATION_DIV);
g_node_append($$,$1);
g_node_append($$,$3);
}
}
|
variable_decimale TOK_AFFECT_MOD expression_arithmetique TOK_FINSTR{
Variable* var=g_hash_table_lookup(table_variable,(char*)g_node_nth_child($1,0)->data);
if(var==NULL){
fprintf(stderr,"\tERREUR : Erreur de semantique a la ligne %d. Variable %s jamais declaree !\n",lineno,(char*)g_node_nth_child($1,0)->data);
error_semantical=true;
}else{
$$=g_node_new((gpointer)AFFECTATION_MOD);
g_node_append($$,$1);
g_node_append($$,$3);
}
}
|
variable_decimale TOK_INCREMENTATION TOK_FINSTR{
printf("\t\t\tIncrementation de +1 sur la variable\n");
$$=g_node_new((gpointer)AFFECTATION_INCR);
g_node_append($$,$1);
}
|
variable_decimale TOK_DECREMENTATION TOK_FINSTR{
printf("\t\t\tDecrementation de -1 sur la variable\n");
$$=g_node_new((gpointer)AFFECTATION_DECR);
g_node_append($$,$1);
}
|
variable_booleenne TOK_AFFECT expression_booleenne TOK_FINSTR{
/* $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. */
printf("\t\tAffectation sur la variable\n");
Variable* var=g_hash_table_lookup(table_variable,(char*)g_node_nth_child($1,0)->data);
if(var==NULL){
/* On cree une Variable et on lui affecte le type que nous connaissons et la valeur */
var=malloc(sizeof(Variable));
if(var!=NULL){
var->type=strdup("booleen");
var->value=$3;
/* On l'insere dans la table de hachage (cle: <nom_variable> / valeur: <(type,valeur)>) */
if(g_hash_table_insert(table_variable,g_node_nth_child($1,0)->data,var)){
$$=g_node_new((gpointer)AFFECTATIONB);
g_node_append($$,$1);
g_node_append($$,$3);
}else{
fprintf(stderr,"ERREUR - PROBLEME CREATION VARIABLE !\n");
exit(-1);
}
}else{
fprintf(stderr,"ERREUR - PROBLEME ALLOCATION MEMOIRE VARIABLE !\n");
exit(-1);
}
}else{
$$=g_node_new((gpointer)AFFECTATION);
g_node_append($$,$1);
g_node_append($$,$3);
}
}
|
variable_booleenne TOK_AFFECT_ET expression_booleenne TOK_FINSTR{
Variable* var=g_hash_table_lookup(table_variable,(char*)g_node_nth_child($1,0)->data);
if(var==NULL){
fprintf(stderr,"\tERREUR : Erreur de semantique a la ligne %d. Variable %s jamais declaree !\n",lineno,(char*)g_node_nth_child($1,0)->data);
error_semantical=true;
}else{
$$=g_node_new((gpointer)AFFECTATION_ET);
g_node_append($$,$1);
g_node_append($$,$3);
}
}
|
variable_booleenne TOK_AFFECT_OU expression_booleenne TOK_FINSTR{
Variable* var=g_hash_table_lookup(table_variable,(char*)g_node_nth_child($1,0)->data);
if(var==NULL){
fprintf(stderr,"\tERREUR : Erreur de semantique a la ligne %d. Variable %s jamais declaree !\n",lineno,(char*)g_node_nth_child($1,0)->data);
error_semantical=true;
}else{
$$=g_node_new((gpointer)AFFECTATION_OU);
g_node_append($$,$1);
g_node_append($$,$3);
}
}
|
variable_texte TOK_AFFECT expression_texte TOK_FINSTR{
/* $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. */
printf("\t\tAffectation sur la variable\n");
Variable* var=g_hash_table_lookup(table_variable,(char*)g_node_nth_child($1,0)->data);
if(var==NULL){
/* On cree une Variable et on lui affecte le type que nous connaissons et la valeur */
var=malloc(sizeof(Variable));
if(var!=NULL){
var->type=strdup("texte");
var->value=$3;
/* On l'insere dans la table de hachage (cle: <nom_variable> / valeur: <(type,valeur)>) */
if(g_hash_table_insert(table_variable,g_node_nth_child($1,0)->data,var)){
$$=g_node_new((gpointer)AFFECTATIONT);
g_node_append($$,$1);
g_node_append($$,$3);
}else{
fprintf(stderr,"ERREUR - PROBLEME CREATION VARIABLE !\n");
exit(-1);
}
}else{
fprintf(stderr,"ERREUR - PROBLEME ALLOCATION MEMOIRE VARIABLE !\n");
exit(-1);
}
}else{
$$=g_node_new((gpointer)AFFECTATION);
g_node_append($$,$1);
g_node_append($$,$3);
}
}
|
variable_texte TOK_AFFECT_PLUS expression_texte TOK_FINSTR{
Variable* var=g_hash_table_lookup(table_variable,(char*)g_node_nth_child($1,0)->data);
if(var==NULL){
fprintf(stderr,"\tERREUR : Erreur de semantique a la ligne %d. Variable %s jamais declaree !\n",lineno,(char*)g_node_nth_child($1,0)->data);
error_semantical=true;
}else{
$$=g_node_new((gpointer)AFFECTATIONT_CONCAT);
g_node_append($$,$1);
g_node_append($$,$3);
}
};
<:vspace>
affichage: TOK_AFFICHER expression_arithmetique TOK_FINSTR{
printf("\t\tAffichage de la valeur de l'expression arithmetique\n");
if(decimal($2)){
$$=g_node_new((gpointer)AFFICHAGED);
g_node_append($$,$2);
}else{
$$=g_node_new((gpointer)AFFICHAGEE);
g_node_append($$,$2);
}
}
|
TOK_AFFICHER expression_booleenne TOK_FINSTR{
printf("\t\tAffichage de la valeur de l'expression booleenne\n");
$$=g_node_new((gpointer)AFFICHAGEB);
g_node_append($$,$2);
}
|
TOK_AFFICHER expression_texte TOK_FINSTR{
printf("\t\tAffichage de la valeur de l'expression textuelle\n");
$$=g_node_new((gpointer)AFFICHAGET);
g_node_append($$,$2);
};
<:vspace>
suppression: TOK_SUPPR variable_texte TOK_FINSTR{
/* On recupere un pointeur vers la structure Variable */
Variable* var=g_hash_table_lookup(table_variable,(char*)g_node_nth_child($2,0)->data);
/* Si on a trouve un pointeur valable */
if(var!=NULL){
/* On verifie que le type est bien un entier - Inutile car impose a l'analyse syntaxique */
if(strcmp(var->type,"texte")==0){
printf("\t\t\tSuppression de la variable texte\n");
$$=g_node_new((gpointer)SUPPRESSIONT);
g_node_append($$,$2);
/* suppression de la variable dans la table de hachage */
printf("suppresion variable %s\n",(char*)g_node_nth_child($2,0)->data);
if(g_hash_table_remove(table_variable,(char*)g_node_nth_child($2,0)->data)){
printf("Variable supprimee !\n");
}else{
fprintf(stderr,"ERREUR - PROBLEME DE SUPPRESSION VARIABLE !\n");
exit(-1);
}
}else{
fprintf(stderr,"\tERREUR : Erreur de semantique a la ligne %d. Type incompatible !\n",lineno);
error_semantical=true;
}
/* Sinon on conclue que la variable n'a jamais ete declaree car absente de la table */
}else{
fprintf(stderr,"\tERREUR : Erreur de semantique a la ligne %d. Variable %s jamais declaree !\n",lineno,(char*)g_node_nth_child($2,0)->data);
error_semantical=true;
}
}
<:vspace>
expression_arithmetique: TOK_ENTIER{
printf("\t\t\tNombre entier : %ld\n",$1);
/* 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. */
int length=snprintf(NULL,0,"%ld",$1);
char* str=malloc(length+1);
snprintf(str,length+1,"%ld",$1);
$$=g_node_new((gpointer)ENTIER);
g_node_append_data($$,strdup(str));
free(str);
}
|
TOK_DECIMAL{
printf("\t\t\tNombre decimal : %f\n",$1);
/* 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. */
int length=snprintf(NULL,0,"%f",$1);
char* str=malloc(length+1);
snprintf(str,length+1,"%f",$1);
$$=g_node_new((gpointer)DECIMAL);
g_node_append_data($$,strdup(str));
free(str);
}
|
variable_entiere{
/* On recupere un pointeur vers la structure Variable */
Variable* var=g_hash_table_lookup(table_variable,(char*)g_node_nth_child($1,0)->data);
/* Si on a trouve un pointeur valable */
if(var!=NULL){
/* On verifie que le type est bien un entier ou un decimal - Inutile car impose a l'analyse syntaxique */
if(strcmp(var->type,"entier")==0){
$$=$1;
}else{
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);
error_semantical=true;
}
/* Sinon on conclue que la variable n'a jamais ete declaree car absente de la table */
}else{
fprintf(stderr,"\tERREUR : Erreur de semantique a la ligne %d. Variable %s jamais declaree !\n",lineno,(char*)g_node_nth_child($1,0)->data);
error_semantical=true;
}
}
|
variable_decimale{
/* On recupere un pointeur vers la structure Variable */
Variable* var=g_hash_table_lookup(table_variable,(char*)g_node_nth_child($1,0)->data);
/* Si on a trouve un pointeur valable */
if(var!=NULL){
/* On verifie que le type est bien un entier ou un decimal - Inutile car impose a l'analyse syntaxique */
if(strcmp(var->type,"decimal")==0){
$$=$1;
}else{
fprintf(stderr,"\tERREUR : Erreur de semantique a la ligne %d. Type incompatible (decimal attendu - valeur : %s) !\n",lineno,(char*)g_node_nth_child($1,0)->data);
error_semantical=true;
}
/* Sinon on conclue que la variable n'a jamais ete declaree car absente de la table */
}else{
fprintf(stderr,"\tERREUR : Erreur de semantique a la ligne %d. Variable %s jamais declaree !\n",lineno,(char*)g_node_nth_child($1,0)->data);
error_semantical=true;
}
}
|
addition{
$$=$1;
}
|
soustraction{
$$=$1;
}
|
multiplication{
$$=$1;
}
|
division{
$$=$1;
}
|
modulo{
$$=$1;
}
|
TOK_PLUS expression_arithmetique{
$$=$2;
}
|
expression_arithmetique TOK_INCREMENTATION{
printf("\t\t\tIncrementation de +1\n");
$$=g_node_new((gpointer)INCREMENTATION);
g_node_append($$,$1);
}
|
expression_arithmetique TOK_DECREMENTATION{
printf("\t\t\tDecrementation de -1\n");
$$=g_node_new((gpointer)DECREMENTATION);
g_node_append($$,$1);
}
|
TOK_MOINS expression_arithmetique{
printf("\t\t\tOperation unaire negation\n");
$$=g_node_new((gpointer)NEGATIF);
g_node_append($$,$2);
}
|
TOK_PARG expression_arithmetique TOK_PARD{
printf("\t\t\tC'est une expression arithmetique entre parentheses\n");
$$=g_node_new((gpointer)EXPR_PAR);
g_node_append($$,$2);
};
<:vspace>
expression_booleenne: TOK_VRAI{
printf("\t\t\tBooleen Vrai\n");
$$=g_node_new((gpointer)VRAI);
}
|
TOK_FAUX{
printf("\t\t\tBooleen Faux\n");
$$=g_node_new((gpointer)FAUX);
}
|
variable_booleenne{
/* On recupere un pointeur vers la structure Variable */
Variable* var=g_hash_table_lookup(table_variable,(char*)g_node_nth_child($1,0)->data);
/* Si on a trouve un pointeur valable */
if(var!=NULL){
/* On verifie que le type est bien un entier - Inutile car impose a l'analyse syntaxique */
if(strcmp(var->type,"booleen")==0){
$$=$1;
}else{
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);
error_semantical=true;
}
/* Sinon on conclue que la variable n'a jamais ete declaree car absente de la table */
}else{
fprintf(stderr,"\tERREUR : Erreur de semantique a la ligne %d. Variable %s jamais declaree !\n",lineno,(char*)g_node_nth_child($1,0)->data);
error_semantical=true;
}
}
|
TOK_NON expression_booleenne{
printf("\t\t\tOperation booleenne Non\n");
$$=g_node_new((gpointer)NON);
g_node_append($$,$2);
}
|
expression_booleenne TOK_ET expression_booleenne{
printf("\t\t\tOperation booleenne Et\n");
$$=g_node_new((gpointer)ET);
g_node_append($$,$1);
g_node_append($$,$3);
}
|
expression_booleenne TOK_OU expression_booleenne{
printf("\t\t\tOperation booleenne Ou\n");
$$=g_node_new((gpointer)OU);
g_node_append($$,$1);
g_node_append($$,$3);
}
|
TOK_PARG expression_booleenne TOK_PARD{
printf("\t\t\tC'est une expression booleenne entre parentheses\n");
$$=g_node_new((gpointer)EXPR_PAR);
g_node_append($$,$2);
}
|
expression_booleenne TOK_EQU expression_booleenne{
printf("\t\t\tOperateur d'egalite ==\n");
$$=g_node_new((gpointer)EGALITE);
g_node_append($$,$1);
g_node_append($$,$3);
}
|
expression_booleenne TOK_DIFF expression_booleenne{
printf("\t\t\tOperateur d'inegalite !=\n");
$$=g_node_new((gpointer)DIFFERENT);
g_node_append($$,$1);
g_node_append($$,$3);
}
|
expression_arithmetique TOK_EQU expression_arithmetique{
printf("\t\t\tOperateur d'egalite ==\n");
$$=g_node_new((gpointer)EGALITE);
g_node_append($$,$1);
g_node_append($$,$3);
}
|
expression_arithmetique TOK_DIFF expression_arithmetique{
printf("\t\t\tOperateur d'inegalite !=\n");
$$=g_node_new((gpointer)DIFFERENT);
g_node_append($$,$1);
g_node_append($$,$3);
}
|
expression_arithmetique TOK_SUP expression_arithmetique{
printf("\t\t\tOperateur de superiorite >\n");
$$=g_node_new((gpointer)SUPERIEUR);
g_node_append($$,$1);
g_node_append($$,$3);
}
|
expression_arithmetique TOK_INF expression_arithmetique{
printf("\t\t\tOperateur d'inferiorite <\n");
$$=g_node_new((gpointer)INFERIEUR);
g_node_append($$,$1);
g_node_append($$,$3);
}
|
expression_arithmetique TOK_SUPEQU expression_arithmetique{
printf("\t\t\tOperateur >=\n");
$$=g_node_new((gpointer)SUPEGAL);
g_node_append($$,$1);
g_node_append($$,$3);
}
|
expression_arithmetique TOK_INFEQU expression_arithmetique{
printf("\t\t\tOperateur <=\n");
$$=g_node_new((gpointer)INFEGAL);
g_node_append($$,$1);
g_node_append($$,$3);
}
|
expression_arithmetique TOK_IN TOK_CROG expression_arithmetique TOK_FINSTR expression_arithmetique TOK_CROD{
printf("\t\t\tOperateur dans\n");
$$=g_node_new((gpointer)DANSII);
g_node_append($$,$1);
g_node_append($$,$4);
g_node_append($$,$6);
}
|
expression_arithmetique TOK_IN TOK_CROD expression_arithmetique TOK_FINSTR expression_arithmetique TOK_CROD{
printf("\t\t\tOperateur dans\n");
$$=g_node_new((gpointer)DANSEI);
g_node_append($$,$1);
g_node_append($$,$4);
g_node_append($$,$6);
}
|
expression_arithmetique TOK_IN TOK_CROG expression_arithmetique TOK_FINSTR expression_arithmetique TOK_CROG{
printf("\t\t\tOperateur dans\n");
$$=g_node_new((gpointer)DANSIE);
g_node_append($$,$1);
g_node_append($$,$4);
g_node_append($$,$6);
}
|
expression_arithmetique TOK_IN TOK_CROD expression_arithmetique TOK_FINSTR expression_arithmetique TOK_CROG{
printf("\t\t\tOperateur dans\n");
$$=g_node_new((gpointer)DANSEE);
g_node_append($$,$1);
g_node_append($$,$4);
g_node_append($$,$6);
};
<:vspace>
expression_texte: TOK_TEXTE{
printf("\t\t\tTexte %s\n",$1);
$$=g_node_new((gpointer)TEXTE);
g_node_append_data($$,strdup($1));
}
|
variable_texte{
/* On recupere un pointeur vers la structure Variable */
Variable* var=g_hash_table_lookup(table_variable,(char*)g_node_nth_child($1,0)->data);
/* Si on a trouve un pointeur valable */
if(var!=NULL){
/* On verifie que le type est bien un entier - Inutile car impose a l'analyse syntaxique */
if(strcmp(var->type,"texte")==0){
$$=$1;
}else{
fprintf(stderr,"\tERREUR : Erreur de semantique a la ligne %d. Type incompatible (texte attendu - valeur : %s) !\n",lineno,(char*)g_node_nth_child($1,0)->data);
error_semantical=true;
}
/* Sinon on conclue que la variable n'a jamais ete declaree car absente de la table */
}else{
fprintf(stderr,"\tERREUR : Erreur de semantique a la ligne %d. Variable %s jamais declaree !\n",lineno,(char*)g_node_nth_child($1,0)->data);
error_semantical=true;
}
};
<:vspace>
addition: expression_arithmetique TOK_PLUS expression_arithmetique{
printf("\t\t\tAddition\n");
$$=g_node_new((gpointer)ADDITION);
g_node_append($$,$1);
g_node_append($$,$3);
};
<:vspace>
soustraction: expression_arithmetique TOK_MOINS expression_arithmetique{
printf("\t\t\tSoustraction\n");
$$=g_node_new((gpointer)SOUSTRACTION);
g_node_append($$,$1);
g_node_append($$,$3);
};
<:vspace>
multiplication: expression_arithmetique TOK_MUL expression_arithmetique{
printf("\t\t\tMultiplication\n");
$$=g_node_new((gpointer)MULTIPLICATION);
g_node_append($$,$1);
g_node_append($$,$3);
};
<:vspace>
division: expression_arithmetique TOK_DIV expression_arithmetique{
printf("\t\t\tDivision\n");
$$=g_node_new((gpointer)DIVISION);
g_node_append($$,$1);
g_node_append($$,$3);
};
<:vspace>
modulo: expression_arithmetique TOK_MOD expression_arithmetique{
printf("\t\t\tModulo\n");
$$=g_node_new((gpointer)MODULO);
g_node_append($$,$1);
g_node_append($$,$3);
};
<:vspace>
%%
<:vspace>
/* Dans la fonction main on appelle bien la routine yyparse() qui sera genere par Bison. Cette routine appellera yylex() de notre analyseur lexical. */
<:vspace>
int main(int argc, char** argv){
/* recuperation du nom de fichier d'entree (langage Simple) donne en parametre */
char* fichier_entree=strdup(argv[1]);
/* ouverture du fichier en lecture dans le flux d'entree stdin */
stdin=fopen(fichier_entree,"r");
/* creation fichier de sortie (langage C) */
char* fichier_sortie=strdup(argv[1]);
/* remplace l'extension par .c */
strcpy(rindex(fichier_sortie, '.'), ".c");
/* ouvre le fichier cree en ecriture */
fichier=fopen(fichier_sortie, "w");
/* Creation de la table de hachage */
table_variable=g_hash_table_new_full(g_str_hash,g_str_equal,NULL,free);
printf("Debut de l'analyse syntaxique :\n");
debut_code();
yyparse();
fin_code();
printf("Fin de l'analyse !\n");
printf("Resultat :\n");
if(error_lexical){
printf("\t-- Echec : Certains lexemes ne font pas partie du lexique du langage ! --\n");
printf("\t-- Echec a l'analyse lexicale --\n");
}
else{
printf("\t-- Succes a l'analyse lexicale ! --\n");
}
if(error_syntaxical){
printf("\t-- Echec : Certaines phrases sont syntaxiquement incorrectes ! --\n");
printf("\t-- Echec a l'analyse syntaxique --\n");
}
else{
printf("\t-- Succes a l'analyse syntaxique ! --\n");
if(error_semantical){
printf("\t-- Echec : Certaines phrases sont semantiquement incorrectes ! --\n");
printf("\t-- Echec a l'analyse semantique --\n");
}
else{
printf("\t-- Succes a l'analyse semantique ! --\n");
}
}
/* Suppression du fichier genere si erreurs analyse */
if(error_lexical||error_syntaxical||error_semantical){
remove(fichier_sortie);
printf("ECHEC GENERATION CODE !\n");
}
else{
printf("Le fichier \"%s\" a ete genere !\n",fichier_sortie);
}
/* Fermeture des flux */
fclose(fichier);
fclose(stdin);
/* Liberation memoire */
free(fichier_entree);
free(fichier_sortie);
g_hash_table_destroy(table_variable);
return EXIT_SUCCESS;
}
<:vspace>
void yyerror(char *s) {
fprintf(stderr, "Erreur de syntaxe a la ligne %d: %s\n", lineno, s);
}
<:vspace>
/* Cette fonction supprime dans la table de hachage toutes les variables declarees pour la premiere fois dans l'arbre syntaxique donne en parametre */
<:vspace>
void supprime_variable(GNode* ast){
/* si l'element n'est pas NULL et que ce n'est pas une feuille et que ce n'est pas un type bloc code (pour eviter de supprimer une variable deja suprimee) */
if(ast&&!G_NODE_IS_LEAF(ast)&&(long)ast->data!=BLOC_CODE){
/* si le noeud est de type declaration */
if((long)ast->data==AFFECTATIONB||(long)ast->data==AFFECTATIONE||(long)ast->data==AFFECTATIONT||(long)ast->data==AFFECTATIOND){
/* suppression de la variable dans la table de hachage */
if(g_hash_table_remove(table_variable,(char*)g_node_nth_child(g_node_nth_child(ast,0),0)->data)){
printf("Variable supprimee !\n");
}else{
fprintf(stderr,"ERREUR - PROBLEME DE SUPPRESSION VARIABLE !\n");
exit(-1);
}
/* sinon on continue de parcourir l'arbre */
}else{
int nb_enfant;
for(nb_enfant=0;nb_enfant<=g_node_n_children(ast);nb_enfant++){
supprime_variable(g_node_nth_child(ast,nb_enfant));
}
}
}
}
<:vspace>
/* Cette fonction dit si un arbre contient un decimal */
<:vspace>
bool decimal(GNode* ast){
/* si l'element n'est pas NULL et que ce n'est pas une feuille et que ce n'est pas un type bloc code (pour eviter de supprimer une variable deja suprimee) */
bool nbdecimal=false;
if(ast&&!G_NODE_IS_LEAF(ast)){
/* si le noeud est de type decimal */
if((long)ast->data==DECIMAL){
nbdecimal=true;
/* si le noeud est une variable */
}else if((long)ast->data==VARIABLE){
/* On recupere un pointeur vers la structure Variable */
Variable* var=g_hash_table_lookup(table_variable,(char*)g_node_nth_child(ast,0)->data);
/* Si on a trouve un pointeur valable */
if(var!=NULL){
/* On regarde si le type de la variable est un decimal */
if(strcmp(var->type,"decimal")==0)
nbdecimal=true;
}
/* sinon on continue de parcourir l'arbre */
}else{
int nb_enfant;
for(nb_enfant=0;nb_enfant<=g_node_n_children(ast);nb_enfant++){
nbdecimal|=decimal(g_node_nth_child(ast,nb_enfant));
}
}
}
return nbdecimal;
}
(:sourcend:)
Bon maintenant vous savez qu'il faut ajouter les nouvelles options dans le générateur de code :
⚠ (:source lang=c header="generation_code.c" linestart=363 linenum:)
case DECIMAL:
fprintf(fichier,"%s",(char*)g_node_nth_child(ast,0)->data);
break;
case AFFECTATIOND:
fprintf(fichier,"\tdouble ");
genere_code(g_node_nth_child(ast,0));
fprintf(fichier,"=");
genere_code(g_node_nth_child(ast,1));
fprintf(fichier,";\n");
break;
case AFFICHAGED:
fprintf(fichier,"\tprintf(\"%%f\",");
genere_code(g_node_nth_child(ast,0));
fprintf(fichier,");\n");
break;
(:sourcend:)
Et maintenant on teste :
⚠ (:source lang=text header="programme.simple" linenum:)
/* PI = 3.1415 */
<:vspace>
d_PI = 3.141592;
<:vspace>
afficher d_PI;
afficher "\n";
<:vspace>
e_PI = d_PI; //Caste automatique
<:vspace>
afficher e_PI;
afficher "\n";
<:vspace>
afficher e_PI*d_PI; //Affiche un decimal (3*3.141592)
afficher "\n";
<:vspace>
afficher d_PI*d_PI; //Affiche un decimal (3.141592 au carre)
afficher "\n";
<:vspace>
<!--
<:vspace>
AFFICHAGE DE LA TABLE DE MULTIPLICATION DE 1 A 10
<:vspace>
-->
<:vspace>
afficher "---------------------------------TABLE DE MULTIPLICATION---------------------------------\n";
afficher "|X\t1\t2\t3\t4\t5\t6\t7\t8\t9\t10\t|\n";
e_i=0;
(10)x
e_j=0;
e_i++;
afficher "|";
afficher e_i;
(10)x
e_j++;
afficher "\t";
afficher e_i*e_j;
;
e_j++;
afficher "\t|\n";
;
afficher "-----------------------------------------------------------------------------------------\n";
<:vspace>
<!--
<:vspace>
AFFICHAGE DE LA TABLE DE DIVISION DE 1 A 10
<:vspace>
-->
<:vspace>
afficher "TABLE DE DIVISION\n";
d_i=0;
(10)x
d_j=0;
d_i++;
(10)x
d_j++;
afficher d_i/d_j;
afficher "\t";
;
d_j++;
afficher "\n";
;
(:sourcend:)
Et cela vous affiche après exécution :
⚠ (:source lang=text:)
3.141592
3
9.424776
9.869600
---------------------------------TABLE DE MULTIPLICATION---------------------------------
|X 1 2 3 4 5 6 7 8 9 10 |
|1 1 2 3 4 5 6 7 8 9 10 |
|2 2 4 6 8 10 12 14 16 18 20 |
|3 3 6 9 12 15 18 21 24 27 30 |
|4 4 8 12 16 20 24 28 32 36 40 |
|5 5 10 15 20 25 30 35 40 45 50 |
|6 6 12 18 24 30 36 42 48 54 60 |
|7 7 14 21 28 35 42 49 56 63 70 |
|8 8 16 24 32 40 48 56 64 72 80 |
|9 9 18 27 36 45 54 63 72 81 90 |
|10 10 20 30 40 50 60 70 80 90 100 |
-----------------------------------------------------------------------------------------
TABLE DE DIVISION
1.000000 0.500000 0.333333 0.250000 0.200000 0.166667 0.142857 0.125000 0.111111 0.100000
2.000000 1.000000 0.666667 0.500000 0.400000 0.333333 0.285714 0.250000 0.222222 0.200000
3.000000 1.500000 1.000000 0.750000 0.600000 0.500000 0.428571 0.375000 0.333333 0.300000
4.000000 2.000000 1.333333 1.000000 0.800000 0.666667 0.571429 0.500000 0.444444 0.400000
5.000000 2.500000 1.666667 1.250000 1.000000 0.833333 0.714286 0.625000 0.555556 0.500000
6.000000 3.000000 2.000000 1.500000 1.200000 1.000000 0.857143 0.750000 0.666667 0.600000
7.000000 3.500000 2.333333 1.750000 1.400000 1.166667 1.000000 0.875000 0.777778 0.700000
8.000000 4.000000 2.666667 2.000000 1.600000 1.333333 1.142857 1.000000 0.888889 0.800000
9.000000 4.500000 3.000000 2.250000 1.800000 1.500000 1.285714 1.125000 1.000000 0.900000
10.000000 5.000000 3.333333 2.500000 2.000000 1.666667 1.428571 1.250000 1.111111 1.000000
(:sourcend:)
Voilà pour cette évolution. La prochaine évolution concernera les entrées (saisies utilisateurs).
<< Évolution 8 : Autres boucles for | Évolution 9 : Les nombres décimaux | Évolution 10 : Les entrées clavier >>
Thomas Tributsch - (CC BY-NC-SA 3.0 FR)