Torre di Hanoi - soluzione ricorsiva
Pubblicato da syscalo il 31/07/2000
Livello intermedio
Introduzione
Tutorial sulla programmazione in assembly in linux, usando la sintassi AT&T.
Ho scritto un programma per risolvere in modo ricorsivo il problema della Torre di Hanoi; tramite questo esempio, diciamo "ludico", possiamo vedere alcune cose relative alla programmazione assembly, come chiamate di funzioni, passaggio dei parametri, uso dello stack ecc.
Programmi usati
Iniziamo
Spiegazione del problema della torre di Hanoi:
Il problema della torre di Hanoi consiste nello spostare n dischi da un piolo ad un altro, avendo a disposizione 3 pioli; in pratica dobbiamo passare da una situazione di questo tipo (esempio con 2 dischi)
__|__ | | _|_____|_ | | ___|_________|________|_____________|_______Ad una di questo tipo:
| __|__ | | _|_____|_ | ________|________|_________|________|_______Ma è necessario rispettare le seguenti regole:
Ecco alcune indicazioni per capire meglio il codice sorgente e i commenti:
# sezione dati
.data
Intestazione:
.asciz "\n\
### ###\n\
# #\n\
# Soluzione ricorsiva torre di Hanoi #\n\
# #\n\
# Scritto da syscalo #\n\
# #\n\
# file: hanoi.S #\n\
# compilare con: gcc -o hanoi hanoi.S #\n\
# #\n\
### ###\n\
\n"
Movimenti:
.asciz "Muovi %d da %c a %c\n"
NumeroMosse:
.asciz "\nCon %d dischi sono necessarie %d mosse\n\n"
LeggiN:
.asciz "Quanti sono i dischi?"
d:
.ascii "%d"
# contatore numero di mosse da effettuare
Contatore:
.long 0
# numero di dischi
N:
.byte 0
## sezione codice
.text
.global main
main:
### salvataggio registri a cura della procedura chiamata ###
### %ebp, %ebx, %esi, %edi ###
pushl %ebp
movl %esp, %ebp #allocazione stack frame
pushl %ebx
pushl %esi
pushl %edi
#visualizzazione Intestazione
pushl $Intestazione
call puts
addl $4, %esp #pulisce stack dai parametri
#acquisizione numero dischi
pushl $LeggiN
call puts
addl $4, %esp
pushl $N
pushl $d
call scanf
addl $8, %esp
#passaggio parametri alla procedura hanoi
pushl $'C' #attraverso...
pushl $'B' #in...
pushl $'A' #da...
pushl (N) #numero dischi
call hanoi
addl $16, %esp
#visualizzazione numero di mosse necessarie
pushl (Contatore)
pushl (N)
pushl $NumeroMosse
call printf
addl $12, %esp
#valore di ritorno in %eax: 0==tutto ok
xorl %eax, %eax
#ripristino registri
popl %edi
popl %esi
popl %ebx
movl %ebp, %esp #disallocazione stack frame
popl %ebp
ret
### ###
# Procedura hanoi #
# #
# Chiamata ricorsivamente #
### ###
hanoi:
pushl %ebp #salvataggio registro %ebp
movl %esp, %ebp #allocazione stack frame
### non salvo gli altri registri perchè non vengono usati ###
#test sul numero di dischi
#se c'è 1 disco esegue la singola mossa e termina
cmpl $1, 8(%ebp) #8(%ebp) contiene il numero di dischi
jg piuDi1
#visualizza il movimento da effettuare
pushl 16(%ebp) #in...
pushl 12(%ebp) #da...
pushl 8(%ebp) #numero disco
pushl $Movimenti
call printf
addl $16, %esp
incl Contatore
jmp fine
piuDi1:
#chiama la procedura hanoi per un numero di dischi pari a n-1
pushl 16(%ebp) #in...
pushl 20(%ebp) #attraverso...
pushl 12(%ebp) #da...
pushl 8(%ebp) #numero disco:
decl (%esp) #n-1
call hanoi
addl $16, %esp
#visualizza il movimento da effettuare
pushl 16(%ebp) #in...
pushl 12(%ebp) #da...
pushl 8(%ebp) #numero disco
pushl $Movimenti
call printf
incl Contatore
addl $16, %esp
#chiama la procedura hanoi per un numero di dischi pari a n-1
pushl 12(%ebp) #da...
pushl 16(%ebp) #in...
pushl 20(%ebp) #attraverso...
pushl 8(%ebp) #numero disco:
decl (%esp) #n-1
call hanoi
addl $16, %esp
fine:
movl %ebp, %esp #disallocazione stack frame
popl %ebp #ripristino registro %ebp
ret
bye to all, syscalo
Conclusioni
That's all!