I have written this program from a diagram given to me. I just can't figure out where and how to stop it from running. It keeps asking for inputs forever. Where to add exit command in my program? Any idea?
Thank you.
INCLUDE Irvine32.inc
.data
A DWord ?
B dword ?
prompta byte "what is your digit a?",0
promptb byte "what is your digit b?",0
message0 byte "you are in s0 with output ",0
message1 byte "you are in s1 with output ",0
message2 byte "you are in s2 with output ",0
message3 byte "you are in s3 with output ",0
.code
main PROC
call s0
call waitmsg
Initial State is S0
myexit proc
mov eax, white+16*black
call settextcolor
call waitmsg
ret
myexit endp
This exit procedure here isn't working
readdigits proc
mov edx, offset prompta
call writestring
call readint ; dword into eax
mov a,eax
mov edx, offset promptb
call writestring
call readint
mov b,eax
ret
readdigits endp
Procedures for S0,S1,S2,S3 Start here
s0 proc
mov edx,offset message0
call writestring
mov eax,0 ;Output is 0 in State 0
call writedec
call crlf
call readdigits
.if(a==0)&&(b==0)
call s0
.endif
.if(a==1)&&(b==1)
call s1
.endif
call s2
ret
s0 endp
s1 proc
mov edx,offset message1
call writestring
mov eax,0 ;Output is 1 in State 0
call writedec
call crlf
call readdigits
.if(a==0)&&(b==0)
call s2
.endif
.if(a==1)&&(b==1)
call s3
.endif
call s1
ret
s1 endp
s2 proc
mov edx,offset message2
call writestring
mov eax,1 ;Output is 1 in State 2
call writedec
call crlf
call readdigits
.if(a==0)&&(b==0)
call s0
.endif
.if(a==1)&&(b==1)
call s1
.endif
call s2
ret
s2 endp
s3 proc
mov edx,offset message3
call writestring
mov eax,1 ;Output is 1 in State 2
call writedec
call crlf
call readdigits
.if(a==0)&&(b==0)
call s2
.endif
.if(a==1)&&(b==1)
call s0
.endif
call s1
ret
s3 endp
main endp
end main
Normally for a state-machine, you'd write it as a single function, using jmp
instead of call
to go to the next state.
Your state functions never return, they always jump to a new state (or to re-run the current state, like the call s1
at the bottom of s1
.) The ret
at the end is never reached, so you're just pushing an ever-growing amount of return addresses that prevent you from actually returning to main
.
Use labels like s1:
instead of s1 proc
. Or you can still use that MASM syntax to pretend each one is a separate functions, but use jmp s2
to tail-call the next state.
Then when you detect a termination condition as the next state, you can ret
, and it will return to main
.
This has the big advantage that you can use conditional branches like jne s1
instead of jumping over a call/jmp. MASM's .if
syntax might not be powerful enough to do that for you, but you're getting huge missed optimizations from using that anyway. e.g. a==0 && b==0
can be checked with mov eax, a
/ or eax, b
/ jz both_were_zero
. Plus, with only 2 "variables", keep them in call-preserved registers like ebx
and esi
or something, instead of keeping them in memory at all. That's what registers are for! You're writing in asm
Also, you can optimize by laying them out so s3
can fall-through into s1
instead of ending with jmp s1
. Or keep it simple and keep the jmp
. (If I was doing this optimization, I'd leave the jmp s1
as a comment as documentation that the fall-through to s1
as the next state is intentional.)
You have the rest of your code nested inside your main proc
, which is weird but maybe not causing an actual problem. But the first code block with the start of main
shows that it falls through from call waitmsg
into myexit proc
? That's super weird, but should actually work if myexit
is what you want to happen.
Also, you don't have a main endp
line until the end of your file, so you're telling the assembler that the other proc
declarations are inside main
.