Мне нужно разобрать строку типа func1(arg1, arg2); func2(arg3, arg4);
. Это не очень сложная проблема синтаксического анализа, поэтому я бы предпочел не прибегать к flex/bison или подобным утилитам.
Мой первый подход состоял в том, чтобы попытаться использовать реализацию POSIX C regcomp/regexec
или Boost C++ std::regex
. Я написал следующее регулярное выражение, которое не работает (далее объясню почему).
"^"
"[ ;\t\n]*"
"(" // (1) identifier
"[a-zA-Z_][a-zA-Z0-9_]*"
")"
"[ \t\n]*"
"(" // (2) non-marking
"\["
"(" // (3) non-marking
"[ \t]*"
"(" // (4..n-1) argument
"[a-zA-Z0-9_]+"
")"
"[ \t\n]*"
","
")*"
"[ \t\n]*"
"(" // (n) last argument
"[a-zA-Z0-9_]+"
")"
"]"
")?"
"[ \t\n]*"
";"
Обратите внимание, что группа 1
захватывает идентификатор, а группы 4..n-1
предназначены для захвата аргументов, кроме последнего, который захватывается группой n
.
Когда я применяю это регулярное выражение, скажем, к func(arg1, arg2, arg3)
, результат, который я получаю, представляет собой массив {func, arg2, arg3}
. Это неправильно, потому что arg1
в нем нет!
Проблема в том, что в стандартных библиотеках регулярных выражений подмаркировки фиксируют только последнее совпадение. Другими словами, если вы, например, применили регулярное выражение "((a*|b*))*"
к "babb"
, результаты внутреннего совпадения будут bb
, а все предыдущие захваты будут забыты.
Еще меня здесь раздражает то, что в случае ошибки нет способа узнать, какой символ не был распознан, поскольку эти функции предоставляют очень мало информации о состоянии парсера при отклонении ввода.
Так что я не знаю, не упустил ли я что-то здесь... В этом случае я должен использовать вместо этого sscanf
или что-то подобное?
Обратите внимание, что я предпочитаю использовать стандартные библиотеки C/C++ (и, возможно, повысить).