我制作了一个状态机编译器

2021-03-20 15:38:17

Makina是一个分层状态机源到源代码转换器。它将状态机描述作为输入,并生成这些状态机的C语言实现。

作为Makina Compiler的输入给出的每个文件都代表了单个状态机。在文件的顶部,使用机器语句指定计算机的名称:

当然,状态机通常具有多个状态。尽可能多的状态可以添加到单个机器中:

除各种状态外,状态机还定义了事件。事件是导致状态机采取行动的触发器。要为事件分配一个态度,状态必须包含一个可以如下所示的事件处理程序:

该状态已关闭现在具有命名为Open的事件的处理程序。处理程序使机器烤箱从关闭到打开。事件处理程序的完整语法如下所示:

角度括号中的东西可以是符合标识符的C语言概念的任意标识符。方括号中的东西是可选的。在上面的情况下,处理程序包括可选的转换目标,但不是保护或动作。

护卫和操作可用于创建复杂的行为。如果状态包括保护的处理程序,那么实现保护者的用户定义的函数必须返回要触发处理程序的真值。例如:

如果一个状态具有定义的前两个处理程序并且正在处理事件foo首先,将调用某些用户定义的(c语言)函数you_guard。如果其返回值为true,则将调用函数guarded_action。如果某些_geard返回0,则计算机将继续检查事件Foo的处理程序。下一个定义的处理程序未被保护,因此将调用函数default_action。

所有操作和警卫都是用户作为C语言函数实现的,具有以下原型:

为避免复制类似状态的事件处理程序,Makina允许您定义将未处理事件的子状态定义为父状态。烤箱机的封闭状态可能有几个子状态:

机箱;初始状态关闭{开放式 - >打开;初始状态空闲{开始 - >烹饪; }状态烹饪{条目enable_heater;关于超时 - >闲置的;退出禁用_发器;国家公开{关闭 - >关闭;开始错误;}

现在封闭状态有两个子状态:空闲和烹饪。此外,所关闭和关闭的状态已被指定为首字母。在这种情况下,这是一个严格必要的,因为默认初始状态是首先在文档顺序中出现的初始状态,但已添加以显示语法。初始状态是首先在初始化机器时输入的状态。

由于封闭的子状态都没有定义打开事件的处理程序,如果烤箱计算机在处理打开事件的任一状态中,则将触发父状态' s处理程序以及任何关联的操作或转换,将被触发。在这种情况下,开放事件将导致转换到打开状态,而不管哪个子状态有效。

条目和退出操作类似于事件处理程序,除了在输入或退出状态时触发它们。例如:条目处理程序条目enable_heater;在状态Close.Cooking导致输入状态时要调用函数enable_heater。同样,退出禁用_发器;当状态关闭时会调用禁用丢失。退出。如果在父状态中定义导致转换的事件,则将触发退出处理程序的事件是在上面的示例中的打开事件的情况下的父状态定义。

克隆回购并使用Intellij构建Makina-Compiler项目。 或从这里下载最新的罐子。 两个文件,< machine-name> .h和< machine-name> .c将在与<输入文件和gt中的相同目录中创建(或覆盖!)。