Ragel:避免"""子句功能

时间:2015-06-20 14:26:51

标签: ragel

我正在为相当简单的二进制协议编写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

Click to see image

如您所见,在状态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

如何实现?

1 个答案:

答案 0 :(得分:2)

is_checksum_correct如何运作?根据您发布的内容,when条件在读取校验和之前发生。我的建议是检查message_received内的校验和并处理那里的任何错误。这样,您可以摆脱第二个when,问题就不复存在了。

看起来语义条件在Ragel中是一个相对较新的功能,虽然它们看起来非常有用,但如果你想要最佳代码,它们可能还不够成熟。