Ragel: avoid redundant "when" function calls

I'm writing a Ragel machine for a fairly simple binary protocol, and what I'm presenting here is an even more simplified version, without any error recovery, just to demonstrate the problem I'm trying to solve.

So, the message to parse looks like this:

<1 byte: length> <$length bytes: user data> <1 byte: checksum>

      

The machine looks like this:

%%{
   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;
}%%

      

As you can see, first we get 1 byte, which represents the length; then we get data

bytes until we get the required number of bytes (check is done with is_waiting_for_data

), and when we get the next (additional) byte, we check if it is the correct checksum (on is_checksum_correct

). If so, the machine is waiting for the next message; otherwise, that particular machine stops (I have not included any error recovery here to simplify the diagram).

The diagram for this looks like this:

$ ragel -Vp ./msg.rl | dot -Tpng -o msg.png

      

Click to see image

As you can see, in state 1, when we receive user data, the conditions are as follows:

0..255(is_waiting_for_data, !is_checksum_correct),
0..255(is_waiting_for_data, is_checksum_correct)

      

Thus, on each data byte, it redundantly names is_checksum_correct

, although the result does not matter.

The condition should be just as simple: 0..255(is_waiting_for_data)

How to do it?

+3


source to share


1 answer


How does it work is_checksum_correct

? The condition when

occurs before the checksum is read according to what you posted. My suggestion would be to check the checksum inside message_received

and handle any error there. This way you can get rid of the second when

and the problem will no longer exist.



It looks like semantic conditions are a relatively new feature in Ragel, and while they look really useful, they may not be mature enough if you want optimal code.

+2


source







All Articles