2015-06-20 4 views
3

Я пишу машину Ragel для довольно простого бинарного протокола, и то, что я представляю здесь, является еще более упрощенной версией без какого-либо восстановления ошибок, просто чтобы продемонстрировать проблему. m пытается решить.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? Условие when происходит до считывания контрольной суммы в соответствии с тем, что вы опубликовали. Мое предложение было бы проверить контрольную сумму внутри message_received и обрабатывать любую ошибку там. Таким образом, вы можете избавиться от второго when, и проблема больше не будет существовать.

Похоже, что семантические условия являются относительно новой функцией в Ragel, и, хотя они выглядят действительно полезными, возможно, они недостаточно зрелы, но если вам нужен оптимальный код.