Boost.Spirit: настройка под грамматики во время синтаксического анализа

Чтобы справиться с большим временем компиляции и повторным использованием грамматик, я разбил свою грамматику на несколько суб-грамматик, которые вызываются последовательно. Одна из них (назовем ее: грамматика SETUP) предлагает некоторую конфигурацию анализатора (через синтаксический анализатор символов), поэтому более поздние подграмматики логически зависят от этой грамматики (опять же через другие синтаксические анализаторы символов). Таким образом, после синтаксического анализа SETUP необходимо изменить синтаксические анализаторы следующих подграмматик.

Мой вопрос: как подойти к этому эффективно, сохранив при этом слабую связь между подграмматиками?

В настоящее время я вижу только две возможности:

  • Обработчик on_success грамматики SETUP, который мог бы выполнять эту работу, но это внесло бы некоторую связь.
  • После НАСТРОЙКИ проанализируйте все в строку, создайте новый синтаксический анализатор (из измененных символов) и проанализируйте эту строку на втором этапе. Это оставило бы некоторые накладные расходы.

Я бы хотел иметь обработчик on_before_parse, который может быть реализован любой грамматикой, которая должна выполнять некоторую работу перед каждым синтаксическим анализом. С моей точки зрения, это привело бы к меньшему связыванию, и некоторая настройка парсера могла бы пригодиться и в других ситуациях. Возможно ли что-то подобное?

Обновление:

Извините за отрывочность, это не было моим намерением.

Задача состоит в том, чтобы проанализировать вход I с некоторыми ключевыми словами, такими как #task1 и #task2. Но будут случаи, когда эти ключевые слова должны быть разными, например $$task1 и $$task2.

Итак, проанализированный файл будет начинаться с

setup {
  #task1=$$task1
  #task2=$$task2
}

realwork {
  ...
}

Некоторые наброски кода: Дан основной парсер, состоящий из нескольких (как минимум двух) парсеров.

template<typename Iterator>
struct MainParser: qi::grammar<Iterator, Skipper<Iterator>> {

  MainParser() : MainParser::base_type(start) {
    start = setup >> realwork;
  }

  Setup<Iterator>    setup;
  RealWork<Iterator> realwork;

  qi::rule<Iterator, Skipper<Iterator> > start;
}

Setup и RealWork сами являются парсерами (мои вспомогательные парсеры сверху). Во время настройки некоторые ключевые слова грамматики могут быть изменены, поэтому в части настройки есть правило qi::symbols<char, keywords>. Вначале эти символы будут содержать #task1 и #task2. После анализа первой части файла они содержат $$task1 и $$task2.

Поскольку ключевые слова изменились и RealWork нужно проанализировать I, ему необходимо знать о новых ключевых словах. Поэтому мне нужно перенести символы с Setup на RealWork во время обработки файла.

Я вижу два подхода:

  • Сообщите Setup о RealWork и перенесите символы из Setup в RealWork в qi::on_success обработчике Setup. (плохо, сцепление)
  • Переключитесь на два шага анализа. start из MainParser будет выглядеть как

    start = setup >> unparsed_rest
    

    и будет второй парсер после MainParser. Схематично:

    SymbolTable Table;
    string Unparsed_Rest;
    MainParser.parse(Input, (Unparsed_Rest, Table));
    
    RealWordParser.setupFromAlteredSymbolTable(Table);
    RealWorkParser.parse(Unparsed_Rest);
    

    Накладные расходы на несколько шагов синтаксического анализа.

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

Надеюсь, что такой обработчик qi::on_before_parse, как qi::on_success. По идее, этот обработчик будет запускаться каждый раз, когда синтаксический анализатор начинает синтаксический анализ ввода. Теоретически просто перехват в начале разбора, как у нас есть перехваты on_success и on_error.


person Mike M    schedule 22.07.2013    source источник
comment
Я сделал все, что мог, с некоторыми общими комментариями. Надеюсь, эти вещи помогут вам на правильном пути. Если нет, я предлагаю вам вернуться с конкретным вопросом. Мне больше нравится код, чем «идеи», потому что идеи часто значат для вас нечто иное, чем для меня.   -  person sehe    schedule 22.07.2013
comment
@sehe: Большое спасибо за ваши усилия. Я попытался уточнить, как разбивается грамматика и как должен работать синтаксический анализ.   -  person Mike M    schedule 23.07.2013


Ответы (1)


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

Разделение проблем

Похоже, вам нужно отделить построение AST от шагов преобразования / обработки.

Состав парсера

Конечно, вы можете составлять грамматики. Просто составляйте грамматики, как если бы вы управляли правилами, и скрывайте реализацию этих грамматик любым традиционным способом (pImpl идиома, постоянные статические внутренние правила, все, что соответствует требованиям).

Однако композиция обычно не требует элемента, управляемого «событием»: если вы чувствуете необходимость разбора в два этапа, мне кажется, вы просто изо всех сил пытаетесь сохранить обзор, но рекурсивный грамматики descent или PEG, естественно, хорошо подходят для описания подобных грамматик одним махом (или одним проходом, если хотите).

Однако, если вы обнаружите, что

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

Вы могли бы рассмотреть

  1. Уловка Набиалека (я несколько раз показывал / упоминал об этом в моем [tag: boost-spirit] ответы на этом сайте
  2. Вы можете создавать правила динамически (это не рекомендуется, потому что вы столкнетесь с смертельными ловушками, связанными с копированием деревьев выражений Proto, что приведет к висячим ссылкам). Я также показал некоторые ответы, которые иногда делают это:

    ПОВТОР: не пытайтесь это сделать, если вы не знаете, как обнаружить UB и исправить ситуацию с помощью Proto.

Надеюсь, эти вещи помогут вам на правильном пути. Если нет, я предлагаю вам вернуться с конкретным вопросом. Мне больше нравится код, чем «идеи», потому что идеи часто значат для вас нечто иное, чем для меня.

person sehe    schedule 22.07.2013