Задача: Попытка скопировать строку в обратном порядке в другую строку и отобразить ее с помощью строковых операций. - PullRequest
0 голосов
/ 06 мая 2018

Привет, я пытаюсь получить строку из пользовательского символа за символом, а затем сохранить обратную строку в неинициализированной переменной. После я хочу отобразить эту неинициализированную переменную. Я знаю, что есть другие способы сделать это с помощью, но я хочу сделать это с помощью строковых операций. Я думал, что инструкция std могла бы использоваться для обхода строки в обратном порядке. Я знаю, что cld используется для установки порядка слева направо. Я также проверил учебник, и он сказал pushf перед использованием std и popf после использования. Если это так, то куда следует помещать push и pop.

  INCLUDE   PCMAC.INC
                .MODEL SMALL
                .386
                .STACK 128
;================================================
                .DATA
prompt1         DB          13, 10,'Enter a character(Press ENTER to end Expression): $'
prompt2         DB          'Are you done ?:    $'
prompt3         DB          13, 10,'Not valid choice try again', 13, 10,'$'     
userExp         DB          50 DUP (?)
bwUserExp       DB          50 DUP (?)      
validity        DB          'Invalid$','Valid$'         
;================================================               
                .CODE
                EXTRN       PutStr : NEAR, GetCh : NEAR, PutCh : NEAR
Main            PROC        NEAR
                mov         ax, @DATA
                mov         ds, ax
                mov         es, ax
                xor         bx, bx              ;Clears bx register
                xor         cx, cx              ;Clears cx register

DispPrompt:     _PutStr     prompt1             ;Displays prompt1 to screen

GetEXP:         _GetCh      al                  ;Gets character from user
                cmp         al, 13              ;Compares character 
                                                ;to Carriage return 
                je          LoadUserExp         ;If equal to the carriage
                                                ;return user jumps to
                                                ;LoadUserExp 
                cmp         al, 97              ;Compares character to a 
                jge         AddtoExp            ;If equal or greater than
                                                ;a user jumps to AddtoExp
                cmp         al, 122             ;Compares character to z 
                jle         AddtoExp            ;If equal or greater than
                                                ;a user jumps to AddtoExp
                jmp         GetEXP              ;Jumps to GetEXP if character 
                                                ;is not any of the matching
                                                ;characters

AddtoExp:       mov         userExp + bx, al    ;Adds character from 
                                                ;al to userExp array    
                inc         bx                  ;increments bx to
                                                ;increment the position
                                                ;in the array
                jmp         GetEXP              ;Jumps to GetEXP

LoadUserExp:    
                mov         si, OFFSET userExp      ;Loads userExp into si
                mov         di, OFFSET bwUserExp    ;Loads bwUserExp into di
                std                                 ;Tells the program to
                                                    ;go from Right to the Left
                mov         cx, bx                  ;Moves bx (the size of the array) into cx
                rep         movsb                   ;Moves the contents of si into di

DispLoop:       
                mov         cx, bx                  ;Moves bx (the size of the array) into cx
                xor         bx, bx                  ;Clears the bx register

DisplayExp:     mov         al, bwUserExp + bx      ;Moves the character 
                                                    ;in position bx into al
                _PutCh      al                      ;Displays the value of
                                                    ;al to the screen
                inc         bx                      ;increments bx to increment 
                                                    ;the position in the array
                dec         cx                      ;Decrements cx 
                jcxz        done                    ;Jumps to done if
                                                    ;cx is zero
                jmp         DisplayExp              ;Jumps to DisplayExp 
                                                    ; if cx is not zero

done:           mov         ax, 4c00h
                int         21h             

Main            ENDP                            
;================================================
END             Main            

1 Ответ

0 голосов
/ 06 мая 2018

Ваш код показывает несколько проблем, но давайте сосредоточимся на «строке» инструкции.

О DF (флаг направления)

cld установит DF в регистре FLAGS на ноль. std установит DF на единицу.

Цель pushf совета состоит в том, чтобы сохранить исходное значение DF, т. Е. Включающая пара pushf + popf должна быть вокруг всей вашей операции, где вы изменяете DF, чтобы сохранить исходное значение, и если ваша Код работает только один раз и не вызывается из внешних функций, вы можете решить не заботиться об оригинальном DF.

В соглашениях о вызовах x86 часто решается, что DF ожидается равным нулю, тогда вам не нужно сохранять исходное значение, вам просто нужно очищать DF после каждой части кода, которая действительно нуждается в DF = 1, перед вызовом другой подпрограммы. Это соглашение обычно работает хорошо, так как вам нужно DF = 1 только в редких случаях.

О movs для обращения строки

movs[b/w/d] загрузит значение из [ds:si] и сохранит его в [es:di], а затем настроит значения si и di, либо добавив (при DF = 0) размер элемента, либо вычтя (DF = 1) размер элемента.

Так что вы не можете сделать это ++si и --di, что потребует перевернуть DF в середине инструкции. movsb, таким образом, не подходит для ваших нужд.

Кроме того, вы загружаете di с адресом начала буфера, поэтому даже если movsb будет делать то, что вы хотите, вы перезапишите буфер userExp вместо записи результата в буфер bwUserExp .

Вы можете использовать строковые инструкции для вашей задачи следующим образом:

            mov         si, OFFSET userExp       ; source buffer
            lea         di, [bx + bwUserExp - 1] ; end(!) of destination buffer
            mov         cx, bx                   ; cx = size of user input
reverse_loop:
            cld                                  ; DF=0
            lodsb                                ; al = one character, ++si
            std                                  ; DF=1
            stosb                                ; store character, --di
            dec         cx
            jnz reverse_loop
            cld                                  ; DF=0 for future use

Как видите, это не самый красивый кусок кода и выглядит неоправданно запутанным, строковые инструкции не очень подходят для вашей задачи, вам лучше выполнить задачу без них, например:

            mov         si, OFFSET userExp       ; source buffer
            lea         di, [bx + bwUserExp]     ; beyond end of destination buffer
            mov         cx, bx                   ; cx = size of user input
reverse_loop:
            mov         al,[si]
            dec         di
            inc         si
            mov         [di],al
            dec         cx
            jnz reverse_loop
            ; di points at bwUserExp here

О других проблемах вашего кода

                ...
                cmp         al, 97              ;Compares character to a 
                jge         AddtoExp            ;If equal or greater than
                                                ;a user jumps to AddtoExp
                cmp         al, 122             ;Compares character to z 
                jle         AddtoExp            ;If equal or greater than
                                                ;a user jumps to AddtoExp
                jmp         GetEXP              ;Jumps to GetEXP if character 
                                                ;is not any of the matching
                                                ;characters

Это позволяет пользователю вводить, например, ~ (126) в качестве допустимого символа, потому что 126> = 97. Также я всегда хмуруюсь о ветвях со знаком математики, используемых вместе с символами ASCII, так как я считаю символы ASCII беззнаковыми , но технически это ничего не меняет в вашем случае, так как вас интересует только диапазон 97..122, поэтому ввод некоторого символа DOS с кодом выше 128 (не являющимся обычным ASCII в любом случае), рассматриваемого как отрицательное значение, подходит для вы.

Вы можете исправить + упростить логику, например:

                ...
                cmp         al, 'a'
                jb          GetEXP              ; ignore characters below 'a'
                cmp         al, 'z'
                ja          GetEXP              ; ignore characters above 'z'
AddtoExp:
                ... valid 'a'..'z' input, add to buffer ...

И

            dec         cx                      ;Decrements cx 
            jcxz        done                    ;Jumps to done if
                                                ;cx is zero
            jmp         DisplayExp              ;Jumps to DisplayExp 

... пока это работает, вы можете сделать более простой и производительный:

            dec         cx                      ;Decrements cx 
            jnz         DisplayExp              ;Jumps to DisplayExp until cx is zero
...