У меня есть проект (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 ++
синтаксический анализатор. Это просто быстрый взлом, сделанный только для одной цели: разобрать последнее утверждение. это
в состоянии сделать все вышеупомянутые юнит-тесты. Но, к сожалению, для более длинных фрагментов это было
невыносимо медленно
Вопрос: как сделать лучше парсер?
Правильный способ сделать это, вероятно, будет использовать реальный парсер (из
что-то вроде CLANG) но я немного опасаюсь сложности
этого усилия
Не тоже высоко. Простой факт заключается в том, что C ++ похож на HTML — вам нужна настоящая библиотека, поэтому, если вы не хотите тратить годы на разработку своего собственного, практически единственный способ — использовать существующий синтаксический анализатор C ++. Clang — единственный вариант в этом отношении. Так что, как бы сложно это ни было, у вас нет другого выбора.
Других решений пока нет …