Ricerca di un carattere in una stringa

Avviare il "Blocco note" e scrivere quanto segue:

.model small

ASSUME DS:frase

.stack 100H

frase SEGMENT

  testo db "Questo testo è lungo 78 caratteri, nella posizione 42 contiene il carattere p.",13,10,"$"

 

  msg db "Carattere non trovato $"

  msg1 db "Il carattere cercato si trova in posizione x $"

frase ENDS

 

.code

inizio:

  mov ax, frase

  mov ds, ax

  mov es, ax

 

  MOV dx, offset testo

  mov ah, 09h

  int 21h

 

  CLD

  MOV DI, offset testo

  MOV CX, offset msg

  MOV AL, 'p'

  REPNE SCASB

 

  JCXZ noTrovato

  MOV DX, offset msg1

  JMP mostra

 

noTrovato: MOV DX, offset msg

mostra: MOV AH, 09

  INT 21h

 

  MOV AX, 4C00h

  int 21h

end inizio

Salvare il file con il nome: cerca.asm.

Il carattere $ al termine di queste righe è utilizzato (dal servizio di stampa del DOS) per segnalare la fine della stringa da mostrare. È una convenzione impiegata solo in ambiente DOS.

Dopo aver assemblato il programma: tasm cerca.asm - ed averlo linkato: tlink cerca.obj, richiamare il debugger: td cerca.exe


Codice Assembler

Il debugger mostra l'assegnazione di memoria del codice macchina, con le relative istruzioni in linguaggio mnemonico:

Nr. Indirizzo Istruzione Macchina Istruzione AsmCommento
1 CS:0000 B8 45 14mov ax, 1445inizializzazione dei registri segmento
2 CS:0003 8E D8mov ds, ax 
3 CS:0005 8E C0mov es, ax i due registri segmento puntano alla base dello stesso segmento
4 CS:0007 BA 00 00mov dx, 0000puntatore alla stringa testo
5 CS:000A B4 09mov ah, 09servizio mostra stringa
6 CS:000C CD 21int 21richiesta del servizio al sistema operativo
7 CS:000E FC cld direzione ricerca: da sinistra a destra
8 CS:000F BF 00 00mov di, 0000 l'offset della stringa si copia in DI
9 CS:0012 B9 51 00mov cx, 0051 la stringa è lunga 81 (=51 esa) caratteri
10 CS:0015 B0 70mov mov al, 70 il carattere da ricercare è p (codice ASCII=70 esa)
11 CS:0017 F2 AErepnz SCASB continua la ricerca finchè non trovi p (flag Z=1)
12 CS:0019 E3 06jcxz 0021 se non è stata trovata alcuna p CX=0
13 CS:001B BA 68 00mov dx, 0068 il carattere cercato è stato trovato
14 CS:001E EB 04jmp 0024 ;stampa il messaggio 'carattere trovato'
15 CS:0020 BA 51 00mov dx, 0051 ;stampa il messaggio 'carattere non trovato'
16 CS:0023 B4 09mov ah, 09 ;si richiede al DOS di mostrare una stringa
17 CS:0025 CD 21int 21 ;chiamata ai servizi del DOS

Le istruzioni 1, 2 e 3 inizializzano i registri segmento DS ed ES per puntare entrambi alla base dello stesso segmento.

Le istruzioni 4, 5 e 6 producono la stampa della stringa testo.

Le istruzioni 7, 8, 9 e 10 preparano la ricerca del carattere:


Esercizi

Eseguire il programma Passo-Passo: posizionare IP alla prima istruzione del programma, premere F7

Osservare l'avanzamento dei registri CX, DI e lo stato delle flag.

Se il carattere viene trovato come si può risalire alla sua posizione in memoria?

Con quali valori il debugger indica lo stato della flag di direzione?

Verificare il corretto funzionamento del programma anche nel caso di un carattere non presente nella stringa.

Apportare le modifiche necessarie per sperimentare il funzionamento del prefisso di ripetizione REPE (Repeat if Equal).

Scrivere un programma per copiare la stringa in un'altra area di memoria.


Ricerca di una word in una stringa

In questo esempio si mostra come ricercare una word (2 byte) in una stringa usando SCASW:

.model small

.code

  ORG 100h

inizio:

  MOV AX, @data

  MOV DS, AX

 

  CLD ; imposta la flag di direzione (0: indirizzi crescenti)

  MOV CX, 4 ; inizializza il contatore con la lunghezza della stringa

  MOV AX, DS ; inserisci in ES:DI il puntatore alla stringa

  MOV ES, AX

  LEA DI, numeri

  MOV AX, 9012h ; La word da cercare nella stringa è 9012h

  REPNE SCASW

  JZ trovata

nonTrovata:

  MOV AL, 'N' ; "No" - non Trovata

  MOV AH, 0Eh

  INT 10h

  JMP esci

trovata:

  MOV AL, 'S' ; "Sì" - trovata!

  MOV AH, 0Eh

  INT 10h

  DEC DI ; DI contiene l'offset della word 9012h nella stringa:

esci:

  MOV AX, 4C00h

  int 21h

.data

  numeri DW 1234h, 5678h, 9012h, 3456h

END inizio

La direttiva ORG (ORiGin) specifica l'offset, nel segmento codice, da cui deve iniziare la memorizzazione del programma

Avviare il debugger ed eseguire il programma passo passo.

Verificare che l'offset indicato dal programma corrisponda alla posizione della word all'interno della stringa


Procedura Mostra stringa terminata dal carattere NUL.

In qualsiasi linguaggio di programmazione una stringa è un array di caratteri dichiarato con una dimensione massima, ma usato solo parzialmente. Quindi si deve adottare un metodo per riconoscere il numero di caratteri effettivamente presenti nella stringa.

Un primo metodo consiste nello scrivere la lunghezza della stringa (cioè il numero di caratteri che la compongono) nel primo elemento dell'array. L'altro metodo ricorre a un carattere per marcare la fine, ad esempio il linguaggio C interpreta il carattere NUL (codice ASCII 0) come Fine Stringa.

Preparare, con il blocco note, il file seguente:

Il seguente sottoprogramma Assembler mostra sullo schermo una stringa di caratteri terminata con NUL. Riceve come parametro l'indirizzo della stringa sorgente nel registro BX.

.model small

.data

  latino db 'Vulpem pilum mutare, non mores', 10, 13, 0

  italiano db 'La volpe cambia il pelo, non i costumi', 10, 13, 0

  autore db 'Svetonio', 10, 13, 0

 

.code

stampa PROC

ciclo:

  MOV DL, [BX] ; BX punta alla stringa da mostrare

; il carattere puntato viene copiato in DL.

  AND DL, DL ; Se in DL è stato scritto il valore 0 (NUL) …

  JZ esci ; salta alla fine del sottoprogramma.

  INC BX ; altrimenti punta al carattere successivo

  MOV AH, 2 ; la funzione 2 del servizio 21

; mostra sullo schermo il carattere contenuto in DL.

  INT 21h

  JMP ciclo ; prelevare il prossimo carattere della stringa

esci:

  RET ; Ritorna al programma chiamante

stampa ENDP

inizio:

  MOV AX, @data

MOV DS, AX

 

  MOV BX, offset latino ; indirizzo della prima stringa

  CALL stampa ; mostra la prima stringa sullo schermo

  MOV BX, offset italiano ; indirizzo della seconda stringa

  CALL stampa ; mostra la seconda stringa sullo schermo

  MOV BX, offset autore ; indirizzo della terza stringa

  CALL stampa ; mostra la terza stringa sullo schermo

  MOV AX, 4C00h

  int 21h

END inizio

Il programma precedente contiene tre stringhe terminate dal carattere NUL.

La sezione codice contiene una procedura e il programma principale.

Richiamare il debugger ed eseguire il programma passo passo:

Osservare il valore del registro SP (Stack Pointer) prima e dopo l'istruzione CALL.


Trasformare una stringa in minuscolo

Scrivere il seguente programma:

.model small

.data

  latino db 'FACTA, NON VERBA', 10, 13, 0

.code

Il programma utilizza la funzione di stampa di una stringa già proposta nell'esercizio precedente:

stampa PROC

ciclo:

  MOV DL, [BX]

  AND DL, DL

  JZ esci

  INC BX

  MOV AH, 2

  INT 21h

  JMP ciclo

esci:

  RET

stampa ENDP

Nello stesso segmento codice viene definita una procedura che trasforma un carattere in minuscolo:

Minus PROC

ripeti:

  LODSB ; si copia il carattere puntato da SI in AL e SI si incrementa per puntare al carattere successivo

  AND AL, AL ; Se si è letto il carattere NUL

 JZ fine ; Allora salta all'istruzione fine

 CMP AL, 'A'

  JB riscrivi

  CMP AL, 'Z'

  JA riscrivi

  OR AL, 20h ; forza il bit 5 a 1

riscrivi:

  STOSB ; memorizza il carattere da AL all'indirizzo puntato da DI

  JMP ripeti

fine:

  RET

Minus ENDP

Il programma principale:

inizio:

  MOV AX, @data

  MOV DS, AX

  MOV ES, AX

 

  MOV BX, offset latino

  CALL stampa

 

  CLD ; Direzione di scansione della stringa

  MOV SI, offset latino ; Stringa sorgente

  MOV DI, offset latino ; e stringa destinazione coincidono

  CALL Minus ; chiama il sottoprogramma.

 

  MOV BX, offset latino

  CALL stampa

 

  mov AX, 4C00h

  int 21h

END inizio

Modificare il programma per trasformare la stringa in maiuscolo.