assembly 如何处理文件中的字符串并在YASM 8086中对其进行排序

8ftvxx2r  于 2022-11-24  发布在  其他
关注(0)|答案(1)|浏览(129)

我被一个任务卡住了。
我必须写一个程序,它从文件中读取字符串,按第六列对最后10个字符串进行排序,然后在一个新文件中输出排序后的字符串。
前两列包含带有[1; 20]个字符,则3-5列包含[-100; 100]和第6列包含真实的[-9.99; 9.99].每一部分用';'符号。
输入档案:

48CBC0h ucbe5u F bc6; 6  laY xdU;-62;-29;11;-6.34
AJKCvwHUvmL CjWRl;WQc1 E2wzyTU;3;-20;24;8.26
9jicRCI8S b ; p9m R7iHqOj  9ig h;-93;19;-92;6.18
Xv ;IufLkIUp;-23;-94;76;2.63
A o8P8T 26;Zy J IVg6;-80;-58;-42;-5.96
hlwCw   Z8ChU;KX0 w C3 N60 KZV;-94;61;-71;-3.31
Rtqn58 2 l BTWdVgl H;rd U ;9;70;10;8.66
M x91pVZ6UQ Nb;p;-5;-27;74;4.04
rq8s3Gc Bj x 2XG ;8E cTH  a ZF VLp2E;-4;21;-89;7.9
 ca yfUpVXuC7  ;sXvttLZs4  nqcv 5fTg;-34;-40;14;-5.19
 j;yL7  G dG   C vR  B;70;-89;-87;-9.52
 2n 5 O F MMc16; Awcsl2sI;-97;-82;34;1.01
EeLVLB;qR q4i  D5q ;70;49;-11;-5.43
 nsWW j9;AGBGVXO N;59;97;74;6.22
ou 7vCvBUc;yVW30Jwcv Qtj;18;-10;77;9.38

我试图保存这些行的指针,以及第六列,我没有开始考虑排序函数。
以下是我目前为止所写的内容:

%include 'yasmmac.inc'

org 100h

section .text

   start:

        mov si, 0x80
    mov di, readFile
    dec di
    mov cl, byte [si]
    cmp cl, 01
    jg .name
    .name:
        inc si
        mov al, byte [si]
        mov byte [di], al
        inc di
    loop .name

   macPutString 'Input name for writing file', crlf, '$'
   mov al, 128
   mov dx, writeFile
   call procGetStr
   macNewLine

   mov dx, readFile
   call procFOpenForReading
   jnc .reading
   macPutString 'Error occured', crlf, '$'
   jmp .end

   
   .reading:    
    mov [readingD], bx  
    mov di, pointers
    xor dx, dx
    dec dx
        .whileNotEndOfFile:
        push bx
        mov bx, numberOfLines
        inc word [bx]
        pop bx
        mov [di], dx
        inc di
        inc di
        .tillLineEnds:
            inc dx
            call procFGetChar
            cmp ax, 0x0
            je .readingClose
            cmp cl, 0x0a
            jne .tillLineEnds
            jmp .whileNotEndOfFile

   .readingClose:
   call procFClose
   mov di, pointers
   inc word[di]

   mov dx, writeFile
   call procFCreateOrTruncate
   jnc .filter
   macPutString 'Error occured', crlf, '$'
   jmp .end

   .filter:
    mov [writingD], bx
    push bx
    mov bx, numberOfLines
    dec word [bx]
    cmp word [bx], 0x000a
    jl .errorInfo
    pop bx
    jge .continue

    .errorInfo:
    pop bx
    mov bx, [writingD]
    mov cx, 0x0050
    mov dx, error
    call procFWrite
    mov bx, [readingD]
    call procFClose
    mov bx, [writingD]
    call procFClose
    jmp .end

    .continue:
    mov dx, readingFile
        call procFOpenForReading
    jnc .secondReading
    macPutString 'Error occured', crlf, '$'
    jmp .pabaiga

    .secondReading:
    mov [readingD], bx

    mov dx, numberOfLines
    sub dx, 0x000a
    xor cx, cx
    mov cx, dx
    xor ax, ax
    cmp cx, 0x0
    jg .skipLines
    mov di, sixth
    jmp .sixthColumn

    .skipLines:
       push cx
        .skip:
        call procFGetChar
        cmp cl, 0x0a
        jne .skip
       pop cx
    loop .skipLines
    
    .sixthColumn:
       xor si, si
        .skipSign:
        call procFGetChar
        cmp cl, ';'
        jne .skipSign
        inc si
        cmp si, 0x0005
        jl .skipSign

        .save:
        call procFGetChar
        cmp ax, 0x0
        je .ifNotEnd
        cmp cl, 0x0a
        je .ifNotEnd
        cmp cl, '.'
        je .save
        mov [di], cl
        inc di
        jmp .save
    .ifNotEnd:
    cmp ax, 0x0
    je .endReading
    jmp .sixthColumn

.endReading:
call procFClose

.end
   exit

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;     
%include 'yasmlib.asm'
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
section .data
   
readingFile:
   times 255 db 00 
writingFile:
   times 255 db 00
readingD:
   dw 0000
writingD:
   dw 0000
error:
   db 'Not enough data', 0x0d, 0x0a, '$'
numberOfLines:
   times 128 db 00
pointers:
   times 3000 db 00
sixth:
   times 20000 db 00

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
section .bss

先谢谢你了。

gopyfrb3

gopyfrb31#

回顾您的工作(最重要的部分)

mov si, 0x80
mov di, readFile
dec di
mov cl, byte [si]
cmp cl, 01
jg .name
.name:
   inc si
   mov al, byte [si]
   mov byte [di], al
   inc di
loop .name

我在从命令行获取filespec的代码中发现了3个问题:

  • 由于mov di, readFiledec di中的递减,接下来的循环将写入位于 readFile 缓冲区之外的字节!
  • 您总是运行 .name 循环
jg .name
.name:

这个构造在汇编编程中是没有意义的。如果条件是greater,那么你跳转到 .name,但是如果条件是not greater,那么你在 .name 中失败。无论如何,你总是在 .name 中运行代码。

  • loop .name指令依赖于整个CX寄存器,而您只初始化了它的最低8位(mov cl, byte [si])。

在 *.阅读 * 中,接下来的代码将递增 numberOfLines 变量:

push bx
mov bx, numberOfLines
inc word [bx]
pop bx

首先,你可以在一条指令inc word [numberOfLines]中完成这一操作,其次,为什么在知道下一行会被找到之前就增加行计数呢?在程序的后面,你会无条件地减少计数。类似的情况也会发生在你存储的第一个指针上:您开始将其赋值为-1,然后在稍后的某个时间点将其无条件地设置为0。
.continue 中,您在关闭源文件后重新打开它,但您现在使用的是不同的文件规范

.continue:
   mov dx, readingFile
   call procFOpenForReading

确定文件位置在 readFilereadingFile
我在下面提出的替代解决方案将不需要阅读源文件两次。
.secondReading 中,您忘记了用于取消引用的方括号。

mov dx, numberOfLines
sub dx, 0x000a
xor cx, cx
mov cx, dx
xor ax, ax
cmp cx, 0x0
jg .skipLines
mov di, sixth
jmp .sixthCollumn

因此,后面的 .skipLines 将运行很多次迭代!而且由于您隐藏mov di, sixth指令的位置,*. sixthColumn * 中的代码将写入DI寄存器恰好指向的任何位置!

numberOfLines:
   times 128 db 00
pointers:
   times 3000 db 00
sixth:
   times 20000 db 00

为什么你要保留这么大的字节数来处理10行呢?多了肯定不是更好!

numberOfLines: dw 0
pointers:      times 10 dw 0
sixth:         times 10 dw 0

我的解决方案(如果 * 您仔细研究它,它将非常重要)

提示:20 + 1 + 20 + 1 + 4 + 1 + 4 + 1 + 4 + 1 + 5 + 2 = 64(最长线)

xor  si, si            ; NumberOfLines
  mov  bx, [ReadingD]    ; Handle
.reuseBuffers:
  mov  bp, Buffers       ; 10 slots of 64 bytes each
.nextLine:
  mov  di, bp            ; Begin of current slot
  lea  bp, [di + 64]     ; End of current slot
.nextByte:
  call procFGetChar      ; -> AX CL CF
  jc   .err              ; A DOS error occured
  test ax, ax
  jz   .eof              ; Reached the end of the file
  cmp  di, bp
  jnb  .err              ; Line is longer than expected
  mov  [di], cl
  inc  di
  cmp  cl, 10            ; Check for end of the line
  jne  .nextByte         ; No
  inc  si                ; Yes, NumberOfLines++
  cmp  bp, Buffers + 640 ; Check for the end of the buffer chain
  jb   .nextLine         ; No
  jmp  .reuseBuffers     ; Yes, go recycle
.err:

  ...

.eof:
  cmp  si, 10            ; NumberOfLines
  jb   .err


Buffers: times 10*64 db 0

最后10行现在保存在10个64字节缓冲区中。顺序并不重要,因为任务要求您对它们进行排序(使用第6列)。
我很期待看到您将如何排序记录。我个人会将第6列的定点()数字转换为[-999,999]范围内的整数(忽略小数点),并将它们存储在一个字大小的数组中,以备排序。我会使用索引从0到9的数组,而不是包含指针的辅助数组。
第一个数组中的条件交换必须与第二个数组中的无条件交换相匹配。在x86中尝试进行冒泡排序时,在分段错误的答案中可以找到一个很好的冒泡排序,但可以随意使用您喜欢的任何排序算法...
)请注意以下行:
rq8s3Gc Bj x 2XG ;8E cTH a ZF VLp2E;-4;21;-89;7.9
从以前类似的问答中,我的印象是第6列的数字都是2位数的分数。这一行没有使用“7.90”。要么是你打错了,要么你必须在程序中考虑到这一点。

相关问题