Установите правило на основе значения глобальной переменной

В моем лексере и парсере от ocamllex и ocamlyacc у меня есть .mly следующим образом:

%{
  open Params
  open Syntax
%}

main:
| expr EOF { $1 }

expr:
| INTEGER { EE_integer $1 }
| LBRACKET expr_separators RBRACKET { EE_brackets (List.rev $2) }

expr_separators:
  /* empty */  { [] }
| expr         { [$1] }
| expr_separators ...... expr_separators { $3 :: $1 }

В params.ml определена переменная separator. Его значение равно ; или , и устанавливается вышестоящей системой.

В .mly я хочу, чтобы правило expr_separators определялось на основе значения Params.separator. Например, когда params.separtoris ;, только [1;2;3] рассматривается как expr, а [1,2,3] - нет. Когда params.separtoris ,, только [1,2,3] считается expr, а [1;2;3] - нет.

Кто-нибудь знает, как изменить лексический анализатор и парсер, чтобы это понять?

PS:

Значение Params.separator устанавливается перед синтаксическим анализом, во время синтаксического анализа оно не изменится.

В настоящий момент в лексере , возвращает токен COMMA, а ; возвращает SEMICOLON. В парсере есть и другие правила, в которых задействованы COMMA или SEMICOLON.

Я просто хочу установить правило expr_separators таким образом, чтобы оно учитывало ; и игнорировало , (которое может быть проанализировано другими правилами), когда Params.separator равно ;; и он считает , и игнорирует ; (который может быть проанализирован другими правилами), когда Params.separator равно ,.


person SoftTimur    schedule 22.08.2020    source источник
comment
IMHO парсеры, управляемые таблицами, не подходят для такого рода вещей. В их таблицах закодирована фиксированная грамматика. Таблицы основаны на статическом анализе продукции и составляющих их токенов и не будут работать, если токены изменяют идентичность динамически. Вы можете обработать это в своем лексере, если запятая и точка с запятой не отображаются где-либо еще в грамматике. Вы могли бы рассмотреть возможность использования запятой и точки с запятой все время, но после синтаксического анализа проверять, что был использован правильный разделитель.   -  person Jeffrey Scofield    schedule 22.08.2020
comment
Что вы собираетесь делать, если используется неправильный разделитель? Вызвать синтаксическую ошибку? Разобрать его каким-нибудь другим идиосинкразическим способом (например, распознать не-разделитель как идентификатор)? Или так же как сбой разбора? Если ответ не похож на вариант 2, попытка ограничения синтаксического анализа действительно бесполезна, если вы можете легко выполнить проверку в действии сокращения.   -  person rici    schedule 22.08.2020
comment
Спасибо ... Пожалуйста, посмотрите мой новый комментарий в OP.   -  person SoftTimur    schedule 22.08.2020


Ответы (1)


В некотором смысле этот запрос по существу аналогичен запросу макроса-препроцессора на изменение его подстановки во время выполнения или компилятору для изменения типа переменной. Как и в случае с самой программой, после того, как грамматика скомпилирована (будь то исполняемый код или таблица синтаксического анализа), невозможно вернуться и изменить ее. По крайней мере, так обстоит дело с большинством генераторов парсеров LR (k), которые производят детерминированные парсеры.

Более того, кажется маловероятным, что единственное отличие параметра конфигурации - это выбор одного токена-разделителя. Если невыбранный токен разделителя может быть проанализирован другими правилами, то он может быть проанализирован этими другими правилами, если он является выбранным токеном разделителя, если только настройка конфигурации также не приводит к подавлению этих других правил. Итак, как минимум кажется, что вы будете смотреть на что-то вроде:

expr : general_expr
expr_list : expr
%if separator is comma
expr : expr_using_semicolon
expr_list : expr_list ',' expr
%else
expr : expr_using_comma
expr_list : expr_list ';' expr
%endif

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

Генераторы синтаксических анализаторов, которые создают общие синтаксические анализаторы, легче справляются с динамическими модификациями во время выполнения; у многих таких генераторов синтаксического анализатора есть механизмы, которые могут это делать (хотя они не обязательно являются эффективными механизмами). Например, инструмент Bison может создавать парсеры GLR, и в этом случае вы можете выбрать или отменить выбор определенных правил с помощью действия предиката. Генератор OCAML GLR Dypgen позволяет динамически добавлять наборы правил в грамматику во время синтаксического анализа. (Я никогда не использовал dypgen, но все еще хочу попробовать; это выглядит интересно.) И есть много других.

Поигравшись с функциями динамического синтаксического анализа в некоторых парсерах GLR, я могу только сказать, что мой личный опыт был немного неоднозначным. Изменение грамматик во время выполнения - хрупкая техника; грамматики, как правило, не очень легко разделить на независимые части, поэтому изменение правила грамматики может иметь неожиданные последствия в тех местах, на которые вы не рассчитываете. Вы не всегда точно знаете, какой язык принимает ваш синтаксический анализ, потому что динамические модификации трудно предсказать. И так далее. Я предлагаю, если вы попробуете эту технику, начать с простейших возможных модификаций и приложить гораздо больше усилий к грамматическим тестам (что, в любом случае, всегда является хорошей идеей).

person rici    schedule 22.08.2020
comment
Когда вы говорите две грамматики, вы имеете в виду два .mly файла? - person SoftTimur; 22.08.2020
comment
@SoftTimur: да, хотя, как я уже сказал, они оба могут быть сгенерированы из одной исходной грамматики. - person rici; 22.08.2020