[英]fgoto on binary variable length protocol with ragel
我試圖將解析器編寫為簡單的二進制協議
拉吉爾腳本
static int len;
static unsigned char command;
static int indexx;
static unsigned char data[0x10000];
static unsigned char checksum;
%%{
machine themachine;
action out_of_frame_action { }
action start_of_frame_action {}
action first_byte_len_action { len = fc *256; }
action second_byte_len_action { len += fc; }
action command_action { command = fc; indexx=0; len--;}
action data_action {
if(!len)
fgoto check;
else
{
data[indexx++];
len --;
}
}
action checksum_action { checksum = fc; }
stx = 0x02;
first_byte_len = any;
second_byte_len = any;
command = any;
data = any*;
checksum = any;
main := (^stx* $ out_of_frame_action)
(stx > start_of_frame_action)
(first_byte_len > first_byte_len_action)
(second_byte_len > second_byte_len_action)
(command > command_action)
(data $ data_action) ;
check := (checksum % checksum_action) ;
}%%
但是結果機不會跳到檢查(5)狀態,因此不會執行checksum_action,也不會返回到第一個狀態以繼續解析。
怎么了?
遵循@Roman建議我發布了一個完整的示例。 此示例也不起作用,因為得到錯誤的校驗和。
#include <stdint.h>
#include <stdio.h>
static int len;
static unsigned char command;
static int indexx;
static unsigned char data[0x10000];
static unsigned char checksum;
%%{
machine themachine;
stx = 0x02;
action out_of_frame_action
{
printf("OOF %02X\n",fc);
}
action start_of_frame_action
{
printf("STX ");
}
action first_byte_len_action
{
printf("fbl[%d] ",(int)(fc));
len = 256*((unsigned char)fc);
}
action second_byte_len_action
{
len += (unsigned char )fc ;
printf("sbl[%d] Len=%d ",(int)(fc),len);
indexx=0;
len-=2; // Checksum and command are included on message len
}
action command_action
{
command = fc;
printf("CMM=%02X ", command);
}
action check_len
{
len > 0
}
action data_action
{
data[indexx++]=fc;
printf("[%02X]",(unsigned char) fc);
len--;
}
action checksum_action
{
checksum = fc;
printf(" Chk=%02X \n",checksum);
}
first_byte_len = any ;
second_byte_len = any;
command = any;
data = any*;
checksum = any;
check = (checksum % checksum_action);
main := ((^stx* $ out_of_frame_action)
(stx > start_of_frame_action)
(first_byte_len > first_byte_len_action)
(second_byte_len > second_byte_len_action)
(command > command_action)
(data when check_len $ data_action)
check
)**;
}%%
%% write data;
int main(void)
{
uint8_t buf[] = {
0x00, // OOF 00
0x00, // OOF 00
0x02,0x00,0x03,0x20,0x01,0x21, // STX fbl[0] sbl[3] Len = 3 CMM=20 [01] Chk=21
0x00, // OOF 00
0x00, // OOF 00
0x02,0x00,0x05,0x81,0x01,0x02,0x03,0x87, // STX fbl[0] sbl[5] Len = 5 CMM=81 [01][02][03] Chk=87
0x02,0x00,0x03,0x03,0x01,0x04, // STX fbl[0] sbl[3] Len = 3 CMM=03 [01] Chk=04
0x02,0x00,0x05,0x07,0x01,0x02,0x03,0x0D // STX fbl[0] sbl[5] Len = 5 CMM=07 [01][02][03] Chk=0D
};
int cs;
uint8_t *p, *pe, *eof;
p = buf;
eof = pe = buf + sizeof(buf)/sizeof(uint8_t);
%% write init;
%% write exec;
}
我改變
check = (checksum % checksum_action);
通過
check = (checksum > checksum_action);
但不是解決方案。
goto
無效,但是我可能根本不使用fgoto
簡化事情。 這里沒有必要,您可以使用語義條件( when
) 因此,我對您的原始代碼做了一些小的更改:
--- main.c.orig 2017-12-17 11:48:49.369200291 +0300
+++ main.c 2017-12-20 22:51:11.096283379 +0300
@@ -12,14 +12,12 @@
action first_byte_len_action { len = fc *256; }
action second_byte_len_action { len += fc; }
action command_action { command = fc; indexx=0; len--;}
+ action check_len {
+ len
+ }
action data_action {
- if(!len)
- fgoto check;
- else
- {
- data[indexx++];
- len --;
- }
+ data[indexx++];
+ len--;
}
action checksum_action { checksum = fc; }
@@ -30,13 +28,13 @@
data = any*;
checksum = any;
-main := (^stx* $ out_of_frame_action)
+ check = (checksum % checksum_action);
+main := ((^stx* $ out_of_frame_action)
(stx > start_of_frame_action)
(first_byte_len > first_byte_len_action)
(second_byte_len > second_byte_len_action)
(command > command_action)
- (data $ data_action) ;
+ (data when check_len $ data_action) check)**;
-check := (checksum % checksum_action) ;
}%%
請注意, when
將其用於data
簡化其操作,還請注意主字段中最長匹配的kleene star運算符**
,指示其在成功解析幀后循環回到起始位置。 這使我們進入了這張漂亮的圖,它可能更接近您想要的圖:
在第一個示例中, fgoto
將使用校驗和數據,因此以后需要校驗和時將不可用。 您可以使用fhold
防止其被消耗。 checksum_action
也應該回到main(並使用$
過渡而不是'%',只有在EOF
時才會發生)。
action data_action {
if(!len) {
fhold;
fgoto check;
} else {
data[indexx++] = fc;
len --;
}
}
action checksum_action { checksum = fc; fnext main; }
(或者您可以將校驗和邏輯放在data_action
代碼中)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.