Парсер C кода.
Поиск парсера для C кода – по-прежнему увлекательное занятие. Для Win32.Utf8 мне нужен был парсер для анализа заголовочных файлов Win32 API и извлечения из них прототипов функций и объявлений структур. Требований к нему было не очень много:
- Разбор заголовка размером 2-3MB (размер windows.h после препроцессора) должен занимать разумное время – 20-30 секунд на типичной машине. В моем случае в качестве эталона выступает Athlon XP 1.5GHz;
- Требовалось умение работать с нестандартными расширениями C - __declspec и прочим;
- Парсер должен извлекать SAL описания параметров функций и членов структур;
- Результат разбора должен быть удобен для последующего анализа;
Очевидный вариант – адаптировать парсер из GCC был отброшен сразу. Это не совсем тривиально, да и адаптировать его под себя не просто. Другой интересный вариант – использовать GCC-XML был также отвергнут из-за несовместимости с пунктами 2 и 3. Вывод напрашивался один – придётся писать собственный парсер.
Встала другая проблема какой парсер генератор использовать. Поскольку в качестве основного языка для проекты был выбран Python, то и рассматривались варианты генерирующие код на Python (или позволяющие писать код правил на Python). В финал вышли три претендента: PLY, SPARK и DParser.
PLY – полный аналог пары Lex и Yacc. PLY устраивал почти всем, кроме того факта, что он базируется на алгоритме LALR. Грамматика языка C не однозначна с точки зрения LALR и поэтому без специальных ухищрений парсить C код с помощью Yacc не получается.
C С++ в этом плане вообще беда. Его грамматика ещё более неоднозначна и с LR/LALR алгоритмами совсем не уживается.
В отличие от PLY, SPARK использует алгоритм Earley и может справиться с неоднозначной грамматикой без особых проблем. Подвох, однако, заключается в том, что сложность этого алгоритма – O(n3). Отзывы о SPARK это только подтверждали – медленный.
Несмотря на это я решил попробовать. Проведённый эксперимент показал, что SPARK вовсе даже и не медленный. Он ОЧЕНЬ И ОЧЕНЬ медленный. И к тому же охочий до памяти.

При попытке разобрать заголовок размером 2.5MB SPARK почти сразу израсходовал свободные 1.5GB памяти. Через несколько секунд, поняв, что так просто от назойливого приложения не отделаться, система сбросила в swap всё что могла. Освободившиеся два гигабайта были сожраны без промедления, после чего система впала в депрессию. Положение спасла ошибка в грамматике. Парсер поперхнулся на незнакомом слове «extern» и вывалился.
Интересно также, что на стареньком Althon XP график использования памяти рисовал симпатичную логарифмическую кривую.
DParser тоже использует O(n3) алгоритм - GLR (Generalized LR), что не предвещало ничего хорошего. Впрочем GLR может быть значительно быстрее Earley в случае «почти детерминированной грамматики», включая грамматику C. К сожалению DParser не совсем тривиально подключается к Python под Windows. Так что и DParser пришлось исключить.
Осталась проблема как совместить неоднозначную грамматику C и PLY. Корень проблемы заключается в ключевом слове «typedef», вернее способности C объявлять новые типы с его помощью. Конструкции вроде:
typedef int foo;
foo;
foo x;
volatile foo;
int foo;
могут означать совсем разные вещи в зависимости от того, встретилась ли перед ними строчка «typedef bar foo;» или нет. Традиционно, эта проблема решается глобальным списком типов, пополняемого парсером. В процессе разбора лексер обращается к этому списку для разрешения неоднозначности: «является ли этот идентификатор именем типа или нет». Крайне полезная ссылка по этой теме (особенно последний пост): http://groups.google.com/group/comp.compilers/browse_thread/thread/82a790cb7997aa70/c0797b5b668605b4.
Парсер C кода….
Поиск парсера для C кода – по-прежнему увлекательное занятие. Для Win32.Utf8 мне…
Можно попробовать GOLD Parser Builder. Там есть готовые грамматики для С. Поддерживает несколько языков. Алгоритм LALR. GNU Bison к стати также поддерживает кроме LALR(1) еще и GLR.
Коллега, возьмите Coco/R или ANTLR. Для последнего существует очень много грамматик, но первый легче в изучении и так же поставляется с некоторым множетсвом грамматик популярных языков. Есть среди них и классический С. Я когда-то использовал Coco/R для анализа java-кода и у меня остались хороши впечатления о нем.
И еще, это субъективно, без чиcленных замеров, но как мне показалось Coco/R делает парсер, который ощутимо резвее чем его аналог, сделанный ANTLR, т.к. Coco/R создает recursive descent parser.
А чем он лучше того же Yacc или Bison? И как, кстати, там добавлять код к правилам? Из документации нифига не понятно.
На него Google дает всего 60 тысяч ссылок, а его сайт вообще не отзывается. Стрёмно такое использовать вообще.
ANTLR был в списке кандидатов. По большому счету у меня руки не дошли его попробовать. PLY ещё хорош тем, что его можно прямо в дерево исходников положить. С ANTLR такой номер сложнее провернуть (если не тащить за собой кучу Java кода).
Все не так страшно.
Coco/R есть в наличии в Интернете и более того, г-н Терри написал свою вторую книгу “Compiling with C# and Java” именно для Coco/R. Впрочем первая его книга так же была связана с Coco/R. Воспользуйтесь вот этой ссылкой http://www.scifac.ru.ac.za/coco/, чтобы было не так “стремно” ;). Хотя конечно … на вкус и цвет … . Что же касается ANTLR, то насколько я понял сейчас есть вариант работающий в .net и mono без привязки к JVM. Посмотрите ANTLR Tool Binaries по ссылке Download на http://www.antlr.org. А если интерес к ANTLR не угаснет, то я готов выслать Вам руководство “The Definitive ANTLR Reference”.
С Уважением,
ALOHA
А не могли бы вы кинуть pdf ку на borboss@gmail.com?
Я просто сейчас пишу диплом и много использую в нем antlr. А адекватной документаци мало =(
Здравствуйте ALOHA,
Я бы очень хотела попросить вас послать мне если можете книгу “The Definitive ANTLR Reference”. Сейчас как раз работаю с этим, пытаюсь создать парсер на Java и эта книжка мне просто необходима как вода
Перед эитим все имплементовала в JFlex b BYACCj, но из-за вопросов с лицензированием, все, что я делала сказали переделать с использованием ANTLR…Вот так вот утром чловека удивят тем что надо все переделывать
Пожалуйста, помогите мне с книжкой.
Анастасия.
http://www.amazon.com/Definitive-ANTLR-Reference-Domain-Specific-Programmers/dp/0978739256
А чем он лучше того же Yacc или Bison? И как, кстати, там добавлять код к правилам? Из документации нифига не понятно.
Ничем не лучше. Код к правилам добавляется потом когда вы engine для грамматики используете. С точки зрения алгоритма (LALR) он не лучше yacc. С точки зрения что он грамматику компилирует а потом движок эту граматику в рантайме загружает для разбора - он получше. Хотя критерии могут быть разными.
Подскажите, где найти граматику Delphi для Coco/R?