Извлечение информации с использованием грамматик BNF

Я хотел бы извлечь информацию из текста и иметь возможность запрашивать ее.

Структура этого текста будет определяться грамматикой БНФ (или ее вариантом), а извлекаемая информация будет указываться во время выполнения (синтаксис запроса в данный момент не имеет значения).

Итак, требования просты, на самом деле:

  • Получите структурированный текст
  • Загрузите его в пригодной для эксплуатации форме, используя грамматику для его анализа.
  • Запустите запрос, чтобы выбрать некоторые его части

Чтобы проиллюстрировать пример, предположим, что у нас есть такая грамматика (в настроенном формате BNF):

<digit> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
<id> ::= 15 * digit

<hex> ::= 10 * (<digit> | a | b | c | d | e | f)

<anything> ::= <digit> | .... (all characters)

<match> ::= <id> (" " <hex>)*

<nomatch> ::= "." <anything>*

<line> ::= (<match> | <nomatch> | "") [<CR>] <LF>

<text> ::= <line>+

Для чего такой текст будет соответствовать:

012345678901234
012345678901234 abcdef0123

Nor the previous line nor this one would match

И затем я хотел бы перечислить все теги, которые появляются в правиле, например, используя синтаксис, подобный XPath:

match//id

который вернет список.


Это звучит относительно просто, за исключением того, что у меня есть два больших ограничения:

  • грамматика BNF должна быть прочитана во время выполнения (из структуры, подобной строке/вектору)
  • запросы также будут считываться во время выполнения

Некоторые уточнения:

  • ожидается, что грамматика не будет часто меняться, поэтому шаг «компиляции» для создания структуры в памяти приемлем (и, возможно, необходим для достижения хорошей скорости)
  • главное скорость, бонусные баллы за оперативный сбор нужных порций
  • бонусные баллы за возможность иметь обратные вызовы для устранения неоднозначности (иногда, например, для необходимой информации об устранении неоднозначности может потребоваться доступ к БД)
  • бонусные баллы за составные грамматики (в пользу модульности и повторного использования элементов грамматики)

Я знаю, например, lex/yacc и flex/bison, однако они, похоже, создают только код C/C++ для компиляции, а это не то, что мне нужно.

Знаете ли вы о надежной библиотеке (желательно бесплатной и с открытым исходным кодом), которая может преобразовать грамматику BNF в синтаксический анализатор «на лету» и создать структурированный вывод в памяти из основного текста с помощью этого синтаксического анализатора?

EDIT: я открыт для альтернатив. На данный момент идея заключалась в том, что, возможно, регулярные выражения могли бы позволить такое извлечение, однако, учитывая сложность задействованных грамматик, это может быстро стать уродливым, и, таким образом, поддержка регулярных выражений станет довольно ужасной задачей. Кроме того, разделяя грамматики и извлечение, я надеюсь, что смогу повторно использовать одну и ту же грамматику для разных нужд извлечения, а не каждый раз иметь немного разные регулярные выражения.


person Matthieu M.    schedule 12.06.2012    source источник
comment
Если ничего не помогает, напишите генератор парсера в Boost.Spirit. ;-) Метамета с шаблонным метапрограммированием.   -  person Konrad Rudolph    schedule 12.06.2012
comment
Я думаю, что это частичный обман: stackoverflow. ком/вопросы/7392302/. Он охватывает только создание синтаксического анализатора, а не другие детали, относящиеся к этому вопросу. И на него нет ответов вида да, и вот ссылка на него. Так что я не утверждаю, что этот вопрос лишний.   -  person Steve Jessop    schedule 12.06.2012
comment
Похоже, вы пытаетесь построить машину регулярных выражений (поправьте меня, если я ошибаюсь). Попробуйте использовать конечные автоматы, если вы.   -  person dirkgently    schedule 12.06.2012
comment
У меня есть библиотека-компилятор, которая может вас заинтересовать. Она читает грамматику на лету, создает грамматику таблицы и кэширует их, поэтому повторные запуски выполняются быстро. Входной формат не BNF, и вы должны выполнить семантический анализ с помощью подпрограмм действий. Я написал это быстро и грязно на C++, поэтому реализация может выглядеть не слишком красиво. Он принимает неоднозначные грамматики, но вы можете разрешить их только во время создания таблицы, а не при разборе. Через несколько месяцев я закончу переписывать его на C с лучшей и быстрой подструктурой, но его использование не будет сильно отличаться.   -  person Shahbaz    schedule 12.06.2012
comment
@dirkgently Нет, это не обычные грамматики (которые можно описать регулярными выражениями), это контекстно-свободные грамматики. Хотя он мог бы использовать конечный автомат со стеком.   -  person Eric Finn    schedule 12.06.2012
comment
@dirkgently: регулярные выражения есть вариант, но мы пойдем по этому пути только в том случае, если не будет лучшего варианта. Я бы предпочел декоррелировать синтаксический анализ из извлечения, если это возможно, чтобы синтаксический анализ был указан, а менее опытные люди могли указать извлечение; повторное использование.   -  person Matthieu M.    schedule 12.06.2012
comment
@Matthieu: мне кажется, что вы, возможно, могли бы скомпилировать свою грамматику + извлечение в регулярные выражения (где под регулярными выражениями я имею в виду то, что принимают настоящие библиотеки регулярных выражений, они на самом деле более либеральны, чем обычные грамматики, и злоупотребляют терминология). Это все еще может позволить извлечение быть отдельным вводом, на более простом языке и, следовательно, выполнимым менее опытными людьми. Но правила извлечения могут повлиять на то, какие регулярные выражения вы получите. Затем вы, конечно, скомпилируете регулярное выражение. Должны быть подмножества BNF, которые легко интерпретировать как регулярные выражения, я просто не уверен, что именно.   -  person Steve Jessop    schedule 12.06.2012
comment
@MatthieuM.: Обратите внимание, что я использовал термин регулярное выражение вольно. Я делал акцент на государственной машине; мой личный опыт работы с конечными автоматами по сравнению с механизмами регулярных выражений был сильно смещен в сторону конечных автоматов просто из-за превосходной производительности и того факта, что вы можете определять переходы во время выполнения и по-прежнему иметь возможность анализировать практически любой правильно сформированный ввод. Обратите внимание, что это достаточно распространенное явление: почти в каждом проекте наступает время, когда вы застреваете, изобретая DSL (о чудо, я снова ухожу :P).   -  person dirkgently    schedule 12.06.2012
comment
Как вы думаете, было бы лучше встроить интерпретатор Lua/JavaScript и позволить пользователю поиграть с ним (на общепонятном языке)? Это зависит от вашего класса пользователей и их навыков. (Возможно, это будет перебор!)   -  person dirkgently    schedule 12.06.2012
comment
@dirkgently: черт возьми, замените BNF некоторыми правилами, чтобы построить дерево DOM из входных данных. И замените запрос, чтобы выбрать некоторую его часть, на jQuery (или XPath). Все любят jQuery (или XPath)! И вы можете обвинить в любых проблемах с производительностью свой движок javascript (или saxon).   -  person Steve Jessop    schedule 12.06.2012
comment
@dirkgently: нет, встраивание любого интерпретатора или JIT-компилятора не вариант (я думал об этом: p).   -  person Matthieu M.    schedule 12.06.2012
comment
@SteveJessop: я понимаю, что ты имеешь в виду. Я думал о сопоставителе, несущем запрос XPath, чтобы передать его напрямую, а не создавать полноценный AST в памяти. Я немного боюсь, что перевод в регулярные выражения превратится в кошмар обслуживания, даже с хорошим набором тестов: регулярные выражения в основном предназначены только для записи, поэтому декодирование сгенерировано компьютером для целей отладки... это субъективно, но я боюсь чем это может грозить!   -  person Matthieu M.    schedule 12.06.2012
comment
@MatthieuM: это правда, но я пытаюсь думать об этом так, что байт-код LLVM также не читается человеком, и мы не против использовать это в качестве переходного этапа в компиляции. Конечно, если бы я был тем, кто писал часть цепочки инструментов C++ для LLVM, я бы быстро стал намного лучше читать байт-код. Проблема с регулярными выражениями, заметьте, в том, что они не удобочитаемы и для них трудно найти хороший дизассемблер ;-)   -  person Steve Jessop    schedule 12.06.2012


Ответы (2)


У меня есть проприетарное решение, которое может преобразовать источник грамматики в представление в памяти. В результате получается чистая структура данных. Любой код может использовать его. У меня также есть класс C++, который фактически реализует синтаксический анализатор. Обработчики правил реализованы как виртуальные методы.

Основное отличие нашего решения от YACC/Bison заключается в том, что код C/C++ не генерируется. Это означает, что грамматика может быть перезагружена без перекомпиляции приложения. Грамматика может быть дополнена идентификаторами приложений, которые используются в коде обработчиков правил.

person Kirill Kobelev    schedule 13.06.2012
comment
Спасибо за ответ, мне нужно время, чтобы проверить это точно, а тем временем +1 за уже предоставленный многообещающий ответ. - person Matthieu M.; 14.06.2012
comment
Я смотрел на сайте, но не мог найти соответствующий код. Можно ли просмотреть документацию/API этого парсера? А так, мне трудно высказаться по этому поводу... - person Matthieu M.; 15.06.2012
comment
Матье, дай мне свой адрес электронной почты. Я пришлю вам некоторую информацию. Исходный язык похож на YACC, но не совсем такой же. Пример исходной грамматики находится по адресу cdsan.com/GraCpp_Grammar.php. Исходную грамматику можно взять как из файла на диске, так и из буфера памяти. - person Kirill Kobelev; 15.06.2012
comment
Спасибо, я не видел грамматики :) Я отправил электронное письмо через контактную форму веб-сайта. - person Matthieu M.; 15.06.2012
comment
Матье, пожалуйста, будь разумным. Я говорил не о грамматиках вообще, которые вы много раз видели, а о примере в конкретном языке определения грамматики, который имеет разделы (‹терминалы›, ‹правила›, ‹язык› и т.д.), особенности, описывающие конфликты. Я не уверен, что существует какой-либо другой язык определения грамматики, в котором есть концепция ожидаемых грамматических конфликтов. - person Kirill Kobelev; 15.06.2012
comment
Я не понял этот последний комментарий, извините. О каких конфликтах вы говорите? - person Matthieu M.; 15.06.2012
comment
Здесь трудно объяснить концепцию грамматического конфликта. Вы можете найти краткую информацию в en.wikipedia.org/wiki/LL_parser. Простые грамматики, такие как грамматика, необходимая для синтаксического анализа таких выражений, как (5+3)*7, не имеют конфликтов. Они есть в более сложных грамматиках, таких как грамматика C++. Bison хорошо подходит только для грамматик без конфликтов. Мой синтаксический анализатор определений грамматики гораздо более продвинут в этой области. - person Kirill Kobelev; 16.06.2012
comment
А, спасибо за наводку. Я еще не уверен, будут ли конфликты в грамматиках, с которыми я буду работать (первые несколько, которые я видел, не имели конфликтов). - person Matthieu M.; 16.06.2012

Система синтаксического анализатора GOLD создает таблицу синтаксического анализа LALR, которая, по-видимому, загружается AFAIK во время выполнения. Я считаю, что у него есть механизм "анализа" С++, поэтому его легко интегрировать.

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

Я не знаю, как вы привязываете действия к сокращениям, что вы, вероятно, хотели бы сделать. У меня нет особого опыта работы с GOLD. "Золотой" удачи вам.

person Ira Baxter    schedule 13.06.2012
comment
Я хотел бы иметь возможность прикрепить действия проверки к некоторым элементам, если это возможно, но в противном случае это можно было бы решить позже. Пока я могу эффективно извлекать информацию, у меня будет внешний код для обработки информации. - person Matthieu M.; 14.06.2012