Assembler pro blbé 3.díl Petr Klimovič l.p.1996 Jak jsem minule slíbil, zkusíme si vyrobit program pro konverzi češtiny. První návrh vypadal asi takto: MODEL SMALL .STACK 200 .DATA FTabulka db 'TABULKA.TAB',0 ;nazev prev. tabulky FVstup db 'VSTUP.TXT',0 ;nazev vstupniho fajlu FVystup db 'VYSTUP.TXT',0 ;nazev vystupniho fajlu FH2 dw 0 ;filehandle vstupniho FH2 dw 0 ;filehandle vystupniho MTabulka db 256 DUP (0) ;sem se nacte tabulka Buffer db 30000 DUP (0) ;buffer pro nacitana data .CODE START: Tabulka ;Nactu prevodni tabulku Otevri ;Otevru zdroj Vytvor ;Vytvorim cil Smycka: Nacti ;Nactu do bufferu kus textu Preved ;Prevedu jej Zapis ;Zapisu prevedeny text do fajlu jne Smycka ;a furt dokola, cely soubor Zavri1 ;Zavru zdrojovy Zavri2 ;Zavru cilovy mov ax, 4c00h ;Konec programu, navrat do DOSu int 21h END START Je to vlastně hrubý návrh. Vypadá to, že by to takto mohlo fungovat, teď zbývá "jenom" naprogramovat jednotlivé procedury. Procedura je kus kódu začínající příkazem PROC. Za ním je uveden název procedury, pak následují normální assemblerovské příkazy a celé to končí příkazem ENDP a za ním opět název procedury. Takže třeba procedura, která přičte jedničku k AX (mimochodem pěkná kravina). PROC Pricti inc ax ret ENDP Pricti Potom můžete uvést v hlavním programu příkaz call Přičti, který způsobí zvýšení ax o jedničku. Příkaz call je volání procedury. Důležitá je instrukce ret, které způsobí návrat z procedury. Ještě bych měl vysvětlit co dělá DUP. MTabulka db 256 DUP (0) způsobí, že proměnná MTabulka bude zpočátku obsahovat 256 nul. Začneme výrobou procedury Tabulka, ta má za úkol načíst ze souboru převodní tabulku do paměti. Takže otevření souboru, načtení 256 bajtů (to je celá tabulka) a uzavření souboru. PROC Tabulka mov ax, 3D00h ;Otevreni souboru, read only mov dx, offset FTabulka ;DS:DX ukazuje na nazev fajlu int 21h mov bx, ax ;filehandle do bx push bx ;uschovat na pozdeji mov ah, 3Fh ;cteni souboru mov cx, 0FFh ;FF bajtu (256) mov dx, offset MTabulka ;DS:DX kam nacist int 21 pop bx ;vyndat uschovane filehandle mov ah, 3Eh ;zavreni souboru int 21 ret ENDP Tabulka Další je Otevri a Vytvor, mělo by to být lehké. PROC Otevri mov ax, 3D00h ;Otevreni souboru, read only mov dx, offset FVstup ;DS:DX ukazuje na nazev fajlu int 21h mov FH1, ax ;schovat filehandle ret ENDP Otevri PROC Vytvor mov ah, 3Ch ;Vytvoreni souboru mov cl, 0 ;Zadny specialni atribut mov ds offset FVystup ;DS:DX jmeno vyrabeneho fajlu int 21h mov FH2, ax ;Schovat filehandle ret ENDP Vytvor Procedura Nacti by měla vždy načíst do bufferu bajty ze vstupního souboru. Když jich načtu méně, než jsem zadal, znamená to, že jsem na konci souboru. PROC Nacti mov bx, FH1 ;filehandle do bx mov ah, 3Fh ;cteni souboru mov cx, 30000 ;30000 bajtu, cely buffer mov dx, offset Buffer ;DS:DX kam nacist int 21 push ax ;ulozit kolik bajtu bylo nacteno ret ENDP Nacti Další procedura převádí podle tabulky. Tabulka je vlastně 256 čísel. Jestliže má třeba AL hodnotu 15, najde se v tabulce 15-tý údaj a ten se uloží do AL. Takže tabulka, která neprovádí žádný převod, bude obsahovat postupku 0,1,2,3,4,5,6,7,8,9,10,11,....255. PROC Preved cld ;Ukazatele se budou zvysovat mov bx, offset MTabulka ;Ukazatel do tabulky mov si, offset Buffer ;Ukazatel do bufferu (cteni) mov di, si ;Ukazatel do bufferu (zapis) mov cx, ax ;Kolik bajtu budu prevadet xor ah, ah ;Znuluju AH Kolco: push bx ;Schovam si zacatek tabulky lodsb ;AL = [DS:SI] add bx, ax ;Posunu se v tabulce mov al, [ds:bx] ;Prevedu stosb ;Zapisu zpatky do bufferu pop bx ;Zase ukazuji na zacatek tab. loop Kolco ;a dalsi bajt bafru ret ENDP Preved Další věc je opět jednoduchá, zápis převedeného bufferu do fajlu. PROC Zapis mov ah, 40h ;Zapis fajlu mov bx, FH2 ;filehandle pop cx ;kolik bajtu zapsat push cx ;jeste se to bude hodit mov dx, offset Buffer ;Kde jsou zapisovana data int 21h ret ENDP Zapis Takže to sepíšu dohromady a vykašlu se na procedury, jelikož žádnou z nich nevykonávám víckrát, nemají smysl a navíc ještě přidávají ret, což je malilinkatá ztráta času. Celkový zdroják Většinu těchto instrukcí znáte, zbývá vysvětlit tři nové: LODSB Naplní AL hodnotou, kterou vezme z [DS:SI], potom posune SI, tak, aby ukazoval na další bajt. Buďto jej zvýší, nebo sníží o jedničku. Jestli se bude zvyšovat, nebo snižovat, záleží na nastavení DF (Direction Flag), DF je příznak, kterým směrem probíhají takovéto operace. STOSB Obrácená instrukce k LODSB. Uloží AL do paměti na adresu určenou ES:DI a poté opět upraví ukazatel (v tomto případě DI), buď jej zvýší, nebo sníží. CLD Tohle je právě to, co určuje, jestli se ukazatele budou zvyšovat, nebo snižovat. Tímto příkazem nastavíte DF tak, aby se ukazatel zvyšoval. Pro nastavení na snižování je instrukce STD. Aha, jak se tak dívám, tak ono je tu novějších věcí víc, takže: ZÁSOBNÍK výheň