Porovnavanie retazcov I.

   Dnes si pohovorime (presnejsie popiseme) o jednej typickej ulohe, ktora sa vyskytuje pri programovani nielen strojovom kode, ale aj vo vyssich programovacich jazykoch. Touto ulohou je porovnanie dvoch retazcov. Vo vyssich jazykoch je na provnavanie retazcov alebo nejaky prikaz ci operator, alebo aspon nejaka standartna kniznicna funkcia. Ale v strojovom kode nic take nemame, preto si to musime sami poctivo naprogramovat.

   Este pred tym, ako prejeme k samotnemu algoritmu a k programu, musime si najskor definovat strukturu udajovych prvkov. Ludsky povedane, musi nam byt jasne ze ake retazce vlastne budeme porovnavat. Lebo tazko sa nam bude pisat program na spracovanie niecoho, ked ani nevieme ako to vlastne vyzera... Zvolme si, ze nase sa budu skladat z jednotlivych bajtov. Mohli by sa skladat aj z inych poloziek (napr. z dvojbajtovych hodnot), ale to by uz bolo ovela zlozitejsie. Majme teda v pameti dva retazce - prvy je na adrese add1, druhy na adrese add2. To ze je retazec na adrese XYZ znamena, ze na tejto adrese je jeho zaciatocny alebo prvy bajt. Druhy bajt je na adrese XYZ+1, treti na XYZ+2 a tak postupne az po posledny. Nech su tieto nase retazce rovnako dlhe a nech maju dlzku len. Tymto sme si presne definovali strukturu udajov a mozme si vymysliet nejaky rafinovany porovnavaci algoritmus.
   So samotnym algoritmom sa trapit nemusime, pretoze ho uz davno vymysleli mudre hlavy (hlavicky-makovicky). Len si ho pripomenieme. Najprv sa porovnaju prve bajty v retazcoch. Ak su rozne, vysledok celeho porovnavania retazcov bude taky isty ako vysledok porovnania tychto dvoch bajtov a algoritmus konci. Ale ak su tieto dva bajty rovnake, celu cinnost dokola opakujeme s nasledujucimi (druhymi, tretimi,atd.) bajtami v retazcoch az kym alebo nenarazime na rozne bajty alebo neprideme na koniec aspon jedneho retazca. V nasom pripade su oba retazce rovnako dlhe, cize prideme na konce oboch retazcov naraz. V tomto pripade vyhlasime oba retazce za zhodne a rovnake.
   Tak, mame strukturu udajov a algoritmus a konecne mozeme prikrocit k napisaniu samotneho programu. Pre samotne porovnanie dvoch bajtov by sa nam hodila instrukcia, ktora porovnava dva bajty v pameti. Ale taka zial neexistuje. Preto sa musime uspokojit s instrukciou, pri ktorej je jeden bajt v pameti a druhy v akumulatore. Je to cp (hl). Tato instrukcia adresu bajtu v pameti chce v registri HL, preto si aj my do tohoto registra umiestnime adresu prveho retazca. Druhy bajt musi byt v akumulatore, preto ho sem musime nejak dostat. No a na to mame hned celu plejadu instrukcii. Pre nas najvhodnejsia bude instrukcia ld a,(de). Z tohto hned vidime, ze vhodne miesto pre adresu druheho retazca bude register DE. Ked budeme mat bajty porovnane, musime sa rozhodnut - alebo su rozne a program ukoncime (vyriesi to instrukcia ret nz), alebo budeme pokracovat porovnavanim dalsich bajtov. Aby sme vedeli, kolko bajtov este mame porovnat, potrebujeme na zaciatku prace vediet dlzku retazcov. Este mame volny registrovy par BC, preto ho vyuzijme a do neho umiestnime tuto dlzku. Register BC nas bude pocas nasho porovnavania informovat, ze kolko bajtov ostava este do konca retazcov.

   Nas program bude (po prvom priblizeni) vyzerat takto:

    
 ld hl,add1 adresa prveho retazca 
 ld de,add2 adresa druheho retazca 
 ld bc,len dlzka retazcov 
loop ld a,(de) vezme bajt z druheho retazca 
 cp (hl) porovna s bajtom z prveho retazca 
 ret nz pri rozdiele - vysledok je jasny 
 inc hl dalsi bajt prveho retazca 
 inc de dalsi bajt druheho retazca 
 dec bc do konca ostava o jeden bajt menej 
 ld a,b \kontrola, ci register BC 
 or /je uz nulovy 
 jr nz,loop ak nie tak porovnavame dalej 
 ret  ak ano tak sme vycerpali celu dlzku 
   retazcov, nenasli sme ziadny rozdiel 
   a mozme teda vyhlasit retazce  za 
   zhodne. 

   Nas program vracia priznaky (alebo aj prizraky - ako chcete) nastavene ako instrukcia cp pre jednotlive bajty: ZERO=1 ak su retazce zhodne alebo ZERO=0 ak su rozdielne. Ak su rozdielne tak sa este CARRY nastavi nasledovne: CARRY=1 ak je prvy retazec vecsi a CARRY=0 ak je vecsi ten druhy.
   Ta kontrola ci je register BC nulovy je znama a velmi casto pouzivana programatorska finta a mnohi ju uz poznaju. Ale pre tych, ktori ju este nepoznaju si ju teraz vysvetlime. Instrukcia dec bc nam sice zmensi register BC o jednotku, ale nenastavuje ziadne priznaky. Preto si musime nulovost BC otestovat sami. Registrovy par BC obsahuje nulu prave vtedy, ked nulu obsahuje aj register B aj register C. Tato "definicia" nam tak trosku pripomina definiciu bitovej logickej funkcie OR - vysledok je nulovy prave vtedy, ak oba vstupne argumenty su nulove. Tato podobnost vobec nie je nahodna a my ju teraz velmi zakerne zneuzijeme - v nasej kontrole pouzijeme instrukciu, ktora robi prave tuto funkciu. Ako prvy argument jej podstrcime register B (cez akumulator) a druhym argumentom bude zase register C. Register B sme museli dat do akumulatora preto, lebo instrukcia or pracujuca s registrami B a C neexistuje, vzdy jeden z operandov musi byt akumulator. No a instrukcia or nam na rozdiel od dec bc uz nastavuje priznak ZERO, takze vlaste uz vieme, ci je v BC nula a mozeme spravit podmieneny skok.
   Na zaver tejto lekcie vam dam jednu malu domacu ulohu. Ked si pozorne prezriete tabulky, zistite, ze su tam instrukcie na blokove prehladavanie. Skuste porozmyslat, ci by sa tieto instrukcie nedali nejako vyuzit v nasom programe. Mala pomocka: insrukcia cpi sa da velmi pekne pouzit, skuste prist na to, ako. Spravne riesene sa dozviete v buducej tretej lekcii.

Vas Busy.

Nazad / back , predchadzajuca a dalsia lekcia