LINUX.ORG.RU

Альтернатива flex


0

1

Решил наконец изучить flex & bison. Изучил, понравилось. Начал прикручивать парсер к C++ проекту, полез глубже копаться (начал пока с голого лексера), и охренел.

Во-первых, код ни разу не exception-safe. Как вам это (сгенерённый код):

YY_BUFFER_STATE yyFlexLexer::yy_create_buffer( std::istream* file, int size )
{
        YY_BUFFER_STATE b;
    
        b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state )  );
        if ( ! b )
                YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );

        b->yy_buf_size = size;

        /* yy_ch_buf has to be 2 characters longer than the size given because
         * we need to put in 2 end-of-buffer characters.
         */
        b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2  );
        if ( ! b->yy_ch_buf )
                YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );

        b->yy_is_our_buffer = 1;

        yy_init_buffer( b, file );

        return b;
}

Если лень читать - при фейле alloc вызывается YY_FATAL_ERROR. Что прикажете мне в ней делать? Если просто вывести ошибку и сделать вид что ничего не случилос (ну или установить флаг и выкинуть результаты кривого парсинга), то после фейла первого аллока при обращении к b->yy_ch_buf будет SEGV. А если кинуть исключение, при фейле второго alloc'а память, выделенная в первом весело утекает. Получается, что делать остаётся только abort, весело.

Во-вторых, C++'ный лексер наследуется от помоечного класса yyFlexParser, набитого кучей ненужной гадости типа работы с потоками, которые мне нахрен не сделись, вместо того чтобы наследоваться от виртуального интерфейса и дать мне возможность самому определить как работать с вводом/выводом, как выделять память и как обрабатывать ошибки. На самом деле, я пришёл к выводу что из C++ удобнее будет использовать сишный reentrant лексер, а не плюсовый, но невозможность обработки ошибок остаётся, и мусор там свой есть.

В bison глубоко не копал, но сдаётся мне там будут свои проблемы с памятью и исключениями.

В общем, хочется инструмента из этого века - удобного, гибкого и безопасного. В идеале - сочетающего лексер, парсер и кнопку «сделать заебись», но хотя бы по минимуму - нормальный лексер, который не генерит говнокод, позволяет управлять буферами как я хочу и не суёт в нос работу с FILE* или ++'ными потоками. В качестве лексера на ум приходит только ragel, но может есть лучшее и/или комплексное решение?

★★★★★

>нормальный лексер, который не генерит говнокод, позволяет управлять буферами как я хочу и не суёт в нос работу с FILE* или ++'ными потоками.

Элементарно, Ватсон. 90000 белых руб. в месяц + соц. пакет + отпуск + соблюдение ТК и у тебя будет отличный биологический лексер с безопасными исключениями, без говнокода, с кучей настроек под конкретную задачу.

anonymous
()

В идеале - сочетающего лексер, парсер

см. lemon parser - парсер от sqlite (http://www.hwaci.com/sw/lemon/). Сам пришёл к выводу использовать его вместо связки bison+flex, за потоко-безопасность и с надеждой на работу с unicode, хотя-бы с utf8

есть ещё antlr (http://www.antlr.org/) но он монструозен в своей универсальности. И вследствии ориентации на яву, плюсы к нему прибиваются аршинными гвоздями. То есть только если у вас в проекте есть большая грамматика, то оправдан ANTLR - у него есть ГУЙ для отладки.

за boost::spirit ничего не скажу, и со его счастливыми пользователями не знаком. Но ведь, если звёзды зажигают, значит это ком-нибудь нужно..

MKuznetsov ★★★★★
()
Ответ на: комментарий от MKuznetsov

> см. lemon parser - парсер от sqlite (http://www.hwaci.com/sw/lemon/). Сам пришёл к выводу использовать его вместо связки bison+flex, за потоко-безопасность и с надеждой на работу с unicode, хотя-бы с utf8

Тот факт что он одним файлом меня радует, но там же нет лексера.

slovazap ★★★★★
() автор топика

ANTLR, но он LL, а не LR.

Deleted
()

> Если лень читать - при фейле alloc вызывается YY_FATAL_ERROR. Что прикажете мне в ней делать?

как уже задолбали идиоты которые орут по каждому чиху в котором не разбирались
сходи что ли мануал по flex/lexx дочитай а?
там все настраивается
тот же fatal под свой обработчик

anonymous
()

Флексы, бизоны... Ну прям 60-е на дворе.

Бедняша, иди просветлись комбинаторными парсерами (Parsec) и Parsing expression grammars (Frisby).

anonymous
()
Ответ на: комментарий от anonymous

Ну прям 60-е на дворе.

Будто что-то кардинально новое появилось в парсинге с того времени.

buddhist ★★★★★
()
Ответ на: комментарий от anonymous

> там все настраивается

тот же fatal под свой обработчик

Научись читать тред для начала, умник.

Бедняша, иди просветлись комбинаторными парсерами (Parsec) и Parsing expression grammars (Frisby).

Haskell мне нужен ещё меньше, чем Java.

slovazap ★★★★★
() автор топика
Ответ на: комментарий от slovazap

> Научись читать тред для начала, умник.
...

но невозможность обработки ошибок остаётся, и мусор там свой есть.


я перечитал и мое мнение не изменилось
иди дальше учи flex/lexx, все там нормально ловится и настраивается
и мусора нет, если руки не из одного места


anonymous
()
Ответ на: комментарий от anonymous

> я перечитал и мое мнение не изменилось

Ну раз не изменилось, попробуй тогда ответить на конкретные вопросы, умник:

Как избежать утечки памяти если любой из malloc'ов в yy_create_buffer может вернуть 0. Как сделать C++ парсер, у которого в классе не будет указателей на потоки.

flex/lexx

lexx это такой сериал про стрекозу, к лексическим анализаторам никакого отношения не имеет, равно как и твои ответы к топику.

slovazap ★★★★★
() автор топика
Ответ на: комментарий от slovazap

умник, а ты прочитал уже документацию до того места где YY_FATAL_ERROR может переопределятся на свой? как и многое другое, это раз.

два - никто не заставляет тебя ворочать как ты это ворочаешь через одно место опциями flex в .l файле все устанавливается и переопределяется до уровня когда все перехватывается %option уже все изучил?

утечки памяти это обычно у новичков которые первый раз что то увидели

flex/yacc это фактически один и тот же инструмент но ты похоже не в зуб ногой об этом

или ты как последний баран сидишь и правишь .c файл сгенерированый flex -ом?

оффициальную документацию в гугле как минимум по flexx осилишь найти?

lexx это такой сериал про стрекозу, к лексическим анализаторам никакого отношения не имеет, равно как и твои ответы к топику.

s/lexx/yacc/

anonymous
()
Ответ на: комментарий от anonymous

> умник, а ты прочитал уже документацию до того места где YY_FATAL_ERROR может переопределятся на свой?

А ты прочитал первое соощение где я это написал? Начни с этого.

И ответь на два заданных вопроса, понос твой бесполезен абсолютно.

slovazap ★★★★★
() автор топика
Ответ на: комментарий от sergej

> flex++/bison++ не подойдут?

Это и есть flex/bison.

slovazap ★★★★★
() автор топика

Я думаю, если *alloc() вернёт NULL, утечки памяти - это последнее, что должно волновать ТСа.

kemm
()

В общем я написал парсер руками за несколько часов - получилось гораздо менее геморройно чем ковыряться в тухлятине (flex/bison) и монстрятине (spirit/antlr).

В моём случае синтаксис довольно простой, а для сложного я бы взял ragel + lemon - серьёзные, фичастные и проверенные инструменты.

Ещё нашлась интересная штука http://piumarta.com/software/peg/ - парсер и лексер в одном флаконе, исходников всего 3 файла, MIT, так что легко встраивается в проект для несложных вещей.

Имеет, правда, всё ту же проблему с выделением памяти без проверки на ошибки и умеет только не-reentrant парсеры, но учитывая что она встраивается, можно поправить шаблон генерящихся файлов (он в compile.c) целиком под себя - думаю, не очень сложно будет сделать как минимум reentrant парсер с проверкой ошибок выделения, а может быть и плюсовый класс.

slovazap ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.