COMPILATEUR DECA Documentation de conception
Transcription
COMPILATEUR DECA Documentation de conception
PROJET GENIE LOGICIEL COMPILATEUR DECA Documentation de conception GROUPE 8 - EQUIPE GL42 BION Jorey DOUDECHE Amine POLISANO Kévin THIARD Florence 27 janvier 2012 Table des matières 1 Étape A : Analyse syntaxique 1.1 Description . . . . . . . . . . . . . . . . . . . 1.2 Architecture . . . . . . . . . . . . . . . . . . . 1.3 Choix de conception . . . . . . . . . . . . . . 1.3.1 Choix d'accrochage du numéro de ligne . . . . . . . . . . . . . . . . 2 Étape B : Vérications contextuelles et Décoration 2.1 Description . . . . . . . . . . . . . . . . . . . . . . . 2.2 Architecture . . . . . . . . . . . . . . . . . . . . . . . 2.3 Choix de conception . . . . . . . . . . . . . . . . . . 2.3.1 Rôle des procédures Verif_NonTerminal . . . 2.3.2 Utilisation systématique du case . . . . . . . 2.3.3 Traitement itératif des règles récursives . . . . 2.3.4 Messages d'erreur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Étape C : Génération de code 3.1 Description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2 Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.3 Choix de conception . . . . . . . . . . . . . . . . . . . . . . . . . 3.3.1 Considérations générales sur les paramètres des procédures 3.3.2 Convention d'utilisation des registres . . . . . . . . . . . . 3.3.3 Gestion du contexte grâce au paramètre Ctx . . . . . . . . 3.3.4 Structure de données pour la table des méthodes . . . . . 3.3.5 Rôle de la procédure Optimise . . . . . . . . . . . . . . . 3.3.6 Gestion des tests et réservation de mémoire dans la pile . . 3.3.7 Sauvegarde des registres dans le code des méthodes . . . . 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 2 2 4 4 . . . . . . . 6 6 6 7 7 8 8 8 . . . . . . . . . . 9 9 9 10 10 11 11 11 12 13 13 Introduction Le compilateur Deca que nous proposons est composé de 3 grandes parties distinctes, correspondant aux 3 étapes de la compilation. L'étape A, ou Analyse Syntaxique, a pour rôle de lire le chier source et de construire un arbre qui représente le programme. L'étape B, ou Analyse Contextuelle, décore cet arbre en ajoutant des informations de contexte (typage, super-classe, numéro de champ ou de méthode. . .). Enn, l'étape C utilise cet arbre décoré pour générer le code assembleur correspondant. Au cours des étapes A et B, on eectue également les vérications correspondant à leur niveau d'analyse, et lèvent les erreurs correspondantes. Chacune des 3 parties est composée de diérents modules que nous allons présenter. 1 Étape A : Analyse syntaxique Cette section concerne les chiers se trouvant dans le répertoire Syntaxe/. 1.1 Description Dans cette première partie de l'analyse, nous créons une représentation intermédiaire du programme d'entrée sous forme d'arbre abstrait non décoré, en suivant la grammaire abstraite de la spécication. Pour cela, nous avons utilisé les utilitaires Aex et Ayacc qui génèrent les analyseurs respectivement lexical et syntaxique en Ada, composés de plusieurs paquetages dont nous ne détaillerons pas le fonctionnement. Cette génération est eectuée à partir de 2 chiers : • lexical.l : contient les expressions régulières permettant de reconnaître les diérents lexèmes du langage, et une suite d'instructions permettant de stocker des informations (numéro de ligne, valeur éventuelle) pour chaque mot reconnu. • syntaxe.y : contient l'ensemble des règles de la grammaire syntaxique du langage Deca, des informations sur l'associativité et la priorité des opérateurs, ainsi qu'une suite d'instructions permettant de construire le sous-arbre associé à chaque règle. 1.2 Architecture L'architecture adoptée pour cette partie est la suivante : 2 Syntaxe Packages générés par Ayacc Lexical Dictionnaire Packages générés par Aflex Attributs Arbres Erreurs_Lexicales Fig. 1 Architecture de la partie Syntaxe Description du rôle des paquetages qui apparaissent ci-dessus : • Lexical : c'est l'analyseur lexical généré par Aex à partir de lexical.l. Il lit le chier source, reconnaît les lexèmes, et construit les feuilles de l'arbre correspondantes grâce au type abstrait Attribut décrit plus loin, en accrochant le numéro de ligne du mot reconnu (voir 1.3.1). • Syntaxe : c'est l'analyseur syntaxique généré par Ayacc à partir de syntaxe.y. Il lit les lexèmes fournis par Lexical et construit l'arbre à l'aide des règles de la grammaire syntaxique, en utilisant aussi le type abstrait Attribut. • Les carrés colorés contiennent les autres paquetages générés par les utilitaires. Ces paque- tages servent à la gestion plus bas niveau de la lecture du chier (buers, etc.). Etant le résultat de la génération automatique, ils n'entrent pas dans le cadre de cette documentation. • Erreurs_Lexicales : contient les procédures d'achage de messages d'erreurs pour les erreurs lexicales. • Dictionnaire : paquetage générique utilisé ici par Lexical pour répertorier les lexèmes. • Attributs : contient les primitives permettant de gérer les éléments de type abstrait Attribut qu'utilise Ayacc. Un attribut correspond en fait à un noeud de l'arbre agrémenté. Dans le cas des feuilles, une valeur éventuelle (entier, ottant, nom, ou chaîne) est ajoutée par Lexical à sa création, ainsi que le numéro de ligne. Dans le cas des non-terminaux, c'est Syntaxe qui ajoute le numéro de ligne (voir 1.3.1). • Arbres : contient les primitives de construction de l'arbre. 3 1.3 Choix de conception La plupart des paquetages de cette partie sont issus de la génération automatique par Aex et Ayacc, c'est pourquoi il y a peu de décisions de conception ici. 1.3.1 Choix d'accrochage du numéro de ligne Comme vu en 1.2, nous ajoutons à chaque noeud un attribut contenant un numéro de ligne lors de la construction de l'arbre. Le choix du numéro de ligne est évident pour tous les terminaux du lexique correspondant aux feuilles de l'arbre abstrait : il s'agit du numéro de ligne du lexème dans le chier original1 . C'est pour cela qu'il est aecté par Lexical. Cependant, en ce qui concerne les non-terminaux de la grammaire abstraite, et donc les noeuds qui ne sont pas des feuilles, nous avons du choisir le numéro de ligne de l'un des termes de la partie droite de la règle correspondante (c'est-à-dire de l'un de ses ls). Ceci est donc eectué dans Syntaxe. Exemple : Le choix du terminal pour récupérer le numéro de ligne pour le noeud aectation n'a pas d'inuence dans le cas de gauche, mais en a une dans le cas de droite : 1: x=1; 1: x 2: = 3: 1 4: ; Nous avons choisi ici de donner le numéro de ligne de l'opérateur = (ici ligne 2) au noeud de l'aectation. Le tableau qui suit récapitule les choix que nous avons fait pour l'ensemble des noeuds de l'arbre abstrait. Lorsque le numéro de ligne est accroché à une liste, il s'agit en réalité du numéro de ligne du premier arbre de cette liste (ou 0 si la liste est vide). Noeud non-terminal Programme Classe Ident Champ program classe ident champ champ Partie droite de la règle Accrochage ligne sur : liste_classes principal principal Classe_Lex ident ext_classe ident Idf_Lex Idf_Lex type suite_decl_champ ' ;' suite_decl_champ Protected_Lex type suite_decl_champ suite_decl_champ ' ;' Decl_Champ decl_champ ident initialisation ident Methode methode type ident '(' liste_param ')' ident liste_declarations bloc Parametre parametre type ident ident Decl_Variable decl_variable type suite_decl_var ' ;' type Decl_Var decl_var ident initialisation ident 1 aucun lexème ne contient de retour à la ligne, donc aucun ne se trouve sur 2 lignes à la fois 4 Noeud non-terminal Nop Retour Si Tantque Cond Ecriture Ecriture_Ligne Aect Ou Et Egal_Egal Di Inf Sup Inf_Egal Sup_Egal Instanceof Plus Moins Mult Div Reste Moins_Unaire Non Conversion Entier Flottant Chaine Vrai Faux Null This Lecture_Entier Lecture_Flottant Creation Appel Selection Principal inst inst inst inst suite_cond inst inst exp exp exp exp exp exp exp exp exp exp exp exp exp exp exp exp exp exp exp exp exp exp exp exp exp exp exp exp exp place place Partie droite de la règle Accrochage ligne sur : ' ;' ' ;' Return_Lex exp ' ;' Return_Lex suite_cond sinon suite_cond While_Lex '(' exp ')' bloc While_Lex If_Lex '(' exp ')' bloc If_Lex Print_Lex '(' liste_exp ')' ' ;' Print_Lex Println_Lex '(' liste_exp ')' ' ;' Println_Lex place '=' exp '=' exp Or_Lex exp Or_Lex exp And_Lex exp And_Lex exp Egal_Egal_Lex exp Egal_Egal_Lex exp Diff_Lex exp Diff_Lex exp '<' exp '<' exp '>' exp '>' exp Inf_Egal_Lex exp Inf_Egal_Lex exp Sup_Egal_Lex exp Sup_Egal_Lex exp exp Instanceof_Lex Instanceof_Lex exp '+' exp '+' exp '-' exp '-' exp '*' exp '*' exp '/' exp '/' exp '%' exp '%' '-' exp '-' ' !' exp ' !' Cast_Lex '<' type '>' '(' exp ')' Cast_Lex Entier_Lex Entier_Lex Flottant_Lex Flottant_Lex Chaine_Lex Chaine_Lex True_Lex True_Lex False_Lex False_Lex Null_Lex Null_Lex This_Lex This_Lex ReadInt_Lex '(' ')' ReadInt_Lex ReadFloat_Lex '(' ')' ReadFloat_Lex New_Lex ident '(' ')' New_Lex place '(' liste_exp ')' place exp '.' ident '.' liste_declarations bloc liste_declarations 5 2 Étape B : Vérications contextuelles et Décoration Cette section concerne les chiers situés dans le répertoire Verif/. 2.1 Description Cette partie est chargée de décorer l'arbre abstrait avec des informations contextuelles. Elle utilise pour cela la grammaire attribuée fournie dans la spécication. Au cours de cette phase, le compilateur eectue aussi la vérication contextuelle et l'enrichissement de l'arbre. Elle fonctionne en 3 passes : 1. Recensement des noms de classes, vérication de l'utilisation des extends 2. Recensement des noms de méthodes et de champs, vérication des types des champs 3. Vérication du corps des méthodes, vérication du programme principal 2.2 Architecture L'architecture adoptée pour cette partie est la suivante : Verif Verif_Passe_1 Tests_Types Verif_Passe_2 Verif_Commun Verif_Passe_3 Decors Erreurs_Contextuelles Symboles Utilitaires pour la vérification Fig. 2 Architecture de la partie Verif Description du rôle des paquetages qui apparaissent ci-dessus : • Verif_Passe_[123] : contiennent chacun un certain nombre de procedures dont le nom est de la forme Verif_NonTerminal , ainsi que quelques procédures annexe au besoin. Cha- cune de ces procedures est chargée de traiter la ou les règles correspondant au non-terminal donné par son nom (voir 2.3.1). 6 • Symboles : contient les primitives de gestion de la table des symboles. Il consiste principalement en 2 variables globales : Env_Types qui contient les types prédénis et les classes déclarées, et Env_Exp_Object, qui contient la méthode equals de la classe par défaut Object. L'initialisation contient le codage en dur des types prédénis et de la classe Object. • Tests_Types : contient l'implémentation du type Operateur ainsi que diérentes fonc- tions utilisées pour dénir la grammaire attribuée. C'est le cas des fonctions d'accès au type de retour de certaines opérations, ainsi que des opérations sur les environnements (Union_disjointe et Empilement). • Verif_Commun : contient les procédures traitant les règles communes aux trois passes (pour les non-terminaux ident et type ), ainsi que les exceptions et fonctions utilitaires communes aux packages de vérication contextuelle. • Erreurs_Contextuelles : permet de gérer les messages d'erreurs de manière centralisée, en utilisant les numéros de passe, de règle, et d'erreur. • Decors : contient les primitives de gestion des décors des arbres. 2.3 2.3.1 Choix de conception Rôle des procédures Verif_NonTerminal Les paquetages Verif_Passe_[123] sont essentiellement constitués de procédures appelées Verif_NonTerminal , où NonTerminal désigne un non-terminal de la grammaire attribuée du langage Deca fournie dans la spécication. Elles comportent toutes un paramètre A qui est l'arbre correspondant au non-terminal à traiter (ou L s'il s'agit d'une liste2 ), ainsi que des paramètres in et out représentant les attributs respectivement hérités et synthétisés. Concrètement, chacune de ces procédures eectue les actions suivantes : 1. choix de la règle à utiliser à l'aide d'un case sur le type de noeud du paramètre (voir 2.3.2) 2. appel des procédures correspondant aux non-terminaux de la partie droite 3. aectations implicites et explicites 4. ltrages d'attributs et vérication des conditions 5. ajout d'un décor aux noeuds de l'arbre où c'est pertinent, ce qui permet de stocker les informations de contexte pour la partie C N.B. : L'ordre est parfois modié selon les cas Si une erreur contextuelle est décelée au point 4, un appel à la procédure Message_Erreur est eectué (voir 2.3.4) et l'exception Erreur_Verif_Locale est levée. 2 les listes ne sont pas traitées de la même manière, veuillez vous référer au point 2.3.3 pour plus de précisions 7 2.3.2 Utilisation systématique du case Dans les procédures vues en 2.3.1, l'utilisation de la structure case en Ada paraît superue lorsqu'un seul cas est possible. C'est en réalité un choix qui s'est avéré intéressant pour plusieurs raisons, il a permis en eet de : 1. programmer de manière défensive car l'appel à Acces_Noeud_XXX lève une exception en cas d'incohérence interne 2. s'assurer que tous les types de noeuds soient bien traités3 pour les procédures où c'est nécessaire 3. rester général et systématique pour toutes les autres procédures 4. synthétiser le code à l'inverse d'une structure conditionnelle en if 2.3.3 Traitement itératif des règles récursives Nous souhaitons attirer l'attention du lecteur sur le traitement des règles récursives, qui sont traduites sous forme de listes dans l'arbre abstrait. La traduction exacte de ces règles récursives suggérait d'utiliser une procédure récursive également, an de rester systématique. Cependant, cela aurait compliqué le code avec des accès à une sous-liste de la liste mère. Nous avons donc choisi de traiter ces règles de manière itérative, à l'aide du parcours de liste fourni par le package Listes. Il nous a donc fallu adapter les opérations sur les attributs pour qu'elles conviennent à cette nouvelle forme. 2.3.4 Messages d'erreur Pour plus de lisibilité du code, les messages d'erreur sont tous contenus dans le paquetage Erreurs_Contextuelles. Ainsi, dans les paquetages Verif_Passe_[123], il sut d'appeler la procedure Message_Erreur avec les bons numéros de passe, de règle et d'erreur sans se soucier du message descriptif. 3 erreur de compilation des sources Ada si un cas est oublié 8 3 Étape C : Génération de code Cette section concerne les chiers situés dans le répertoire Gencode/. 3.1 Description Cette partie implémente la dernière étape de la compilation, à savoir la génération de code. C'est sur cette partie que la conception de l'architecture a pris le plus de temps. Elle fonctionne en 2 passes : 1. Génération du code de construction de la table des méthodes 2. Génération du code des sous-programmes d'initialisation des classes Génération du code des méthodes des classes Génération du code du programme principal Génération du code des messages d'erreur 3.2 Architecture L'architecture adoptée pour cette partie est la suivante : Gencode Gencode_Tables_Methodes Gencode_Classes Table_Etiquettes Gencode_Bloc Passe 1 Passe 2 Gencode_Instructions Gencode_Expressions Gencode_Assembleur Gencode_Commun Pseudo_Code Ensemble de primitives pour la génération de code Fig. 3 Architecture de la partie Gencode 9 Description du rôle des paquetages qui apparaissent ci-dessus : • Gencode_Commun : fournit les exceptions, ainsi que des macros pour récupérer plus simple- ment les informations dans l'arbre abstrait. • Gencode_Assembleur : contient les étiquettes d'erreur et la dénition du type Non_Scratch, et fournit des macros et utilitaires pour tout ce qui se rapproche du code assembleur. Il fournit en particulier la procedure Optimise (voir 3.3.5), les fonctions Prepare_TSTO et Prepare_ADDSP (voir 3.3.6), ainsi que les procédures de gestion de Ctx, variable sur laquelle nous reviendrons en 3.3.3. • Gencode_Expressions : fournit les procédures de traitement des expressions arithmétiques et booléennes, mais aussi de l'instruction new et de l'aectation (qui sont des expressions). • Gencode_Instructions : fournit la procédure Gen_Inst qui génère le code de toute instruction, en prenant en paramètre un noeud de type Noeud_Arbre_INST. • Table_Etiquettes : abstrait une structure de données qui permet de représenter la table des étiquettes des méthodes de chaque classe. Il instancie pour cela le package générique Tables. • Gencode_Tables_Methodes : fournit une procédure de génération du code permettant de créer la table des méthodes au début du programme. Il s'appuie principalement sur les procédures du paquetage Table_Etiquettes (voir 3.3.4). • Gencode_Bloc : fournit les procédures de génération de code pour une liste d'instructions ou une liste de déclarations. • Gencode_Classes : fournit une procédure de génération de code pour les classes. Pour chaque classe, il génère le code d'initialisation de ses champs et le code de ses méthodes. • Gencode : contient la procédure qui orchestre la génération du code, ainsi que la procédure Gen_Principal qui génère le code du programme principal à l'aide des packages précédem- ment cités. 3.3 3.3.1 Choix de conception Considérations générales sur les paramètres des procédures La génération de code s'eectue en parcourant l'arbre abstrait. Ainsi toutes les procédures de génération de code prennent en paramètre un noeud de l'arbre (ou une liste). Elles possèdent pour la plupart un autre paramètre appelé Ctx sur lequel nous reviendrons en 3.3.3. Les procédures de génération du code des expressions prennent en outre en paramètre un registre Res (Non_Scratch) qui indique où stocker la valeur de l'expression. Cette valeur est de nature diérente suivant que l'expression est arithmétique (valeur entière ou ottante), booléene (0 ou 1) ou s'applique à des objets (adresse). 10 3.3.2 Convention d'utilisation des registres Nous avons choisi pour plus de commodité d'utiliser les registres banalisés non scratch dans l'ordre de leur numérotation. Ainsi, si l'on demande l'évaluation d'une expression dans R4, cela signie que les registre R2 et R3 ne doivent pas être écrasés (à moins d'être sauvegardés) et que les registres R4 à R15 sont libres4 , donc utilisables à souhait sans sauvegarde. Il est également convenu que lors d'un appel à Gen_Inst, tous les registres non scratch (R2 à R15) sont disponibles. Ils ont donc été sauvegardés au préalable s'ils sont utilisés. Le type Non_Scratch déni dans Gencode_Assembleur permet de ltrer les registres utilisés lors d'appel aux procédures de génération des expressions, an d'éviter l'utilisation malencontreuse d'un registre scratch qui pourrait s'avérer problématique5 . 3.3.3 Gestion du contexte grâce au paramètre Ctx Le paramètre in out Ctx apparaît dans la plupart des procédures de cette section. Il est de type Contexte déni dans Gencode_Assembleur comme un enregistrement comme suit : type Contexte Classe : Methode : Pile : PileMax : Rmax : end record; is record access String; access String; Natural; Natural; Non_Scratch; Les 2 premiers champs servent à savoir dans quelle classe et quelle méthode on se trouve depuis n'importe quelle procédure (ceci est notamment nécessaire dans la procédure qui génère le code de return pour le choix de l'étiquette de saut). Les 3 champs suivants peuvent être mis à zéro6 par un appel à la procédure RAZ_Stats. • Pile est incrémenté et décrémenté par les PUSH, POP, ADDSP, SUBSP, ce qui permet de connaitre la taille courante de la pile7 . • PileMax garde la valeur maximale atteinte par Ctx.Pile depuis la dernière mise à zéro. (son utilisation est expliquée en 3.3.6) • Rmax contient le registre non scratch maximum (en terme de numéro) utilisé depuis la dernière mise à zéro. Ceci est notamment utilisé pour connaître les registres utilisés par une méthode, et donc savoir lesquels sauvegarder (voir 3.3.7). C'est en eet possible grâce à la convention vue en 3.3.2. 3.3.4 Structure de données pour la table des méthodes Nous utilisons le package Table_Etiquettes comme un dictionnaire : nous rangeons dans la table chaque classe avec sa table des méthodes. La structure de donnée associée est appelée TableMethodes et est dénie comme suit : type Tableau is array (Positive range <>) of Etiq; 4 en réalité, les registres disponibles ne vont jusqu'à R15 que si l'option -r ne les limite pas expression peut contenir un appel de méthode qui pourrait écraser les registres non scratch 6 pour Rmax, il s'agit de lui donner pour valeur le registre par défaut R_Defaut, qui est une constante xée à R2 dans gencode_assembleur.ads 7 c'est une taille relative, dépendant de la dernière mise à zéro 5 une 11 type EtiqMethodes is access Tableau; type TableMethodes is record Adr_TM : Operande; Super : Operande; Tab : EtiqMethodes; end record; Les deux champs suivants représentent la table telle qu'elle sera dans la pile : • Super : adresse de la table des méthodes de la super-classe • Tab : tableau des étiquettes des méthodes Nous avons également ajouté un troisième champs pour plus de commodité dans le paquetage utilisateur Gencode_Tables_Methodes : • Adr_TM : adresse de la table des méthodes de la classe courante Nous avons adopté cette structure de façon à pouvoir facilement changer l'opérande de la dénition de chaque classe. Nous avons par ailleurs masqué l'utilisation de la table grâce à un ensemble de mutateurs et accesseurs dont les noms sont susamment explicites pour se passer d'explications. 3.3.5 Rôle de la procédure Optimise La procédure Optimise permet d'abstraire les choix de registres dans le calcul des expressions. En eet, il est bienvenu d'économiser des PUSH et POP qui ne sont pas obligatoires en utilisant un maximum de registres disponibles, plutôt que de sauvegarder ceux que l'on utilise déjà. Sa déclaration est la suivante : generic with procedure Modifier(R : in Non_Scratch; Ctx : in out Contexte); procedure Optimise(Res : in Non_Scratch; Res2 : out Registre; Ctx : in out Contexte); Cette procédure prend tout son sens lorsqu'il s'agit d'évaluer une expression à 2 opérandes, c'est pourquoi la procédure Modifier est souvent un simple appel à Gen_Exp qui doit évaluer le deuxième opérande. Une utilisation usuelle de Optimise est donc de commencer par évaluer le premier opérande dans Res et de laisser Optimise évaluer le deuxième dans un registre Res2 qui dépend de la disponibilité du registre qui suit Res : Si ce registre est autorisé, alors c'est lui qui est utilisé pour stocker le deuxième opérande. Si Res était le dernier registre autorisé, alors Optimise le sauvegarde, l'utilise pour l'évaluation8 , puis stocke le deuxième opérande dans R0 avant de restaurer Res. Le paramètre out Res2 contient nalement le registre où se trouve eectivement le résultat de Modifier. On eectue alors l'opération souhaitée entre Res et Res2. 8 car on ne peut pas utiliser un registre scratch pour l'évaluation d'une expression (voir 3.3.2) 12 3.3.6 Gestion des tests et réservation de mémoire dans la pile Le problème des instructions TSTO et ADDSP est qu'on ne connaît pas leur opérande à priori. En eet, la quantité à tester ou réserver dépend de ce qui suit. C'est pourquoi nous avons créé des fonctions et procédures utilitaires pour préparer leur utilisation. Les fonctions suivantes retournent l'Inst (de type TSTO ou ADDSP) qu'il faut conserver pour modication ultérieure : function Prepare_ADDSP return Inst; function Prepare_TSTO return Inst; La procédure suivante permet plus tard de changer l'opérande en plaçant la valeur Val dans l'instruction. procedure Change_TSTO_ADDSP(I : in Inst; Val : in Integer); On utilise souvent Ctx.PileMax (voir 3.3.3) pour connaître la valeur à placer comme argument Val ici. 3.3.7 Sauvegarde des registres dans le code des méthodes Comme indiqué dans la spécication, les registres non scratch utilisés par une méthode doivent être sauvegardés au début de son exécution. Cependant, il se pose le même problème qu'en 3.3.6, à savoir que l'on ne connaît pas les registres à sauvegarder lorsqu'on génère le début du code de la méthode. Pour pallier ce problème, nous avons créé une procédure Prepare_Sauvegarde_Regitres qui retourne la ligne courante du code lors de son appel. La mémorisation de cette ligne permet ensuite d'insérer les lignes de sauvegarde des registres une fois que l'on connaît les registres à insérer. Cette insertion est eectuée avec la procédure suivante de Gencode_Assembleur : -- Insere la sauvegarde des registres de Non_Scratch'First a Ctx.Rmax procedure Sauvegarde_Registres(L : in Ligne; Ctx : in out Contexte); Pour savoir quels registres insérer, cette procédure se base sur la valeur de Ctx.Rmax (voir 3.3.3). 13 PROJET GENIE LOGICIEL Documentation de Validation GROUPE 8 - EQUIPE GL42 BION Jorey DOUDECHE Amine POLISANO Kévin THIARD Florence 23 janvier 2012 1 Table des matières 1 Conception de tests 3 2 Conventions de nommage 4 3 Resultats de la couverture des tests avec Gcov 5 4 Tests syntaxiques 6 5 Tests lexicaux 7 2 1 Conception de tests An de s'assurer que le code écrit implantait dèlement les fonctionnalités que l'on attendait du compilateur, nous avons eectué de nombreux de tests tout en respectant les conventions de nommage décrite dans les consignes de Validation du compilateur Deca. En eet, chaque test est précédé d'un chire allant de 0 à 7, celui-ci correspond à l'itération dans laquelle nous nous situions, l'écriture du code s'étant fait par étapes : 0 Programme vide 1 Hello World print et println de diverses expressions 2 Expressions simples 3 Boucle conditionnelle if et itérative while 4 Variables 5 Classe 6 Classe avec méthodes 7 Cast & Instanceof Par ailleurs, l'écriture du test consistant à vérier la bonne implémentation de chaque itération s'est accompagnée de l'écriture de tests valides et invalides. En eet, un test a pour but de prouver que le compilateur fonctionne correctement mais aussi d'exhiber le plus grand nombre d'erreurs possibles, s'il y'en a, et de s'assurer que les exceptions étaient bien toutes relevées correctement (pour éviter des erreurs telles que Constraint_Error ou Access_Check_Failed qui ne sont d'aucune utilité pour le client dont la connaissance de l'aspect technique du produit est très partielle). Nous avons, dans un premier temps, classé les règles de la grammaire utile pour chaque itération. Dans un second temps, nous avons relevé toutes les erreurs susceptibles d'être levées par l'écriture du code associée à l'itération courante. Ainsi, nous avons pu créé des tests invalides et s'assurer que toutes les erreurs étaient levées et cela, de plusieurs manières diérentes, an d'avoir une base de tests la plus riche possible. D'autre part, an de tester la pertinence de nos tests, nous avons utilisé l'outil gcov et vérié que le programme de test passait par toutes les règles de la grammaire nécessaire à l'itération courante. A noter, qu'une couverture de 100% dans gcov est dicile à obtenir pour certains chiers tels que verif_passe_3.adb car certaines lignes du code sont associées à des erreurs interne et par conséquent, le programme n'est pas supposé passer par ces lignes lors de l'exécution des tests. Nous y reviendrons plus tard. De plus, nous avons tenté d'eectuer deux types de tests. D'une part des tests dit en boite blanche qui est une technique de conception de test, en général fonctionnel, fondée sur l'analyse de l'implémentation du code, d'autre part, des tests dits en boite noire qui est une technique de conception de test, fonctionnel ou non, qui n'est pas fondée sur l'analyse de l'implémentation du code mais sur une manière plus générale de coder les fonctionnalités testées. 3 2 Conventions de nommage Concernant les tests de vérication contextuelle, nous avons nommé les chiers de tests invalides de la façon suivante : NuméroItération_NuméroException_TypeErreur.deca // // // // // Description Trop de Resultat parametres pour la methode translater : Erreur Ligne : contextuelle 18 // Ligne 18 // Regle 3.97 // Historique // Cree le : Trop de parametres pour l ' appel de methode (3.97 −2) : 12/01/2012 c l a s s Point { void t r a n s l a t e r ( int a ) { } } int a ; { ( new Point ( ) ) . t r a n s l a t e r ( a , a ) ; } Voici l'exemple d'un chier de test invalide. Nous prenons bien soin à relever le numéro de la ligne ou le programme renvoie une erreur, le numéro de la règle associée à l'erreur, et enn le message précis renvoyé par le programme lors de la vérication contextuelle. En eet, le script de vérication des tests vérie que le message attendu et le message renvoyé par le programme en cas d'erreur est bien identique, un espace supplémentaire pouvant aboutir à une erreur du script. Enn, une description est fournie au cas où le message d'erreur n'est pas susamment explicite. 4 3 Resultats de la couverture des tests avec Gcov Nom Fichier Pourcentage de lignes ... Nb lignes dans le code erreurs_contextuelles.adb 65.22% 92 gencode_expressions.adb 92.39% 289 gencode_assembleur.adb 96.69% 242 gencode_classes.adb 98.81% 168 gencode_instructions.adb 97.22% 72 gencode_tables_methodes.adb 97.01% 67 gencode.adb 92.11% 38 gencode_bloc.adb 100.00% 34 gencode_commun.adb 95.83% 24 listes.adb 100.00% 6 symboles.adb 98.18% 55 table_etiquettes.adb 81.48% 54 tables.adb 100.00% 9 tests_types.adb 97.46% 118 verif_passe_3.adb 95.50% 511 verif_passe_2.adb 92.35% 196 verif_passe_1.adb 100.00% 46 verif_commun.adb 88.00% 25 verif.adb 83.33% 12 Nous constatons que la couverture est globalement satisfaisante. Comme nous l'avions précisé précédemment, il est dicile d'obtenir une couverture parfaite (100%) pour tout les chiers. En eet, certaines lignes de ces derniers correspondent à des erreurs internes, et sont donc inaccesibles au programme via les tests eectués. 5 4 Tests syntaxiques Nom Fichier Initialisation_erronee.deca Nature de l'erreur int x = .3 Omission_Type.deca "x = 3 ;" Separateur_variables.deca Point_Virgule.deca "int x y" "int x" Accolade_fermante.deca Accolades_manquantes_if.deca "class A { ..." "if (true) exp" Aectation_Egalite.deca "int x = .3" Description Erreur sur le Non-Terminal EXP : après = on attend une exp qui ne peut commencer par "." on ne trouve pas deux idf de suite (cf. règle decl_var) Séparateur de variables inexistant Point virgule manquant (cf. règle decl_variable) Accolade_fermante manquante (cf. 3.7) Invalide car il faut un bloc (cf. regle suite_cond) Après "=" on attend une exp, qui ne peut commencer par "." Commentaires_ Multilignes.deca "/* commentaires */" Else_seul.deca Methode_sans_corps.deca Pb_parenthesage.deca Puissance_indenie.deca Return_seul.deca Separateur_parametres.deca Accolade_ouvrante.deca Accolades_Inversees.deca Bloc_Avec_ Instruction_Fausse.deca Boucle_avec_condition_ non_parenthesee.deca Boucle_while_condition_ manque_parenthese.deca cast_sans_crochets.deca Declaration_dans_ un_bloc.deca Elsif_sans_condition.deca Exp_non_reconnue.deca Exp_non_reconnue1.deca Exp_non_reconnue2.deca Exp_non_reconnue3.deca aucune instruction ne commence par "/" "else { }" Une instruction ne peut commencer par else (cf. inst) "methode( ) ;" On attend un bloc (cf. 3.19) "((1+2)*(3+4)" Parenthésage incorrect (cf. 3.60) "n**2" N'est pas une expression correcte (cf. 3.52) "return ;" Impossible, ; il faut renvoyer une exp et ; n'en est pas une (cf. règles inst et exp) "Ma_methode(x ; y)" Les séparateurs de paramètre doivent être des virgules (cf. règle suite_param) "class A { ..." accolade_fermante manquante (cf 3.6) "class A } ..." accolade_fermante manquante (cf 3.6) "{ - }" Instruction incorrecte "while cond ..." "while (cond ..." " y = cast(oat) x ; " "{ int x=1 ; }" "} elsif {" "A => B" "A <> B" "A & B" "A | B" 6 Condition pour la boucle while sans parentheses Condition pour la boucle while sans parentheses Omission de crochets <> pour l'operateur cast Declaration à l'interieur d'un bloc d'instruction ( cf regle 3.19 ) Elsif sans condition Expression non reconnue Expression non reconnue (cf 3.76) Expression non reconnue (cf 3.81) Expression non reconnue (cf 3.82) Expression_Conditionelle_ "{ if Booleen }" Expression conditionelle sans parenthèses Sans_Parentheses.deca Instructions_en_dehors "x=1 ; {}" Instructions en dehors d'un bloc b (cf 3.31) _bloc.deca Listes_declarations_ "{ int x = 1 ; }" Liste de declarations à l'interieur d'un dans_un_bloc.deca bloc, contraire à la regle 3.5. Omission_separateur_ "print(x y) ; " Omission séparateur dans l'achage de print_variables.deca plusieurs variables Omission_separateur_ "println(x y) ; " Omission séparateur dans l'achage de println_variables.deca plusieurs variables Print_sans_ " print x ; " Omission parentheses pour l'achage parentheses.deca Println_sans_ " printn x ; " Omission parentheses pour l'achage parentheses.deca readFloat_sans " x = readFloat ; " Omission de parentheses pour l'operateur readFloat _parentheses.deca readInt_sans " x = readInt ; " Omission de parentheses pour l'operateur readInt _parentheses.deca 5 Tests lexicaux On rappele qu'un identicateur doit impérativement commencer par une lettre, $ ou _ d'après la dénition de IDF : IDF = (LETTRE +'$' + '_' )(LETTRE + CHIFFRE + '$' + '_')*. Nom Fichier Nature de l'erreur Description Idf_non_reconnu_1.deca "" idf non reconnu, Idf_non_reconnu_2.deca "@" idf non reconnu Idf_non_reconnu_3.deca "[" idf non reconnu Idf_non_reconnu_4.deca "]" idf non reconnu Idf_non_reconnu_5.deca " &" idf non reconnu Idf_non_reconnu_6.deca "|" idf non reconnu Idf_non_reconnu_7.deca "34" idf non reconnu Idf_non_reconnu_8.deca "à" idf non reconnu Idf_non_reconnu_9.deca "é" idf non reconnu Idf_non_reconnu_10.deca "ù" idf non reconnu Idf_non_reconnu_11.deca "" idf non reconnu Idf_non_reconnu_12.deca "ç" idf non reconnu Idf_non_reconnu_13.deca "ν " idf non reconnu Idf_non_reconnu_14.deca "" idf non reconnu Idf_non_reconnu_15.deca "?" idf non reconnu Declaration_type_ada.deca " :" n'est pas un token Trop_Caracteres.deca Plus de 1024 caractères 7 Erreurs gl42 23 janvier 2012 1 Erreurs contextuelles Règle Type 0.1/0.2 Filtrage d'attribut synthétisé 0.3 1.4-1 1.4-2 1.4-3 2.4-1 2.4-2 2.9 2.12 2.13 2.14 2.16-1 2.16-2 2.16-3 Opération partielle Condition Opération partielle Opération partielle Condition Operation partielle Operation partielle Condition Condition Opération partielle Opération partielle Condition Condition 2.17-1 2.17-2 2.17-3 Opération partielle Condition Condition 2.17-4 Condition 2.17-5 Condition 2.22 3.6-1 3.6-2 3.23 3.27 3.30 3.34 Condition Opération partielle Condition Opération partielle Condition Opération partielle Condition Message Erreur interne (il n'y a que des idf de type ou de classe dans Env_Types) Identicateur non déni Identicateur de classe attendu pour [super] Redénition de l'identicateur de classe [nom] Identicateur de classe non déni [super] Erreur interne (dejà testée en 1.4) Erreur interne (dejà testée en 1.4) Champ ou méthode [nom] déjà déclaré Déclaration de champs de type `void' Déclaration de champs de type `void' Champ [nom] déjà déclaré Erreur interne (dejà testée en 1.4) Erreur interne (dejà testée en 1.4) Masquage de la méthode héritée [nom] par une déclaration de champ Erreur interne (dejà testée en 1.4) Erreur interne (dejà testée en 1.4) Masquage du champ hérité [nom] par une déclaration de méthode Signature incompatible pour la Redénition de la méthode [nom] Type de retour incompatible pour la redénition de la méthode [nom] Paramètre formel [nom] de type `void' (interdit) Erreur interne (dejà testée en 1.4) Erreur interne (dejà testée en 1.4) Pusieurs paramètre formels de même nom [nom] Déclaration de variable(s) de type `void' interdite Variable [nom] déjà déclarée Instruction `return' incompatible avec le type de retour `void' 1 3.44 Condition 3.45 3.50 Filtrage d'attribut synthétisé Condition 3.52 Opération partielle 3.53 Opération partielle 3.54 Condition 3.57 Filtrage d'attribut synthétisé 3.58 Opération partielle 3.59 Condition 3.64..84 Filtrage d'attribut synthétisé 3.86/87-1 Filtrage d'attribut synthétisé 3.86/87-2 3.86/87-3 3.87-4 3.87-5 Opération partielle Condition Condition Condition 3.87-6 Condition 3.88..90 Filtrage d'attribut synthétisé 3.91 3.93 Filtrage d'attribut synthétisé Filtrage d'attribut synthétisé (ou condition) 3.94 Filtrage d'attribut synthétisé 3.95 Filtrage d'attribut hérité 3.97/98-1 Filtrage d'attribut hérité 3.97/98-2 Filtrage d'attribut hérité Types [type1] et [type2] incompatibles pour l'aectation Condition non booléenne print/println : type [type] incompatible (type `int', `oat', ou `String' attendu) Opérateur [op] indéni pour les types [type1] et [type2] Opérateur [op] indéni pour le type [type] Utilisation de this en dehors d'une classe new : identicateur de classe attendu pour [nom] instanceof : types [type1] et [type2] incompatibles cast : types [type1] et [type2] incompatibles Erreur Interne Objet attendu en partie gauche de sélection (avant `.') Erreur Interne (déjà testée car 3.86/87-1 est passée) Erreur Interne (déjà testée par 3.86/87-1) Champ protégé non visible dans le programme principal Champ protégé non visible dans [classe1] qui n'est pas un sous-type de [classe2] Champ protégé non visible dans [classe1] qui n'est pas un sous-type de [classe2] Identicateur de champ, de paramètre ou de variable attendu Identicateur de champ attendu Objet attendu en partie gauche d'appel de méthode (avant `.') Identicateur de méthode attendu Cette méthode attend des paramètres Paramètre(s) manquant(s) pour l'appel de méthode Trop de paramètres pour l'appel de méthode 2 Charte de travail en équipe : Projet Génie Logiciel BION Joffrey, DOUDECHE Amine, POLISANO Kevin, THIARD Florence, Ensimag, Equipe 42 1. Les compétences de l’équipe, ses points forts et ses points faibles Synthèse des rendus personnels Nous avons effectué une synthèse des rendus personnels après quelques jours de travail sur le projet génie logiciel. Globalement, le leadership est contrasté mais est plus élevé pour Joffrey, ce qui nous a mené à le nommer chef de projet, nous y reviendrons plus tard. Concernant la planification et l'organisation, Amine s'assure que le planning est à jour et qu'il est respecté par l'ensemble de l'équipe. L'esprit d'équipe est quant à lui omniprésent et laisse présager un bon déroulement du projet ainsi qu'une bonne ambiance de travail, mais peut également compenser les faiblesses individuelles dans d'autres domaines. Enfin, aucun membre n'a de problème particuliers de communication orale comme écrite, ce qui facilitera le déroulement de la soutenance et des suivis. Matrice SWOT : Points forts et points faibles en tant qu’équipe FORCES Très bonne communication au sein du groupe Niveau de compétence technique globalement élevé OPPORTUNITES Avoir un lieu où se réunir en dehors de l'Ensimag, accessible et convivial FAIBLESSES Ponctualité MENACES Le retard d’un membre de l’équipe entrainant un retard général pour le rendu (travail en parallèle) Les surcharges de travail 2. Les valeurs communes Chaque membre, ayant des taches de difficultés variables à réaliser, et étant conscient des dates limites de rendu, doit bien évidemment donner son maximum afin de réaliser ces dernières et ne pas hésiter à solliciter de l’aide de la part de ses camarades afin d’éviter tout retard sur le projet dont le temps de réalisation est relativement court. Conformément au planning joint en annexe, chacun a un certain nombre de tâches à effectuer en un temps souhaité. A partir du moment ou le travail est complet à la date butoir, des comportements tels que des retards ou des absences ponctuels à certaines réunions d’équipe sont acceptés. En effet, chacun est conscient des responsabilités qui lui incombent ainsi que de la difficulté dans laquelle il peut mettre son groupe en cas de laisser allers répétés et injustifiés. Des réunions d’équipe sont mises en place régulièrement afin de faire un bilan de l’état d’avancement de chacun, faire part des initiatives prises et des difficultés rencontrées. Lesdites initiatives, prises seul, sont les bienvenues tant qu'elles n'entraînent pas de changement irréversible ni de modification majeure. Dans le cas inverse, une consultation d'au moins 2 autres membres est souhaitée. Somme toute, il est souhaitable que chaque membre soit présent lors de ces réunions, sauf problème personnel (rendez-vous, maladie …). Chacun doit essayer d’apporter un regard constructif et critique sur le travail des autres tout en les respectant. 3. Rôles et responsabilités dans l’équipe La répartition des taches s’est effectuée en fonction des préférences des uns et des autres, mais également en fonction des compétences techniques de chacun (Assembleur, Ada…). Étant le seul membre du groupe à avoir suivi l'enseignement Architecture 2 au deuxième semestre en première année, Joffrey a une bonne connaissance du langage d'assemblage, ce qui facilite. Ayant en outre une vision assez globale du projet, nous l'avons désigné en tant que « chef de projet ». En effet, ses connaissances lui ont facilité la compréhension du sujet ainsi que les attentes vis-à-vis du projet. Il devra s’assurer que chaque membre, éventuellement aidé par ses camarades, accomplisse les tâches qui lui auront été attribuées en respectant les délais du planning. Il devra également s'assurer de la cohérence des différents modules. Cependant, les membres du groupe ne devront pas voir le chef de projet comme une personne exigeante et inflexible mais au contraire comme une personne à l’écoute et soucieuse du bon avancement de l’équipe et à qui ils n’hésiteront pas à lui faire part de leur problèmes. Mis à part ce rôle qui demeurera fixe, les autres rôles (conception, développement, tests...) pourront varier selon les tâches à effectuer et les envies afin que chacun puisse apprendre quelque chose du projet. 4. La communication au sein de l’équipe De manière générale, chaque étape qui précède l'écriture de code sera effectuée au minimum par binôme, ceci afin de confronter nos points de vue de façon constructive et d'avancer efficacement dans le projet. Nous nous séparerons ensuite les taches pour le code brut dans le but de paralléliser l'écriture des procédures pour optimiser notre rendement. Les différentes difficultés rencontrées seront traitées en équipe afin que chacun d'entre nous maîtrise au mieux la totalité du projet. Toutefois cette organisation doit rester souple et adaptative : si l'un des membres a terminé sa tâche en avance, ou si à l'inverse une tâche s'avère plus complexe ou longue que prévue, une redistribution des efforts est possible et encouragée. Par ailleurs, concernant la communication dans l'équipe, chaque membre doit faire preuve d'un très bon état d'esprit en étant à l'écoute de chacun de ses camarades. En effet, cela doit être facilité par une confiance globale au sein de notre groupe qui nous permettra partager l'ensemble des problèmes rencontrés afin de faciliter leurs résolutions. Des réunions d’équipe auront lieu régulièrement et devront contribuer à cette bonne communication (celles-ci se tiendront la plupart du temps à l'Ensimag ou chez Joffrey qui a un appartement de taille adéquate pour nous accueillir, en particulier pour Kévin, l’appartement se situant au rez-de-chaussée facilitant ainsi l’accès aux personnes à mobilité réduite). Les membres de l'équipe essayeront au maximum de travailler dans un même lieu durant la journée, afin de faciliter davantage la communication ; de plus ils s'engagent à être joignable (dans les limites du raisonnable) Le fait de se retrouver en dehors de l'Ensimag nous permettra de développer une meilleure cohésion des membres de l'équipe et de mieux nous connaître, mais également de se réunir et d’aborder des sujets autres que le projet GL. Ainsi, au choix, un goûter ou un repas devra être organisé chaque semaine. Trois des membres de l'équipe (Amine, Kévin, Joffrey) avaient déjà travaillé ensemble pour le projet C en première année. Les méthodes de travail sont sensiblement similaires à celle de l'année précédente. La présence d'une quatrième personne n'a pas été un problème, au contraire. Cela a souvent apporté un point de vue pertinent concernant de nombreuses problématiques afin d'étayer notre réflexion pour apporter des solutions simples et partagées. 2EQI %REP]WI PI\MGSW]RXE\MUYI 0I\IYV 4EVWIYV 'SYVW 8( 6¬HEGXMSR HI PE GLEVXI HI XVEZEMP %GXMZMX¬W 4IVWSRRIPPIW 7OM 'SQTMPEXIYV K¬VERX ,IPPS ;SVPH 0IGXYVI (SGYQIRXEXMSR 8IWXW %REP]WI GSRXI\XYIPPI +IWXMSR HI PE XEFPI HIW W]QFSPIW -QTPIQIRXEXMSR HI PE +VEQQ %XXVMFY¬I +¬R¬VEXMSR HI GSHI %REP]WI HIW IVVIYVW GSRXI\XYIPPIW -QTP¬QIRXEXMSR HIW IVVIYVW GSRXI\XYIPPIW 'SQTMPEXIYV WERW SFNIX )\TVIWWMSRW 7MQTPI )XETI & )XETI ' )GVMXYVI HIW TVSKVEQQI HI XIWXW 8IWXW :EVMEFPIW )XETI & )XETI ' )GVMXYVI HIW TVSKVEQQI HI XIWXW 8IWXW (IFSKEKI 7XVYGXYVI GSRHMXMSRRIPPI -J )XETI & )XETI ' )GVMXYVI 8IWXW 4EVXMI & )GVMXYVI 8IWXW 4EVXMI ' 8IWXW (IFSKEKI &SYGPI ;LMPI )XETI & )XETI ' )GVMXYVI 8IWXW 4EVXMI & )GVMXYVI 8IWXW 4EVXMI ' 8IWXW (IFSKEKI 'SQTMPEXIYV TSYV PE XSXEPMX¬ HY PERKEKI 6IZYI H EVGLMXIGXYVI 4EVXMI ' 3FNIXW 7ERW Q¬XLSHIW )XETI & )XETI & (¬GSVEXMSR )XETI ' )GVMXYVI 8IWXW 4EVXMI & )GVMXYVI 8IWXW 4EVXMI ' 8IWXW (IFSKEKI 3FNIXW EZIG Q¬XLSHIW )XETI & )XETI & (IGSVEXMSR )XETI ' )GVMXYVI HIW 8IWXW 4EVXMI & )GVMXYVI HIW 8IWXW 4EVXMI ' 8IWXW (IFSKEKI 'EWX -RWXERGI SJ )XETI & )XETI ' )GVMXYVI HIW 8IWXW 4EVXMI & )GVMXYVI HIW 8IWXW 4EVXMI ' 8IWXW (IFSKEKI (SGYQIRXEXMSR 9XMPMWEXIYV (SGYQIRXEXMSR 'SRGITXMSR (SGYQIRXEXMSR :EPMHEXMSR 6IRHY ZIVWMSR MRXIVQ¬HMEMVI 6IRHY *MREP 6IRHY HSGYQIRXEXMSR 6IRHY &MPER 7SYXIRERGI ;SVO ;IIO ;IIO ;IIO ;IIO 1 H H H H H H H L H L H L H L H H L H L H H H L H L H L H L L H L H H L H L H L H L H L H H L L H L H L H L H L H L L H L H L H L H L H L H H L H L H H L H L H L H L L H L H L H L H L L L *PSVIRGI %QMRI .SJJVI] /IZMR .SJJVI] /IZMR *PSVIRGI %QMRI .SJJVI] /IZMR *PSVIRGI %QMRI .SJJVI] ? A %QMRI ? A .SJJVI] /IZMR *PSVIRGI %QMRI .SJJVI] /IZMR *PSVIRGI %QMRI /IZMR .SJJVI] .SJJVI] /IZMR %QMRI *PSVIRGI /IZMR *PSVIRGI /IZMR .SJJVI] /IZMR *PSVIRGI %QMRI .SJJVI] %QMRI *PSVIRGI /IZMR /IZMR *PSVIRGI .SJJVI] %QMRI /IZMR *PSVIRGI /IZMR *PSVIRGI .SJJVI] %QMRI /IZMR *PSVIRGI *PSVIRGI /IZMR .SJJVI] /IZMR *PSVIRGI %QMRI .SJJVI] %QMRI /IZMR *PSVIRGI *PSVIRGI /IZMR %QMRI .SJJVI] /IZMR *PSVIRGI .SJJVI] *PSVIRGI .SJJVI] %QMRI .SJJVI] /IZMR *PSVIRGI .SJJVI] %QMRI *PSVIRGI .SJJVI] /IZMR *PSVIRGI %QMRI .SJJVI] .SJJVI] /IZMR %QMRI *PSVIRGI .SJJVI] /IZMR *PSVIRGI %QMRI L H H L H L .SJJVI] /IZMR *PSVIRGI .SJJVI] /IZMR *PSVIRGI %QMRI .SJJVI] /IZMR *PSVIRGI %QMRI PROJET GENIE LOGICIEL Bilan GROUPE 8 - EQUIPE GL42 BION Jorey DOUDECHE Amine POLISANO Kévin THIARD Florence 27 janvier 2012 Introduction Durant les trois semaines qui constituent le projet GL, nous avons pu mettre à l'épreuve l'organisation et les méthodes de travail que nous nous étions xées au départ. Il s'agit ici de faire le point sur notre évolution et les enseignements que nous en avons tiré. Dans un premier temps, nous aborderons le sujet sous l'angle du travail d'équipe et de la coopération. Nous nous attarderons ensuite sur les objectifs réalisés (ou non) et l'organisation du projet lui même. Enn, nous développerons les apports et les conclusions que nous tirons de notre expérience pour notre vie professionnelle et à plus court terme pour nos successeurs. 1 L'équipe 1.1 Ses forces, ses faiblesses, ses hauts et ses bas... ... Plus de hauts que de bas. En eet, le principal point fort de l'équipe relevé dans la charte au début du projet - à savoir sa bonne ambiance et sa bonne communication - n'a pas été démenti. Ni sang, ni larme, ni hurlement à rapporter, donc. Globalement, le niveau de stress de l'équipe est demeuré relativement bas... peut-être trop ? En eet, si cela nous a permis d'aborder sereinement les dicultés, cela a aussi pu parfois nous faire perdre le sens de l'urgence et des priorités. Dans la même tonalité, nous avons abordé la gestion des risques avec un peu trop d'optimisme, en négligeant les risques non inhérents à notre équipe mais pourtant bien réels, typiquement les faiblesses de l'infrastructure technique mise à notre disposition (serveur ensibm). Si ces problèmes n'avaient pas été rapidement résolus, notre avancement en aurait réellement souert, faute d'anticipation. Quant à la ponctualité que nous avions identiée comme une faiblesse dans la charte, elle s'est en n de compte révelée peu gênante. Les retards du matin pour certains ont été compensés par un travail plus tardif, selon les rythmes de chacun. Toutefois, durant l'intersection (non vide !) de ces diérentes plages horaires, la plus grande partie du travail a été comme nous l'avions prévu réalisée dans un lieu commun, ce qui nous a eectivement permis d'être très réactifs lors du développement : par exemple, un bug mis en évidence par un membre de l'équipe chargé des tests et de la validation pouvait être aussitôt rapporté au développeur, qui pouvait à son tour solliciter l'aide des autres membres de l'équipe an de le corriger. De même, les doutes concernant les choix de conception précédents, leurs faiblesses et leurs limitations par rapport aux nouvelles fonctionnalités exigées par l'itération courante pouvaient être immédiatement partagés (en particulier avec le chef de projet), étudiés et résolus. Une question technique, par exemple sur le détail d'un des langages utilisés, pouvait également trouver de cette manière une réponse immédiate en protant des compétences diverses des membres de l'équipe. 1 1.2 L'organisation Les choix principaux de notre organisation étaient initialement de désigner un chef de projet, xe, et de faire tourner les autres rôles au sein de l'équipe. Concernant le deuxième point, si nous avons eectivement permuté au cours du temps les tâches type développement et type validation (à première vue moins passionnantes1 ), il y a eu peu d'échange entre les parties B et C du projet. Parvenu à un certain niveau de complexité, il aurait été contre-productif de devoir se réapproprier l'architecture, l'esprit et l'ensemble des reexions menées sur une partie sans y avoir participé depuis le début. L'organisation s'est donc nalement stabilisée, en fonction des compétences techniques et préférences de chacun, autour de deux binômes développeur/testeur (Jorey/Amine pour la partie B, Kevin/Florence pour la partie C), les rôles alternant éventuellement au sein du binôme. Les deux membres conservaient un point de vue technique sur la partie concernée, ainsi les questions délicates de conception et d'algorithmique ont été résolues conjointement. Cette organisation segmentée nous a permis de mettre en évidence l'importance du chef de projet. En eet, de nous quatre, Jorey a pu et su garder une vision globale du projet et en particulier de l'architecture et du travail restant à réaliser, matérialisée par des notes synthétiques envoyées à l'ensemble de l'équipe. Bien qu'il n'existe pas de relation hiérarchique entre nous, et que la plupart des décisions aient été prises collectivement, nous avons jugé important qu'un membre de l'équipe puisse trancher et prendre une décision en cas de divergence, an que l'ensemble de l'équipe puisse avancer - notamment les décisions concernant les choix de conception à adopter. Jorey a parfaitement rempli ce rôle. 1 Bien que débusquer le test qui mettra au jour le bug dissimulé dans le code de ses co-équipiers ne soit pas dénué d'intérêt et demande un certain sens du dé... 2 2 Organisation et déroulement du projet 2.1 Planication Le planning prévisionnel établi en début de projet a été amené à évoluer de façon signicative. En eet, à mesure que notre connaissance du sujet gagnait en profondeur, nous nous sommes fait une idée plus claire des diérentes tâches et surtout du temps nécessaire à leur réalisation, et avons eectué divers changements de conception : il était donc logique de modier les durées allouées aux tâches inachevées et à venir. An de conserver cette souplesse du planning, des bilans informels étaient eectués à la n de chaque journée pour évaluer l'avancement de chacun et les tâches à attribuer. Nous avons de plus proté du rythme suggéré par les suivis et le rendu intermédiaire pour eectuer des bilans formels2 et plus en profondeur, au cours desquels le planning prévisionnel était systématiquement réévalué. 2.2 Historique et déroulement Après l'étape A, réalisée au début du projet, nous avons choisi de paralléliser la conception et le développement des étapes B et C, selon des itérations de complexité croissante : "Hello World" Mini-Deca (sans objet) Expressions simples Variables Structure de contrôle "If" Structure de contrôle "While" Deca (avec objet) Objet sans méthodes Objet avec méthodes Nous avions tablé au départ sur un parallélisme complet des étapes B et C, mais cela n'a pas toujours été le cas dans les faits, l'étape B progressant plus rapidement et "débordant" régulièrement de l'itération. La souplesse du planning nous a permis de nous adapter à cette progression asymétrique, en reportant les ressources ainsi libérées sur les tâches de documentations, et, en n de projet, sur la partie C, particulièrement exigeante sur les deux dernières itérations. Le fonctionnement par itérations est une des caractéristiques des méthodes de développement "agile", et nous nous sommes rendu compte que nous avions de façon naturelle adopté certaines de ces méthodes. En particulier, nous avons consacré relativement peu de temps à la conception des partie B et C au début du projet : lorsque l'objectif est de compiler un simple "Hello world", il est dicile d'imaginer et d'élaborer ecacement l'architecture adéquate pour compiler l'ensemble du langage. En revanche, à mesure de l'évolution des besoins à chaque itération, l'architecture à été anée et le code remanié an de le rendre plus léger, général et évolutif : la partie C en particulier a ainsi fait l'objet de nombreux "refactorings". Ne pas hésiter à revenir sur ce qui était déjà établi constituait une prise de risques certaine - surtout à l'approche des dates de rendu mais nous a en n de compte permis de soumettre un produit plus lisible. 2 toutes proportions gardées 3 En revanche, ce fonctionnement itératif a été moins respecté pour l'écriture des tests et la validation. De fait, accaparés par la compréhension du sujet, nous avons commencé tardivement l'écriture des tests - avec des conséquences néfastes, notamment : La négligence des tests de l'analyse lexicale en début de projet, d'où la détection après le rendu d'un bug pourtant simple à corriger, et que des tests adéquat aurait pu et du mettre en évidence bien plus tôt. Un manque de synchronisation entre le développement et la validation, de sorte que certains bugs du compilateur Mini-Deca n'ont été détectés qu'après le rendu intermédiaire. 2.3 Objectifs xés et réalisés Dès l'amorce de ce projet, notre équipe s'était xé deux objectifs : fournir un compilateur Deca fonctionnel pour la date de rendu (23 janvier 2012 à 16h) éventuellement aborder la réalisation, même partielle, de l'extension du produit initial, "Maxi-Deca" Le premier objectif a été accompli avec succès. En revanche, le second n'a pu être réalisé. En eet, le bon avancement du projet à son commencement nous avait laissé présager une bonne marge concernant le rendu du produit nal. Cependant, à 72h de la date butoir, nous avons du faire un choix entre : réaliser le second objectif et limiter l'exhaustivité des tests concernant le produit initial se focaliser sur le produit initial, et optimiser sa conception en essayant de factoriser le code au maximum et faciliter sa lisibilité Dans un souci de satisfaction du client, nous avons préféré nous concentrer sur l'optimisation et la validation du produit initial. An d'améliorer la lisibilité du code et le rendre plus évolutif, la conception de l'architecture du produit a été revue une dernière fois, nous avions donc besoin du temps restant pour garantir que ce remaniement n'aurait pas d'impact sur la fonctionnalité du produit. Cette stratégie a d'ailleurs porté ses fruits puisqu'en multipliant le nombre de tests, nous avons pu détecter certaines erreurs qui nous avaient échappé jusque-là. 4 3 Apport du projet 3.1 Apports personnels Le projet nous a permis de conrmer ou d'inrmer les caractéristiques personelles que nous avions décrites individuellement dans la che d'auto évaluation. 3.1.1 Jorey Si je devais résumer ce que ce projet m'a apporté concernant l'organisation, je dirais qu'étant chef de projet, j'ai appris qu'il fallait vraiment savoir gérer les priorités. Je suis personnellement très maniaque en terme de propreté du code, commentaires et choix des noms de variables, ce qui porte parfois préjudice à mon ecacité, surtout quand il s'agit de compléter du code écrit par quelqu'un d'autre (que je me sens alors obligé de remanier). Il faut donc que j'apprenne à déterminer correctement si j'ai le temps de m'occuper de ces détails qui sont, bien qu'importants, malgré tout secondaires. En terme de gestion de projet, il m'est apparu plus ecace aussi de prendre le temps de rééchir de manière précise aux tâches de chacun, plutôt que de dénir des rôles approximatifs qui au nal poussent à se reposer des questions et nuisent à la productivité. Cependant, il est dicile de savoir à l'avance quelles choses précises chacun pourra faire, et combien de temps cela prendra avant d'avoir une nouvelle tâche à assigner. 3.1.2 Kevin J'ai pour habitude lors de projets d'approfondir certains points qui m'intéressent. Cela me prend beaucoup de temps, mais je prends d'ordinaire sur mon temps libre pour assouvir ma curiosité . Lors du projet GL j'ai du déroger à ma règle pour me focaliser sur les choses essentielles sans m'égarer sur des questions qui sortent du cadre de ce projet, car nous étions tenu par le planning et que le temps était un élément clef a prendre en compte. Cela m'a donc forcé à travailler avec des contraintes de temps d'une part et d'autre part à beaucoup échanger avec mes co-équipiers avant d'entreprendre quelque-chose de façon à obtenir au nal un tout cohérent et uniforme, alors que je suis bien souvent autonome dans mon travail. Le projet GL fut pour ma part une bonne expérience de coopération et enrichissante également au niveau informatique. 3.1.3 Amine Quelques jours après avoir commencé le projet GL, nous avons rempli une che d'auto évaluation sur nos caractéristiques personnelles et techniques. L'un de mes traits de caractère qui me semblait le moins pertinent pour le projet était le leadership. En général, c'est un aspect que j'aime mettre en avant à travers les diérentes disciplines (sport, associations . . . ). Cependant, au vu des compétences techniques des autres membres de l'équipe, qui sont, il faut l'avouer, supérieures aux miennes, il m'a parut déplacé de vouloir faire preuve de leadership d'autant plus que je ne faisais pas partie des membres de l'équipe qui maitrisaient le mieux le sujet. J'ai ainsi été étonné de voir que j'ai fait preuve de leadership malgré moi en me souciant régulièrement du respect du planning, de la mise à jour de ce dernier, mais également de s'assurer que chacun respecterait ses engagements, moi inclus. Je pense que le projet m'a permis d'avoir le sens des responsabilités dans une nouvelle discipline : le travail scolaire en équipe (car jusque là, la plupart des projets se faisaient par binôme, et les durées de projets étaient bien plus longues que le projet GL). En eet, lorsque vous savez qu'un de vos collègues ne peut avancer dans son travail, tant que votre tâche n'est pas accomplie, 5 vous avez une pression positive qui dynamise votre travail et qui optimise votre rendement (ce qui rejoint une autre caractéristique commune de l'équipe : l'absence de stress). 3.1.4 Florence Issue d'une formation plutôt axée sur le calcul scientique, j'abordais le projet GL avec une certaine appréhension technique : je n'avais que très peu "touché" aux divers sujets abordés (théorie des langages, langage d'assemblage...) et encore moins au langage utilisé pour le développement ; je craignais donc d'être un poids pour l'équipe. Je me suis cependant rendu compte que j'étais capable d'assimiler rapidement ces nouveaux aspects techniques, et de m'adapter en comblant mes manques éventuels par une recherche ecace d'information, an d'apporter une réelle contribution à l'avancement du projet : j'ai donc particulièrement pris conance en la "débrouillardise" mentionnée sur ma che d'évaluation. L'organisation et la planication n'ont jamais été mon point fort : lors des précédents projets réalisés en binôme, j'avais souvent tendance à m'éparpiller et à laisser des questions certes importantes mais non pertinentes lors des premiers stades bloquer mon avancement en début de projet - quitte à compenser en prenant sur moi une grosse partie du travail à réaliser en urgence en n de projet. Un tel fonctionnement est bien entendu inapplicable dans le cadre du projet GL, à cause des contraintes de temps et des étroites dépendances entre les tâches réalisées par les diérents membres de l'équipe. Le développement itératif et le cadre formé par l'équipe m'ont donc aidée à dépasser cette faiblesse en me focalisant sur l'essentiel et en respectant la planication des tâches à réaliser. 6 4 Conclusion et facteurs clés de succès Le premier conseil que nous pourrions donner aux futurs élèves, serait de constituer au plus tôt leur équipe de façon à s'entourer de personnes avec lesquelles ils pourraient travailler à plein temps, dans la bonne humeur et sans créér de conits. Nous avons pu réaliser à quel point la bonne entente au sein d'un groupe était primordiale, en voyant la tournure que prenaient les choses dans certaines équipes au fur et à mesure que les échéances approchaient. Ces trois semaines nous ont permis de nous rendre compte que le niveau technique d'une équipe ne sut pas à assurer le bon déroulement et la nalité d'un projet tel que celui-ci, s'il n'est pas soumis à une certaine rigueur et à une organisation carrée. Même en équipe de quatre il devient nécessaire d'avoir un bon équilibre entre les domaines techniques et relationnels, d'où l'importance des interventions de l'équipe SHEME. Le second conseil serait donc de ne pas prendre la préparation des suivis comme une perte de temps mais au contraire de rentabiliser ce temps pour faire le point sur l'avancement du projet et revoir si besoin le planning. Les suivis se sont en fait imposés d'eux mêmes comme des jalons, et en particulier le rendu intermédiaire qui permettait à mi-parcours d'avoir un compilateur fonctionnel pour le langage Deca non objet. Enn, d'un point de vue plus technique, nous avons pris conscience de l'importance cruciale de la validation dans le cycle de développement. Certains cas tests peuvent paraître sur le moment inutiles ou superus et permettent cependant de détecter des erreurs, inévitables sur un projet de cette taille, souvent faciles à corriger mais néfastes pour la crédibilité du produit. Notre conseil serait donc de ne pas négliger cette étape et d'y consacrer une part importante des ressources dès le début du projet. 7 5 Annexe - Planning eectif du projet 2EQI %REP]WI PI\MGSW]RXE\MUYI 0I\IYV 4EVWIYV 'SYVW 8( 6¬HEGXMSR HI PE GLEVXI HI XVEZEMP %GXMZMX¬W 4IVWSRRIPPIW 7OM 'SQTMPEXIYV K¬VERX ,IPPS ;SVPH 0IGXYVI (SGYQIRXEXMSR 8IWXW %REP]WI GSRXI\XYIPPI +IWXMSR HI PE XEFPI HIW W]QFSPIW -QTPIQIRXEXMSR HI PE +VEQQ %XXVMFY¬I +¬R¬VEXMSR HI GSHI %REP]WI HIW IVVIYVW GSRXI\XYIPPIW -QTP¬QIRXEXMSR HIW IVVIYVW GSRXI\XYIPPIW 'SQTMPEXIYV WERW SFNIX )\TVIWWMSRW 7MQTPI )XETI & )XETI ' )GVMXYVI HIW TVSKVEQQI HI XIWXW 8IWXW :EVMEFPIW )XETI & )XETI ' )GVMXYVI HIW TVSKVEQQI HI XIWXW 8IWXW (IFSKEKI 7XVYGXYVI GSRHMXMSRRIPPI -J )XETI & )XETI ' )GVMXYVI 8IWXW 4EVXMI & )GVMXYVI 8IWXW 4EVXMI ' 8IWXW (IFSKEKI &SYGPI ;LMPI )XETI & )XETI ' )GVMXYVI 8IWXW 4EVXMI & )GVMXYVI 8IWXW 4EVXMI ' 8IWXW (IFSKEKI 'SQTMPEXIYV TSYV PE XSXEPMX¬ HY PERKEKI 6IZYI H EVGLMXIGXYVI 4EVXMI ' 3FNIXW 7ERW Q¬XLSHIW )XETI & )XETI & (¬GSVEXMSR )XETI ' )GVMXYVI 8IWXW 4EVXMI & )GVMXYVI 8IWXW 4EVXMI ' 8IWXW (IFSKEKI 3FNIXW EZIG Q¬XLSHIW )XETI & )XETI & (IGSVEXMSR )XETI ' )GVMXYVI HIW 8IWXW 4EVXMI & )GVMXYVI HIW 8IWXW 4EVXMI ' 8IWXW (IFSKEKI 'EWX -RWXERGI SJ )XETI & )XETI ' )GVMXYVI HIW 8IWXW 4EVXMI & )GVMXYVI HIW 8IWXW 4EVXMI ' 8IWXW (IFSKEKI (SGYQIRXEXMSR 9XMPMWEXIYV (SGYQIRXEXMSR 'SRGITXMSR (SGYQIRXEXMSR :EPMHEXMSR 6IRHY ZIVWMSR MRXIVQ¬HMEMVI 6IRHY *MREP 6IRHY HSGYQIRXEXMSR 6IRHY &MPER 7SYXIRERGI ;SVO ;IIO ;IIO ;IIO ;IIO 1 H H H H H H H L H L H L H L H H L H L H H H L H L H L H L L H L H H L H L H L H L H L H H L L H L H L H L H L H L L H L H L H L H L H L H H L H L H H L H L H L H L L H L H L H L H L L L *PSVIRGI %QMRI .SJJVI] /IZMR .SJJVI] /IZMR *PSVIRGI %QMRI .SJJVI] /IZMR *PSVIRGI %QMRI .SJJVI] ? A %QMRI ? A .SJJVI] /IZMR *PSVIRGI %QMRI .SJJVI] /IZMR *PSVIRGI %QMRI /IZMR .SJJVI] .SJJVI] /IZMR %QMRI *PSVIRGI /IZMR *PSVIRGI /IZMR .SJJVI] /IZMR *PSVIRGI %QMRI .SJJVI] %QMRI *PSVIRGI /IZMR /IZMR *PSVIRGI .SJJVI] %QMRI /IZMR *PSVIRGI /IZMR *PSVIRGI .SJJVI] %QMRI /IZMR *PSVIRGI *PSVIRGI /IZMR .SJJVI] /IZMR *PSVIRGI %QMRI .SJJVI] %QMRI /IZMR *PSVIRGI *PSVIRGI /IZMR %QMRI .SJJVI] /IZMR *PSVIRGI .SJJVI] *PSVIRGI .SJJVI] %QMRI .SJJVI] /IZMR *PSVIRGI .SJJVI] %QMRI *PSVIRGI .SJJVI] /IZMR *PSVIRGI %QMRI .SJJVI] .SJJVI] /IZMR %QMRI *PSVIRGI .SJJVI] /IZMR *PSVIRGI %QMRI L H H L H L .SJJVI] /IZMR *PSVIRGI .SJJVI] /IZMR *PSVIRGI %QMRI .SJJVI] /IZMR *PSVIRGI %QMRI 8