регулярное выражение — & quot; просто & quot; парсер для переполнения стека

У меня есть проект (SCC), который похож на REPL для C ++. По подсказке Буша я могу сделать

scc '2+2'

Или немного сложнее:

scc  'double x = 0.5;  sin(x)'

что эквивалентно:

scc  'double x = 0.5;  cout << sin(x) << endl;'

Если последнее (и только возможное) выражение-выражение не заканчивается точкой с запятой, оно отправляется std::cout,
Мой вопрос касается разбора последней статьи из фрагмента кода C ++.
Я хорошо знаю, насколько сложен синтаксический анализ C ++. Разбор последнего утверждения с помощью простого сценария sed, просто поиск последнего ';' изначально был достаточно хорош для меня.
Но сейчас проект больше, чем маленький личный проект, и мне нужен лучший парсер.

Ниже приведен мини-тестовый модуль для моего текущего анализатора SED. Вы можете увидеть регулярное выражение SED, которое я использую для анализа:

    cat  <<EOF  | sed    's/$//;s/[ \t]*$//;s/\(.*[;}]\)*\([^;}]\+$\)/\0    ==>>  \1   PRINT(\2);/'print
no-print;
OK;  print
OK;  no-print;
OK;  no-print;  print
FAIL;   while(a){b;}  no-print
FAIL;   while(a)  no-print
OK;     for(a;b;c) {no-print}
FAIL;   for(a;b;c) no-print
OK;     {}
OK;     {no-print-code-block;}
FAIL;  print_rvalue_t{1}
FAIL;   f(int{1})
FAIL;   f(";")
FAIL;   f(';')
FAIL;   f("}")
EOF

Первая строка после cat-линии пустая строка. Вторая строка — одна пробел.
3-й — устав не заканчивается ';' — должен быть напечатан. 4-й — 2-х балетный
сниппет. И так далее. Если там есть FAIL — парсер не удастся на этой строке. Выход
выглядит так:

    print   ==>>     PRINT(print);
no-print;
OK;  print      ==>>  OK;   PRINT(  print);
OK;  no-print;
OK;  no-print;  print   ==>>  OK;  no-print;   PRINT(  print);
FAIL;     while(a){b;}  print     ==>>  OK;       while(a){b;}   PRINT(  no-print);
FAIL;   while(a)  no-print      ==>>  FAIL;   PRINT(    while(a)  no-print);
OK;     for(a;b;c) {no-print}
FAIL;   for(a;b;c) no-print     ==>>  FAIL;     for(a;b;   PRINT(c) no-print);
OK;     {}
OK;     {no-print-code-block;}
FAIL;  print_rvalue_t{1}
FAIL;   f(int{1})       ==>>  FAIL;     f(int{1}   PRINT());
FAIL;   f(";")  ==>>  FAIL;     f(";   PRINT("));
FAIL;   f(';')  ==>>  FAIL;     f(';   PRINT('));
FAIL;   f("}")  ==>>  FAIL;     f("}   PRINT("));

Линии без ==>> маркером являются строки, которые проходят через парсер без изменений. После того, как маркер преобразуется в фрагмент, где заключено последнее утверждение PRINT( ),
Как вы можете видеть, текущий анализатор SED не очень хорош.

Поэтому я ищу что-то лучшее. Я приму ответ, даже если это не так
100% правильно при разборе. Даже лучше сценарий SED будет достаточно для меня.
Правильный способ сделать это, вероятно, будет использовать настоящий парсер (из чего-то вроде
CLANG) но я немного опасаюсь сложности этой работы.

Я пытался написать парсер в boost / xpressive — http://github.com/lvv/scc/blob/master/sccpp.h . Потому что это не настоящий C ++
синтаксический анализатор. Это просто быстрый взлом, сделанный только для одной цели: разобрать последнее утверждение. это
в состоянии сделать все вышеупомянутые юнит-тесты. Но, к сожалению, для более длинных фрагментов это было
невыносимо медленно

Вопрос: как сделать лучше парсер?

1

Решение

Правильный способ сделать это, вероятно, будет использовать реальный парсер (из
что-то вроде CLANG) но я немного опасаюсь сложности
этого усилия

Не тоже высоко. Простой факт заключается в том, что C ++ похож на HTML — вам нужна настоящая библиотека, поэтому, если вы не хотите тратить годы на разработку своего собственного, практически единственный способ — использовать существующий синтаксический анализатор C ++. Clang — единственный вариант в этом отношении. Так что, как бы сложно это ни было, у вас нет другого выбора.

1

Другие решения

Других решений пока нет …