IN 103 - Cours 7 1 Piles Une pile est une structure de données permettant de stocker des éléments d’un même type. Une pile d’entiers permettra de stocker des entiers, une pile de stocker des struct blah t . Une pile est une structure struct blah t permettra de dernier entré-premier sorti . push : on empile (rajoute) une information sur le sommet de la pile. pop : on dépile (retire) l’information se trouvant au sommet de la pile. push (stack, elem4) 1) elem4 2) elem4 pop (stack) elem3 pop (stack) elem4 elem3 elem3 elem2 elem2 elem1 elem2 elem1 elem1 En C on représente l’espace de stockage d’une pile par un tableau. Pour savoir où empiler et d’où dépiler, on mémorise un pointeur de pile indique la prochaine place libre dans le tableau. Le pointeur de pile n’est pas un pointeur C : c’est un entier positif représentant un indice dans le tableau de la pile. En C, une pile de taille fixe (64) contenant des éléments de type par une structure : un type est représentée #define MAX SIZE 64 struct s t a c k { unsigned i n t sp ; /∗ P o i n t e u r de p i l e . ∗/ u n t y p e data [ MAX SIZE ] ; /∗ Zone de s t o c k a g e de l a p i l e . ∗/ }; Initialement, une pile est vide (ne contient pas d’éléments) : le pointeur de pile est à 0. Essayer de dépiler dans une pile vide ( pointeur de pile == 0) provoque une erreur. Essayer d’empiler dans une pile pleine ( pointeur de pile == MAX SIZE) provoque une erreur. ??? sp data[MAX_SIZE − 1] ??? ??? data[2] ??? ??? data[1] 5 42 data[0] 42 1 sp 2 sp push (stack, 5) : — Vérifier que sp < M AX SIZE — 5 mis à l’indice sp ⇒ 1 — Incrémenter sp : sp ← sp + 1 ⇒ 2 push (stack, 5) 1 ??? data[MAX_SIZE − 1] ??? 5pop sp ??? data[2] ??? 5 data[1] ?5? 42 data[0] 42 2 sp 1 (stack) — Vérifier que sp > 0 — Décrémenter sp : sp ← sp−1 ⇒ 1 — Retourner la valeur à l’indice sp (sommet de la pile) sp pop (stack) On peut implanter une pile de taille non fixe en allouant dynamiquement (avec malloc) le tableau et en le ré-allouant (nouvelle allocation, recopie, libération de l’ancien tableau) lorsque la pile est pleine. 2 Du code source à l’exécution Code source = description statique. Exécutable = comportement dynamique. Le langage dans lequel est écrit le source possède une sémantique dynamique. Processus du code source à l’exécution : 1. Découpe du source en mots et vérification de bonne orthographe : analyse lexicale. 2. Assemblage des mots en taxique. phrases et vérification de bonne grammaire : analyse syn- 3. Analyses sémantiques et vérification du sens correct des phrases. 4. Production de code assembleur et optimisation. 5. Production de code binaire : assemblage. 6. Regroupement final de tous les composants : édition de lien. 7. Chargement en mémoire puis exécution. 3 Exécution (mono-tâche et simplifiée) Un CPU possède quelques zones de stockage internes rapides : les registres. Un CPU ne comprend que des instructions élémentaires : déplacement de données, arithmétique, logique, saut, (+ quelques autres). Cycle infini du CPU : récupérer l’instruction courante, la décoder, l’exécuter, passer à l’instruction suivante. Adresse de l’instruction courante : dans un registre dédié PC . Pour effectuer des saut conditionnels, il est nécessaire de mémoriser le statut des conditions testées : un registre dédié SR avec 1 bit par condition (résultat nul, positif, négatif, débordement . . . ). Pour les appels de fonctions et les variables locales, il faut une pile d’exécution. Adresse du pointeur de pile : dans un registre dédié SP . Charger un code en mémoire c’est recalculer les adresses figurant dans ses instructions en fonction de là où il a été logé. Lancer un code chargé en mémoire lui attribuer une zone de pile (initialiser SP), effacer les bits de conditions (SR) et mettre le PC à l’adresse de début de ce code. C’est un des rôles du système d’exploitation (OS) de charger et lancer l’exécution. 2