INF123 - Examen 12 mai 2016 Éléments de correction Partie 1 : Ensembles de mots (∼ 5 points) Question 1 : (0,5 point) Dessinez un exemple de valeur de la variable noms (déclarée ligne 21) représentant l’ensemble {crayon, chat, papillon, gendarme, potage, bateau}. tab crayon card 6 chat papillon gendarme potage bateau Question 2 : (2,5 points) Écrivez les fonctions : — init vide (lignes 23-25) qui initalise un ensemble vide. — est vide (lignes 27-29) qui retourne 1 si e est vide, 0 sinon. — chercher (lignes 31-33) qui recherche le mot m dans l’ensemble e et qui retourne — l’indice où se trouve m s’il est présent dans e, — -1 sinon. — ajouter (lignes 35-37) qui ajoute le mot m à l’ensemble e, s’il n’est pas déjà présent. void i n i t v i d e ( ens mots ∗e ) { e−>c a r d=0 ; } i n t e s t v i d e ( ens mots ∗e ) { r e t u r n e−>c a r d==0 ; } i n t ch er c he r ( ens mots ∗e , char m[ ] ) { i n t i =0 ; w h i l e ( i <e−>c a r d && strcmp ( e−>tab [ i ] , m) ) { i++ ; } i f ( i==e−>c a r d ) r e t u r n −1 ; e l s e return i ; } void a j o u t e r ( ens mots ∗e , char m[ ] ) { int i ; i=c h e r c h e r ( e , m) ; i f ( i ==−1) { s t r c p y ( e−>tab [ e−>c a r d ] , m) ; e−>c a r d++ ; } } Question 3 : (2 points) Écrivez la fonction initialiser (lignes 39-41) qui initialise l’ensemble de mots m à partir des mots contenus dans le fichier de nom nom fich. Si l’ouverture du fichier est impossible, un message d’erreur approprié est affiché et le programme se termine. void i n i t i a l i s e r ( ens mots ∗e , char nom fich [ ] ) { FILE ∗ f ; c h a r mot [LG MAX MOTS] ; f=f o p e n ( n o m f i c h , ” r ” ) ; i f ( f==NULL) { f p r i n t f ( s t d e r r , ” o u v e r t u r e de %s i m p o s s i b l e \n ” , n o m f i c h ) ; exit (2) ; } init vide (e) ; f s c a n f ( f , ”%s ” , mot ) ; while ( ! f e o f ( f )) { a j o u t e r ( e , mot ) ; f s c a n f ( f ,”% s ” , mot ) ; } fclose ( f ) ; } Partie 2 : Lignes (∼ 5 points) Question 4 : (2 points) Écrivez la fonction lire ligne (lignes 43-46) dont la spécification est la même que la fonction lire ligne de l’interpréteur : f étant un descripteur de fichier ouvert en lecture, la fonction lit et stocke dans phrase la prochaine ligne de ce fichier sous la forme d’une chaı̂ne de caractères, c’est-à-dire en remplaçant le ’\n’ par ’\0’. Elle renvoie 0 si la fin de fichier est atteinte sans qu’aucun caractère n’ait été lu, 1 sinon. i n t l i r e l i g n e ( FILE ∗ f , c h a r p h r a s e [ ] ) { char c ; i n t i =0 ; f s c a n f ( f , ”%c ” , &c ) ; w h i l e ( ! f e o f ( f ) && c ! = ’ \ n ’ ) { p h r a s e [ i ]= c ; i++ ; f s c a n f ( f , ”%c ” , &c ) ; } phrase [ i ]= ’\0 ’ ; i f ( f e o f ( f ) && ( i ==0)) r e t u r n 0 ; e l s e return 1 ; } Question 5 : (3 points) Écrivez la fonction prochain mot. v o i d p r o c h a i n m o t ( c h a r p h r a s e [ ] , i n t ∗ i n d c o u r , c h a r mot [ ] ) { i n t i =0 ; i n t j =∗ i n d c o u r ; w h i l e ( p h r a s e [ j ]== ’ ’ ) { j++ ; } w h i l e ( p h r a s e [ j ] ! = ’ \ 0 ’ && p h r a s e [ j ] ! = ’ ’ ) { mot [ i ]= p h r a s e [ j ] ; i ++; j ++; } mot [ i ] = ’ \ 0 ’ ; ∗ i n d c o u r=j ; } Partie 3 : Automate reconnaisseur (∼ 5 points) Question 6 : (1 point) Dessinez l’automate obtenu en ajoutant un nouvel état de numéro 6 vers lequel vont toutes les transitions qui ne sont pas dessinées sur l’automate de la figure 3, en particulier les transitions étiquetées par INCONNU. Indication : l’état 6 est un état puits, c’est-à-dire que toutes les transitions issues de l’état 6 mènent à l’état 6. 2 ARTICLE NOM 0 VERBE 1 ARTICLE 2 NOM 3 4 5 <>VERBE <>ARTICLE <>NOM <>NOM 6 <> ARTICLE TOUT TOUT Question 7 : (1 point) En considérant l’ensemble d’entrées {ARTICLE, ADJECTIF, NOM, VERBE, CONJONCTION, INCONNU}, complétez l’automate pour tenir compte des adjectifs et des conjonctions. Veillez à ce que de chaque état soit issue une et une seule transition pour chaque entrée possible. CONJONCTION ADJECTIF ADJECTIF ADJECTIF ADJECTIF ARTICLE 0 NOM VERBE 1 2 ARTICLE 3 4 NOM 5 <>{VERBE, ADJECTIF} <.>{NOM, ADJECTIF} <>ARTICLE <.>{NOM, ADJECTIF} 6 <>{CONJONCTION, ADJECTIF} <> ARTICLE TOUT Question 8 : (1 point) Représentez la fonction de transition de votre automate par un tableau à deux dimensions dont les lignes sont indexées par les numéros des états (de 0 à 6), et les colonnes par les entrées. Etat\Entree 0 1 2 3 4 5 0 ARTICLE 1 6 6 4 6 6 6 ADJECTIF 6 1 2 6 4 5 6 NOM 6 2 6 6 5 6 6 VERBE 6 6 3 6 6 6 6 CONJONCTION 6 6 6 6 6 0 6 INCONNU 6 6 6 6 6 6 6 Question 9 : (2 points) La fonction analyse renvoie 1 si la chaı̂ne phrase en argument est reconnue par l’automate, 0 sinon. À l’aide des fonctions prochain mot et nature mot, complétez cette fonction. i n t analyse ( char phrase [ ] ) { i n t t r a n s i t i o n [ 7 ] [ 6 ] ={ /∗ de 0 ∗ / { 1 , 6 , 6 , 6 , 6 , 6 } , /∗ de 1 ∗ / { 6 , 1 , 2 , 6 , 6 , 6 } , /∗ de 2 ∗ / { 6 , 2 , 6 , 3 , 6 , 6 } , /∗ de 3 ∗ / { 4 , 6 , 6 , 6 , 6 , 6 } , /∗ de 4 ∗ / { 6 , 4 , 5 , 6 , 6 , 6 } , /∗ de 5 ∗ / { 6 , 5 , 6 , 6 , 0 , 6 } , /∗ t o u t bon ∗/ /∗ de 6 ∗ / { 6 , 6 , 6 , 6 , 6 , 6} /∗ p o u b e l l e ∗/ } ; i n t i =0 ; c h a r mot [LG MAX MOTS] ; i n t e t a t c o u r =0 ; 3 int etat suiv ; int entree ; while ( phrase [ i ]!= ’\0 ’) { p r o c h a i n m o t ( p h r a s e , &i , mot ) ; e n t r e e=n a t u r e m o t ( mot ) ; e t a t s u i v=t r a n s i t i o n [ e t a t c o u r ] [ e n t r e e ] ; e t a t c o u r=e t a t s u i v ; } r e t u r n ( e t a t c o u r ==5) ; } Partie 4 : Shell (∼ 2 points) Question 10 : (2 points) Écrivez un script shell qui prend en arguments un ou plusieurs noms de fichiers contenant des phrases et qui affiche pour chacun d’eux : — les phrases du fichier <nom du fichier> sont correctes si toutes les phrases du fichier son correctes — le fichier <nom du fichier> contient au moins une phrase incorrecte sinon. De plus, le script affichera un message d’erreur si aucun argument ne lui est fourni, ou si un des arguments n’est pas le nom d’un fichier existant. Indications : Si toutes les phrases du fichier analysé sont correctes, le programme analyser ne produit pas d’affichage. Sinon, une ligne est affichée par l’instruction de la ligne 113. On rappelle (cf memo-bash) que le test [ -n <cha^ ıne> ] vaut vrai si la chaı̂ne n’est pas vide. #!/ b i n / bash i f [ $# −eq 0 ] then echo $0 n e c e s s i t e au moins un argument exit fi for do file in $∗ i f [ ! −f $ f i l e ] then echo ” $ f i l e n ’ e x i s t e pas ” else i n c o r r e c t=$ ( . / a n a l y s e r A r t i c l e s Noms A d j e c t i f s Verbes C o n j o n c t i o n s $ f i l e | g r e p ’ pas c o r r e c t e ’ ) i f [ −n ” $ i n c o r r e c t ” ] then echo ” $ f i l e c o n t i e n t au moins une p h r a s e i n c o r r e c t e ” else echo ” l e s p h r a s e s du f i c h i e r $ f i l e s o n t c o r r e c t e s ” fi fi done Partie 5 : Intersection d’ensembles (∼ 3 points) Question 11 : (2 points) Écrivez une fonction de profil void intersection(ens mots *A, ens mots *B, ens mots *C) (lignes 80-82) qui construit dans C l’intersection des ensembles A et B. Indications — Utilisez les fonctions sur les ensembles de mots de la partie 1. — Les ensembles ne sont pas triés. Un algorithme possible est le suivant : pour chaque élément de A, on cherche s’il est dans B, si oui, on l’ajoute à C. v o i d i n t e r s e c t i o n ( e n s m o t s ∗A, e n s m o t s ∗B, e n s m o t s ∗C) { 4 int i ; i n i t v i d e (C) ; f o r ( i =0 ; i < A−>c a r d ; i ++) { i f ( c h e r c h e r (B, A−>tab [ i ] ) != −1) { a j o u t e r (C, A−>tab [ i ] ) ; } } } Question 12 : (1 point) Complétez la fonction main en signalant par un message si les ensembles des noms et des adjectifs, ou si les ensembles des noms et des verbes, ont une intersection non vide (on ne teste pas d’autres intersections d’ensembles). Ne recopiez pas toute la fonction main, indiquez les modifications apportées à l’aide des numéros de lignes. e n s m o t s InterNomsAdjs , InterNomsVerbes ; i n t e r s e c t i o n (&noms , &a d j e c t i f s , &InterNomsAdjs ) ; i n t e r s e c t i o n (&noms , &v e r b e s , &InterNomsVerbes ) ; i f ( ! e s t v i d e (& InterNomsAdjs ) ) { p r i n t f ( ” A t t e n t i o n : homonymies e n t r e noms e t a d j e c t i f s \n ” ) ; } i f ( ! e s t v i d e (& InterNomsVerbes ) ) { p r i n t f ( ” A t t e n t i o n : homonymies e n t r e noms e t v e r b e s \n ” ) ; } Bonus : intersection de séquences triées (∼ 2 points) Question 13 : (2 points) a) La fonction intersection que vous avez écrite à la question 11 répond-elle au problème (c’est-à-dire, si A et B sont triés, est-ce que C l’est) ? Justifiez votre réponse b) En tirant parti du fait que A et B sont triés, écrivez une nouvelle fonction C intersection triee (lignes 84-86) plus efficace. On rappelle que la comparaison selon l’ordre lexicographique des chaı̂nes de caractères s’effectue avec la fonction int strcmp(char ch1[], char ch2[]) dont le résultat est négatif, nul ou positif selon que ch1 est avant ch2, égal à ch2, ou après ch2 dans l’ordre lexicographique. a) Oui : les mots de A, triés par ordre croissants sont examinés dans cet ordre et insérés le cas échéant selon le même ordre. v o i d i n t e r s e c t i o n t r i e e ( e n s m o t s ∗A, e n s m o t s ∗B, e n s m o t s ∗C) { int i , j , k ; i n t rescomp ; i n i t v i d e (C) ; i =0 ; j =0 ; k=0 ; w h i l e ( i < A−> c a r d && j < B−> c a r d ) { rescomp= strcmp (A−>tab [ i ] , B−>tab [ j ] ) ; i f ( rescomp==0) { s t r c p y (C−>tab [ k ] , A−>tab [ i ] ) ; i++ ; j++ ; k++ ; } e l s e i f ( rescomp <0) i++ ; else j ++; } C−>c a r d=k ; } 5