Reputation: 1073
So I'm writing a uni assignment - a program that subtracts two entered decimals (max 10 characters ea). The first iteration works as intended. However, when I restart the program, for some reason the second operand is remembered. The prompt to enter it does come up, but is then skipped as if I've entered something already - the same thing I entered the first iteration, in fact. The question is: why does it happen and how do I fix it? The first prompt works correctly.
The prompt is under INPUT_2:
.model small
.386
stack 100h
dataseg
inputMsg1 db 0Ah, 0Dh, 'Enter first operand', 0Ah, 0Dh, '$'
inputMsg2 db 0Ah, 0Dh, 'Enter second operand', 0Ah, 0Dh, '$'
inputMax1 db 11
inputLen1 db ?
input1 db 12 dup(?)
input1Packd db 5 dup(0)
inputMax2 db 11
inputLen2 db ?
input2 db 12 dup(?)
input2Packd db 5 dup(0)
packMode db 0 ;Режим упаковки: 1 - первая цифра, 2 - вторая
resMsg db 0Ah, 0Dh, 'Result: $'
res db 9 dup(' '),'$'
retryMsg db 0Ah, 0Dh
db 'Press Any Key to continue, ESC to quit'
db '$'
errorMsg db 0Ah, 0Dh, 'Something went wrong. Try again$'
codeseg
START:
startupcode
jmp INPUT_1
INPUT_1_ERROR:
lea DX, errorMsg
mov AH, 09h
int 21h
INPUT_1:
lea DX, inputMsg1
mov AH, 09h
int 21h
lea DX, inputMax1
mov AH, 0Ah
int 21h
cmp inputLen1, 0
jz INPUT_1_ERROR
INPUT_1_PROCESS:
lea BX, input1
lea DX, input1Packd
xor CX, CX
mov CL, inputLen1
mov SI, CX
dec SI
mov DI, 4
INPUT_1_LOOP:
mov AL, [BX][SI]
cmp AL, '0'
jb INPUT_1_ERROR
cmp AL, '9'
ja INPUT_1_ERROR
and AL, 0Fh
mov AH, packMode
cmp AH, 0
jnz INPUT_1_PACK_SECOND
INPUT_1_PACK_FIRST:
inc AH
push BX
mov BX, DX
mov [BX][DI], AL
pop BX
jmp INPUT_1_PACK_FINISHED
INPUT_1_PACK_SECOND:
dec AH
shl AL, 4
push BX
mov BX, DX
or [BX][DI], AL
pop BX
dec DI
INPUT_1_PACK_FINISHED:
mov packMode, AH
dec SI
loop INPUT_1_LOOP
mov packMode, 0
jmp INPUT_2
INPUT_2_ERROR:
lea DX, errorMsg
mov AH, 09h
int 21h
INPUT_2:
lea DX, inputMsg2
mov AH, 09h
int 21h
lea DX, inputMax2
mov AH, 0Ah
int 21h
cmp inputLen2, 0
jz INPUT_2_ERROR
INPUT_2_PROCESS:
lea BX, input2
lea DX, input2Packd
xor CX, CX
mov CL, inputLen2
mov SI, CX
dec SI
mov DI, 4
INPUT_2_LOOP:
mov AL, [BX][SI]
cmp AL, '0'
jb INPUT_2_ERROR
cmp AL, '9'
ja INPUT_2_ERROR
and AL, 0Fh
mov AH, packMode
cmp AH, 0
jnz INPUT_2_PACK_SECOND
INPUT_2_PACK_FIRST:
inc AH
push BX
mov BX, DX
mov [BX][DI], AL
pop BX
jmp INPUT_2_PACK_FINISHED
INPUT_2_PACK_SECOND:
dec AH
shl AL, 4
push BX
mov BX, DX
or [BX][DI], AL
pop BX
dec DI
INPUT_2_PACK_FINISHED:
mov packMode, AH
dec SI
loop INPUT_2_LOOP
MATH_SETUP:
mov SI, 4
mov CX, 4
mov DI, 7
MATH:
lea BX, input1Packd
mov AL, [BX][SI]
lea BX, input2Packd
mov AH, [BX][SI]
sbb AL, AH
pushf
das
dec SI
mov AH, AL
lea BX, res
and AL, 0Fh
or AL, 30h
mov [BX][DI], AL
dec DI
shr AH, 4
or AH, 30h
mov [BX][DI], AH
dec DI
popf
loop MATH
lea BX, res
mov CX, 7
mov SI, 0
SHORTEN:
mov AL, [BX][SI]
cmp AL, '0'
jnz WRAPUP
inc SI
loop SHORTEN
WRAPUP:
push CX
lea DX, resMsg
mov AH, 09h
int 21h
lea DX, res
pop CX
cmp CX, 0
jz SKIP_SHORTEN
PRINT_SHORTEN:
add DX, 7
sub DX, CX
jmp FINISH_SHORTEN
SKIP_SHORTEN:
add DX, 6
FINISH_SHORTEN:
mov AH, 09h
int 21h
lea DX, retryMsg
mov AH, 09h
int 21h
mov AH, 01h
int 21h
cmp AL, 1Bh
jz QUIT
lea BX, input1Packd
mov DX, 1
BCD_CLEANUP:
mov DI, 0
mov CX, 5
BCD_CLEANUP_LOOP:
mov [BX][DI], 0
inc DI
loop BCD_CLEANUP_LOOP
lea BX, input2Packd
cmp DX, 1
mov DX, 0
jz BCD_CLEANUP
jmp START
QUIT:
exitcode 0
end START
Any better code suggestions welcome as well, but not needed if you don't have an answer for the question.
Upvotes: 2
Views: 773
Reputation: 39556
The DOS buffered input function 0Ah allows you to have a preset text in the storage space of the input buffer that you provide. For a complete explanation of this DOS function see how buffered input works.
The first time that your program runs the inputLen1 and inputLen2 fields are empty because of how you defined them in the source using db ?
which translates to zero.
But when you re-run the code this is no longer the case! The lengths still show what you got in the previous run. You need to zero both these fields before invoking function 0Ah again on the same input buffers.
mov DX, 0
jz BCD_CLEANUP
mov inputLen1, DL ;DL=0
mov inputLen2, DL ;DL=0
jmp START
The MATH loop has a couple of problems regarding the CF
.
The sbb al, ah
instruction depends on the value in the carry flag, but you neglect to make sure it is off on the first iteration of this loop. Just add clc
:
clc
MATH:
lea BX, input1Packd
mov AL, [BX][SI]
lea BX, input2Packd
mov AH, [BX][SI]
sbb AL, AH
The das
instruction consumes the carry flag that you get from the sbb
instruction, but it's the carry flag that you get from the das
instruction that you need to preserve/restore to have it propagate through the loop.
sbb AL, AH
das
pushf
...a program that subtracts two entered decimals (max 10 characters ea)...
If ever you enter 9 or 10 characters, those most significant digits will not be taken into account because MATH_SETUP really limits you to 8 characters (which in turn is a good thing since the res buffer only has room to show 8 characters)!
MATH_SETUP:
mov SI, 4 <-- Could permit 10 packed BCD digits
mov CX, 4 <-- Max 8 characters
mov DI, 7 <-- Max 8 characters
Upvotes: 2