我正在为相当简单的二进制协议编写Ragel机器,我在这里展示的是更简化的版本,没有任何错误恢复,只是为了演示我试图解决的问题。
因此,要解析的消息如下所示:
<1 byte: length> <$length bytes: user data> <1 byte: checksum>
机器如下所示:
%%{
machine my_machine;
write data;
alphtype unsigned char;
}%%
%%{
action message_reset {
/* TODO */
data_received = 0;
}
action got_len {
len = fc;
}
action got_data_byte {
/* TODO */
}
action message_received {
/* TODO */
}
action is_waiting_for_data {
(data_received++ < len);
}
action is_checksum_correct {
1/*TODO*/
}
len = (any);
fmt_separate_len = (0x80 any);
data = (any);
checksum = (any);
message =
(
# first byte: length of the data
(len @got_len)
# user data
(data when is_waiting_for_data @got_data_byte )*
# place higher priority on the previous machine (i.e. data)
<:
# last byte: checksum
(checksum when is_checksum_correct @message_received)
) >to(message_reset)
;
main := (msg_start: message)*;
# Initialize and execute.
write init;
write exec;
}%%
如您所见,首先我们收到代表长度的1个字节;然后我们收到data
字节,直到我们收到所需的字节数(检查由is_waiting_for_data
完成),当我们收到下一个(额外)字节时,我们检查它是否是正确的校验和(通过{ {1}})。如果是,机器将等待下一条消息;否则,这台特定的机器会停止运转(为了简化图表,我还没有故意在此处进行任何错误恢复)。
它的图表如下:
is_checksum_correct
如您所见,在状态1中,当我们收到用户数据时,条件如下:
$ ragel -Vp ./msg.rl | dot -Tpng -o msg.png
因此,在每个数据字节上,它会冗余地调用0..255(is_waiting_for_data, !is_checksum_correct),
0..255(is_waiting_for_data, is_checksum_correct)
,尽管结果并不重要。
条件应该很简单:is_checksum_correct
如何实现?
答案 0 :(得分:2)
is_checksum_correct
如何运作?根据您发布的内容,when
条件在读取校验和之前发生。我的建议是检查message_received
内的校验和并处理那里的任何错误。这样,您可以摆脱第二个when
,问题就不复存在了。
看起来语义条件在Ragel中是一个相对较新的功能,虽然它们看起来非常有用,但如果你想要最佳代码,它们可能还不够成熟。