Analizziamolo...
TUT6.COM TUT6.ASM ;TUT6.ASM - by b0nuS 1997 SEG_A SEGMENT ASSUME CS:SEG_A, DS:SEG_A ORG 100H Ribalta PROC FAR inizio: jmp START ;salta a START max_len EQU 1000 ;massima lunghezza sorgente db max_len+1 dup(?) ;stringa da ribaltare destinaz db max_len dup(?) ;stringa ribaltata START: mov si,0 ;punta al primo elemento dell'array prossimo_car: mov ah,01h ;legge un car dalla tastiera int 21h cmp al,0Dh ;è = a return ? je fine_lettura ;se si smetti di leggere mov sorgente[si],al ;sposta il carattere in sorgente inc si ;incrementa si jmp prossimo_car ;leggi il prossimo car fine_lettura: mov cx,si push cx ;memorizza la lunghezza nello stack mov bx,OFFSET sorgente mov si,OFFSET destinaz add si,cx ;aggiunge a si la lunghezza della stringa dec si ;decrementa si Ribaltamento: mov al,[bx] ;routine di ribaltamento mov [si],al ; parto dal fondo e la copio inc bx ; in destinaz dec si loop Ribaltamento ; salto a Ribaltamento pop si ;prelevo la lunghezza mov destinaz[si+1],'$' ;aggiungo il terminatore mov ah,09h mov dx,OFFSET destinaz int 21h ;stampo la stringa ribaltata RETN Ribalta ENDP SEG_A ENDS END inizio
max_len EQU 1000
----------------------
Questa dichiara una costante max_len che vale 1000 tramite la direttiva EQU.
Sorgente db max_len dup(?)
--------------------------
Questa dichiara una specie di array di byte di lunghezza max_len non
inizializzato. Conoscete già le direttive DB e DUP , questo è un ulteriore modo
di combinarle.La stessa istruzione in C sarebbe:
char Sorgente[max_len];L'istruzione successiva è la stessa cosa (a parte quel +1 che sarà chiarito in seguito).
mov si,0 prossimo_car: mov ah,01h ;legge un car dalla tastiera int 21h cmp al,0Dh ;è = a return ? je fine_lettura ;se si smetti di leggere mov sorgente[si],al ;sposta il carattere in sorgente inc si ;incrementa si jmp prossimo_car ;leggi il prossimo car fine_lettura:questo frammento di programma legge dalla tastiera una stringa carattere per carattere; si utilizza l'int 21h,01h che ritorna il carattere letto in al.
JE - Salta se sono uguali (ZF = 1)
JNE - Salta se sono diversi (ZF = 0)
JZ - Salta se è zero (ZF = 1)
JNZ - Salta se non è zero (ZF = 0)
(Nota : questi due salti condizionati sono la stessa cosa hanno solo nomi diversi !!)
JC - Salta se c'è stato riporto (CF = 1)
JNC - Salta se non c'è stato riporto (CF = 0)
JP - Salta se il Parity flag è 1
JNP - ...
JS - Salta se il Sign flag è 1
JNS - ...
Abbiamo poi due categorie per il confronto tra numeri con segno e senza segno la differenza è che nei numeri con segno il bit più significativo rappresenta appunto il segno del numero (ricordate il complemento a 2)
Con segno:
JG - Salta se il primo è maggiore del secondo
JNG - ...
JGE - salta se il primo è maggiore o uguale del secondo
JNGE - ...
JL - Salta se il primo è minore del secondo
JNL - ...
JLE - Salta se il primo è minore o uguale del secondo
JNLE - ...
Senza segno:
JA - Salta se il primo è più grande del secondo
JNA - ...
JB - Salta se il primo è più piccolo del secondo
JNB - ...
JAE - ...
JBE - ...
Queste istruzioni di salto condizionato sono indispensabili per il controllo
del flusso del programma per costruire i costrutti if...then e i cicli.
Tornando al nostro programma l'istruzione successiva al salto è
mov sorgente[si],alin al c'è il carattere appena letto che deve essere copiato nella variabile sorgente, quest'ultima viene trattata a tutti gli effetti come un array di caratteri dove il registro si rappresenta l'indice che nell'istruzione successiva viene incrementato (inc si) per prepararsi sulla prossima posizione libera.
nome_etichetta: ;nota: termina con i due punti .... .... .... jmp nome_etichetta ;nota: non termina con i due puntiIl successivo frammento di programma prepara le due stringhe per il ribaltamento:
mov cx,si push cx ;memorizza la lunghezza nello stack mov bx,OFFSET sorgente mov si,OFFSET destinaz ;sposto si alla fine della stringa sorgente/destinazione add si,cx ;aggiunge a si la lunghezza della stringa dec si ;decrementa siLa prima istruzione mette in cx la lunghezza della stringa che è contenuta nell'indice dell'array (si); tale valore viene anche salvato nello stack per utilizzarlo in futuro (push cx).
A questo punto viene effettuata la copia ribaltata nella stringa destinazione:
Ribaltamento: mov al,[bx] ;routine di ribaltamento mov [si],al ; parto dal fondo e la copio inc bx ; in destinaz dec si loop Ribaltamento ; salto a RibaltamentoLa situazione è questa :
+---------------- CX -------------+ ------------------------------------- destinaz : |?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?| ------------------------------------- ^ | si ------------------------------------- sorgente: |c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c| ------------------------------------- ^ | bxsi punta alla posizione cx della stringa destinazione, bx punta all'inizio della stringa sorgente e in cx c'e la lunghezza della stringa da ribaltare quindi non ci resta che scrivere un ciclo di questo tipo (in C):
while (cx>0) { destinazione[si] = sorgente[bx]; bx++; si--; cx--; }che in assembly risulta come sopra (a parte che il nostro prg assembly non funziona però correttamente se la stringa in ingresso è vuota, cioè non funziona bene nel caso di input vuoto (se premo solo RETURN); ecco un piccolo esercizio per voi, capite qual'è il problema e come porvi rimedio).
L'ultima parte del programma provvede alla visualizzazione della stringa ribaltata :
pop si ;prelevo la lunghezza mov destinaz[si+1],'$' ;aggiungo il terminatore mov ah,09h mov dx,OFFSET destinaz int 21h ;stampo la stringa ribaltatale prime due istruzioni servono per aggiungere alla fine della stringa il terminatore '$' indispensabile per stampare una stringa con la funzione 21h,09h; senza questo verrebbero visualizzati strani caratteri (faccine, cuoricini, ecc...)
destinaz db max_len+1 dup(?) ;stringa ribaltata
anzichè con
destinaz db max_len dup(?) ;stringa ribaltata
Il programma non effettua nessun controllo sulla lunghezza dell'input (che ne dite di aggiungerlo per esercizio?).
Spero che abbiate capito il funzionamento di questo secondo programma, non che sia molto più difficile del primo però introduce alcuni controlli di fondamentale importanza quali i salti e i cicli indispensabili per scrivere programmi che facciano qualcosa !!!
Assembly Page di Antonio |
|