簡體   English   中英

fgoto使用ragel進行二進制可變長度協議

[英]fgoto on binary variable length protocol with ragel

我試圖將解析器編寫為簡單的二進制協議

  • 0或更多的幀外字節
  • 使用STX(0x02)開始幀
  • 兩個messaje長度字節的messaje長度。
  • 一個命令字節。
  • 0個或更多數據字節。
  • 一個checkun字節。

拉吉爾腳本

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);

但不是解決方案。

  1. 如果您向我們提供了示例輸入和完整的源代碼以驗證程序的整體,那就太好了。
  2. 我不確定為什么您的goto無效,但是我可能根本不使用fgoto簡化事情。 這里沒有必要,您可以使用語義條件( when
  3. 您的計算機不會返回到初始狀態,因為沒有任何提示。

因此,我對您的原始代碼做了一些小的更改:

--- 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM