Реализация "*?" (ленивый »*") рисунок регеекс в комбинаториальных анализах GLR

StackOverflow https://stackoverflow.com/questions/4365881

  •  09-10-2019
  •  | 
  •  

Вопрос

Я реализовал комбинаторные сингические анализаторы. Среди них есть:

  • char(·) Парсер, который потребляет указанный символ или диапазон символов.
  • many(·) Комбинатор, который повторяет указанный парсер от нуля до бесконечных времен.

Пример: "char('a').many()" будет соответствовать строке с любое количество "a"-С.

Но many(·) Комбинатор жадный, так, например, char('{') >> char('{') >> char('a'..'z').many() >> char('}') >> char('}') (куда ">>" последовательное цепочка парсеров) успешно потребляет все "{{foo}}some{{bar}}" нить.

Я хочу реализовать ленивую версию many(·) который, используемый в предыдущем примере, потреблять "{{foo}}" Только. Как я могу это сделать?

Редактировать:

Может быть, я запутался Ya все. В моей программе Parser - это функция (или «функтор» с точки зрения C ++), который принимает «шаг» и возвращает лес «шаги». «Step» может иметь в виду окно (это означает, что анализатор успешно потреблял часть ввода) и проваливается тип (что означает, что парсер столкнулся с ошибкой). Есть больше типов шагов, но они вспомогательные.

Parser = f(Step) -> Collection of TreeNodes of Steps.

Поэтому, когда я анализую вход, я:

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

  • Образуют начальный шаг от ввода.

  • Дайте начальный шаг к функции комплексной парсеры.

  • Фильтр Treenodes со ступеньками, оставляя только в порядке (или с минимальными сжатиями, если были ошибки в входе).

  • Соберите информацию с шагов, которые были оставлены.

Это было полезно?

Решение

Рассмотреть регулярное выражение <.*?> и ввод <a>bc<d>ef. Отказ Это должно найти <a>, и никаких других совпадений, верно?

Теперь рассмотрим регулярное выражение <.*?>e с тем же входом. Это должно найти <a>bc<d>e, правильно?

Это представляет дилемму. Для ради пользователя, мы хотим поведение комбинатора >> быть понятым с точки зрения двух двух операндов. Тем не менее, нет способа произвести поведение второго парсера с точки зрения того, что находит первым.

Один ответ предназначен для каждого парсера для создания последовательность Из всех анализа, упорядоченных путем предпочтения, а не неупорядоченным набором всех парсеров. Жадные сопоставления вернутся в сортировку дольше всего до самого короткого; не жадный, самый короткий дольше всего.

Другие советы

Я реализовал и использовал Parsers GLR в течение 15 лет в качестве языковых передних концов для системы преобразования программы.

Я не знаю, что такое «комбинаторный парсер GLR», и я незнаком со своей нотакой, поэтому я не совсем уверен, как это интерпретировать. Я предполагаю, что это какой-то каррическая обработка функции? Я представляю, что ваши правила комбинатора эквивалентны определению граммера с точки зрения символов терминала, где «char ('a'). Многие" соответствуют правилам грамматики:

 char = "a" ;
 char = char "a" ;

Фарсеры GLR, действительно, создают все возможные анализаторы. Ключевым пониманием Parsing GLR является его PSuedo-параллельная обработка всех возможных анализа. Если ваши «комбинаторы» могут предложить несколько анализа (то есть они создают грамматические правила, которые эквивалентны вышеупомянутому), а вы действительно имеете их соединение с анализатором GLR, они все будут пробовать, и только те последовательности продуктов, которые плитка Текст будет выживет (то есть вся действительная промежутка, например, неоднозначные анализы) выживут.

Если у вас действительно реализовано анализатор GLR, эта коллекция всех возможных часовых анализов была бы крайне ясна для вас. Тот факт, что это не намекает на то, что вы реализовали, не является парсером GLR.

Возможен восстановление ошибок с анализатором GLR, так же, как и в любой другой технологии анализа. Что мы делаем, это сохранить набор живых разборов до точки ошибки; Когда ошибка обнаружена, мы пытаемся (в PSuedo-Parallel, оборудование Parsing GLR делает это легко, если оно она правильно согнута) все следующее: а) Удаление оскорбления токена, б) вставки всех токенов, которые по существу следуют (х) где X живой анализ. По сути, удалите токен или вставьте один ожидаемый в живом анализе. Затем мы снова включаем парсер GLR. Выживут только действительные анализа (например, ремонт). Если текущий токен не может быть обработан, анализатор перерабатывает поток с токеном удаленным, выживает. В худшем случае восстановление ошибки анализатора GLR заканчивается, бросая все жетоны в EOF. Серьезным недостатком этого является время бегового анализатора GLR, радикально растет, пока разрабатывает ошибки; Если в одном месте много, время восстановления ошибки может пройти через крышу.

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

(Этот ответ основан на моей тускренной памяти и смущенном возможном недоразумении расставания GLR. Надеюсь, кто-то эксперт придет.)

Не жадные функциональные возможности - это не что иное, как механизм определения определения неоднозначности. Если у вас действительно есть генерализованный парсер (который не требует необитания для производства своих результатов), то «не жадность» не имеет смысла; Те же результаты будут возвращены, является ли оператор «не жадным».

Нередное поведение неоднократного определения может быть применено к полному набору результатов, предусмотренных обобщенным анализатором. Работа влево-справа, фильтруйте неоднозначные подгруппы, соответствующие не жадным оператору, чтобы использовать кратчайшее совпадение, которое все еще привело к успешному анализу оставшегося ввода.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top