rapport

RAPPORT DE PROJET DE COMPILATION Graphe d’appel d’un code Pseudo-pascal or 8 Sni* to View Table des matières 1 Sujet et choix du langage . 1. 1 Introduction au sujet.. 1 Choix du langage 3 Front end . 3. 1 Définition des types . … 3 cela, il faut dans un premier temps,écrire un analyseur lexical et syntaxique (Front-end), en s’aidant de d’ocamlleWocamlyacc. Cet analyseur devra reconnaître un programme Pseudo-Pascal et retourner l’arbre de syntaxe abstraite associé et rafficher sur la sortie standard.

La deuxième partie (Middle-end) consiste à transformer l’arbre e syntaxe Obtenu précédemment en un graphe d’appel. La troisième et dernière partie (Back-end), Porte sur la création du dessin du graphe d’appel. Pour ceci,il faudra générer un fichier dot qui pourra ensuite être converti en image. 1. 2 Choix du langage : Nous avons fait le choix d’utiliser le langage Caml pour ce projet car il nous semblait plus pratique d’utilisation dans ce cadre précis. Nous avons donc utilisé Lex et Yacc pour nous aider lors la transformation du code Pascal en un graphe d’appel.

Les fichiers d’entrée de camllex et camlyacc ont les extensions . mll et . mly sur e fonctionnement de ces traits avancés. 2 Front-End L’objectif du Front-end est simple à comprendre : À partir du code Pascal, nous devons générer l’arbre de syntaxe abstraite correspondant. pour ce faire, nous devons créer des types Ocaml, couvrant toute la grammaire du langage Pseudo-Pascal, pour que notre programme puisse le reconnaitre. 3. 1 Définitions des types Dans un fichier type. li, nous avons défini les différents types Ocaml qui pourraient ensuite nous servir pour la construction de l’arbre de syntaxe abstrait type_expr nous permettant de différencier les types d’expressions Int, booléan ou tableau Un type var_list qui définie le type d’un identifiant, ceci est composé d’un caractère alphabétique suivi d’un nombre quelconque de caractères alphanumériques. un type program qui donne la structure d’un programme Pseudo-pascal, il contient trois éléments : -> La déclaration des variables. La déclaration des fonctions et procédures. -> les instructions.

Un type expression qui permet d’avoir la syntaxe d’une expression ou condition. – Un type binop qui représente Les opérateurs unalres et binaires, qui apparaissent dans la syntaxe des expressions. lls s’appliquent des expressions de type integer_ Tous produisent un résultat de type Int, sauf les opérateurs binaires de comparaison, qui produisent un résultat de type booléen. – Un type instruction qui permet de donner la syntaxe des instruction ou des fonctions données par le programme, ceci peut être par exemple,un appel de procédure, une affectation dans une variable,ou une affectation dans un tableau …

On peut trouver également des les procédures et fonctions prédéfinies comme par exemple la fonction Write_int, Read_int.. 3. 2 Analyseur lexical Le format Pascal étant composé d’objets, ensembles nan- rdonnés d’éléments, il a fallu récupérer les données qui s’y trouvaient et ensuite les reconvertir en un format manipulable en Caml. c’est ici qu’entrent en compte futilisation de lex,yacc, donnant des fonctions permettant le parsing du Pascal. exer : L’analyse lexicale se trouve tout au début de la chaîne de compilation, elle collabore compilation, elle collabore avec l’analyse grammaticale pour passer de la syntaxe concrète à la syntaxe abstraite. La mission de l’analyse lexicale est de transformer une suite de caractères en une suite de mots, dit aussi lexèmes (tokens). Ocamlex permet de créer un analyseur lexical ( permet de reconnaitre des mots et émet des tokens à chaque fois qu’un mot est reconnu. Sa structure est la suivante : (* Fichier lexer. mll *) Code Ocaml : typiquement des inclusions de fichiers.

Dans ce cas particulier, nous aurons besoin des définitions des tokens qui se trouveront dans le parser. On inclue donc le parser : open Parser rule token parse (* Cette ligne marque le début de la reconnaissance des mots : dans ce qui suit, nous allons associer un token à chaque mot reconnu. *) I regexl { } (k Le mot désigné par l’expression regulière regex est associé au token I regex2 { NOM } Utilisation de l’Ocamllex pour écrire l’analyseur lexical : L’outil ocamllex est lui même un compilateur, qui prend comme source les expressions régulières (dans un fichier nom. ll) et produit un programme Ocaml (dans un fichier nom. ml), programme qui réallse l’automate. on donc commence par écrire le code source dans un fichier lexer. mll,la commande #ocamllex lexer. mll produit un nouveau fichier lexer. ml. qui est donc le code du lexer 3. 1 Analyseur syntaxique PAGF des instructions en Ocaml à partir d’une suite de takens. En effet, Le lexer crée dans la partie précédente fournit eaucoup de tokens,on pourra donc définir des suites de tokens particulieres capables de reconnaître certaines instructions ( appel de fonctions .. ,le parser associera donc chaque suite de tokens une partie de l’arbre de syntaxe qu’on veut obtenir. Chaque token peut etre considéré comme un élément terminal d’une règle. Utilisation d’ocamlyacc pour écrire l’analyseur syntaxique: Le parser contient deux parties , la première est consacré à la définition des tokens, la seconde est asscié la définitions de la grammaire du langage. Dans un fichier parser. mly (* Code Ocaml : comme pour le lexer, c’est souvent des nclusions de fichiers. Ici, nous avons besoin des types définis plus haut.

On inclue donc le fichier des types : *) open Types %token NOM DU TOKEN Cette ligne définit le token du lecer %t0ken UN AUTRE TOKEN %token Ce token a un type (qui peut être n’importe quel type). C’est parce qu’il contient une valeur %start main l* Ceci défini le point d’entrée de la grammaire. */ %type main Ici on définit le type de retour du parser. En l’occurence, le parser doit retourner l’arbre de syntaxe qui est du type program . É/ /k Ci-dessous, les définitions des ordres de priorité et de l’associativité.

L’ordre de priorité détermine uelle o ération est prioritaire sur une autre. ou ‘right’. Certains takens peuvent être non associatifs (‘nonassoc’). %nonassoc SEMI_COLON l* point virgule : non associatif */ %left PLUS MINUS + et – : associatifs à gauche, de même priorité mais plus élevée que pour ; %left TIMES DIV /* x et / : associatifs à gauche, de même priorité mais plus élevée que pour et- %% l* Sépare la définition des tokens de celle de la grammaire. ma. n: program EOF {$1 } Ces deux lignes forment une règle de la grammaire..

On va reconnaitre un programme Pascal suivi d’une fin de fichier (token EOF). / TOKENI TOKEN2 autre regle TOKEN3 {$3 une règle basique. Associe un type (expression entre accolades) à une liste de tokens. $3 référence le troisième mot (autre_regle). autre_regle: TOKEN4 TOKEN5 TOKEN6 autre_regle { $4 } /* Cette règle a deux cas. Le symbole signifie « OU ». On peut reconnaitre la première suite de tokens, ou la deuxième. */ I TOKEN7 TOKEN8 { unwpe($l) } ce cas n’a que des éléments terminaux (que des tokens).

C’est généralement ici que l’an associe le type. $1 référence le premier token, il possède donc une valeur qui sera placée dans « UnType ». *l une fois le fichier parser. ly est finit,on tape la commande ocamlyacc parser. mly pour générer le fichier du code du parser  » parser. ml ». middle-end, nous devons convertir l’arbre de syntaxe abstraite en un graphe d’appel. Le graphe d’appel représente les appels des fonctions les unes aux autres. Les nœuds du graphe d’appel sont les fonctlons du programme, et les arêtes sont les appels entre fonctions. ?criture d’un Middle End: Le but de cette partie est de convertir l’arbre de syntaxe abstraite Obtenue précédemment et qui est représenté par l’imbrication de type Ocaml (Program(Var_declarations(… ), en un graphe d’appel eprésenté par un ensemble de couple dont le premier élèment est le nom de la fonction et le deuxième représente l’ensemble des noms de ses fonction filles. Pour réaliser ce travail, il a fallut qu’on utilise les structures de données ‘Set’ ( ensemble d’objets) et ‘Pmap’ ( un ensemble de clefs aux quelles on associe un objet).

Il faut donc convertir l’imbrication des types, en map de couples (string, set de strings), les strings correspondant aux noms des fonctions. les fonctions des maps et sets sont ensuite utilisables en faisant et MonModuleMap. nom_de_la_fonction. Afin d’extraire les appels de fonction du programme, ous devons déconstruire nos types petit petit à l’aide de ‘ match.. with’. On crée ensuite la fonction make_call_graph qui va créer le graphe d’appel à partlr de l’arbre abstralte qul lui est donnée en entrée,On passera par deux fnctons auxiliaires qui analyse uniquement une instruction, et make call_graph_expr qui analyse une expression. . Back-end Le back-end sert à générer un fichier dot, qui pourra ensuite être converti en une image. Nous avons un ensemble de couples (nom d’une fonction, ensemble des noms des fonctions filles). Tout ce que nous avons à faire, c’est d’écrire dans le fichier dot chaque elation. Conversion en fichier. dot . Le fichier . dot est de la forme : digraph unNom noeud_parent noeud_fils; noeud; Quand le fichier dot est généré, il ne reste plus qu’à taper la commande suivante : dot -Tpng -o nom_image. png , pour générer l’image correspondante au graphe d’appel.

Difficultés rencontrées La principale difficulté a surtout été de comprendre comment fonctionnaient lex et yacc, afin de pouvoir les utiliser pour parser le code pascal et le rendre ensuite sous une forme plus propre pour l’utilisateur. une fois cela surmonté, il a ensuite fallu faire un choix en terme e fonction d’affichage, ce qui a posé quelques problèmes car il fallait penser à rappeler certaines autres fonctions pour ensuite l’afficher, et la boucle à réaliser n’a pas été évidente à trouver. Conclusion Ce projet nous a permis d’approfondir nos connaissances en Caml, et de découvrir également le JSON, un langage qui permet de gérer les objects et les arrays de façon efficace, et qui peut se reconvertir, comme on l’a vu, en d’autres langages. Il s’agit donc d’un langage pratique pour l’échange de données d’un langage ? un autre, et qui est très facile à écrire et comprendre.