我尝试将解析器编写为简单的二进制协议
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 recomendations我发布了一个完整的例子。这个例子不起作用,因为得到错误的校验和。
#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);
但不是解决方案。
答案 0 :(得分:0)
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星型运算符**
,指示它在成功后循环回到开头帧解析。这让我们看到了这个漂亮的图表,它可能更接近你想要的东西:
答案 1 :(得分:0)
在您的第一个示例中,fgoto
会使用校验和数据,以便以后在您需要校验和时不可用。您可以使用fhold
来防止它被使用。 checksum_action
也应该返回主页(并使用$
转换而不是&#39;%&#39;这只会在EOF
时发生。 )。
action data_action {
if(!len) {
fhold;
fgoto check;
} else {
data[indexx++] = fc;
len --;
}
}
action checksum_action { checksum = fc; fnext main; }
(或者您可以将校验和逻辑放在data_action
代码中)。