Я нашел решение. Вам нужно справиться с детерминизмом. Это не было ясно изначально, но правильное решение что-то вроде этого:
inner_text = any*;
tag_cdata = '<![CDATA[' inner_text >text_begin %text_end ']]>' %cdata_end;
action text_begin {
text_begin_at = p;
}
action text_end {
text_end_at = p;
}
action cdata_end {
delegate.cdata(data.byteslice(text_begin_at, text_end_at-text_begin_at))
}
По сути, вы будете ждать, пока вы не уверены, что вы разобраны полный CDATA тег перед срабатыванием обратного вызова, используя информацию, которую ранее захватили.
Кроме того, я обнаружил, что некоторые формы недетерминизма в Ragel должны быть явно обработаны с использованием приоритетов. Хотя это кажется немного уродливым, это единственное решение в некоторых случаях.
При работе с рисунком, например (a+ >a_begin %a_end | b)*
, вы обнаружите, что события вызывают для каждого встречающегося a
, а не в самой длинной подпоследовательности. Эта двусмысленность, в некоторых случаях, может быть решена с использованием самого длинного матча kleene star **
. Что это значит, он предпочитает сопоставлять существующий шаблон, а не обертывать.
Что удивило меня, это то, что на самом деле это изменяет способ вызова событий. В качестве примера, это создает машину, которая не в состоянии буфера более одного символа в то время, при вызове функции обратного вызова:
%%{
machine example;
action a_begin {}
action a_end {}
main := ('a'+ >a_begin %a_end | 'b')*;
}%%
Производит:
Вы заметите, что он называет a_begin
и a_end
каждый раз.
В отличие от этого, мы можем сделать внутренний цикл и обработка событий жадные:
%%{
machine example;
action a_begin {}
action a_end {}
main := ('a'+ >a_begin %a_end | 'b')**;
}%%
, который производит:
Разве это не странно, когда вы нашли собственное решение в год будущее и думаю, я действительно написал это !? :) – ioquatix