Я новичок в Ragel и пытаюсь разобрать определенный шаблон выражения Regex. Я хочу действия done
выполняется, если совпадение найдено и parse_error
выполняется, если не найдено ни одного совпадения даже для одного отсутствующего символа.
Вот код, который я написал:
#include <iostream>
#include <string.h>
#include <stdio.h>
%%{
action done {
printf("done\n");
}action parse_error {
printf("error : %c\n",fc);
}machine ldf;
main := (':'.'LoadSdf'.[0-9]+.[a-zA-Z0-9_\-\.])@done | //execute done
(^(':'.'LoadSdf'.[0-9]+.[a-zA-Z0-9_\-\.])) $err(parse_error); //execute parse error for no match
}%%
%%write data;
int main(int argc, char** argv)
{
int cs;
if(argc > 1) {
char *p = argv[1];
char *pe = p+strlen(p) + 1;
%%write init;
%%write exec;
}
return 0;
}
Поведение, которое я вижу, состоит в том, что действия done
а также parse_error
оба выполняются, когда есть идеальное совпадение с выражением регулярного выражения.
Кто-нибудь может дать несколько советов, как мне справиться с этим делом?
Есть несколько проблем с этим кодом. Во-первых, техническая ошибка — у вас нет pe
определение (оно включает нулевой символ и ваша машина не должна заботиться о нолях (конечно, вы можете заставить его обрабатывать их, но это просто усложняет вещи без причины)). Также полезно иметь eof
определяется, потому что это должно быть ошибкой, когда у вас есть что-то вроде «: Load» во входных данных (пропуская «Sdf» и следующие фрагменты). Это исправлено
-char *pe = p+strlen(p) + 1;
+char *pe = p+strlen(p);
+char *eof = pe;
Другая проблема заключается в том, что нет необходимости совмещать какую-либо машину и ее негатив для контроля ошибок. Это разные действия. Посмотрите на изображение вашей машины:
Вы можете видеть, что в середине просто нет правильной обработки ошибок здесь, и в конце концов вы можете иметь done()
вызывается несколько раз, потому что указано, что это происходит при переходе в одно из конечных состояний. Вероятно, он должен быть запущен только при правильном завершении машины (то есть при достижении EOF в конечном состоянии).
Так что если вы хотите изменить определение вашей машины на
main := (':'.'LoadSdf'.[0-9]+.[a-zA-Z0-9_\-\.]) %/done $!(parse_error);
вы, вероятно, получите то, что вы хотите:
$ ./a.out "asdf"error : a
$ ./a.out "qwerty"error : q
$ ./a.out ":Load"error :
$ ./a.out ":LoadSdf"error :
$ ./a.out ":LoadSdf1212"done
$ ./a.out ":LoadSdf1q"done
$ ./a.out ":LoadSdf1qwe"error : w
Который выглядит так в графической форме:
Других решений пока нет …