2015-12-01 4 views
0

Я тестирую функциональность для действий в режиме и из состояния в Ragel. У меня есть следующие программы Ragel:Почему Ragel выполняет действия State и From-State дважды?

ragelScaffolding.rl:

#include <stdio.h> 
#include <stdbool.h> 
#include <string.h> 

char *p, *pe; 
int cs; 

void runRagelMachine(char instructions[], int instructionLen){ 
p = instructions; 
pe = p + instructionLen; 
%%{ 
    machine test; 
    action testToAction1{ 
     puts("1"); 
    } 

    action testFromAction1{ 
     puts("f1"); 
    } 

    action testToAction2{ 
     puts("2"); 
    } 

    test = (
     start: (
      any -> s1 
     ), 
     s1: (
      any -> s2 
     )$to(testToAction1) $from(testFromAction1), 
     s2: (
      any -> final 
     )$to(testToAction2) 
    ); 

    main := test; 
    write data; 
    write init; 
    write exec; 
}%% 
} 

int main(){ 

char buf[1024]; 
runRagelMachine(buf, 1024); 
} 

Я бы ожидать, что это выход следующее:

1 
f1 
2 

Но вместо этого он выводит:

1 
f1 
1 
2 
f1 
2 

Который говорит мне, что он выполняет эти действия дважды. Я думал о том, почему это может быть так и для чтения документации, но я не могу понять, почему это происходит. Это происходит при компиляции с Ragel 6.9 и 7 (и компиляция C с gcc). Документация говорит следующее:

To-состояния действия выполняются всякий раз, когда конечный автомат переходит в определенное состояние, либо естественным движением над переходом или с помощью передачи действия на основе управления, таких как fgoto. Они выполняются после действий в переходном состоянии, но до того, как текущий символ продвинут и протестирован в конце входного блока.

Но ничего не происходит в выполнении действий дважды. Я был бы очень признателен за любую помощь или разъяснение по этому вопросу.

Заранее спасибо.

+0

Это должно быть право? –

+0

Спасибо за указание опечатки, исправлено. – gentleBandit

ответ

0

При попытке понять, как работает Ragel, вы можете создать графический файл Graphviz с параметром -V.

Вот Graphviz из файла Ragel:

enter image description here

После недолгого размышления на свой вопрос, вот как я думаю, что Ragel работает: я сделал это соответствие что-то точное вместо любого , это облегчает понимание.

Я изменил свой код:

test = (
     start: (
      '1' -> s1 
    )$to(testFromAction1), 
     s1: (
      '2' -> s2 
    )$to(testToAction1), 
     s2: (
      '3' -> final 
    )$to(testToAction2) 
    ); 

и назвать его:

int main() 
{ 
    char buf[5]; 

    strcpy(buf, "1341"); 
    runRagelMachine(buf, 5); 
} 

Это не должно совпадать полностью.

в GraphVis теперь выглядит следующим образом:

enter image description here

в значительной степени то же самое, но если я запускаю его, вот выход:

f1 
1 

Это соответствует '1' , который инициировал начальное состояние и назывался testFromAction1. Ничего не согласовано в состоянии s1, что не помешало вызову testToAction1.

если мы называем его:

strcpy(buf, "1234"); 
    runRagelMachine(buf, 5); 

Он должен соответствовать со всеми государствами. Мы получаем следующий вывод:

f1 
1 
1 
2 
2 

Ragel является разбор нашей строки пошагово дерева.

  • Во-первых, он ищет начальное состояние «0» на входе. Он вызывает testToAction1 (печатает f1) и оценивает s1. В этом случае он печатает первый «1».
  • Затем курсор парсеров перемещается к «1» входа. Он проверяет соответствие текущего состояния (s1). Для этого он снова оценивает s1, поэтому печатается вторая «1». Поскольку s1 вызывает состояние s2, он также оценивает s2, что является причиной первого «2». Поскольку текущие данные под курсором соответствуют «2», курсор перемещается в «3».
  • Теперь мы оцениваем шаг s2 еще раз, печатает '2', так как мы его выполняем, чтобы получить окончательное состояние.

Если мы запуская его с одним последним поддельным ввода подтверждает эту логику:

strcpy(buf, "1243"); 
    runRagelMachine(buf, 5); 

на этот раз она печатает:

f1 
1 
1 
2 

Мы можем видеть здесь остановили синтаксический на Цифра «4», но у нас есть 4 строки. той же логикой, как описано выше.

Я не уверен, что он полностью отвечает на ваш вопрос, но я надеюсь, что это поможет понять немного Ragel.

+0

Thtat определенно соответствует выходу, но все еще не уверен, почему это так. – gentleBandit

+0

добавил несколько деталей к моему первоначальному отклику. Все еще не уверен, действительно ли он отвечает на вопрос :) – Gnusam

1

Проблема заключается в использовании $ операторов, которые работают на все государства, что означает действие будет работать на стартовом состоянии каждой метки , а также государства, которые контролируют передаются. Вы должны использовать операторы > в этом случае, которые выполняются только при вводе состояния начала на каждой метке. Это гарантирует, что каждое действие вызывается только один раз для каждой метки. Таким образом, машина будет выглядеть следующим образом:

test = (
    start: (
     any -> s1 
    ), 
    s1: (
     any -> s2 
    )>to(testToAction1) >from(testFromAction1), 
    s2: (
     any -> final 
    )>to(testToAction2) 
); 

Вот диаграмма состояний выше:

State diagram for the above machine

Как вы можете видеть, каждое действие вызывается только один раз.

Смежные вопросы