Créer son propre langage de programmation de A à Z
<< Évolution 6 : Les chaînes de caractères (Partie 1 - Variable et déclaration) | Évolution 7 : Les chaînes de caractères (Partie 2.1 - Concaténation et ré-allocation dynamique de la mémoire)
Cette évolution est bien plus légère que la précédente. On va juste concaténer une variable avec une autre chaîne sous la forme d'affectation avec le lexème "+=". Ce lexème existe déjà (Voir évolution 4 sur les raccourcis syntaxiques), on a donc nul besoin de toucher à l'analyseur lexical.
Évolution 7 du langage :
⚠ (:source lang=bnf linenum:)
<affectation> ::= <affectation>
| variable_texte "+=" <expression_texte> ";"
(:sourcend:)
Vous voyez que c'est vraiment une petite évolution. On ajoute un numéro pour l'arbre abstrait syntaxique dans le fichier d'entête :
⚠ (:source lang=c header="simple.h" linestart=79 linenum:)
#define AFFECTATIONT_CONCAT 55
(:sourcend:)
On met à jour le non terminal affectation dans l'analyseur syntaxique :
⚠ (:source lang=c header="syntaxe_simple.y" linestart=238 linenum:)
affectation: variable_arithmetique 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_arithmetique 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_arithmetique 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_arithmetique 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_arithmetique 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_arithmetique 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_arithmetique 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_arithmetique 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)AFFECTATIONNT);
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)AFFECTATIONT);
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);
}
};
(:sourcend:)
Puis ??? Le générateur de code pardi !
⚠ (:source lang=c header="generation_code.c" linestart=341 linenum:)
case AFFECTATIONT_CONCAT:
fprintf(fichier,"\tif((");
genere_code(g_node_nth_child(ast,0));
fprintf(fichier,"=realloc(");
genere_code(g_node_nth_child(ast,0));
fprintf(fichier,",sizeof(char)*(strlen(");
genere_code(g_node_nth_child(ast,0));
fprintf(fichier,")+strlen(");
genere_code(g_node_nth_child(ast,1));
fprintf(fichier,")+1)))==NULL){\n");
fprintf(fichier,"\tprintf(\"Erreur de reallocation memoire sur la variable ");
genere_code(g_node_nth_child(ast,0));
fprintf(fichier," !\");\n\texit(-1);\n\t}\n\tstrcat(");
genere_code(g_node_nth_child(ast,0));
fprintf(fichier,",");
genere_code(g_node_nth_child(ast,1));
fprintf(fichier,");\n");
break;
(:sourcend:)
Et on a fini. On compile et on teste :
⚠ (:source lang=text header="programme.simple" linenum:)
t_CONVERSATION = "Thomas :
";
<:vspace>
t_THOMAS = "\"Bon je dois me forcer à écrire un truc.";
<:vspace>
t_THOMAS += " Ceci dans le simple but de tester si la concaténation fonctionne.";
<:vspace>
t_THOMAS += "\nAu fait, je vous l'ai dit que j'aime bien l'univers Disney ?\"";
<:vspace>
t_CONVERSATION += t_THOMAS;
<:vspace>
t_CONVERSATION += "\n\nMickey Mouse :
";
<:vspace>
t_MICKEY = "\"Salut Thomas ! On ne t'a pas déjà dit que tout le monde s'en moque un peu ?\"";
<:vspace>
t_CONVERSATION += t_MICKEY;
<:vspace>
t_CONVERSATION += "\n\nThomas :
";
<:vspace>
t_THOMAS = "\"Je rêve ou Mickey est vraiment en train de me parler là ??\"";
<:vspace>
t_CONVERSATION += t_THOMAS;
<:vspace>
t_CONVERSATION += "\n\nMickey Mouse :
";
<:vspace>
t_MICKEY = "\"Oui et je suis même en train d'écouter du Coldplay avec Pluto ou Dingo. (Je sais plus lequel des 2 est mon ami ou mon chien)\"";
<:vspace>
t_CONVERSATION += t_MICKEY;
<:vspace>
t_CONVERSATION += "\n\nThomas :
";
<:vspace>
t_THOMAS = "\"Pluto c'est ton chien ! Faudrait que j'arrête de faire du Bison moi...\"";
<:vspace>
t_CONVERSATION += t_THOMAS;
<:vspace>
t_CONVERSATION += "\n\nMickey Mouse :
";
<:vspace>
t_MICKEY = "\"Ah oui toi aussi tu t'y es mis ! Dur de décrocher à ça, c'est vraiment trop fort ! Chez Disney, tout nos sites (go.com) ont été conçu avec une technologie Java qui a été développé par la Walt Disney Internet Group. Il s'agit de Tea Trove, une alternative à JSP qui répond efficacement à nos attentes. Cela va presque faire 16 ans qu'on le maintient. Puis on est aussi en partie à l'origine de Squeak, un dialecte de Smalltalk utilisé entre autre pour faire des applications interactives et ludiques destinées aux enfants.\"";
<:vspace>
t_CONVERSATION += t_MICKEY;
<:vspace>
t_CONVERSATION += "\n\nThomas :
";
<:vspace>
t_THOMAS = "\"Ok donc comme ça Mickey fait du développement informatique... Bon il est temps que je m'arrête sur ce programme test, ça part pas mal en live là. J'ai suffisamment écrit pour tester si oui ou non la concaténation fonctionne.\"\n";
<:vspace>
t_CONVERSATION += t_THOMAS;
<:vspace>
afficher t_CONVERSATION;
<:vspace>
supprimer t_THOMAS;
supprimer t_MICKEY;
supprimer t_CONVERSATION;
(:sourcend:)
Cela devrait vous sortir ceci :
⚠ (:source lang=text:)
Thomas :
"Bon je dois me forcer à écrire un truc. Ceci dans le simple but de tester si la concaténation fonctionne.
Au fait, je vous l'ai dit que j'aime bien l'univers Disney ?"
<:vspace>
Mickey Mouse :
"Salut Thomas ! On ne t'a pas déjà dit que tout le monde s'en moque un peu ?"
<:vspace>
Thomas:
"Je rêve ou Mickey est vraiment en train de me parler là ??"
<:vspace>
Mickey Mouse :
"Oui et je suis même en train d'écouter du Coldplay avec Pluto ou Dingo. (Je sais plus lequel des 2 est mon ami ou mon chien)"
<:vspace>
Thomas :
"Pluto c'est ton chien ! Faudrait que j'arrête de faire du Bison moi..."
<:vspace>
Mickey Mouse :
"Ah oui toi aussi tu t'y es mis ! Dur de décrocher à ça, c'est vraiment trop fort ! Chez Disney, tout nos sites (go.com) ont été conçu avec une technologie Java qui a été développé par la Walt Disney Internet Group. Il s'agit de Tea Trove, une alternative à JSP qui répond efficacement à nos attentes. Cela va presque faire 16 ans qu'on le maintient. Puis on est aussi en partie à l'origine de Squeak, un dialecte de Smalltalk utilisé entre autre pour faire des applications interactives et ludiques destinées aux enfants."
<:vspace>
Thomas :
"Ok donc comme ça Mickey fait du développement informatique... Bon il est temps que je m'arrête sur ce programme test, ça part pas mal en live là. J'ai suffisamment écrit pour tester si oui ou non la concaténation fonctionne."
(:sourcend:)
La prochaine évolution sera par contre beaucoup moins courte et plus complexe. L'évolution 8 est la suite de cette partie. Nous allons donner au langage la possibilité de concaténer les chaînes et variables de textes entre elles directement avec l'opérateur "+". Cela signifiera de la génération de nœuds d'arbre syntaxique à l'analyse syntaxique ainsi que de la création de variables temporaires. Bref, serrez les dents pour cette évolution !
<< Évolution 6 : Les chaînes de caractères (Partie 1 - Variable et déclaration) | Évolution 7 : Les chaînes de caractères (Partie 2.1 - Concaténation et ré-allocation dynamique de la mémoire)
Thomas - (CC BY-NC-SA 3.0 FR)