Ручные парсеры — рекурсивный спуск или конечный автомат — тяжело поддерживать. Flex и Bison громоздкие и усложняют сборку. CParseC — библиотека парсер-комбинаторов на чистом C99, которая решает обе проблемы.
Это один заголовочный файл cparsec.h без зависимостей (даже libc не требуется). Парсеры композируются через макросы, которые генерируют инлайнимые функции. Разбор идёт без копирования (zero-copy), память выделяется только в пользовательской арене, скрытых аллокаций нет. Для скорости используются макросы вместо указателей на функции, а для некоторых комбинаторов — SIMD через memchr (требуется #define CPC_USE_MEMCHR).
Пример парсера CSV на CParseC занимает несколько строк и опережает BurntSushi/rust-csv примерно в 1,25 раза на миллионе строк, а attoparsec-csv — почти в 20 раз. Результаты подтверждены непрерывным бенчмаркингом на CI.
Базовые комбинаторы: CPC_STRING (ожидает точную строку), CPC_ALT (пробует первый, при неудаче — второй), CPC_RIGHT, CPC_LEFT, CPC_APPLY (выполняет два подряд и возвращает оба результата списком). Для повторений — CPC_MANY, CPC_SEP_BY и их варианты с 1. Есть CPC_TAKE_WHILE, CPC_TAKE_TILL, CPC_ONE_OF, CPC_END_OF_LINE, CPC_ANY, CPC_EOF, CPC_MAP, CPC_PURE. Специализированные SIMD-версии: CPC_TAKE_TILL_ONE_OF и CPC_TAKE_QUOTED (парсит строку в кавычках с экранированием).
Для удобства можно использовать безымянные версии макросов (с суффиксом _, например CPC_STRING_) — они требуют CPC_USE_UNNAMED и полагаются на nested functions, statement exprs и __COUNTER__ (нестандартные расширения C99). У каждого макроса есть _LABEL вариант, чтобы переопределить встроенное сообщение об ошибке.
Благодаря работе со срезами, откат (backtrack) дешёвый — try не нужен. В отличие от Haskell, парсеры CParseC всегда завершаются: many, manyTill, sepBy и sepBy1 не могут уйти в бесконечный цикл. Всё вдохновлено Parsec и AttoParsec, но адаптировано под C с минимумом оверхэда.