2015-06-20 27 views
3

我正在寫一個相當簡單的二進制協議的Ragel機器,我在這裏展示的是甚至更簡化的版本,沒有任何錯誤恢復,只是爲了演示問題,試圖解決。Ragel:避免「when」子句功能的多餘調用

所以,這裏要解析的消息是這樣的:

<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 

Click to see image

正如你看到的,在狀態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)

如何實現這一目標?

回答

2

is_checksum_correct應該如何工作?根據您發佈的內容,條件發生在讀取校驗和之前。我的建議是檢查message_received內的校驗和並處理那裏的錯誤。這樣,你可以擺脫第二個when並且問題不再存在。

看起來語義條件在Ragel中是一個相對較新的功能,儘管看起來非常有用,但如果您需要最優代碼,它們可能還不夠成熟。