在一个句子中逐字排序字符串ASC / DSC

时间:2015-06-12 11:41:42

标签: assembly x86-16

我在程序集8086中需要一个程序

输入:一句话(字符串) 输出:逐字逐句排序或按用户希望降序

请帮助

1 个答案:

答案 0 :(得分:0)

由于您要求提供家庭作业帮助,因此最好关注算法而不是代码。

我假设你是在DOS环境下编程,如果不是这样,只需将概念翻译成你的操作系统。

您需要做的第一件事就是要求用户输入。在DOS中有几种方法可以做到这一点,根据您的需要,您必须选择最适合的方法。我认为缓冲输入是最好的选择,使用INT 21/AH=0ah。您可以使用Ralph Brown Interrupt List的在线版本作为参考。

你有一个带有输入字符串的缓冲区,你需要扫描它并识别单词。单词由特定字符分隔,让我们假设只有一个空格(ASCII代码20h)字符用作单词分隔符。您不能假设在两个连续的单词之间只出现一个空格 识别单词的开头和结尾很容易,但是一旦你开始和结束,你如何保存一个单词? 单词是字符串,字符串的问题是它们具有可变长度,因此您无法将它们复制到固定大小的缓冲区中,因为您必须交换它们才能对需要使用间接层的单词进行排序。
不是从输入字符串中复制单词,而是使用DOS字符串终止符$(ASCII代码24h)终止每个单词,并将指针保存到它们的开头。这是概念的丑陋图片

Example of a tokenized input

现在你可以减少排序指向字符串数组的问题,这是一项简单的任务 首先需要一个字符串比较器,比如strcmp,一个比较字符串A和B的函数,如果A<则返回-1。 B,如果A = B,则为0;如果A> B,则为1。 B.字符串上有许多命令,字典顺序是问题所针对的。您可以在互联网上找到有关此主题的教程 在比较器之后你需要一个排序算法,冒泡排序效率很低但很容易实现。这里的技巧是你比较字符串,但交换指针!

最后,您只需按照在数组中找到它们的顺序打印字符串。

我做了一个简单的DOS COM程序来解决你的问题。我警告你,你应该只使用它作为样本,它使用原始8086中没有的许多指令,并在堆栈上创建输入缓冲区和数组。无论如何这里是它的输出(在DOSBox中)和在源代码下面(对于NASM)

enter image description here

;COM binaries are loaded in a new segment starting at offset 100h
;The area between the start of the segment and the offset 100h is the PSP (Program segment prefix)
org 100h

;Data and code is in one section 
section .text

start:
   ;Set the stack as far away as possible from the code but still in the same segment 
   mov ax, cs
   mov ss, ax
   xor sp, sp

   ;All other segment registers points to CS segment
   push cs
   pop ds
   push es
   pop ds 

   ;Be sure DF is 0
   cld


   mov ah, 09h
   mov dx, strInputSentence
   int 21h

   ;Allocate space for 255 byte buffer (the max) but keep the SP aligned at WORD boundary
   sub sp, 100h
   push 00ffh               ;Push the Buffer structure for INT 21/0ah
   mov WORD [buffer], sp
   ;Get the input string 
   mov dx, sp
   mov ah, 0ah
   int 21h

   ;Reserve an array of 256 WORD
   sub sp, 200h
   mov WORD [tokens], sp

   ;Tokenize the string
   mov bx, WORD [buffer]        
   movzx ax, BYTE [bx+01h]      ;String length
   add bx, 02h                  ;String start

   push ax
   push bx
   push WORD [tokens]           ;Output array
   push 0ffh                    ;Max items in output array
   call tokenize
   mov WORD [tokens_num], ax    ;Words found

   test ax, ax
   jz .no_words

   call show_original
   call show_ascending
   call show_descending

jmp .end

.no_words:
   mov ah, 09h 
   mov dx, strNoWords
   int 21h

.end:   
   mov ax, 4c00h
   int 21h 

strInputSentence    db "Please, type a sentence: ", 24h
buffer              dw 0   
tokens              dw 0   
tokens_num          dw 0
strOriginalOrd      db 0dh, 0ah, "Here are the words as typed: " 
strCRLF             db 0dh, 0ah, 24h
strNoWords          db 0dh, 0ah, "No words typed!", 24h  
strAscendingOrd     db "Here are the words sorted in ascending order:", 0dh, 0ah, 24h  
strDescendingOrd    db "Here are the words sorted in descending order:", 0dh, 0ah, 24h    

show_original:
   mov dx, strOriginalOrd
   mov ah, 09h
   int 21h 

   mov si, WORD [tokens]
   mov cx, WORD [tokens_num];

.orig_ord:
   mov dx, WORD [si]
   int 21h 
   mov dx, strCRLF
   int 21h
   add si, 02h 
loop .orig_ord

    ret 


show_ascending:
   mov dx, strAscendingOrd
   mov ah, 09h
   int 21h 

   push strcmp
   push WORD [tokens]
   push WORD [tokens_num]
   call bubble_sort

   mov si, WORD [tokens]
   mov cx, WORD [tokens_num];

.asc_ord:
   mov dx, WORD [si]
   int 21h 
   mov dx, strCRLF
   int 21h
   add si, 02h 
loop .asc_ord

   ret 


show_descending:
   mov dx, strDescendingOrd
   mov ah, 09h
   int 21h 

   push stricmp
   push WORD [tokens]
   push WORD [tokens_num]
   call bubble_sort

   mov si, WORD [tokens]
   mov cx, WORD [tokens_num];

.asc_ord:
   mov dx, WORD [si]
   int 21h 
   mov dx, strCRLF
   int 21h
   add si, 02h 
loop .asc_ord

   ret 

;Number of char   
;Sentence
;Array of pointers
;Array items
tokenize:
    push bp
    mov bp, sp

    sub sp, 02h

    push di
    push es
    push cx
    push si
    push bx
    push dx 

    mov dx, WORD [bp+0ah]
    mov cx, WORD [bp+04h]
    mov di, WORD [bp+06h]
    mov si, WORD [bp+08h]
    xor bx, bx

    mov BYTE [bp-02h], 00h  ;Status, 0 = Looking for a word start, 1 = Looking for word end

    ;DX = Character left to parse
    ;CX = Entries available in output array 
    ;DI = Ptr to Output array current entry
    ;SI = Ptr to current char in input string 
    ;BX = Words found

.look_for:
    test cx, cx
    jz .end 

    test dx, dx
    jz .end 

    lodsb
    dec dx

    ;   char is 20h    Status
    ;   0               0     found start 
    ;   0               1     jump back 
    ;   1               0     jump back 
    ;   1               1     found end 

    cmp al, 20h
    sete ah
    xor ah, BYTE [bp-02h]
    jnz .look_for

    ;Change status (0->1, 1->0)
    mov ah, BYTE [bp-02h]
    not ah 
    and ah, 01h 
    mov BYTE [bp-02h], ah
    jnz .found_start

    ;Found word end

    mov BYTE [si-01h], 24h      ;24h terminate the word

jmp .look_for

.found_start:
    ;Found word start 
    lea ax, [si-01h]
    stosw                       ;Save the pointer to the word
    dec cx                      ;Less available entries
    inc bx                      ;One more word found
jmp .look_for 

.end:
    mov BYTE [si], 24h      ;24h terminate last word
    mov ax, bx

    pop dx
    pop bx
    pop si
    pop cx
    pop es
    pop di 

    add sp, 02h

    pop bp
    ret 08h


;string1
;string2
strcmp:
    push bp
    mov bp, sp

    push si
    push di 
    push bx 

    mov si, WORD [bp+06h]
    mov di, WORD [bp+04h]

.compare:
    lodsb
    mov ah, BYTE [di]
    inc di 

    ;AH = String 2 char
    ;AL = String 1 char

    ;If String1 is ended, check the other string
    cmp al, 24h
    mov bl, ah              ;Value to check as terminator
    mov bh, 0ffh            ;Return value if the other string is not ended
    jz .strend

    ;If String2 is ended, check the other string
    cmp ah, 24h
    mov bl, al              ;Value to check as terminator
    mov bh, 01h             ;Return value if the other string is not ended
    jz .strend 

    ;Compare
    sub al, ah
    jz .compare             ;If equals, repeat
jmp .end                    ;Result is computed, just end

.preend:
    xor al, al              ;Equals

.end:
    pop bx 
    pop di 
    pop si 

    pop bp
    ret 04h 

.strend:
    cmp bl, 24h             ;Other string is ended, too?
    jz .preend              ;Success!

    mov al, bh              ;Return appropriate value
jmp .end 

;Like strcmp but negated
stricmp:
    push bp
    mov bp, sp 

    push WORD [bp+06h]
    push WORD [bp+04h]
    call strcmp 
    neg al 

    pop bp
    ret 04h


;comparer
;array
;elements
bubble_sort:
    push bp
    mov bp, sp

    sub sp, 02h 

    pusha

    cmp WORD [bp+04h], 2    ;Less than 2 element -> Already ordered
    jb .end

    mov di, WORD [bp+08h]   ;Comparer

.cycle:
    mov BYTE [bp-02h], 00h  ;No swap done
    mov cx, WORD [bp+04h]   ;Elements in array
    mov si, WORD [bp+06h]   ;Array
    dec cx                  ;Elements are compared in pairs

.sort:  
    lodsw
    push ax
    lodsw
    push ax
    call di                 ;Compare current and next string

    sub si, 02h             ;Get back to next string 
    cmp al, 00h
    jg .swap                ;If current > next, swap

.continue:  
    dec cx                  ;Elements left to compare
jnz .sort

    ;If no swap, the array is sorted
    cmp BYTE [bp-02h], 00h
    jne .cycle  

jmp .end

.swap:
    ;Naive swap
    mov ax, WORD [si-02h]
    mov bx, WORD [si]
    mov WORD [si], ax
    mov WORD [si-02h], bx 

    ;At least one swap done
    mov BYTE [bp-02h], 01h

jmp .continue   

.end:   
    popa 

    add sp, 02h 

    pop bp
    ret 06h