TASM最后一个字母和行长

时间:2015-11-24 09:06:12

标签: assembly dos tasm 16-bit

我正在尝试制作一个可以从文件中取一行的TASM程序,检查它是否超过5个符号长,检查它是否是回文然后输出它是否是回文。到目前为止,我的程序能够告诉它何时需要输出帮助,读取文件并输出答案。我的问题有两个:

1)你如何指出TASM中一行的最后一个字母?我的回文检查工作通过比较第一个和最后一个字母,检查它们是否相同,如果是,则向上移动1并向下移动1,检查那些2等。如果任何两个不相同,则不是回文。

2)你如何检查以确定相关的行至少有6个字母/数字?

供参考,以下是目前的代码:

.model small
.stack 100H
.data

about       db 'Programa iesko palindromu nuskaitytoje eiluteje arba faile.',13,10,9,'2uzdasm.exe [/?] destinationFile [ - | sourceFile1 [sourceFile2] [...] ]',13,10,13,10,9,'/? - pagalba',13,10,'$'

err_source      db 'Source failo nepavyko atidaryti skaitymui',13,10,'$'
err_destination     db 'Destination failo nepavyko atidaryti rasymui',13,10,'$'

sourceF     db 12 dup (0)
sourceFHandle   dw ?

destF       db 12 dup (0)
destFHandle     dw ?

buffer      db 2000 dup (?)
simbolis    db ?

palindromas db 'Tai yra palindromas',13,10,'$'
nepalindromas db 'Tai nera palindromas',13,10,'$'

.code

START:
mov ax, @data
mov es, ax

mov si, 81h

call space_skip

    mov al, byte ptr ds:[si]    ; nuskaityt simboli
    cmp al, 13          ; ner parametru, tai tada
    jne _1
    jmp help            ; pagalba

_1:

    ;; ar /? yra
    mov ax, word ptr ds:[si]
    cmp ax, 3F2Fh           ; jei nuskaityta "/?" - 3F = '?'; 2F = '/'
    jne _2
    jmp help                    ; rastas "/?", vadinasi reikia isvesti pagalba


_2:

    ;; destination failo pavadinimas
    lea di, destF
    call    read_filename       ; perkelti is parametro i eilute
    cmp byte ptr es:[destF], '$' ; jei nieko nenuskaite
    jne _3
    jmp help

_3:

    ;; source failo pavadinimas
    lea di, sourceF
    call    read_filename       ; perkelti is parametro i eilute

    push    ds
    push    si

    mov ax, @data
    mov ds, ax

    ;; rasymui
    mov dx, offset destF    ; ikelti i dx destF - failo pavadinima
    mov ah, 3ch         ; isvalo/sukuria faila - komandos kodas
    mov cx, 0           ; normal - no attributes
    int 21h         ; INT 21h / AH= 3Ch - create or truncate file.
                ;   Jei nebus isvalytas - tai perrasines senaji,
                ;   t.y. jei pries tai buves failas ilgesnis - like simboliai isliks.
    jnc _4          ; CF set on error AX = error code.
    jmp err_dest

_4:
    mov ah, 3dh         ; atidaro faila - komandos kodas
    mov al, 1           ; rasymui
    int 21h         ; INT 21h / AH= 3Dh - open existing file.
    jnc _5          ; CF set on error AX = error code.
    jmp err_dest

_5:
    mov destFHandle, ax     ; issaugom handle

    jmp startConverting

readSourceFile:
    pop si
    pop ds

    ;; source failo pavadinimas
    lea di, sourceF
    call    read_filename       ; perkelti is parametro i eilute

    push    ds
    push    si

    mov ax, @data
    mov ds, ax

    cmp byte ptr ds:[sourceF], '$' ; jei nieko nenuskaite
    jne startConverting
    jmp closeF

startConverting:
    ;; atidarom
    cmp byte ptr ds:[sourceF], '$' ; jei nieko nenuskaite
    jne source_from_file

    mov sourceFHandle, 0
    jmp skaitom

source_from_file:
    mov dx, offset sourceF  ; failo pavadinimas
    mov ah, 3dh                 ; atidaro faila - komandos kodas
    mov al, 0                   ; 0 - reading, 1-writing, 2-abu
    int 21h         ; INT 21h / AH= 3Dh - open existing file
    jc  err_sourc       ; CF set on error AX = error code.
    mov sourceFHandle, ax   ; issaugojam filehandle

skaitom:
    mov bx, sourceFHandle
    mov dx, offset buffer       ; address of buffer in dx
    mov cx, 20              ; kiek baitu nuskaitysim
    mov ah, 3fh             ; function 3Fh - read from file
    int 21h

    mov cx, ax              ; bytes actually read
    cmp ax, 0           ; jei nenuskaite
    jne _6          ; tai ne pabaiga

    mov bx, sourceFHandle   ; pabaiga skaitomo failo
    mov ah, 3eh         ; uzdaryti
    int 21h
    jmp readSourceFile      ; atidaryti kita skaitoma faila, jei yra

_6:
    mov si, offset buffer   ; skaitoma is cia
    mov bx, destFHandle     ; rasoma i cia

    cmp sourceFHandle, 0
    jne _7
    cmp byte ptr ds:[si], 13
    je  closeF

_7:
    push    cx          ; save big loop CX

atrenka:
    lodsb               ; Load byte at address DS:(E)SI into AL
    push    cx          ; pasidedam cx
    call    palloop
    mov ah, 40h         ; INT 21h / AH= 40h - write to file
    int 21h
    pop cx
    jc  help            ; CF set on error; AX = error code.
    loop    atrenka

    pop cx
    loop    skaitom

help:
    mov ax, @data
    mov ds, ax

    mov dx, offset about         
    mov ah, 09h
    int 21h

    jmp _end

closeF:
    ;; uzdaryti dest
    mov ah, 3eh         ; uzdaryti
    mov bx, destFHandle
    int 21h

_end:
    mov ax, 4c00h
    int 21h  

err_sourc:
    mov ax, @data
    mov ds, ax

    mov dx, offset err_source        
    mov ah, 09h
    int 21h

    mov dx, offset sourceF
    int 21h

    mov ax, 4c01h
    int 21h  

err_dest:
    mov ax, @data
    mov ds, ax

    mov dx, offset err_destination         
    mov ah, 09h
    int 21h

    mov dx, offset destF
    int 21h

    mov ax, 4c02h
    int 21h  

space_skip PROC near

space_skip_loop:
    cmp byte ptr ds:[si], ' '
    jne space_skip_end
    inc si
    jmp space_skip_loop
    space_skip_end:
    ret

    space_skip ENDP

    read_filename PROC near

    push    ax
    call    space_skip

read_filename_start:
    cmp byte ptr ds:[si], 13    ; jei nera parametru
    je  read_filename_end   ; tai taip, tai baigtas failo vedimas
    cmp byte ptr ds:[si], ' '   ; jei tarpas
    jne read_filename_next  ; tai praleisti visus tarpus, ir sokti prie kito parametro
    read_filename_end:
    mov al, '$'         ; irasyti '$' gale
    stosb                           ; Store AL at address ES:(E)DI, di = di + 1
    pop ax
    ret
    read_filename_next:
    lodsb               ; uzkrauna kita simboli
    stosb                           ; Store AL at address ES:(E)DI, di = di + 1
    jmp read_filename_start

    read_filename ENDP

palloop PROC near
    mov     al, [si]
    ;mov        [di], al
    cmp     al, [di]
    jne     notpal
    inc     si
    dec     di
    cmp     si, di
    jl      palloop
    jmp     ispal

notpal:
    lea dx, nepalindromas
    mov cx, 20
    ret

ispal:
    lea dx, palindromas
    mov cx, 20
    ret

    palloop ENDP

    end START

1 个答案:

答案 0 :(得分:0)

我想,

mov bx, sourceFHandle
mov dx, offset buffer   ; address of buffer in dx
mov cx, 20              ; kiek baitu nuskaitysim
mov ah, 3fh             ; function 3Fh - read from file
int 21h

会让你遇到麻烦。尝试使用fread(buffer,1,20,sourceFHandle)创建一个C程序,您将看到缓冲区的组织相当困难(如何处理数据?溢出?)。

我建议阅读一行而只是一行(“fgets”)。一行可以以字符0x0D(回车= CR)或0x0Ah(换行= LF)或EOF(文件结束)结束。 MS-DOS用于新行通常是两者的组合(CRLF)。 MS-DOS中没有函数读取一行直到其中一个分隔符,因此您必须逐个字符地读取并将其与中断条件进行比较。由于句柄有自己的缓冲区并且设法从磁盘获取数据块,因此这不是一个很好的性能问题。

示例:

...
read_line PROC
    lea di, buffer
    dec di

    @@0:                        ; Read until CR or LF
    inc di
    mov ah, 3Fh                 ; READ FROM FILE OR DEVICE
    mov bx, sourceFHandle       ; File handle
    mov dx, di                  ; Buffer for data
    mov cx, 1                   ; Read one character
    int 21h                     ; Call MS-DOS
    jc @@done                   ; Error
    test ax, ax                 ; EOF
    je @@done

    mov al, [di]                ; Fetched character
    cmp al, 0Dh                 ; CR?
    je @@1                      ; Yes: break
    cmp al, 0Ah                 ; LF?
    jne @@0                     ; No: loop

    @@1:                        ; Read until NOT CR or LF (skip empty lines)

    mov ah, 3Fh                 ; READ FROM FILE OR DEVICE
    mov bx, sourceFHandle       ; File handle
    mov dx, di                  ; Buffer for data
    mov cx, 1                   ; Read one character
    int 21h                     ; Call MS-DOS
    jc @@done                   ; Error
    test ax, ax                 ; EOF
    je @@done

    mov al, [di]                ; Fetched character
    cmp al, 0Dh                 ; CR?
    je @@1                      ; Yes: loop
    cmp al, 0Ah                 ; LF?
    je @@1                      ; Yes: loop

    ; Adjust file pointer, so that it points to the beginning of the next line

    mov ah, 42h                 ; LSEEK - SET CURRENT FILE POSITION
    mov al, 1                   ; Move from current file position
    mov bx, sourceFHandle       ; File handle
    mov dx, -1                  ; Move by CX:DX = -1 bytes
    mov cx, dx                  ; CX:DX = FFFF:FFFF
    int 21h                     ; Call MS-DOS

    @@done:
    test ax, ax                 ; AX == 0 && DI == &buffer[0] => EOF
    jne @@2
    cmp di, OFFSET buffer
    @@2:
    mov byte ptr [di], '$'
    ret                         ; DI: pointer to '$'. ZF==1: EOF.
read_line ENDP
...

由于DI指向行的$ - 分隔符,您可以通过减去缓冲区的偏移量来计算字符串的长度(例如sub di, OFFSET buffer)。将DI减去一个会带您到最后一个字母。

顺便说一句:当你编程更有条理的时候,局外人更容易提供帮助:更多的程序,更少的跳跃。