Ваш код показывает несколько проблем, но давайте сосредоточимся на «строке»
инструкции.
О 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