如何以及在哪里结束这个有限状态机程序的工作?
How and where to end this finite state machine program working?
我根据给我的图表编写了这个程序。我只是想不出在哪里以及如何从 运行 中阻止它。它永远要求输入。在我的程序中的哪里添加退出命令?有什么想法吗?
谢谢。
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
初始状态为 S0
myexit proc
mov eax, white+16*black
call settextcolor
call waitmsg
ret
myexit endp
此处的退出程序无效
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
S0、S1、S2、S3 的程序从这里开始
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
通常对于 state-machine,您会将其编写为单个函数,使用 jmp
而不是 call
进入下一个状态。
您的状态函数从不 return,它们总是跳到一个新状态(或跳到 re-run 当前状态,例如 s1
底部的 call s1
.) 最后的 ret
永远不会到达,所以你只是推送了 ever-growing 数量的 return 地址,这些地址实际上阻止你 returning 到 main
.
使用 s1:
之类的标签,而不是 s1 proc
。或者您仍然可以使用 MASM 语法假装每个函数都是单独的函数,但使用 jmp s2
到 tail-call 下一个状态。
然后当你检测到一个终止条件作为下一个状态时,你可以ret
,它将return到main
.
这有一个很大的优势,你可以使用像 jne s1
这样的条件分支,而不是跳过 call/jmp。 MASM 的 .if
语法可能不够强大,无法为您做到这一点,但无论如何您都会因使用它而错过大量优化。例如a==0 && b==0
可以用 mov eax, a
/ or eax, b
/ jz both_were_zero
检查。另外,只有 2 个 "variables",将它们保存在 call-preserved 寄存器中,例如 ebx
和 esi
之类的,而不是将它们完全保存在内存中。这就是寄存器的用途!你在写 asm
此外,您可以通过对它们进行布局进行优化,这样 s3
就可以 fall-through 变成 s1
而不是以 jmp s1
结尾。或者保持简单并保持 jmp
。 (如果我正在做这个优化,我会留下 jmp s1
作为注释作为文档,fall-through 到 s1
作为下一个状态是有意的。)
您将其余代码嵌套在 main proc
中,这很奇怪,但可能不会导致实际问题。但是以 main
开头的第一个代码块表明它从 call waitmsg
落入 myexit proc
?这太奇怪了,但如果 myexit
是你想要发生的事情,它应该真的有效。
此外,在文件末尾之前没有 main endp
行,因此您告诉汇编程序其他 proc
声明在 main
中。
我根据给我的图表编写了这个程序。我只是想不出在哪里以及如何从 运行 中阻止它。它永远要求输入。在我的程序中的哪里添加退出命令?有什么想法吗?
谢谢。
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
初始状态为 S0
myexit proc
mov eax, white+16*black
call settextcolor
call waitmsg
ret
myexit endp
此处的退出程序无效
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
S0、S1、S2、S3 的程序从这里开始
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
通常对于 state-machine,您会将其编写为单个函数,使用 jmp
而不是 call
进入下一个状态。
您的状态函数从不 return,它们总是跳到一个新状态(或跳到 re-run 当前状态,例如 s1
底部的 call s1
.) 最后的 ret
永远不会到达,所以你只是推送了 ever-growing 数量的 return 地址,这些地址实际上阻止你 returning 到 main
.
使用 s1:
之类的标签,而不是 s1 proc
。或者您仍然可以使用 MASM 语法假装每个函数都是单独的函数,但使用 jmp s2
到 tail-call 下一个状态。
然后当你检测到一个终止条件作为下一个状态时,你可以ret
,它将return到main
.
这有一个很大的优势,你可以使用像 jne s1
这样的条件分支,而不是跳过 call/jmp。 MASM 的 .if
语法可能不够强大,无法为您做到这一点,但无论如何您都会因使用它而错过大量优化。例如a==0 && b==0
可以用 mov eax, a
/ or eax, b
/ jz both_were_zero
检查。另外,只有 2 个 "variables",将它们保存在 call-preserved 寄存器中,例如 ebx
和 esi
之类的,而不是将它们完全保存在内存中。这就是寄存器的用途!你在写 asm
此外,您可以通过对它们进行布局进行优化,这样 s3
就可以 fall-through 变成 s1
而不是以 jmp s1
结尾。或者保持简单并保持 jmp
。 (如果我正在做这个优化,我会留下 jmp s1
作为注释作为文档,fall-through 到 s1
作为下一个状态是有意的。)
您将其余代码嵌套在 main proc
中,这很奇怪,但可能不会导致实际问题。但是以 main
开头的第一个代码块表明它从 call waitmsg
落入 myexit proc
?这太奇怪了,但如果 myexit
是你想要发生的事情,它应该真的有效。
此外,在文件末尾之前没有 main endp
行,因此您告诉汇编程序其他 proc
声明在 main
中。