私はかなり単純なバイナリ プロトコル用の 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)
それを達成する方法は?