Not a kernel guy

… in the Windows kernel team

Thursday, August 16, 2007

Парсер C кода.

Поиск парсера для C кода – по-прежнему увлекательное занятие. Для Win32.Utf8 мне нужен был парсер для анализа заголовочных файлов Win32 API и извлечения из них прототипов функций и объявлений структур. Требований к нему было не очень много:

  1. Разбор заголовка размером 2-3MB (размер windows.h после препроцессора) должен занимать разумное время – 20-30 секунд на типичной машине. В моем случае в качестве эталона выступает Athlon XP 1.5GHz;
  2. Требовалось умение работать с нестандартными расширениями C - __declspec и прочим;
  3. Парсер должен извлекать SAL описания параметров функций и членов структур;
  4. Результат разбора должен быть удобен для последующего анализа;

Очевидный вариант – адаптировать парсер из 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 вовсе даже и не медленный. Он ОЧЕНЬ И ОЧЕНЬ медленный. И к тому же охочий до памяти.

Memory usage by SPARK-based parser of C code.

При попытке разобрать заголовок размером 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.

Posted at 2:36 pm •

RSS feed | Trackback URI

10 Comments »

Trackback by Зеркало: Not a kernel guy — August 16, 2007 @ 2:44 pm

Парсер C кода….

Поиск парсера для C кода – по-прежнему увлекательное занятие. Для Win32.Utf8 мне…

 
Comment by Yuriy Volkov — August 16, 2007 @ 11:54 pm

Можно попробовать GOLD Parser Builder. Там есть готовые грамматики для С. Поддерживает несколько языков. Алгоритм LALR. GNU Bison к стати также поддерживает кроме LALR(1) еще и GLR.

 
Comment by ALOHA — August 17, 2007 @ 1:30 am

Коллега, возьмите Coco/R или ANTLR. Для последнего существует очень много грамматик, но первый легче в изучении и так же поставляется с некоторым множетсвом грамматик популярных языков. Есть среди них и классический С. Я когда-то использовал Coco/R для анализа java-кода и у меня остались хороши впечатления о нем.
И еще, это субъективно, без чиcленных замеров, но как мне показалось Coco/R делает парсер, который ощутимо резвее чем его аналог, сделанный ANTLR, т.к. Coco/R создает recursive descent parser.

 
Comment by Not a kernel guy — August 17, 2007 @ 8:40 am

 

GOLD Parser Builder

А чем он лучше того же Yacc или Bison? И как, кстати, там добавлять код к правилам? Из документации нифига не понятно.

Coco/R

На него Google дает всего 60 тысяч ссылок, а его сайт вообще не отзывается. Стрёмно такое использовать вообще.

ANTLR

ANTLR был в списке кандидатов. По большому счету у меня руки не дошли его попробовать. PLY ещё хорош тем, что его можно прямо в дерево исходников положить. С ANTLR такой номер сложнее провернуть (если не тащить за собой кучу Java кода).

 
Comment by ALOHA — August 17, 2007 @ 12:53 pm

Все не так страшно. ;) 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

Comment by Laoboss — February 29, 2008 @ 4:46 am

А не могли бы вы кинуть pdf ку на borboss@gmail.com?

Я просто сейчас пишу диплом и много использую в нем antlr. А адекватной документаци мало =(

 
Comment by Anastasiya — May 22, 2008 @ 12:33 am

Здравствуйте ALOHA,
Я бы очень хотела попросить вас послать мне если можете книгу “The Definitive ANTLR Reference”. Сейчас как раз работаю с этим, пытаюсь создать парсер на Java и эта книжка мне просто необходима как вода :)

Перед эитим все имплементовала в JFlex b BYACCj, но из-за вопросов с лицензированием, все, что я делала сказали переделать с использованием ANTLR…Вот так вот утром чловека удивят тем что надо все переделывать :(

Пожалуйста, помогите мне с книжкой.

Анастасия.

Comment by Not a kernel guy — May 23, 2008 @ 7:28 am
 
 
 
Comment by Yuriy Volkov — August 20, 2007 @ 7:45 am

А чем он лучше того же Yacc или Bison? И как, кстати, там добавлять код к правилам? Из документации нифига не понятно.

Ничем не лучше. Код к правилам добавляется потом когда вы engine для грамматики используете. С точки зрения алгоритма (LALR) он не лучше yacc. С точки зрения что он грамматику компилирует а потом движок эту граматику в рантайме загружает для разбора - он получше. Хотя критерии могут быть разными.

 
Comment by M1 — May 12, 2008 @ 4:05 pm

Подскажите, где найти граматику Delphi для Coco/R?

 

Your Comment (smaller | larger)

You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Powered by WordPress