Générer une image d'un arbre et de ses nœuds
En programmation, nous manipulons souvent des arbres et des graphes, et il vient toujours un moment où nous souhaitons obtenir un affichage de la structure de l'arbre ou du graphe, que ce soit pour assurer la traçabilité (debugging), ou pour présenter la structure à d'autres personnes.
Nous pouvons utiliser l'outil Graphvizref 1 pour afficher la structure d'un arbre sous forme d'image.
Exemple d'image de structure de l'arbre
Voici le code qui à été analysé par le compilateur LSD010 pour afficher cette image de l'arbre.
void main() { { integer k; boolean b; } k=2; b=3<k; }
Code utilisé pour afficher l'arbre
L'exemple suivant nous montre le code en langage C qui permet d'afficher une image des nœuds de l'arbre syntaxique abstrait généré pour le compilateur LSD010 développé dans le cadre du cours de syntaxe et sémantiqueref 2
Code c (project/source/graphVizHelper.h) (19 lignes)
/* * graphVizHelper.h : Helper for the graphViz tool (generation of images from a tree) * @see http://www.graphviz.org/doc/info/command.html * Part of the compiler project for LSD10 language * Gaudry Stéphane * More information on http://www.gaudry.be/programmer-arbre-image-noeuds.html */ #ifndef GRAPHVIZ_HELPER_H #define GRAPHVIZ_HELPER_H #define GRAPHVIZ_CONFIG_FILE "astLSD10.dot" /** * Generates an image of the AST into the current directory */ void printGraph(); //void printGraph(char *xmlFileName, char *graphFileName); #endif
Code c (project/source/graphVizHelper.c) (235 lignes)
/* * graphVizHelper.c : Helper for the graphViz tool (generation of images from a tree) * @see http://www.graphviz.org/doc/info/command.html * Part of the compiler project for LSD10 language * Gaudry Stéphane * More information on http://www.gaudry.be/programmer-arbre-image-noeuds.html */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include "common.h" #include "graphVizHelper.h" #include "y.tab.h" #if(VERBOSE_LEVEL<=DEB_E) #include <errno.h> #endif extern AstNode *rootNode; /* * ********************************************************** * Internal business * ********************************************************** */ #define GRAPH_RIGHT 0 #define GRAPH_LEFT 1 #define GRAPH_ROOT -1 int isGraphVisInstalled() { return 1;//todo : get it dynamically } /** * http://www.graphviz.org/doc/info/command.html */ void generateImage(char *dotFileName) { time_t now; struct tm *timeinfo; char commandString[100]; //todo : set the timeinfo int values on a 2 digits format commandString, "%slsd10_Img%d%d%d%d%d%d.jpg %s", "dot -Tjpg -o", timeinfo->tm_year+1900, timeinfo->tm_mon+1, timeinfo->tm_mday, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, dotFileName); int ret = 0; //printf ("ret = %d\n", ret); } void printGraphDotHeader(FILE * graphFile) { if(graphFile!=NULL) { } } void printGraphDotFooter(FILE * graphFile) { if(graphFile!=NULL) { time_t now; struct tm *timeinfo; // fprintf(graphFile, "}\n"); // fprintf(graphFile, "digraph INFO{\n"); graphFile, "\t\"Generated by the SSHD09 LSD010 compiler\\n%d/%d/%d %dHr %d\\nWith GraphViz engine\" [", timeinfo->tm_mday, timeinfo->tm_mon+1, timeinfo->tm_year+1900, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec ); } } /** * Prints an AST node into the graph file * Pre-condition : dotFile not null */ void printGraphNode(FILE *dotFile, AstNode *node, int depth, int psn) { if(node!=NULL) { if(node->parent!=NULL) { } else { } dotFile, "\"%p\";\n\t\"%p\" [shape=%s, color=\"%s\", fontcolor=\"%s\", label=\"%s%s%s%s : \\n%s %s\\nLine %d char %d\"];\n",//print position? node, node, //node->type>LEX_FIRST_TOKEN&&node->type<LEX_LAST_TOKEN?"polygon":"box", psn==GRAPH_LEFT?"hexagon":(psn==GRAPH_RIGHT?"box":"doublecircle"), (node->type==NODE_TYPE_DECLARATION || node->type==NODE_TYPE_FUNCTION || node->type==NODE_TYPE_PARAM_DECL )?"#677E96":psn==GRAPH_LEFT?"#e6e8f2":(psn==GRAPH_RIGHT?"#AAB5C6":"#C0C0C0"), (node->type==NODE_TYPE_DECLARATION || node->type==NODE_TYPE_FUNCTION || node->type==NODE_TYPE_PARAM_DECL )?"#FFFFFF":"#000000", typeToString(node->type), node->subtype!=NODE_TYPE_NOTHING?" (":"", node->subtype!=NODE_TYPE_NOTHING?typeToString(node->subtype):"", node->subtype!=NODE_TYPE_NOTHING?")":"", typeToString(node->info->type), node->info->name, node->debug->line, node->debug->linePsn ); printGraphNode(dotFile, node->left, depth+1, GRAPH_LEFT); printGraphNode(dotFile, node->right, depth+1, GRAPH_RIGHT); } //else fprintf(dotFile, "null"); } void printGraphDotFromXML(char *xmlFileName, char *dotFileName) { FILE * graphFile; if(xmlFileName==NULL)xmlFileName=AST_XML_FILE; if(dotFileName==NULL)dotFileName=GRAPHVIZ_CONFIG_FILE; if(graphFile!=NULL) { printf("\n;\tGenerating AST Graph from %s into %s file ... (%s, col %d)", xmlFileName, dotFileName, __FILE__, __LINE__); printGraphDotHeader(graphFile); //todo : read info from XML file to generate the dot file printGraphDotFooter(graphFile); #if(VERBOSE_LEVEL<=DEB_EXEC) printMsg(DEB_EXEC,"...OK Graph printed", __FILE__, __LINE__); #endif if(isGraphVisInstalled()==1) { generateImage(dotFileName); } } else { #if(VERBOSE_LEVEL<=DEB_EXEC) printMsg(DEB_EXEC,"Printing AST into Graph file ... Can't open file", __FILE__, __LINE__); #endif } } void printGraphDotFromAST(char *dotFileName) { FILE * graphFile; if(dotFileName==NULL)dotFileName=GRAPHVIZ_CONFIG_FILE; if(graphFile!=NULL) { printf("\n;\tGenerating AST Graph from last compilation into %s file ... (%s, col %d)", dotFileName, __FILE__, __LINE__); printGraphDotHeader(graphFile); printGraphNode(graphFile, rootNode, 0, GRAPH_ROOT); printGraphDotFooter(graphFile); #if(VERBOSE_LEVEL<=DEB_EXEC) printMsg(DEB_EXEC,"...OK Graph printed", __FILE__, __LINE__); #endif } else { #if(VERBOSE_LEVEL<=DEB_EXEC) printMsg(DEB_EXEC,"Printing AST into Graph file ... Can't open file", __FILE__, __LINE__); #endif } } /* * ********************************************************** * Implementation of the header exposed items * See graphVizHelper.h for these functions comments * ********************************************************** */ void printGraph() { printGraphDotFromAST(GRAPHVIZ_CONFIG_FILE); if(isGraphVisInstalled()==1) { generateImage(GRAPHVIZ_CONFIG_FILE); } }
Je reviendrais plus en détails sur le code quand j'aurais plus de temps, mais voici déjà quelques explications...
Comme nous pouvons le constater dans le fichier d'en-tête, une seule fonction est proposée ici : void printGraph();. Cette fonction génère un fichier DOT défini dans l'en-tête par la constante GRAPHVIZ_CONFIG_FILE, car dans notre cas un seul fichier est utilisé et est écrasé à chaque analyse de code avec le compilateur LSD010.
Ce fichier est seulement destiné à être appelé par l'outil GraphViz pour créer une image des nœuds de l'arbre. Comme nous utiliserons le style "dot" de GraphViz pour notre image, nous pouvons retenir "dot" comme extension de notre fichier temporaire, afin de nous en souvenir.
Nous pouvons aussi générer un fichier de configuration pour GraphViz au départ d'un fichier XML généré par void printXMLTree(FILE *file, pAST_NODE node, int depth) lors de la dernière analyse par le compilateur LSD010. Ce fichier contient les différentes données de notre AST [“Abstract Syntaxic Tree”2].
Exemple fichier de configuration pour GraphViz
Reprennons un instant notre exemple de code qui à été analysé par le compilateur LSD010. Voici le fichier de configuration de GraphViz généré par un appel à void printGraph() pour produire l'image de l'exemple.
Code source (astLSD10.dot) (42 lignes)
digraph LSD10{ bgcolor=white node [color="#9DACBF", fontcolor="#000000", style=filled]; edge [arrowsize=2, color="#000000"]; "0x91789c0"; "0x91789c0" [shape=doublecircle, color="#677E96", fontcolor="#FFFFFF", label="Functions : \nNo Type Functions\nLine 1 char 4"]; "0x91789c0" -> "0x9178960"; "0x9178960" [shape=hexagon, color="#e6e8f2", fontcolor="#000000", label="Function : \nvoid main\nLine 1 char 8"]; "0x9178960" -> "0x9178900"; "0x9178900" [shape=hexagon, color="#e6e8f2", fontcolor="#000000", label="Structural node : \nNo Type {{decl}statement}\nLine 9 char 1"]; "0x9178900" -> "0x9178898"; "0x9178898" [shape=hexagon, color="#e6e8f2", fontcolor="#000000", label="function body : \nNODE_TYPE_TODO Statements node\nLine 9 char 1"]; "0x9178898" -> "0x9178830"; "0x9178830" [shape=hexagon, color="#e6e8f2", fontcolor="#000000", label="function body : \nNODE_TYPE_TODO Statements node\nLine 9 char 1"]; "0x9178830" -> "0x91787c8"; "0x91787c8" [shape=box, color="#AAB5C6", fontcolor="#000000", label="Statement : \nNODE_TYPE_CHECK Statement : 'LExpr = RExpr;'\nLine 8 char 6"]; "0x91787c8" -> "0x9178750"; "0x9178750" [shape=hexagon, color="#e6e8f2", fontcolor="#000000", label="Right expression : \nboolean _2\nLine 8 char 6"]; "0x9178750" -> "0x91786f0"; "0x91786f0" [shape=hexagon, color="#e6e8f2", fontcolor="#000000", label="Right expression : \nNODE_TYPE_TODO _1\nLine 8 char 6"]; "0x91786f0" -> "0x9178690"; "0x9178690" [shape=box, color="#AAB5C6", fontcolor="#000000", label="Id : \nNo Type k\nLine 8 char 6"]; "0x9178750" -> "0x9178620"; "0x9178620" [shape=box, color="#AAB5C6", fontcolor="#000000", label="number : \ninteger CONSTANT, NUMBER\nLine 8 char 3"]; "0x91787c8" -> "0x91785b8"; "0x91785b8" [shape=box, color="#AAB5C6", fontcolor="#000000", label="Id : \nNo Type b\nLine 8 char 2"]; "0x9178898" -> "0x9178548"; "0x9178548" [shape=box, color="#AAB5C6", fontcolor="#000000", label="Statement : \nNODE_TYPE_CHECK Statement : 'LExpr = RExpr;'\nLine 7 char 4"]; "0x9178548" -> "0x91784d0"; "0x91784d0" [shape=hexagon, color="#e6e8f2", fontcolor="#000000", label="number : \ninteger CONSTANT, NUMBER\nLine 7 char 3"]; "0x9178548" -> "0x9178468"; "0x9178468" [shape=box, color="#AAB5C6", fontcolor="#000000", label="Id : \nNo Type k\nLine 7 char 2"]; "0x9178900" -> "0x91783f8"; "0x91783f8" [shape=box, color="#AAB5C6", fontcolor="#000000", label="Type declarations : \nNo Type Declarations node\nLine 6 char 1"]; "0x91783f8" -> "0x9178390"; "0x9178390" [shape=hexagon, color="#e6e8f2", fontcolor="#000000", label="Type declarations : \nNo Type Declarations node\nLine 6 char 1"]; "0x9178390" -> "0x9178348"; "0x9178348" [shape=box, color="#AAB5C6", fontcolor="#000000", label="Type declaration : \nboolean b\nLine 5 char 9"]; "0x91783f8" -> "0x9178298"; "0x9178298" [shape=box, color="#AAB5C6", fontcolor="#000000", label="Type declaration : \ninteger k\nLine 4 char 9"]; "Generated by the SSHD09 LSD010 compiler\n22/4/2010 4Hr 1\nWith GraphViz engine" [shape=box, color="#FF9933", fontcolor="#000000"]; }
Code source du compilateur LSD010
Vous pouvez explorer et consulter la totalité du code source de l'exemple du compilateur LSD010 à cette adresse : https://www.gaudry.be/de/langages-lsd10-source.html
Deutsche Übersetzung
Sie haben gebeten, diese Seite auf Deutsch zu besuchen. Momentan ist nur die Oberfläche übersetzt, aber noch nicht der gesamte Inhalt.Wenn Sie mir bei Übersetzungen helfen wollen, ist Ihr Beitrag willkommen. Alles, was Sie tun müssen, ist, sich auf der Website zu registrieren und mir eine Nachricht zu schicken, in der Sie gebeten werden, Sie der Gruppe der Übersetzer hinzuzufügen, die Ihnen die Möglichkeit gibt, die gewünschten Seiten zu übersetzen. Ein Link am Ende jeder übersetzten Seite zeigt an, dass Sie der Übersetzer sind und einen Link zu Ihrem Profil haben.
Vielen Dank im Voraus.
Dokument erstellt 25/04/2010, zuletzt geändert 16/07/2024
Quelle des gedruckten Dokuments:https://www.gaudry.be/de/programmer-arbre-image-noeuds.html
Die Infobro ist eine persönliche Seite, deren Inhalt in meiner alleinigen Verantwortung liegt. Der Text ist unter der CreativeCommons-Lizenz (BY-NC-SA) verfügbar. Weitere Informationen auf die Nutzungsbedingungen und dem Autor.
- ↑a,b,c,d,e LSD010 : Langage Simple et Didactique Il existe une un certain nombre d'interprétations de l'acronyme LSD (Langage Symbolique Didactique, Langage Sans Difficulté, Langage Simple et Didactique). LSD010 est la version 2010 de la suite LSD80, LSD_02, LSD03, LSD04, LSD05, LSD06, LSD07, LSD08, et LSD09.
Referenzen
- Graph Visualization Software : http://www.graphviz.org/Credits.php,
Graphviz
(version 24/04/10) - IHDCB332 - Théorie des langages : Syntaxe et sémantique : PY Schobbens,
Syntaxe et sémantique
(January 2010)
Diese Verweise und Links verweisen auf Dokumente, die während des Schreibens dieser Seite konsultiert wurden, oder die zusätzliche Informationen liefern können, aber die Autoren dieser Quellen können nicht für den Inhalt dieser Seite verantwortlich gemacht werden.
Der Autor Diese Website ist allein dafür verantwortlich, wie die verschiedenen Konzepte und Freiheiten, die mit den Nachschlagewerken gemacht werden, hier dargestellt werden. Denken Sie daran, dass Sie mehrere Quellinformationen austauschen müssen, um das Risiko von Fehlern zu reduzieren.