我正在测试Ragel中的to-and-state动作的功能。我有以下Ragel计划:
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进行编译(并使用gcc编译C)时会发生这种情况。文档说明如下:
只要状态机进入指定状态,就会执行到状态操作 通过过渡的自然运动或基于动作的控制转移,例如fgoto。 它们在转换后的操作之后但在当前字符前进之前执行 并针对输入块的末尾进行测试。
但是没有任何关于两次执行动作的内容。我真的很感谢对此事的任何帮助或澄清。
提前致谢。
答案 0 :(得分:1)
问题是使用在所有状态下执行的$
运算符,这意味着操作将在每个标签的起始状态以及控制转移到<的状态下运行/ em>的。在这种情况下,您应该使用>
运算符,只有在每个标签处输入开始状态时才会执行。这可确保每个标签仅调用一次每个操作。所以,机器看起来像这样:
test = (
start: (
any -> s1
),
s1: (
any -> s2
)>to(testToAction1) >from(testFromAction1),
s2: (
any -> final
)>to(testToAction2)
);
以下是上述状态图:
如您所见,每个动作只被调用一次。
答案 1 :(得分:0)
在尝试了解Ragel的工作原理时,您可以使用-V选项生成Graphviz点文件。
以下是您的Ragel文件的Graphviz:
在你的问题上有一些反思之后,我认为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现在看起来像这样:
几乎相同,但如果我运行它,这是输出:
f1
1
它匹配'1',它触发了启动状态并调用了testFromAction1。在状态s1中没有任何匹配,这不会阻止testToAction1的调用。
如果我们称之为:
strcpy(buf, "1234");
runRagelMachine(buf, 5);
它应该与所有州相匹配。 我们得到了这个输出:
f1
1
1
2
2
Ragel正在以树步骤解析我们的字符串。
如果我们使用最后一个伪输入来运行它,则确认了这个逻辑:
strcpy(buf, "1243");
runRagelMachine(buf, 5);
这次打印:
f1
1
1
2
我们可以在这里看到它停止了'4'数字的解析,仍然我们打印了4行。与前面描述的逻辑相同。
我不确定它完全回答你的问题,但我希望它有助于理解一点Ragel。