2 使用_使用coroutine实现状态机(2)

62872f25c9f085d464fcaa33ef6ad156.png

自从 使用coroutine实现状态机 以来已经有两个星期了,在这两个星期里我把这个想发给实现了。语法做了一点点小修改,但是总的来说没有区别。上一篇文章的计算器的例子作为单元测试的一部分被添加了进去,大家可以在看这两个文件:

CoSmcCalculator.txt:测试用的状态机,支持加法和乘法。

CoSmcCalculator.cpp:生成的C++代码。C++当然没有状态机的功能,所以Workflow脚本的状态机自然被改写成了普通的代码,变成了一个真正的状态机。

Workflow脚本要求使用了$state_machine的类必须继承自system::StateMachine,再加上Workflow不允许多重继承里面出现同一个类多次,所以$state_machine的父类当然不能是$state_machine。这个限制是草稿里面没有的。

整个状态机被编译成了一个使用 coroutine 表达的状态机,而coroutine又被编译成了一个状态机,所以生成的代码里面两个嵌套的状态机被合并到了一起,这么扫一眼根本看不懂(逃

Workflow的状态机支持$goto_state和$push_state两种模式。$goto_state说的是你跳转过去之后就不回来了,如果那个状态结束了之后没有跳转到任何其他状态,那么整个状态机就结束了。$push_state就是还要回来的疑似。$goto_state就像jump,$push_state就像函数调用。函数调用自然是有堆栈的,所以$push_state自然也有堆栈——这个被生成的coroutine的previousCoroutine变量隐式表达成了一个外部访问不了的链表。

这个链表的根节点放在了system::StateMachine类里面,类的 ResumeStateMachine 函数识别了多个coroutine之间切换的意图,把他们有机地结合了起来。因为一个coroutine的暂停和结束,有可能意味着$push_state和"pop_state",自然不能让ResumeStateMachine暂停,而是要继续跑下去,直到状态机真的要开始等待外部的输入为止。

状态机的输入是用$state_input定义的,最后他们就变成了函数。你调用这些函数,就是在输入数据。因此最后在测试用例里面,我们的用例长这样子:

func main():string
{
	var c = new SMCalculator^();
	s=$"[$(c.Value)]";
	var handler = attach(c.ValueChanged, func():void
	{
		s=$"$(s)[$(c.Value)]";
	});

	c.Digit(1);	// 1
	c.Dot();	// 1.
	c.Digit(5);	// 1.5
	c.Add();
	c.Digit(2);	// 2
	c.Digit(1);	// 21
	c.Dot();	// 21.
	c.Digit(2);	// 21.2
	c.Digit(5);	// 21.25
	c.Mul();	// 22.75 (1.5 + 21.25)
	c.Digit(2);	// 2
	c.Equal();	// 45.5 (22.75 * 2)
	c.Clear();	// 0

	detach(c.ValueChanged, handler);
	return s;
}

这个代码模拟了用户点击计算器按钮的过程,Value属性代表了液晶屏上显示的数据,每次有改变的时候,这个值就会被append到全局变量s里面。最后输出的结果自然应该是:

[0][1][1.][1.5][2][21][21.][21.2][21.25][22.75][2][45.5][0]

因为你在点计算器的时候,上面的数字的确就是这么变化的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值