我正在尝试制作一个可以从文件中取一行的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
答案 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
减去一个会带您到最后一个字母。
顺便说一句:当你编程更有条理的时候,局外人更容易提供帮助:更多的程序,更少的跳跃。