Помещение узлов в дерево разбора, которого там быть не должно - PullRequest
7 голосов
/ 07 августа 2011

Я пишу синтаксический анализатор для языка, и сканер рассчитан на

  1. или также возвращает ненужные терминалы (например, пробелы) ИЛИ
  2. не делать этого

на основе логического флага.

Теперь, в парсере, я не хочу загромождать грамматику всеми этими терминалами, они должны каким-то образом "автоматически" проглатываться деревом разбора.что я создаю.

Чтобы сделать это "волшебство", я подумал, что я бы связал терминалы (просто связанный круговой список), чтобы я мог просто итерировать их и "заполнять пробелы", когда происходит сокращение (Я использую генератор парсера LALR (1).

Звучит как здравая идея, хотя есть одна проблема.Помнишь, я сказал «или вернуться ... или нет»?В сценарии (2) я бы освободил терминал, потому что кто знает, что будет дальше?И я не хочу никаких утечек памяти.

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

Я также не могу освободить его условно по той же причине: я не знаю, что будет дальше.Что если не будет запущен процесс «Заполнение бланков»?Что, если не будет никакого дальнейшего сокращения вообще?

У вас были подобные проблемы?Как вы решили это?

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


Addendum

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

1 Ответ

3 голосов
/ 08 августа 2011

Ваш словарный запас немного странный. Большинство синтаксических анализаторов предназначены для распознавания синтаксиса языка. обычно определение языка определяет некоторое понятие терминалов и явно исключает «пробелы», состоящие из неинтересных последовательностей текста между текстом терминалов, часто включая пробелы, вкладки и различные виды автономных комментариев. Таким образом, слово «терминал», используемое при разборе, обычно означает «те атомы языка, которые не являются пробелами». Вы определили это неявно, чтобы включить пробел, и я думаю, что это вызывает ваше горе.

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

Если вы создаете компилятор или интерпретатор, игнорировать пробелы проще всего.

Если вы создаете парсер реинжиниринга (см. Наш Инструментарий реинжиниринга программного обеспечения DMS ), то сбор комментариев (как минимум) в AST важен, так как в конечном итоге один хочет регенерировать текст из связанных AST, и это полезно, если регенерированный текст также содержит комментарии. [Вы можете сделать это другими способами, но они не так просты.]

Лексер DMS создает «микро» токены, которые являются вашей внутренней концепцией для маркеров языка, пробелов и комментариев. Он отбрасывает пробельные микро-токены, потому что они просто ничего не добавляют (см. Обсуждение выше). Как и следовало ожидать, он передает обычные токены парсеру. Он приклеивает токены комментариев к предыдущему или следующему языковому токену, в зависимости от типа токена и места, где они встречаются; для C a / * ... * /, видимый до того, как к нему прикреплен токен, и комментарий // ... к предыдущему токену (с некоторыми более тонкими деталями, которые здесь не обсуждаются). Затем анализ все еще видит только языковые токены, поэтому грамматика не является излишне сложной, и если вся информация, прикрепленная к токену, помещается в дерево, комментарии отправляются в путь.

Теперь люди часто хотят «абстрактные» синтаксические деревья; они хотят пропустить такие вещи, как "(" и ")". Схема, которую я описал выше, прикрепляла комментарии даже к таким конкретным токенам, как эти. Теперь есть сложность: если вы оставите токены (..) вне дерева, прикрепленные комментарии исчезнут. К сожалению. Таким образом, парсеры DMS делают сложную вещь: комментарии, прикрепленные к токенам, которые имеют логическое место в дереве, но на самом деле их там нет («исключенные терминалы»), переносятся в узел родительского дерева с аннотацией о том, что они принадлежат отсутствующему дочернему токену. Да, реализация этого действительно PITA. Хорошей новостью является то, что нам нужно было сделать это только один раз в общем механизме синтаксического анализа DMS, и это работает для многих, многих языков. Но это означает, что вы должны быть готовы создать необычный («реинжиниринг») парсер, и у нас была коммерческая мотивация для этого.

РЕДАКТИРОВАТЬ: Не ясно, почему ОП хочет этого, но он настаивает на захвате пробелов в дереве. Поскольку он не сказал нам, почему, я собираюсь догадаться: он хочет получить точную информацию о столбцах для узлов токенов / деревьев. Это не сложно сделать: научить лексера отслеживать положение (строка / столбец) и пометить каждый токен (микротокены, например, комментарии) начальной / конечной позицией, и позволить анализу хранить эту информацию в дерево. Этот способ также позволяет избежать пробелов в дереве. (DMS делает это тоже, потому что при сообщении о проблемах точная информация полезна, а при регенерации кода часто желательно возвращать код в исходное положение (по крайней мере, в тот же столбец)).

РЕДАКТИРОВАТЬ2: Если ОП настаивает на захвате пробелов, он мог бы рассмотреть возможность анализа анализа без GLR без сканирования . Это сохраняет каждый символ во входном потоке, включая пробелы.

...