我正在为相当简单的二进制协议编写 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
),当我们收到下一个(额外)字节时,我们检查它是否是正确的校验和(由is_checksum_correct
)。如果是,机器将等待下一条消息;否则,这个特定的机器会停止(为了简化图表,我没有故意在这里包含任何错误恢复)。
它的示意图如下所示:
$ ragel -Vp ./msg.rl | dot -Tpng -o msg.png
如您所见,在状态 1 中,当我们接收用户数据时,条件如下:
0..255(is_waiting_for_data, !is_checksum_correct),
0..255(is_waiting_for_data, is_checksum_correct)
因此,在它冗余调用的每个数据字节上is_checksum_correct
,尽管结果根本不重要。
条件应该很简单:0..255(is_waiting_for_data)
如何做到这一点?