Lanalyse lexicale a pour but de retrouver les symboles utilisés par le programmeur à partir de la suite de caractères du texte source. Pour cela, lorsque lon est sur le premier caractère dun symbole, on recherche où il finit, selon la définition de la structure lexicale du langage. Puis, layant reconnu, il est en général codé pour la suite des traitements. Ensuite, on recherche où commence le symbole suivant,
Pour lanalyse lexicale de la première phrase Truc and A = 23, on commence donc par se positionner sur le premier caractère du premier symbole, cest-à-dire T. Sagissant dune lettre, cest donc le début dun identificateur ou dun mot clé. La fin est donc obtenue lorsque lon rencontre un caractère qui nest pas une lettre, cest-à-dire lespace qui suit c. Notre premier symbole est donc lidentificateur Truc. La recherche du début du symbole suivant nous conduit à sauter lespace sans signification et le symbole suivant commence sur le a. Comme précédemment, il sagit dun identificateur ou dun mot réservé, qui se termine sur le d précédant lespace. Nous avons donc le mot réservé and. De même, on isole le symbole suivant qui est lidentificateur A. Ensuite, la recherche du début du symbole suivant nous conduit sur le caractère = qui constitue à lui seul un symbole. Enfin, le symbole suivant commence sur le caractère 2. Il sagit donc dun entier qui se termine sur le premier caractère qui nest pas un chiffre, donc sur la fin de la ligne, et le dernier symbole est donc 23. Nous avons donc le découpage suivant :
Truc and A = 23
Lanalyse de la ligne suivante nous permet disoler dabord le mot réservé not, puis lidentificateur C et le symbole =. Ensuite, le symbole suivant commence sur le 1 qui est un chiffre et sarrête donc sur le premier caractère qui nest pas un chiffre, donc le point. Nous obtenons le symbole entier 1. Le symbole suivant commence sur le point, qui nappartient pas à lensemble des caractères du langage. Il y a donc erreur syntaxique, et lanalyse sarrête.
not C = 1.2
Les lignes suivantes ne posent guère de difficulté, et sanalysent comme nous lavons détaillé précédemment. Nous obtenons les découpages suivants :
A = 12 or 13
A not B
Notons que ce nest pas à lanalyse lexicale de trouver les erreurs syntaxiques ou sémantiques.
Lanalyse syntaxique a pour but de retrouver les règles de syntaxe utilisées par le programmeur pour construire la suite de symboles. Nous partons donc maintenant de la suite de symboles obtenue après analyse lexicale, lorsque celle-ci est correcte, pour trouver les règles utilisées. La première règle part de <condition>, et le développement doit nous permettre daboutir aux symboles eux-mêmes de la phrase analysée. On peut représenter cette suite par un arbre qui décrit ainsi la structure syntaxique de la phrase.
Pour les deux premières phrases, lanalyse est relativement simple. Elle peut être effectuée comme cela a été fait dans les exercices 2.1 et 2.2 du polycopié dexercices. On cherche à développer <condition> en utilisant lune des règles possibles, quil faut essayer successivement, en cas de refus, jusquà trouver le bon choix, ou déceler lerreur syntaxique sil ny en a plus. On obtient les deux arbres suivants.
Pour la troisième, on effectue le développement de la même façon, et nous obtenons :
<condition> -> <facteur> -> <terme> -> <primaire> -> <élément> -> <identificateur> -> A
A ce stade, la phrase continue, mais lanalyse ne peut se poursuivre. Il faudrait donc trouver un autre développement, qui nexiste pas. Il y a donc erreur syntaxique sur le symbole not.
Lanalyse sémantique a pour but de retouver le sens de la phrase, et de déterminer ainsi la suite des opérations à effectuer sur les données. Pour cela, on utilise la structure syntaxique obtenue précédemment. On détermine, dabord les objets manipulés et leurs propriétés. Ensuite, on reporte ces informations dans le graphe, en propageant les propriétés, et en contrôlant leur cohérence. On détermine ainsi la signification des opérations.
Ainsi, pour la première phrase, il y a trois objets Truc (booléen), A (entier) et 23 (entier). En propageant le type entier des deux derniers, on en déduit que légalité est lopération entre entiers, avec un résultat booléen. La propagation au niveau de lopérateur and montre la cohérence de lensemble.
Le graphe suivant décrit les opérations à effectuer. Les valeurs des opérandes et du résultat sont mis entre paranthèses.
De même, pour la deuxième phrase, il y a aussi 3 objets, tous trois entiers, que sont A, 12 et 13. En propageant le type entier des deux premiers, on en déduit que légalité est lopération entre entiers, avec un résultat booléen. La poursuite de la propagation montre la cohérence de type pour lopérande de gauche de or. La propagation du type entier du troisième objet montre une incohérence de type pour lopérande de droite de or (on a un type entier alors quon attend un type booléen). On décèle ainsi une erreur sémantique pour la deuxième phrase.
Dans le système FAT, il y a deux contraintes : il ne peut y avoir plus de 65535 clusters, et le cluster ne peut dépasser 255 secteurs. Le disque comportant 222 secteurs, si on veut que la taille dun cluster soit une puissance de 2, il ne peut dépasser 128 secteurs. Le choix proposé est donc cohérent avec les contraintes, puis que lon a alors 32768 clusters. Notons quune taille de 64 secteurs serait néanmoins acceptable, sous réserve de ne pas disposer de tout lespace, puisquil nous faudrait 65536 clusters, et quil faut pouvoir coder la fin de fichier et létat libre des clusters.
Dans ces conditions, une piste contient 2 clusters, et un cylindre en contient 8. Lespace alloué au fichier est donc constitué des clusters suivants dans lordre : 256, 257, 387, 516, 517, 130, 134, 135. Cela veut dire que le descripteur du fichier contient le numéro de cluster 256 (le premier), et dans la FAT proprement dite, on a les valeurs suivantes pour les entrées de numéro indiqué.
index |
256 |
257 |
387 |
516 |
517 |
130 |
134 |
135 |
valeur |
257 |
387 |
516 |
517 |
130 |
134 |
135 |
EOF |
Pour accéder à un secteur logique de numéro ni du fichier, on commence par rechercher le cluster auquel il appartient, en divisant ce numéro par la taille du cluster en secteurs, cest-à-dire 128. On parcours ensuite la FAT jusquà trouver le cluster physique correspondant. On détrermine ainsi le numéro virtuel du secteur recherché, que lon transforme en triplet <nc, nf, ns> prenant en compte la linéarisation de lespace.
Pour le secteur 5, il sagit dont du secteur relatif 5 du cluster logique 0, qui correspond au cluster physique 256. Il sagit donc du secteur virtuel 256*128+5=32773. Il sagit donc du secteur relatif 32773 mod 1024=5 du cylindre 32773/1024=32, et donc du secteur 5 de la face 0 du cylindre 32. On a donc le triplet <32, 0, 5>.
Pour le secteur 100, il sagit du secteur relatif 100 du cluster logique 0, donc le secteur virtuel 256*128+100=32868. Cest donc cette fois le secteur 100 du cylindre 32, et donc le secteur 100 de la face 0 du cylindre 32, soit <32, 0, 100>
Pour le secteur 800, il sagit du secteur relatif 800 mod 128= 32 du cluster logique 800/128=6. Le parcours de la FAT nous donne 256 (0)->257 (1)->387 (2)->516 (3)->517 (4)->130 (5)->134 (6). Il sagit donc du secteur 32 du cluster physique 134, soit le secteur virtuel 134*128+32=17184. Cest donc le secteur relatif 17384 mod 1024=800 du cylindre 17384/1024=16, qui est le secteur 800 mod 256=32 de la piste située sur la face 800/256=3. On a donc le triplet <16, 3, 32>
Dans le système HFS, on a les mêmes contraintes pour la taille du quantum que pour la taille du cluster du système FAT. La justification dune taille de quantum de 128 secteurs est donc la même.
Dans HFS, lallocation est par zones de taille variable. Les données montrent lexistence de 5 zones, qui peuvent être décrites comme suit : <256, 2>, <387, 1>, <516, 2>, <130, 1>, <134, 2>, où le premier nombre indique le premier bloc physique de la zone et le deuxième le nombre de blocs de la zone. Le descripteur de fichier lui-même contient la description des trois premières zones, cest-à-dire :
Le fichier de description des extensions contiendra la description des deux autres zones. Ce fichier contiendra donc un article constitué des éléments suivants :
Pour accéder à un secteur logique de numéro ni du fichier, il faut déterminer le numéro du bloc logique auquel il appartient et la position relative du secteur logique dans ce bloc (quotient et reste da la division par 128 ici), puis rechercher la zone à la quelle appartient ce bloc logique, en parcourant la liste des zones. Lorsque lon a trouvé la zone, et donc le numéro du premier bloc physique de la zone, on détermine alors le numéro virtuel du secteur recherché, que lon transforme en triplet <nc, nf, ns> prenant en compte la linéarisation de lespace.
Pour le secteur 5, il sagit du secteur relatif 5 du bloc logique 0, qui est le premier bloc de la première zone, qui commence au bloc physique 256. Il sagit donc du secteur virtuel 256*128+5=32773. Il sagit donc du secteur relatif 32773 mod 1024=5 du cylindre 32773/1024=32, et donc du secteur 5 de la face 0 du cylindre 32. On a donc le triplet <32, 0, 5>.
Pour le secteur 100, il sagit du secteur relatif 100 du bloc logique 0, donc le secteur virtuel 256*128+100=32868. Cest donc cette fois le secteur 100 du cylindre 32, et donc le secteur 100 de la face 0 du cylindre 32, soit <32, 0, 100>
Pour le secteur 800, il sagit du secteur relatif 32 du bloc logique 6. Ce bloc nest pas dans la première zone qui contient les bloc logiques 0 et 1, ni dans la seconde qui contient le bloc logique 2, ni dans la troisième qui contient les blocs logiques 3 et 4. Un accès au fichier de descriptions des extensions nous fournit la description des quatrième et cinquième zones. Le bloc nest pas non plus dans la quatrième zone qui contient le bloc 5. On constate que le bloc 6 est donc le premier bloc de la cinquième zone, qui commence au bloc physique 134. Le secteur recherché est donc le secteur virtuel 134*128+32=17384. Cest donc le secteur relatif 17384 mod 1024=800 du cylindre 17384/1024=16, qui est le secteur 800 mod 256=32 de la piste située sur la face 800/256=3. On a donc le triplet <16, 3, 32>
Dans le système UNIX, lallocation est par bloc de taille fixe, ici 2 secteurs, soit 1024 octets. Dans notre configuration, cela veut dire 128 blocs par piste, et 512 blocs par cylindre. Lespace attribué au fichier est dont constitué :
La représentation de lespace alloué au fichier est réparti en plusieurs niveaux, en utilisant au besoin des blocs contenant des numéros de blocs. En supposant les numéros de blocs sur 32 bits, ou 4 octets, un bloc peut contenir 256 numéros de blocs.
Les 10 premiers blocs du fichier sont conservés dans la table TABDIRECT du descripteur de fichier. Cette table contient donc dans lordre 16384, 16385, , 16393.
Les 256 blocs suivants doivent être mémorisés dans un " bloc contenant des numéros de blocs ", et repéré par INDIRECT_1 dans le descripteur du fichier. Pour cela nous prendrons un bloc dans le cylindre 8, par exemple le premier, de numéro 4096 (8*512). Ce bloc contiendra :
Les blocs suivants doivent être mémorisés dans des " blocs contenant des numéros de blocs ", dont les numéros sont mémorisés dans un bloc repéré par INDIRECT_2 dans le descripteur du fichier. Pour cela nous prendrons dabord un bloc dans le cylindre 8, par exemple le second, de numéro 4097 (8*512+1), pour contenir les numéros de blocs de données suivants :
Enfin, nous prendrons un dernier bloc dans le cylindre 8, par exemple le troisième de numéro 4098 (8*512+2), pour repérer le bloc précédent. Il contiendra donc 4097. Le numéro de ce bloc sera dans INDIRECT_2. Nous pouvons donc décrire lensemble par la figure suivante :
Pour accéder à un secteur logique de numéro ni du fichier, on commence par déterminer sil est dans un bloc repéré par TABDIRECT, ou un des blocs INDIRECT. Selon les cas, on doit lire les blocs pointeurs de blocs jusquà trouver le numéro du bloc physique.
Pour le secteur 5, il sagit du secteur 1 du bloc logique 2. Son numéro de bloc physique est obtenu dans lentrée dindice 2 de TABDIRECT. Il sagit donc du bloc physique 16386. Il sagit donc du secteur virtuel 2*16386+1=32773. Il sagit donc du secteur relatif 32773 mod 1024=5 du cylindre 32773/1024=32, et donc du secteur 5 de la face 0 du cylindre 32. On a donc le triplet <32, 0, 5>.
Pour le secteur 100, il sagit du secteur 0 du bloc logique 50. Le numéro de ce bloc est contenu dans le bloc INDIRECT_1 : il sagit de lentrée 40 (50-10) du bloc 4096, qui contient 16434. Cest donc le secteur virtuel 2*16434+0=32868. Cest donc cette fois le secteur 100 du cylindre 32, et donc le secteur 100 de la face 0 du cylindre 32, soit <32, 0, 100>
Pour le secteur 800, il sagit du secteur 0 du bloc logique 400. Cest le bloc relatif 134 (400-10-256) de lensemble des blocs repérés depuis INDIRECT_2. Il faut donc lire le bloc 4098, puis le bloc 4097, et prendre lentrée 134 de ce bloc, ce qui donne le bloc 8592. Cest donc le secteur virtuel 2*8592+0=17384. Cest donc le secteur relatif 17384 mod 1024=800 du cylindre 17384/1024=16, qui est le secteur 800 mod 256=32 de la piste située sur la face 800/256=3. On a donc le triplet <16, 3, 32>
Un processus peut se trouver dans différents états, suivant qu'il dispose de tout ou partie des ressources dont il a besoin pour s'exécuter. On distingue la ressource processeur de l'ensemble des autres ressources. En effet, s'il manque une ressource autre que le processeur, celui-ci ne peut faire évoluer le processus et il est donc inutile que cette ressource chère lui soit allouée. Lorsqu'il manque à un processus une ressource autre que le processeur, il est dans l'état bloqué. Lorsqu'un processus a toutes ses ressources à l'exception du processeur, il est dans l'état prêt. Enfin lorsqu'un processus a toutes ses ressources, y compris le processeur, il est dans l'état actif. L'allocation du processeur consiste à choisir un processus dans l'état prêt, et à lui allouer le processeur, le faisant passer dans l'état actif (transition 3). Un processus actif peut perdre le processeur, et repasser dans l'état prêt lorsque le système désire allouer le processeur à un autre processus (transition 2). Lorsqu'un processus actif demande une ressource qui n'est pas disponible, il passe dans l'état bloqué, et le processeur lui est retiré (transition 1). Lorsque la ressource demandée par un processus devient disponible, elle peut lui être allouée; le processus a alors toutes ses ressources sauf la ressource processeur et passe donc dans l'état prêt (transition 4).
Le processus est dans l'état bloqué lorsqu'il n'a pas toutes ses ressources, à l'exception de la ressource processeur. Pour passer dans cet état, il faut qu'il lui manque une ressource, soit parce qu'on la lui a retiré, ce qui n'est pas prévu ici, soit parce qu'il exprime un nouveau besoin, ce qui implique qu'il dispose du processeur pour exprimer ce besoin, c'est-à-dire qu'il soit actif. En conséquence, la seule transition vers l'état bloqué ne peut venir que de l'état actif. Par ailleurs, un processus quitte l'état bloqué lorsqu'il a toutes ses ressources pour s'exécuter, à l'exception de la ressource processeur, ce qui interdit la transition directe de bloqué à actif.
P1 est lancé à linstant 0, il est donc prêt, et comme il est seul, il devient actif. Au temps 10 ms son opération disque, lecture de B1, est lancée, il passe donc dans létat bloqué. En même temps, P2 est lancé, devient prêt et passe dans létat actif.
Au temps 20, P2 demande un accès disque, lecture de B1, et passe donc en létat bloqué. Mais, comme il y a déjà une opération disque en cours, cet accès ne peut commencer immédiatement. Aucun processus nétant prêt, le processeur est inactif.
Au temps 30, la lecture de B1 pour P1 est terminée et P1 passe dans létat prêt. La lecture de B1 pour P2 commence. P1 étant le seul processus prêt, il devient actif, pour 40 ms.
Au temps 50, la lecture de B1 pour P2 est terminée, et P2 passe dans létat prêt. Étant mis en bout de file des processus prêts, il est derrière P1 qui reste actif.
Au temps 70, P1 demande lécriture de B1, et passe donc dans létat bloqué. P2 devient actif pour 10 ms.
Au temps 80, P2 demande lécriture de B1, et passe dans létat bloqué. Aucun processus nest prêt, et le processeur est inactif.
Au temps 90, lécriture de B1 pour P1 se termine, et P1 passe dans létat prêt. Lécriture de B1 pour P2 commence. P1 étant le seul processus prêt, il devient actif, pour 10 ms.
Au temps 100, P1 demande la lecture de B2 et passe dans létat bloqué. Comme le disque est occupé, la lecture ne commence pas.
Au temps 110, lécriture de B1 pour P2 se termine, et P2 passe dans létat prêt. La lecture de B2 pour P1 commence. P2 ayant terminé son travail sort du système.
Au temps 130, la lecture de B2 pour P2 se termine, et P1 passe dans létat prêt, puis actif.
Au temps 140, P1 a terminé son travail et sort du système.
Le bloc B1 est écrit successivement par chacun des processus, après un certain traitement, qui fait suite à la lecture du même bloc B1. On peut penser que lécriture dépend à la fois du traitement effectué et de la valeur du bloc B1 antérieur à ce traitement. Or une seule de ces écritures, la dernière et donc celle de P2 est conservée, la première est perdue puisque P2 travaille sur la version de B1 avant le traitement par P1 et non sur la version modifiée par P1.
Pour résoudre ce problème, il faut synchroniser les deux processus au moyen, par exemple, dune exclusion mutuelle daccès à leur séquence lecture-traitement-écriture. Nous utiliserons un mécanisme de verrou, et modifions les actions des processus comme suit :
Processus P1 calcul 10 ms |
Processus P2 calcul 10 ms |
P1 est lancé à linstant 0, il est donc prêt, et comme il est seul, il devient actif. Au temps 10 ms, il demande le verrou et lobtient. Puis il demande la lecture de B1, il passe donc dans létat bloqué et la lecture est lancée. En même temps, P2 est lancé, devient prêt et passe dans létat actif.
Au temps 20, P2 demande le verrou. Comme il nest pas libre, P2 passe dans létat bloqué. Le processeur est inactif.
Au temps 30, la lecture de B1 pour P1 est terminée et P1 passe dans létat prêt. P1 étant le seul processus prêt, il devient actif, pour 40 ms.
Au temps 70, P1 demande lécriture de B1, et passe donc dans létat bloqué. Cette écriture est lancée. Le processeur est inactif.
Au temps 90, lécriture de B1 pour P1 se termine, et P1 passe dans létat prêt. P1 étant le seul processus prêt, il devient actif. À ce moment, il libère le verrou, permettant à P2 de devenir prêt, derrière P1 qui reste actif pour 10 ms.
Au temps 100, P1 demande la lecture de B2 et passe dans létat bloqué. La lecture commence. P2 passe dans létat actif, mais demande immédiatement la lecture de B1. P2 passe dans létat bloqué, mais la lecture quil demande ne peut commencer.
Au temps 120, la lecture de B2 pour P2 se termine, et P1 passe dans létat prêt, puis actif. En même temps, la lecture de B1 pour P2 commence.
Au temps 130, P1 a terminé son travail et sort du système. Le processeur est inactif.
Au temps 140, la lecture de B1 pour P2 est terminée, et P2 passe dans létat prêt. Étant seul processus prêt, il devient actif pour 10 ms.
Au temps 150, P2 demande lécriture de B1, et passe dans létat bloqué. Aucun processus nest prêt, et le processeur est inactif.
Au temps 170, lécriture de B1 pour P2 se termine, et P2 passe dans létat prêt. Il libère le verrou, puis ayant terminé son travail sort du système.