vezba 8 - uslovne strukture
DESCRIPTION
Vezba 8 - Uslovne StruktureTRANSCRIPT
-
1
8.
USLOVNE STRUKTURE
Uslovna struktura se definie kao jedan ili vie uslovnih izraza koji zahtevaju izbor
izmeu razliitih logikih grananja. Svakim grananjem se izvrava razliita sekvenca
instrukcija.
8.1 Blokovski IF iskazi
IF struktura podrazumeva da je logiki izraz praen sa dva skupa iskaza: jedan koji se
izvrava kada je izraz taan, a drugi kada je netaan:
if (logiki-izraz)
skup-iskaza-1
else
skup-iskaza-2
Else deo iskaza je opcioni. U asembleru, ova struktura se kodira po koracima. Najpre,
evaluira se logiki izraz tako da se jedan od procesorskih flegova menja. Potom, kreira se serija
skokova koji prosleuju kontrolu ka dva skupa iskaza, na osnovu vrednosti relevantnih flegova.
Primer 1
U sledeem C++ kodu, dva iskaza dodele se izvravaju ako je op1 jednako sa op2:
if( op1 == op2 ) then
{
X = 1;
Y = 2;
}
Ovaj IF iskaz se translira u asemblerski jezik pomou CMP instrukcije posle koje slede
uslovni skokovi. Poto su op1 i op2 memorijski operandi (promenljive), jedna od njih mora biti
premetena u registar pre izvravanja CMP instrukcije. Sledei kod najefikasnije implementira
IF iskaz tako to omoguava kodu da propagira ka dve MOV instrukcije koje elimo da
izvrimo kada je logiki iskaz taan:
mov eax,op1
-
2
cmp eax,op2 ; op1 == op2?
jne L1 ; ne: preskoi sledee naredbe
mov X,1 ; da: dodeli X i Y
mov Y,2
L1:
Ako implementiramo operator == koristei JE instrukciju, rezultujui kod e biti manje
kompaktan (est instrukcija umesto pet):
cmp eax,op2 ; op1 == op2?
je L1 ; da: skoi na L1
jmp L2 ; ne: preskoi dodele
L1: mov X,1 ; dodeli X i Y
mov Y,2
L2:
Primer 2
U FAT32 fajl sistemu, veliina klastera na disku zavisi od celokupnog kapaciteta diska.
U sledeem pseudokodu, podeavamo veliinu klastera na 4.096 ako je veliina diska (u
promenljivoj gigabytes) manja od 8 GB. U suprotnom, podeavamo veliinu klastera na 8.192:
clusterSize = 8192;
if gigabytes < 8
clusterSize = 4096;
Sledi nain kako se moe implementirati isti iskazi u asembleru:
mov clusterSize,8192 ; pretpostavka veeg klastera
cmp gigabytes,8 ; da li je vei od 8 GB?
jae next
mov clusterSize,4096 ; uzmi manji klaster
next:
Primer 3
Sledei pseudokod ima dva grananja:
if op1 > op2 then
call Routine1
else
call Routine2
end if
U sledeem asemblerskom prevodu pseudokoda, pretpostavljamo da su op1 i op2
oznaene promenljive veliine dvostruke rei. Kada se porede promenljive, jedna se mora
premestiti u registar:
mov eax,op1 ; prebaci op1 u registar
cmp eax,op2 ; op1 > op2?
jg A1 ; da: call Routine1
call Routine2 ; ne: call Routine2
jmp A2 ; izlaz iz IF iskaza
A1: call Routine1
A2:
-
3
8.1.1 White box testiranje
Sloeni uslovni iskazi mogu imati nekoliko putanja izvravanja, to ih ini teke za
debagovanje po principu inspekcije (pregleda koda). Programeri esto implementiraju tehniku
poznatu kao white box testiranje, koja verifikuje ulaze i odgovarajue izlaze subrutina. White
box testiranje zahteva da imate kopiju izvornog koda. Dodeljujete veliki skup vrednosti ulaznim
promenljivama. Za svaku kombinaciju ulaza, runo prolazite kroz izvorni kod i verifikujete
putanje izvravanja i izlaze koje daje subrutina. Da vidimo kako se to radi u asembleru tako to
emo implementirati sledei ugnjedeni IF iskaz:
if op1 == op2 then
if X > Y then
call Routine1
else
call Routine2
end if
else
call Routine3
end if
Sledi mogui nain transliranja u asemblerski jezik, sa dodatim brojevima linija. Kod
obre poetni uslov (op1 == op2) i odmah skae na ELSE deo. Sve to je ostalo jeste da se
translira unutranji IF-ELSE iskaz:
1: mov eax,op1
2: cmp eax,op2 ; op1 == op2?
3: jne L2 ; ne: call Routine3
; Obrada unutranjeg IF-ELSE iskaza.
4: mov eax,X
5: cmp eax,Y ; X > Y?
6: jg L1 ; da: call Routine1
7: call Routine2 ; ne: call Routine2
8: jmp L3 ; izlaz
9: L1: call Routine1 ; call Routine1
10: jmp L3 ; izlaz
11: L2: call Routine3
12: L3:
U tabeli 1 su prikazani rezultati white box testiranja ovog koda. U prve etiri kolone,
testne vrednosti su dodeljene promenljivama op1, op2, X i Y. Rezultujue putanje izvravanja
su verifikovane u kolonama 5 i 6.
Tabela 1. Testiranje ugnjedenog IF iskaza
op1 op2 X Y Sekvenca izvravanja linija koda Pozivi
10 20 30 40 1, 2, 3, 11, 12 Routine3
10 20 40 30 1, 2, 3, 11, 12 Routine3
10 10 30 40 1, 2, 3, 4, 5, 6, 7, 8, 12 Routine2
10 10 40 30 1, 2, 3, 4, 5, 6, 9, 10, 12 Routine1
-
4
8.2 Sloeni izrazi
8.2.1 Logiki AND operator
Asemblerski jezik lako implementira sloene logike izraze koji sadre AND operator.
Posmatrajmo sledei pseudokod, u kojem se pretpostavlja da su vrednosti koje se porede
neoznaeni celi brojevi:
if (al > bl) AND (bl > cl) then
X = 1
end if
8.2.2 Evaluacija po principu kratkog spoja
Sledi implementacija po principu evaluacije kratkog spoja, u kojoj se drugi izraz ne
evaluira ako je prvi iskaz netaan. To je standardno za jezike visokog nivoa:
cmp al,bl ; prvi izraz...
ja L1
jmp next
L1: cmp bl,cl ; drugi izraz...
ja L2
jmp next
L2: mov X,1 ; oba tana: podesi X na 1
next:
Kod se moe smanjiti na pet instrukcija tako to se poetna JA instrukcija zameni sa JBE:
cmp al,bl ; prvi izraz...
jbe next ; izai ako je netaan
cmp bl,cl ; drugi izraz
jbe next ; izai ako je netaan
mov X,1 ; oba su tana
next:
Redukcija veliine koda od 29% (sa 7 na 5 instrukcija) se deava jer se procesoru
dozvoljava da propagira kroz kod do druge CMP instrukcije ako prvi JBE skok nije izvren.
8.2.3 Logiki OR operator
Kada sloeni izraz sadri podizraz sastavljen sa OR operatorom, celokupan izraz je taan
ako je bilo koji od podizraza taan. Koristiemo sledei pseudokod kao primer:
if (al > bl) OR (bl > cl) then
X = 1
U sledeoj implementaciji, kod skae na L1 ako je prvi izraz taan. U suprotnom,
propagira do druge CMP instrukcije. Drugi izraz obre operator > i koristi JBE umesto toga:
cmp al,bl ; 1: poreenje AL sa BL
ja L1 ; ako je tano, preskoi sledei iskaz
cmp bl,cl ; 2: poreenje BL sa CL
jbe next ; netano: preskoi sledei iskaz
L1: mov X,1 ; tano: setuj X = 1
-
5
next:
Za sledei sloeni izraz, postoji nekoliko naina implementacije u asembleru.
8.3 WHILE petlje
WHILE petlja testira uslov pre izvravanja skupa iskaza. Sve dok je uslov petlje taan,
iskazi se ponavljaju. Sledea petlja je napisana u C++-u:
while( val1 < val2 )
{
val1++;
val2--;
}
Kada se ova struktura implementira u asemblerskom jeziku, pogodno je obrnuti uslov u
petlji i skoiti na endwhile ako uslov postane taan. Pod pretpostavkom da su val1 i val2
promenljive, moramo kopirati jednu od njih u registar na poetku, a restaurirati vrednost
promenljive na kraju:
mov eax,val1 ; kopiraj promenljivu u EAX
beginwhile:
cmp eax,val2 ; if not (val1 < val2)
jnl endwhile ; izai iz petlje
inc eax ; val1++;
dec val2 ; val2--;
jmp beginwhile ; ponovi petlju
endwhile:
mov val1,eax ; sauvaj novu vrednost za val1
EAX je posrednik (zamena) za val1 unutar petlje. Reference na val1 moraju biti kroz
EAX. Koristi se JNL, to oznaava da su val1 i val2 oznaeni celi brojevi.
Primer: IF iskaz ugnjeden u petlji
Jezici visokog nivoa su posebno dobri za prikaz ugnjedenih kontrolnih struktura. U
sledeem C++ kodu, IF iskaz je ugnjeden unutar WHILE petlje. Rauna se suma svih
elemenata niza veih od vrednosti u sample:
int array[] = {10,60,20,33,72,89,45,65,72,18};
int sample = 50;
int ArraySize = sizeof array / sizeof sample;
int index = 0;
int sum = 0;
while( index < ArraySize )
{
if( array[index] > sample )
{
sum += array[index];
}
index++;
-
6
}
Pre kodiranja ove petlje u asembleru, koristiemo algoritam prikazan na slici 1 da bismo
opisali logiku. Da bismo pojednostavili translaciju i ubrzali izvravanje smanjenjem broja
pristupa memoriji, registri zamenjuju promenljive. EDX = sample, EAX = sum, ESI = index i
ECX = ArraySize (konstanta). Dodata su i imena labela.
Slika 1. Petlja koja sadri IF iskaz
Asemblerski kod
Najlaki nain za generisanje asemblerskog koda iz algoritma je implementacija
posebnog koda za svaki element u algoritmu. Primetite direktnu povezanost izmeu labela u
algoritmu i labela koje se koriste u sledeem kodu:
.data
sum DWORD 0
sample DWORD 50
array DWORD 10,60,20,33,72,89,45,65,72,18
ArraySize = ($ - Array) / TYPE array
.code
main PROC
mov eax,0 ; sum
-
7
mov edx,sample
mov esi,0 ; index
mov ecx,ArraySize
L1: cmp esi,ecx ; if esi < ecx
jl L2
jmp L5
L2: cmp array[esi*4], edx ; if array[esi] > edx
jg L3
jmp L4
L3: add eax,array[esi*4]
L4: inc esi
jmp L1
L5: mov sum,eax
8.3.1 Selekcija na osnovu tabele
Selekcija na osnovu tabele je nain kako se moe koristiti tabela za pretragu koja
zamenjuje strukturu viestrukih selekcija. Da bi se koristila, mora se kreirati tabela koja sadri
vrednosti koje se trae i ofsete labela ili procedura, a potom se mora koristiti petlja za
pretraivanje tabele. Ovo najbolje radi kada se vri veliki broj poreenja.
Na primer, sledi deo tabele koja sadri vrednosti od jednog karaktera i adrese procedura:
.data
CaseTable BYTE 'A' ; vrednost koja se trai
DWORD Process_A ; adresa procedure
BYTE 'B'
DWORD Process_B
(itd.)
Pretpostavimo da se Process_A, Process_B, Process_C i Process_D nalaze na adresama
120h, 130h, 140h i 150h, respektivno. Tabela bi bila smetena u memoriji kao na slici 2.
Slika 2. Tabela ofseta procedura
Programski kod
U sledeem programu, korisnik unosi karakter sa tastature. Koristei petlju, karakter se
poredi sa svakim ulazom u tabeli. Prvo podudaranje prouzrokuje poziv ofseta procedure koja
je smetena neposredno nakon vrednosti. Svaka procedura u EDX uitava ofset razliitog
stringa, koji se prikazuje tokom petlje:
TITLE Tabela ofseta procedura (ProcTble.asm) ; Ovaj program sadri tabelu sa ofsetima procedura. ; Koristi tabelu za izvravanje indirektnih poziva procedura.
-
8
INCLUDE Irvine32.inc .data CaseTable BYTE 'A' ; vrednost koja se trai DWORD Process_A ; adresa procedure EntrySize = ($ - CaseTable) BYTE 'B' DWORD Process_B BYTE 'C' DWORD Process_C BYTE 'D' DWORD Process_D NumberOfEntries = ($ - CaseTable) / EntrySize prompt BYTE "Press capital A,B,C,or D: ",0 ; Definisanje posebne poruke za svaku proceduru. msgA BYTE "Process_A",0 msgB BYTE "Process_B",0 msgC BYTE "Process_C",0 msgD BYTE "Process_D",0 .code main PROC mov edx,OFFSET prompt ; pitaj korisnika da unese karakter call WriteString call ReadChar ; uitaj karakter u AL mov ebx,OFFSET CaseTable ; ukai EBX na tabelu mov ecx,NumberOfEntries ; broja petlje L1: cmp al,[ebx] ; pronaeno podudaranje? jne L2 ; ne: nastavi call NEAR PTR [ebx + 1] ; da: pozovi proceduru ; Ova instrukcija CALL poziva proceduru ija je adresa smetena na memorijskoj lokaciji na koju ukazuje EBX + 1. Indirektan poziv poput ovog zahteva NEAR PTR operator. call WriteString ; prikaz poruke call Crlf jmp L3 ; izai iz pretrage L2: add ebx,EntrySize ; ukai na sledei ulaz loop L1 ; ponovi dok ne bude ECX = 0 L3: exit main ENDP ; Svaka od sledeih procedura premeta razliit ofset stringa u EDX. Process_A PROC mov edx,OFFSET msgA ret Process_A ENDP Process_B PROC mov edx,OFFSET msgB ret Process_B ENDP Process_C PROC mov edx,OFFSET msgC ret Process_C ENDP
-
9
Process_D PROC mov edx,OFFSET msgD ret Process_D ENDP END main
Ovaj metod ima odreene reperkusije, ali moe da smanji veliinu koda. Tabela moe da
radi sa velikim brojem poreenja, a moe se i lake modifikovati neko dugaka serija poreenja,
skokova i CALL instrukcija. Tabela se ak moe rekonfigurisati i u vreme izvravanja.
8.4 Konani automati
Konani automat (finite-state machine, FSM) je maina ili program koji menja stanje na
osnovu nekog ulaza. FSM se jednostavno predstavlja preko grafa koji sadri kvadrate (ili
krugove) koji se nazivaju vorovi, i linija sa strelicama izmeu krugova, koje se nazivaju ivice
(ili lukovi).
Jednostavan primer je prikazan na slici 3. Svaki vor predstavlja stanje programa, a svaka
ivica predstavlja prelaz iz jednog stanja u drugo. Jedan vor je oznaen kao poetno stanje, to
je na dijagramu prikazano sa dolazeom strelicom. Ostala stanja se mogu oznaiti sa brojevima
ili slovima. Jedno ili vie stanja se oznaava kao krajnje stanje, prikazano sa debelom ivicom
oko kvadrata. Krajnje stanje predstavlja stanje u kojem se program moe zaustaviti, a da se ne
prijavi greka. FSM je specifina instanca generalnijeg tipa struktura koje se nazivaju direktni
grafovi.
Slika 3. Jednostavan konani automat
8.4.1 Validacija ulaznog stringa
Programi koji itaju ulazne tokove podataka esto moraju da proveravaju ulaze tako to
obavljaju odreene provere na greke. Na primer, kompajler programskog jezika moe da
koristi FSM da bi proverio izvorne programe i konvertovao rei i simbole u tokene, koji su
obino kljune rei, aritmetiki operatori i identifikatori.
Kada se koristi FSM za proveru validnosti ulaznog stringa, obino se ita ulaz karakter
po karakter. Svaki karakter je predstavljen sa ivicom (prelazom) u dijagramu. FSM detektuje
pogrenu sekvencu ulaza na jedan od dva naina:
Sledei karakteri ne odgovara nijednom prelazu iz trenutnog stanja.
-
10
Kraj ulaza je dostignut, a trenutno stanje je nije krajnje stanje.
Primer sa karakterima u stringu
Hajde da proverimo validnost ulaznog stringa na osnovu dva pravila:
String mora poinjati sa slovom x, a zavravati se sa slovom z.
Izmeu prvog i poslednjeg karaktera, moe postojati nula ili vie slova unutar
opsega {a..y}.
FSM dijagram sa slike 4 opisuje ovu sintaksu. Svaki prelaz je identifikovan sa
pojedinanim tipom ulaza. Na primer, prelaz iz stanja A u stanje B se jedino moe desiti ako se
slovo x oita sa ulaza. Prelaz iz stanja B u samo sebe se deava ako je na ulazu bilo koje slovo
alfabeta osim z. Prelaz iz stanja B u stanje C se deava samo kada se sa ulaza oita slovo z.
Slika 5. FSM za string
Ako je kraj ulaznog toka podataka dostignut dok je program u stanju A ili B, dolazi do
greke, jer je samo stanje C oznaeno kao krajnje stanje. FSM bi prepoznala sledee ulazne
stringove:
xaabcdefgz
xz
xyyqqrrstuvz
Validacija oznaenog celog broja
FSM za parsiranje oznaenog celog broja je prikazana na slici 5. Ulaz se sastoji od
opcionog poetnog znaka posle koga ide sekvenca cifara. Ne postoji maksimalni broj cifara koji
se moe uneti, na osnovu ovog dijagrama.
Slika 5. FSM za oznaene decimalne cele brojeve
-
11
FSM se lako transliraju u asemblerski kod. Svako stanje na dijagramu (A, B, C,) je
predstavljeno sa labelom u programu. Sledee radnje se izvravaju na svakoj labeli:
Pozivom ulazne procedure se oitava sledei karakter sa ulaza.
Ako je stanje krajnje, proveri da li je korisnik pritisnuo taster Enter za kraj.
Jedna ili vie instrukcija za poreenje proverava svaki mogui prelaz koji vodi iz
datog stanja. Svako poreenje je praeno sa instrukcijom uslovnog skoka.
Na primer, u stanju A, sledei kod oitava sledei ulazni karakter i proverava mogui
prelaz u stanje B:
StateA:
call Getnext ; uitaj sledei karakter u AL
cmp al,'+' ; da li poinje sa +?
je StateB ; idi u stanje B
cmp al,'-' ; da li poinje sa -?
je StateB ; idi u stanje B
call IsDigit ; ZF = 1 ako AL sadri cifru
jz StateC ; idi u stanje C
call DisplayErrorMsg ; nekorektan ulaz
jmp Quit
Labela Quit oznaava izlaznu taku programa, na kraju glavne procedure:
Quit:
call Crlf
exit
main ENDP
Sledi i kompletan programski kod.
TITLE Finite State Machine (Finite.asm) INCLUDE Irvine32.inc ENTER_KEY = 13 .data InvalidInputMsg BYTE "Nekorektan ulaz",13,10,0 .code main PROC call Clrscr StateA: call Getnext ; uitaj sledei karakter u AL cmp al,'+' ; da li poinje sa +? je StateB ; idi u stanje B cmp al,'-' ; da li poinje sa -? je StateB ; idi u stanje B call IsDigit ; ZF = 1 ako AL sadri cifru jz StateC ; idi u stanje C call DisplayErrorMsg ; nekorektan ulaz jmp Quit StateB: call Getnext ; uitaj sledei karakter u AL call IsDigit ; ZF = 1 ako AL sadri cifru jz StateC
-
12
call DisplayErrorMsg ; nekorektan ulaz jmp Quit StateC: call Getnext ; uitaj sledei karakter u AL call IsDigit ; ZF = 1 ako AL sadri cifru jz StateC cmp al,ENTER_KEY ; Da li je pritisnut Enter? je Quit ; da: izai call DisplayErrorMsg ; ne: nekorektan ulaz jmp Quit Quit: call Crlf exit main ENDP ;----------------------------------------------- Getnext PROC ; ; Uitava karakter sa standardnog ulaza. ; Prima: nita ; Vraa: AL sadri karakter ;----------------------------------------------- call ReadChar ; ulaz sa tastature call WriteChar ; ispis na ekranu ret Getnext ENDP ;----------------------------------------------- DisplayErrorMsg PROC ; ; Prikazuje poruku o greci koja pokazuje ; da ulazni tok podataka sadri nekorektan unos. ; Prima: nita. ; Vraa: nita ;----------------------------------------------- push edx mov edx,OFFSET InvalidInputMsg call WriteString pop edx ret DisplayErrorMsg ENDP END main
Ovaj program poziva proceduru IsDigit, koja se nalazi u Irvine32 biblioteci. Ona prima
AL registar kao ulaz, a vrednost koja vraa predstavlja podeavanje Zero flega.
;-----------------------------------------------------------
IsDigit PROC
;
; Odreuje da li je karakter u AL validna decimalna cifra.
; Prima: AL = karakter
; Vraa: ZF = 1 ako AL sadri validnu decimalnu cifru; u
suprotnom, ZF = 0.
;-----------------------------------------------------------
cmp al,'0'
jb ID1 ; ZF = 0 kada se skok izvri
cmp al,'9'
-
13
ja ID1 ; ZF = 0 kada se skok izvri
test ax,0 ; setuje ZF = 1
ID1: ret
IsDigit ENDP
U sledeoj tabeli su prikazani ASCII kodovi decimalnih cifara. Poto su vrednosti
kontinualne, treba da proverimo samo opseg izmeu poetne i krajnje vrednosti.
Karakter 0 1 2 3 4 5 6 7 8 9
ASCII kod (hex) 30 31 32 33 34 35 36 37 38 39
U proceduri IsDigit, prve dve instrukcije porede karakter u AL registru sa ASCII kodom
za cifru 0. Ako je numeriki ASCII kod karaktera manji od ASCII koda za 0, program skae na
labelu ID1:
cmp al,'0'
jb ID1 ; ZF = 0 kada doe do skoka
Ali neko moe upitati, ako JB prosleuje kontrolu labeli ID1, kako znamo stanje Zero
flega? Odgovor je u nainu na koji CMP radi: obavlja se implicitno oduzimanje ASCII koda za
nulu (30h) od karaktera u AL registru. Ako je vrednost u AL manja, Carry fleg je setovan, a
Zero fleg je obrisan. Instrukcija JB je dizajnirana da prosleuje kontrolu labeli kada je CF = 1
i ZF = 0.
Potom, kod u proceduri poredi AL sa ASCII kodom za cifru 9. Ako je vrednost vea, kod
skae na istu labelu:
cmp al,'9'
ja ID1 ; ZF = 0 kada doe do skoka
Ako je ASCII kod za karakter u AL vei od ASCII koda cifre 9 (39h), Carry i Zero flegovi
su obrisani. To je upravo kombinacija flegova koja dovodi da JA instrukcija prosledi kontrolu
labeli.
Ako nijedan skok nije izvren (ni JA ni JB), pretpostavljamo da je karakter u AL zaista
cifra. Samim tim, ubacujemo instrukciju koja zasigurno setuje Zero fleg. Testiranje bilo koje
vrednosti sa nulom oznaava da se vri implicitna AND operacija sa svim nulama. Rezultat
mora biti nula:
test ax,0 ; setuje ZF = 1
Instrukcije JA i JB skau na labelu koja je domah posle TEST instrukcije. Ako da, ako se
ti skokovi izvre, Zero fleg e biti obrisan.
8.5 Direktive za uslovnu kontrolu toka
MASM poseduje vei broj direktiva visokog nivoa za uslovnu kontrolu toka koje
pojednostavljuju kodiranje uslovnih iskaza. Pre asembliranja koda, asembler vri
-
14
pretprocesiranje. U ovom koraku, on prepoznaje direktive kao to su .CODE, .DATA, kao i
direktive koje se mogu koristiti za uslovnu kontrolu toka. U tabeli 2 su prikazane ove direktive.
Tabela 2. Direktive za uslovnu kontrolu toka
Direktiva Opis
.BREAK Generie kod za zavretak .WHILE ili .REPEAT bloka.
.CONTINUE Generie kod za skok na poetak .WHILE ili .REPEAT bloka.
.ELSE Poetak bloka iskaza koji se izvravaju kada je .IF uslov netaan.
.ELSEIF uslov Generie kod koji testira uslov i izvrava iskaze koji slede potom, sve dok se ne doe do .ENDIF ili druge .ELSEIF direktive.
.ENDIF Zavrava blok iskaza koji poinje sa .IF, .ELSE ili .ELSEIF direktivom.
.ENDW Zavrava blok iskaza koji poinje sa .WHILE.
.IF uslov Generie kod koji izvrava blok iskaza ako je uslov taan.
.REPEAT Generie kod koji ponavlja izvravanje bloka iskaza sve dok uslov ne postane taan.
.UNTIL uslov Generie kod koji ponavlja izvravanje bloka iskaza izmeu .REPEAT i .UNTIL sve dok uslov ne postane taan.
.UNTILCXZ Generie kod koji ponavlja izvravanje bloka iskaza izmeu .REPEAT i .UNTIL sve dok CX ne postane jednak nuli.
.WHILE uslov Generie kod koji izvrava blok iskaza izmeu .WHILE i .ENDW sve dok je uslov taan.
8.5.1 Kreiranje IF iskaza
Direktive .IF, .ELSE, .ELSEIF i .ENDIF olakavaju kodiranje logike viestrukog
grananja. One ine da asembler generie CMP i instrukcije uslovnog skoka u pozadini, koje se
pojavljuju u izlaznom listingu. Sintaksa je:
.IF uslov1
iskazi
[.ELSEIF uslov2
iskazi ]
[.ELSE
iskazi ]
.ENDIF
Uglaste zagrade oznaavaju da su .ELSEIF i .ELSE opcioni, dok su .IF i .ENDIF
obavezni. Uslov je logiki izraz koji ima iste operatore koji se koriste u C++ i Javi (kao to su
, ==, !=). Izraz se evaluira u vreme izvravanja. Slede primeri validnih uslova, koji koriste
32-bitne registre i promenljive:
eax > 10000h
val1 0) && (eax > 10000h)
(val1
-
15
(val2 != ebx) && !CARRY?
Kompletna lista relacionih i logikih operatora je prikazana u tabeli 3.
Tabela 3. Relacioni i logiki operatori
Operator Opis
expr1 == expr2 Vraa true kada je expr1 jednako sa expr2.
expr1 != expr2 Vraa true kada expr1 nije jednako sa expr2.
expr1 > expr2 Vraa true kada je expr1 vee od expr2.
expr1 >= expr2 Vraa true kada je expr1 vee ili jednako sa expr2.
expr1 < expr2 Vraa true kada je expr1 manje od expr2.
expr1 val1
mov result,1
.ENDIF
Pretpostavlja se da su val1 i result 32-bitni neoznaeni celi brojevi. Kada asembler proita
gornje linije koda, on ih proiruje u sledee asemblerske instrukcije, koje se mogu videti
prilikom debagovanja u Disassembly prozoru:
mov eax,6
cmp eax,val1
jbe @C0001 ; skok na osnovu neoznaenog poreenja
mov result,1
@C0001:
Labela @C001 je kreirana od strane asemblera. To se radi tako da se garantuje da su sve
labele unutar iste procedure jedinstvene.
Poreenje oznaenih i neoznaenih vrednosti
Kada se koristi .IF direktiva za poreenje vrednosti, mora se voditi rauna da MASM
generie uslovne skokove. Ako se poredi neoznaena promenljiva, u generisani kod se ubacuje
-
16
instrukcija neoznaenog uslovnog skoka. Sledei primer je isti kao i gornji, samo sa definisanim
promenljivama:
.data
val1 DWORD 5
result DWORD ?
.code
mov eax,6
.IF eax > val1
mov result,1
.ENDIF
Asembler ovaj kod proiruje koristei JBE (instrukciju neoznaenog skoka):
mov eax,6
cmp eax,val1
jbe @C0001 ; skok na osnovu neoznaenog poreenja
mov result,1
@C0001:
Poreenje oznaenih celih brojeva
Ako .IF direktiva poredi oznaene promenljive, u kod se ubacuju instrukcije oznaenog
uslovnog skoka. Na primer, val2 je oznaena dvostruka re:
.data
val2 SDWORD -1
result DWORD ?
.code
mov eax,6
.IF eax > val2
mov result,1
.ENDIF
Samim tim, asembler generie kod ubacujui instrukciju JLE:
mov eax,6
cmp eax,val2
jle @C0001 ; skok na osnovu oznaenog poreenja
mov result,1
@C0001:
Poreenje registara
Prilikom poreenja vrednosti u dva registra, asembler ne moe znati da li su vrednosti u
njima oznaene ili neoznaene:
mov eax,6
mov ebx,val2
.IF eax > ebx
mov result,1
.ENDIF
-
17
Generie se sledei kod, koji pokazuje da je podrazumevana vrednost neoznaeno
poreenje:
mov eax,6
mov ebx,val2
cmp eax, ebx
jbe @C0001
mov result,1
@C0001:
8.5.2 Sloeni izrazi
Dosta sloenih logikih izraza koristi logike OR i AND operatore. Kada se koristi .IF
direktiva, simbol || oznaava logiki OR operator:
.IF izraz1 || izraz2
iskazi
.ENDIF
Slino, simbol && je oznaka za logiki AND operator:
.IF izraz1 && izraz2
iskazi
.ENDIF
Primer 1
U sledeem primeru je prikazana SetCursorPosition procedura, koja proverava opseg
vrednosti dva ulazna parametra, DH i DL. Y-koordinata (DH) mora biti izmeu 0 i 24. X-
koordinata (DL) mora biti izmeu 0 i 79. U sluaju pogrenog opsega, prikazuje se poruka o
greci.
SetCursorPosition PROC
; Podeava poziciju kursora.
; Prima: DL = X-koordinata, DH = Y-koordinata.
; Proverava opsege DH i DL.
; Vraa: nita
;------------------------------------------------
.data
BadXCoordMsg BYTE "X-koordinata van opsega!",0Dh,0Ah,0
BadYCoordMsg BYTE "Y-koordinata van opsega!",0Dh,0Ah,0
.code
.IF (dl < 0) || (dl > 79)
mov edx,OFFSET BadXCoordMsg
call WriteString
jmp quit
.ENDIF
.IF (dh < 0) || (dh > 24)
mov edx,OFFSET BadYCoordMsg
call WriteString
jmp quit
.ENDIF
call Gotoxy
-
18
quit:
ret
SetCursorPosition ENDP
Sledi kod kojeg generie MASM:
.code
; .IF (dl < 0) || (dl > 79)
cmp dl, 000h
jb @C0002
cmp dl, 04Fh
jbe @C0001
@C0002:
mov edx,OFFSET BadXCoordMsg
call WriteString
jmp quit
; .ENDIF
@C0001:
; .IF (dh < 0) || (dh > 24)
cmp dh, 000h
jb @C0005
cmp dh, 018h
jbe @C0004
@C0005:
mov edx,OFFSET BadYCoordMsg
call WriteString
jmp quit
; .ENDIF
@C0004:
call Gotoxy
quit:
ret
Primer 2
Pretpostavimo da student eli da se registruje za kurs. Koristiemo dva kriterijuma da li
student moe da se registruje: prvi je procena ocena, na skali od 0 do 400, gde je 400 najvea
ocena. Drugi je broj ESPB bodova koje student eli da upie. Moe se koristiti .IF, .ELSEIF i
.ENDIF.
.data
TRUE = 1
FALSE = 0
gradeAverage WORD 275 ; testna vrednost
credits WORD 12 ; testna vrednost
OkToRegister BYTE ?
.code
mov OkToRegister,FALSE
.IF gradeAverage > 350
mov OkToRegister,TRUE
.ELSEIF (gradeAverage > 250) && (credits
-
19
.ENDIF
Sledi i kod koji generie MASM.
mov byte ptr OkToRegister,FALSE
cmp word ptr gradeAverage,350
jbe @C0006
mov byte ptr OkToRegister,TRUE
jmp @C0008
@C0006:
cmp word ptr gradeAverage,250
jbe @C0009
cmp word ptr credits,16
ja @C0009
mov byte ptr OkToRegister,TRUE
jmp @C0008
@C0009:
cmp word ptr credits,12
ja @C0008
mov byte ptr OkToRegister,TRUE
@C0008:
8.5.3 Kreiranje petlji sa .REPEAT i .WHILE
Direktive .REPEAT i .WHILE pruaju alternativan nain pisanja petlji, umesto CMP i
instrukcija uslovnog skoka. Dozvoljavaju korienje uslovnih iskaza prikazanih u tabeli 3.
Direktiva .REPEAT izvrava telo petlje pre testiranja uslova u .UNTIL direktivi:
.REPEAT
iskazi
.UNTIL condition
Direktiva .WHILE testira uslov pre izvravanja petlje:
.WHILE uslov
iskazi
.ENDW
Primeri
Sledei iskazi prikazuju vrednosti od 1 do 10 koristei .WHILE direktivu. EAX je
incijalizovan na nulu pre petlje. Potom, u prvom iskazu unutar petlje, EAX se inkrementira.
Direktiva .WHILE izlazi iz petlje kada EAX bude jednako 10.
mov eax,0
.WHILE eax < 10
inc eax
call WriteDec
call Crlf
.ENDW
Sledei iskazi prikazuju ispis vrednosti od 1 do 10 koristei .REPEAT direktivu:
mov eax,0
.REPEAT
-
20
inc eax
call WriteDec
call Crlf
.UNTIL eax == 10
Primer: petlja koja sadri IF iskaz
Pseudokod za WHILE petlju koja sadri IF iskaz je:
while( op1 < op2 )
{
op1++;
if( op1 == op3 )
X = 2;
else
X = 3;
}
Sledi implementacija ovog pseudokoda koristei .WHILE i .IF direktive. Poto su op1,
op2 i op3 promenljive, premetaju se u registre kako bi se izbeglo posedovanje dva memorijska
operanda u bilo kojoj instrukciji:
.data
X DWORD 0
op1 DWORD 2 ; testni podatak
op2 DWORD 4 ; testni podatak
op3 DWORD 5 ; testni podatak
.code
mov eax,op1
mov ebx,op2
mov ecx,op3
.WHILE eax < ebx
inc eax
.IF eax == ecx
mov X,2
.ELSE
mov X,3
.ENDIF
.ENDW