Les piles
Djamal Rebaïne 2
• Utilité d'une pile Une pile est une zone de mémoire dans laquelle on peut stocker temporairement des registres. Il s'agit d'un moyen d'accéder à des données en les empilant, telle une pile de livre, puis en les dépilant pour les utiliser. Ainsi il est nécessaire de dépiler les valeurs stocker au sommet (les dernières à avoir été stockées) pour pouvoir accéder aux valeurs situées à la base de la pile.
• En réalité il s'agit d'une zone de mémoire et d'un pointeur qui permet de repérer le sommet de la pile.
La pile est de type LIFO (Last In First Out), c'est-à-dire que la
première valeur empilée sera la dernière sortie (Si vous empilez des livres, il vous faudra les dépiler en commençant par enlever les livres du dessus. Le premier livre empilé sera donc le dernier sorti!).
• Les instructions PUSH et POP Les instructions PUSH et POP sont les instructions qui servent à empiler et dépiler les données.
• PUSH registre met le contenu du registre dans la pile (empilement)
• POP registre récupère le contenu de la pile et le stocke dans le
registre (dépilage
Ainsi, l'instruction PUSH BX
empile le contenu du registre BX, et l'instruction
POP AX
récupère le contenu du sommet de la pile et le
transfère dans AX.
Djamal Rebaïne 4
Utilisation de la pile sur un exemple
• Dans l'exemple suivant, que l'on imaginera au milieu d'un programme, on stocke les valeurs contenues dans AX et BX pour pouvoir utiliser ces deux registres, puis
une fois l'opération accomplie on remet les valeurs qu'ils contenaient
précédemment...
• PUSH AX
• PUSH BX
• MOV AX, [0140]
• ADD BX, AX
• MOV [0140], BX
• POP BX
• POP AX
Djamal Rebaïne 6
• Les registres SS et SP Les registres SS et SP sont deux registres servant à gérer la pile:
• SS (Stack Segment, dont la traduction est segment de pile) est un registre 16 bits
contenant l'adresse du segment de pile courant.
• Il doit être initialisé au début du programme
• SP (Stack Pointer, littéralement pointeur de pile)
est le déplacement pour atteindre le sommet de
la pile (16 bits de poids faible).
• SP pointe vers le sommet, c'est-à-dire sur le dernier bloc occupé de la pile. Lorsque l'on
ajoute un élément à la pile, l'adresse contenue dans SP est décrémentée de 2 octets (car un
emplacement de la pile fait 16 bits de longueur).
• En effet, lorsque l'on parcourt la pile de la base vers le sommet, les adresse décroissent.
Par contre l'instruction POP incrémente de 2
octets (16 bits) la valeur de SP.
Djamal Rebaïne 8
• PUSH: SP <- SP - 2
• POP: SP <- SP + 2
• Ainsi, lorsque la pile est vide SP pointe
sous la pile (la case mémoire en-dessous de la base de la pile) car il n'y a pas de
case occupée. Un POP provoquera alors
une erreur...
Déclarer une pile
• Pour pouvoir utiliser une pile, il faut la déclarer, c'est-à-dire réserver un espace mémoire pour son utilisation, puis initialiser les registres avec les valeurs correspondant à la base de la pile, ainsi que son sommet (rappel: situé sous la pile lorsque celle-ci est vide).
• Ainsi pour définir une pile, il s'agit tout d'abord
de la déclarer grâce à la directive SEGMENT
stack.
Djamal Rebaïne 10
Déclaration d'une pile
Pour utiliser une pile en assembleur, il faut déclarer un segment de pile, et y
réserver un espace suffisant. Ensuite, il est nécessaire d'initialiser les registres SS et SP pour pointer sous le sommet de la pile. Voici la déclaration d'une pile de 200 octets :
segment_pile SEGMENT stack ; mot clef stack pour pile DW 100 dup (?) ; réserve espace
base_pile EQU this word ; etiquette base de la pile segment_pile ENDS
Noter le mot clef ``stack '' après la directive SEGMENT, qui indique à l'assembleur qu'il s'agit d'un segment de pile.
Afin d'initialiser SP, il faut repérer l'adresse du bas de la pile; c'est le rôle de la ligne base_pile EQU this word (voir figure suivante).
En fait l’opérateur this word (ne pas oublier que les éléments d’un pile sont
des mots) crée une adresse mémoire qui est le mot suivant et l’assigne à
bas_pile. Comme les adresse d’une pile sont dans l’ordre décroissant, cette
adresse en dessous de l’adrese du début de la pile.
Autrement dit, la déclaration suivante:
First-byte equ this byte
Word table dw 100 dup(?)
permet d’assigner un nom au premier
octet de l’adresse de word-table.
Djamal Rebaïne 12
• Suite aux déclarations, il faut écrire une séquence d'initialisations:
• ASSUME SS:segment_pile ; génère une adresse pour l’emplacement de la ; pile
• MOV AX, segment_pile
• MOV SS, AX ; initialise le segment de pile
• MOV SP, base_pile ; copier l'adresse de la base de la pile dans SP
• Remarquez qu’il n'est pas possible de faire
directement MOV SS, segment_pile car cette
instruction n'existe pas!
Djamal Rebaïne 14
Les procédures-fonctions
La notion de procédure - fonctions
En langage assembleur, on appelle procédure un sous- programme qui permet d'effectuer un ensemble
d'instructions par simple appel de la procédure. Cette notion de sous-programme est généralement appelée fonction dans d'autres langages. Les fonctions et les procédure permettent d'exécuter dans plusieurs parties du programme une série d'instruction, cela permet une simplicité du code et donc une taille de programme
minimale. D'autre part, une procédure peut faire appel à elle-même, on parle alors de procédure récursive (il ne faut pas oublier de mettre une condition de sortie au
risque sinon de ne pas pouvoir arrêter le programme...).
Djamal Rebaïne 16
La déclaration d'une procédure
Étant donnée qu'une procédure est une suite d'instructions, il s'agit de regrouper les instructions composant la procédure entre des mots clés. L'ensemble de cette manipulation est appelée déclaration de procédure.
Ces mots clés permettant la déclaration de la procédure sont le 1. une étiquette (qui représente le nom de la fonction)
précédant
2. le mot clef PROC marquant le début de la procédure,
3. suivi de near (qui signale que la procédure est située dans le même segment que le programme appelant) et
4. RET désignant la dernière instruction,
5. et enfin le mot-clé ENDP qui annonce la fin de la procédure.
Ainsi une déclaration de procédure ressemble à ceci:
Etiquette PROC near instruction1
instruction2 ...
RET
Etiquette ENDP
Djamal Rebaïne 18
Appel d'une procédure
C'est la directive CALL qui permet l'appel d'une procédure. Elle est suivie soit d'une adresse 16 bits, désignant la position du début de la
procédure, ou bien du nom de la procédure
(celui de l'étiquette qui précède le mot clé
PROC).
Comment l'appel et la fin de la procédure
Lorsqu'on appelle une procédure, la première adresse de la procédure est stockée dans le registre IP (pointeur d’instruction), le processeur traite ensuite toutes les lignes d'instructions jusqu'à tomber sur le mot clé RET, qui va remettre dans le registre IP l'adresse qui y était stocké avant l'appel par PROC.
Cela paraît simple mais le problème provient du fait que les procédures peuvent être imbriqués, c'est-à-dire que de saut en saut, le
processeur doit être capable de revenir successivement aux adresses de retour. En fait, à chaque appel de fonction via
l'instruction CALL, le processeur empile l'adresse contenue dans le
registre IP (il pointe alors sur l'instruction suivant l'instruction CALL)
avant de la modifier, à l'appel de l'instruction RET (qui ne prend pas
d'arguments) le contenu de la pile est dépilé puis stocké dans le
registre IP.
Djamal Rebaïne 20
Voici un exemple d’utilisation des procédures aussi simple que possible :
ce programme appelle 12 fois une procédure qui écrit un message à l’écran et rend la main au DOS.
Remarque : Les codes ASCII 10 et 13
représentent respectivement la fin de ligne et le
retour chariot. Grâce à eux, on revient à la ligne
chaque fois qu’on a écrit le message.
Djamal Rebaïne 22
Title les procédures Pile segment stack dw 100 dup (?)
Basedepile equ thisword Pile ends
data segement
message db ’bonjour, monde!’, 10,13, ‘$’
data ends code segment
assume cs:code, ds:code, ss:pile debut:
MOV AX, data ; initialise le segment de données MOV DS, AX
MOV AX, Pile
MOV SS, AX ; initialise le segment de pile MOV SP, basedepile
MOV CX,12
boucle: call ecritmessage ; appel de procédure
LOOP boucle ; décrementer CX d’une unité et aller à ; boucle si CX est différent de 0
; terminer le programme ici par le retour au DOS mov AX, 4C00h
INT 21H
ecritmessage proc near ;notre procédure mov ah, 09h
move dx,offset message int 21h
ret
ecritmessage endp ; fin de la procédure/fonction code ends ; fin du segment de code
end debut ; fin de la porte d’entrée
Djamal Rebaïne 24
Le passage de paramètres
Une procédure effectue généralement des actions sur des données qu'on lui fournit, toutefois dans la déclaration de la procédure il n'y a pas de paramètres (dans des langages évolués on place
généralement les noms des variables comme paramètres entre des parenthèses, séparés par des virgules). Il existe toutefois deux façons de passer des paramètres à une procédure:
Le passage des paramètres par registre: on stocke les valeurs dans les registres utilisés dans la procédure
Le passage des paramètres par pile: on stocke les valeurs dans la pile avant d'appeler la procédure, puis on lit le contenu de la pile dans la procédure.
Le passage de paramètres par registres C'est une méthode simple
pour passer des paramètres: Elle consiste à écrire une procédure en
faisant référence à des registres dans les instructions, et de mettre
les valeurs que l'on désire dans les registres juste avant l’appel de la
fonction...
Le passage des paramètres par registre
Cette manière de procéder est très simple à mettre en oeuvre mais elle est très limité, car on ne peut pas passer autant de paramètres que l'on désire, à cause du nombre limité de registres. On lui
préfèrera le passage des paramètres par pile.
Le passage de paramètres par pile
Cette méthode de passage de paramètres consiste à stocker les valeurs des paramètres dans la pile avant l'appel de procédure
(grâce à l'instruction PUSH), puis de lire le contenu de la pile grâce à un registre spécial (BP: Base pointer) qui permet de lire des
valeurs dans la pile sans les dépiler, ni modifier le pointeur de
sommet de pile (SP).
Djamal Rebaïne 26
L'appel de la procédure se fera comme suit:
PUSH parametre1 ; où parametre1 correspond à une valeur ou une adresse
PUSH parametre2 ; où parametre1 correspond à une valeur ou une adresse
CALL procedure
La procédure commencera par l'instruction suivante:
MOV BP, SP ;permet de faire pointer BP sur le sommet de la pile
Puis pourra contenir des instructions du type:
MOV AX, [BP] ;Stocke la valeur contenue dans le sommet de ;la pile dans AX, sans dépiler
MOV BX, [BP+2] ;Stocke la valeur contenue dans le mot suivant de la
;pile dans BX (un mot fait 2 octets), sans dépiler
• On va écrire une procédure ``SOMME'' qui calcule la somme de 2 nombres naturels de 16 bits.
• Convenons que les entiers sont passés par les registres AX et BX, et que le
résultat sera placé dans le registre AX.
• La procédure s'écrit alors très simplement :
Exemple avec passage par
registre
Djamal Rebaïne 28
SOMME PROC near ; AX <- AX + BX
ADD AX, BX RET
SOMME ENDP
et son appel, par exemple pour ajouter 6 à la variable Truc : MOV AX, 6
MOV BX, Truc
CALL SOMME
MOV Truc, AX
Exemple avec passage par la pile
Cette technique met en oeuvre un nouveau registre, BP (Base Pointer), qui permet de lire des valeurs sur la pile sans les dépiler ni modifier SP.
Le registre BP permet un mode d'adressage indirect spécial, de la forme :
MOV AX, [BP+6]; cette instruction charge le contenu du mot mémoire d'adresse BP+6 dans AX.
Ainsi, on lira le sommet de la pile avec :
MOV BP, SP ;BP pointe sur le sommet
MOV AX, [BP] ;lit sans dépiler et le mot suivant avec : MOV AX, [BP+2] ;2 car 2 octets par mot de pile.
• L'appel de la procédure ``SOMME2'' avec passage par la pile est :
PUSH 6
Djamal Rebaïne 30
; passage de paramètres push AX
push BX push CX push DX
call soubroutine ; branchement vers la procédure ; ... Contineur traitement
soubroutine proc near
mov BP,SP ; pointe vers le sommet de pile
move AX, [BP+2] ; acquérir dernier paramètre (DX) sans dépiler; pourquoi?
move AX, [BP+4] ; acquérir 3ème paramètre (CX) sans dépiler move AX, [BP+6] ; acquérir 2ème paramètre (BX) sans dépiler move AX, [BP+8] ; acquérir premeir paramètre (AX) sans dépiler ...
ret
soubroutine ends
Emplacement de sous-programmes
En général, les sous-programmes sont mis à la fin du programme principal. Mais, on peut aussi les mettre
dans la partie du segment de code. Seulement,il faudra s’assurer que la première instruction de code exécutée soit celle du programme principal. Pour cela, il suffit juste de mettre un JMP juste avant la déclaration du sous-
programme.
Djamal Rebaïne 32
Exemple: le calcul de PGCD de plusieurs nombres
TITLE PGCDdeplusieursnombres SPILE SEGMENT STACK DW 100 DUP(?) SPILE ENDS SDATA SEGMENT
valeurs DB 10,30,40,76,32,52 resultat DB 3 dup(?)
tab_sortie db 7 dup('$') tab_conv db 7 dup('$') start dw 0
SDATA ENDS SCODE SEGMENT
ASSUME CS:SCODE,DS:SDATA JMP debut
PGCD proc near ; déclaration de la fonction repet:
MOV AL,CL MOV AH,0 IDIV CH;
CMP AH,0 JE dfin MOV CL, CH MOV CH, AH JMP repet dfin:
RET ;le PGCD est dans CH PGCD ENDP ;fin de la procédure PGCD
DEBUT:
mov ax,sdata mov ds,ax
mov SI,0; sert d’indice tableau
MOV BX, 5; compteur de nombre à manipuler mov CH, valeurs[SI]
INC SI repeter:
CMP BX,0 JE fin
mov CL, valeurs[SI]
Call PGCD INC SI
DEC BX JMP repeter
Fin: ; le PGCD de tous les nombres est dans CH
Djamal Rebaïne 34 xor ax,ax ; tout ce qui suit sert à afficher les chiffres contenus dans le PGCD qui est dans CH
mov al,ch
mov si, offset tab_conv
mov start, offset tab_conv ;start sert à garder le début du tableau mov bx,0
mov bl,10
division: ; on suppose que la division se fait sur des nombre de 16 bits div bl
cmp al,0 je fin_div add ah,48
mov byte ptr[si],ah mov ah,0
inc si
jmp division fin_div:
add ah,48
mov byte ptr[si],ah
; tab_conv contient le nombre converti à l’envers xor bx,bx
mov bx, offset tab_sortie xor ax,ax
st_bcl:
cmp si,start jb fin_bcl
mov ah , byte ptr[si]
mov byte ptr[bx] , ah dec si
inc bx jmp st_bcl fin_bcl:
mov byte ptr[bx],10 inc bx
mov byte ptr[bx],13 inc bx
mov byte ptr[bx],'$' mov dx,offset tab_sortie mov ah,09h
int 21h
Sortie: MOV AX, 4c00h;
Int 21h SCODE ENDS
END DEBUT
Djamal Rebaïne 36
La récursivité
• Définition:
Une procédure est dite récursive si, et
seulement si, elle fait appel à elle-même,
soit directement soit indirectement
Fonctionnement d’une fonction récursive
• Création d’une pile pour la sauvegarde
entre autres des paramètres d’appels de
la procédure et la l’adresse de retour.
Djamal Rebaïne 38
Calculer le factoriel de n, noté n!
• Le problème est: Calculer le factoriel d'un nombre entier donné en entrée.
• En entrée: Nous avons n nombre entiers qui sont plus grands ou égaux à 0.
• Sortie: Nous avons un nombre entier qui
représente le factoriel de n.
• Fonction principale
• entier n nfact
• lire n
• si (n < 0) alors écrire “entrée négative: ” n
• sinon
• nfact factoriel(n)
• écrire “la factorielle de ” n “est” nfact
• où factoriel satisfait le prototype
Djamal Rebaïne 40
Fonction factoriel int factoriel(entier n) {
si (n < 1) retourner 1
retourner n * factoriel(n-1)
}
Comment le faire en assembleur?
On a besoin d’une pile!
• En effet, à chaque appel récursif, la valeur du paramètre n est sauvegardée dans la pile de travail.
• Ce processus d’empilement est répété jusqu’à ce que le paramètre actuel (de l’appel) n atteigne la valeur 0. Cela correspond à la fin de l’exécution de la fonction
appelante.
• Ensuite, commence le dépilement, et l’exécution de la prochaine instruction de la fonction appelante est
entamée. Ce processus de dépilement est répété
jusqu’à ce qu’on atteigne la valeur de départ du
paramètre n.
Djamal Rebaïne 42
Cela se traduit par le programme assembleur suivant
TITLE factoriel
PILE segment stack dw 100 dup(?)
Basdepile equ this word PILE ends
Data segment N dw 4 fact dw ? Data ends Code segment
assume CS:code, DS:Data, SS:Pile Debut:
MOV AX,Data MOV DS,AX MOV AX,Pile
MOV SS, AX ; initialise le segment de pile
MOV SP, basdepile ; copier l'adresse de la base de la pile dans SP mov BX,n; sauvegarde la valeur de n
mov AX,BX Push AX call factoriel
Fin: pop AX; le résultat calculé par la fonction factoriel est dans AX mov fact, AX
mov AX,4c00h int 21h
Factoriel proc near ; en utilisant la pile CMP AX,0
JA DEPILE MOV AX,1 JMP fin
DEPILE: ; dépiler jusqu’à ce n = 0 DEC AX
PUSH AX ; factoriel(n-1) CALL FACTORIAL
RetourResultat:
POP BX MUL BX fin: ret
factoriel endp ; fin de la procédure code ends
end debut ; fin du programme code
Djamal Rebaïne 44
Calcul d’une somme par récursivité
Title sommerecursive; pour totaliser la somme de 1 jusqu’à n.
PILE segment stack dw 100 dup(?)
Basdepile equ this word PILE ends
Data segment N dw 12 som dw ? Data ends Code segment
assume CS:code, DS:Data, SS:Pile Debut:
MOV AX,Data MOV DS,AX MOV AX,Pile
MOV SS, AX ; initialise le segment de pile
MOV SP, basdepile ; copier l'adresse de la base de la pile dans SP mov CX,n; sauvegarde la valeur de n
XOR AX,AX
CALL sommerecursive
Fin: pop AX; le résultat calculé par la fonction factoriel est dans AX mov fact, AX
mov AX,4c00h int 21h
sommerecursive proc near ; en utilisant des registres
CMP CX,0 JZ fin
ADD AX,CX DEC CX
CALL sommerecursive fin: ret
factoriel endp ; fin de la procédure code ends
end debut ; fin du programme code
Djamal Rebaïne 46
Les nombres de Fibonacci
• Question: Écrire un programme qui calcule le nombre de Fibonacci défini comme suit:
1
; 0
1 n
si ;
1 0
2 1
F F
F F
F n n n
èm
e n
TITLE fibonacci
SPILE SEGMENT STACK DW 100 DUP(?)
SPILE ENDS SDATA SEGMENT n dw 6
SDATA ENDS SCODE SEGMENT
ASSUME CS:SCODE,DS:SDATA DEBUT:
mov ax,sdata mov ds,ax xor ax,ax xor bx,bx mov ax,n call fibo
mov dl,al; afficher le résultat add dl,30h
mov ah,2 int 21h sortie:
MOV AX,4C00H INT 21H
Djamal Rebaïne 48
Fibo proc si1:
cmp ax, 1 ; comparer ax avec 1 ja els ; si n<= 1, retourner 1 mov ax, 1 ; mettre 1 dans ax ret
els:
dec ax ; décrémenter ax de 1 c'est-à-dire égal à n-1 push ax ; mettre n-1 sur la pile
call Fibo ; résultat dans ax
pop bx ; rectifier la pile et bx = n-1 dec bx ; bx = n -2
push ax ; sauvegarder ax = Fibonacci(n-1) sur la pile mov ax,bx ; passe le n-1 à ax pour exécuter Fibonacci(n-2) call Fibo ; résultat dans ax = Fibonacci(n-2)
pop bx ; bx = Fibonacci(n-1)
add ax, bx ; ax = Fibonacci(n-2) + Fibonacci(n-1) ret
Fibo endp
SCODE ENDS
END DEBUT
Les tours de Hanoï
http://www.multimania.com/fmaire/jeux/hanoi/hanoi.html
http://members.aa.net/~wgf/Hanoi/Hanoi.html
Djamal Rebaïne 50
• Description du problème: Montrez comment déplacer n disques de tailles distinctes d'une tige A vers une tige B
• en utilisant comme tampon une tige C. Initialement seule la tige A contient les n disques ordonnés avec le plus
petit sur le dessus. On ne doit déplacer qu'un seul
disque à la fois. Il est interdit de placer un disque sur un autre plus petit.
• Entrée: Un entier n représentant le nombre de disques.
• Sortie: Une série d'instructions de la forme " déplacer i
vers j" indiquant les déplacements nécessaires pour
résoudre le problème.
• Fonction principale entier n
lire n
hanoi(n,1,2,3)
où hanoi satisfait le prototype
hanoi(entier, entier, entier, entier)
Djamal Rebaïne 52
• Supposons qu’on sache comment
déplacer les (n-1) derniers disques de la tour 1 vers la tour 2, en utilisant la tour 3.
• déplacer le disque restant de la tour 1 vers la tour 2
• déplacer maintenant les (n-1) disques de
la tour 3 vers la tour 2, en s’aidant de la
tour 1.
Fonction hanoi Entête:
• hanoi(entier n, entier i, entier j, entier k)
• (Affiche les instructions pour déplacer n disques
• de la tige i vers la tige k) Corps:
• si (n > 0)
• {
• hanoi(n-1, i, k, j)
• écrire "Déplacer i vers k);
• hanoi(n-1, j, i, k)
• }
Djamal Rebaïne 54
#include <iostream.h>
void hanoi (int,int,int,int)
void hanoi(int n,int i,int j,int k){
if (n>0){
hanoi(n-1,i,k,j);
cout <<“déplacer le disque de haut de la tour<<i<<“ à la tour “<<k;
hanoi(n-1,j,k,i);
} main(){
int n;
cin>>n;
hanoi(n,1,2,3);
}
• Cette fonction est à revoir
Tours-de-Hanoi PROC NEAR;
push bp mov eb,sp mov ax,[bp+4]
add eax,0x4 mov dx,[ax]
push dx call atoi
add sp,0x4
push word 0x2 ; INITIALISER LA PILE À dohanoi push word 0x1 ; dohanoi(n, to from, using)
push word 0x3 push word ax call dohanoi add sp,16 mov sp,bp
pop bp
ret
dohanoi: push bp
mov bp,sp
mov ax,[bp+4]
cmp ax,0x0
jle fini dec ax
push [bp+ 12] ; empiler le premier appel récursif push dword [ebp+16]
push dword [ebp+20]
push dword eax call dohanoi add esp,16
push dword [ebp+16] ; a disk moved, so print it push dword [ebp+12]
call DeplaceLe
add esp,8
mov eax,[ebp+8]
dec eax
push dword [ebp+16] ; empiler le deuxième appel récursif push dword [ebp+20]
push dword [ebp+12]
push dword eax call dohanoi
add esp,16
fini: mov esp,ebp pop ebp
ret
deplaceLe: push ebp
mov ebp,esp
push dword [ebp+8]
push dword [ebp+12]
push dword movestr call printf
add esp,0xc mov esp,ebp pop ebp
ret
Tours-de-Hanoi ENDP
Djamal Rebaïne 58
Remarquons qu’il est possible de supprimer
carrément l’appel récursif, en le simulant par des appels successifs à la pile, à travers les empilements et les dépilements.
Reprenons le problème de la fonction factoriel.
Cela se traduit par le programme assembleur suivant
TITLE factoriel
PILE segment stack dw 100 dup(?)
Basdepile equ this word PILE ends
Data segment N dw 4 fact dw ? Data ends Code segment
assume CS:code, DS:Data, SS:Pile Debut:
MOV AX,Data MOV DS,AX MOV AX,Pile
MOV SS, AX ; initialise le segment de pile
MOV SP, basdepile ; copier l'adresse de la base de la pile dans SP mov BX,n; sauvegarde la valeur de n
mov ax,bx call factoriel
Fin: pop AX; le résultat calculé par la fonction factoriel est dans AX
Djamal Rebaïne 60
factoriel proc near push ax
Continuer:
CMP AX,1
JLE dépiler; déplier jusqu’à ce n = 1 dec AX
push AX
JMP continuer Depiler:
POP AX POP CX
mul CX Push AX CMP BX,CX Ja depiler ret
factoriel endp ; fin de la procédure code ends
end debut ; fin du programme code
Inversion d’une chaine de caractères
• Donnée: S une chaine de caractères
• Question: Afficher S dans le sens inverse
Djamal Rebaïne 62
• Fonction principale
• ecrire “introdroduire la chaîne: ”
• inverser
• La fonction inverser fonctionne comme suit:
Tant que le caractère lu n’est pas le point, continuer la lecture;
Arrivé au point, l’affichage commence.
Djamal Rebaïne 64
Entête: inverser Corps:
lire car;
si car <> `.`
inverser;
afficher car;
TITLE inverser
affiche macro chaine ; mov dx,offset chaine ; mov ah, 09h ;
int 21h endm
PILE segment stack dw 100 dup(?) Basdepile equ this word PILE ends
Data segment
Chaine db ‘introduire votre chaine’, 10,13, ‘$’
Data ends Code segment
assume CS:code, DS:Data, SS:Pile Debut:
MOV AX,Data MOV DS,AX MOV AX,Pile
MOV SS, AX ; initialise le segment de pile
MOV SP, basdepile ; copier l'adresse de la base de la pile dans SP Affich chaine
call inverserl
Fin: mov AX,4c00h
Djamal Rebaïne 66
inverser Proc near Continuer:
mov ah,1 ;lecture d’un cacactère int 21h
CMP AL,’.’
JNE dépiler; dépiler jusqu’à ce AL = ‘.’
CBW ; convertir le caractère en un mot ; ou alors faire mov AH,0
push AX
JMP continuer
Depiler: POP AX mov AH,2
int 21
JMP depiler ret
inverser; fin de la procédure
code ends; fin du programme principal end debut
• Rechercher l’élément C dans un tableau trié dans l’ordre croissant.
……… …..
milieu
L u
A
C?
Djamal Rebaïne 68
void recherche(C,L,u:entier; trouve:booleen) { trouve = faux;
si (u <= L) et (non trouve) { milieu = (u - L + 1) div 2;
si A[milieu] = C trouve = vrai;
sinon si A[milieu] > C
recherche(C,L,milieu-1);
sinon recherche(C,milieu+1,u);
}
}
TITLE dichotomique PILE segment stack dw 100 dup(?) Basdepile equ this word PILE ends
Data segment
tableau db 100 dup(?) Valeur db ?
Data ends Code segment
assume CS:code, DS:Data, SS:Pile Debut:
MOV AX,Data MOV DS,AX MOV AX,Pile
MOV SS, AX ; initialise le segment de pile
MOV SP, basdepile ; copier l'adresse de la base de la pile dans SP mov dx,offset tableau
mov ah,0ah; lecture à partir du clavier d’une chaîne de caractères
; qui se termine dès qu’on tape le retour chariot (touche entrée)
Djamal Rebaïne 70