Помещение узлов в дерево синтаксического анализа, которых там быть не должно

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

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

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

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

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

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

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

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

Были ли у вас подобные проблемы? Как вы ее решили?

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


Приложение

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


person Flavius    schedule 07.08.2011    source источник


Ответы (1)


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

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

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

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

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

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

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

EDIT2: если OP настаивает на захвате пробелов, он может рассмотреть возможность изучения анализа GLR без сканера. Это сохраняет каждый символ во входном потоке, включая пробелы.

person Ira Baxter    schedule 07.08.2011
comment
Я знаю, чего хочу, и мне нужны пробелы в дереве. Действительно. Просто то, что я хочу, не обычное, чего хотят люди. И у меня есть веские причины иметь эти жетоны в дереве. Действительно веские причины. Без этих причин я бы не стал этого делать. Но спасибо, что предупредил меня об этом. - person Flavius; 08.08.2011
comment
Да, ясно, что ты знаешь, чего хочешь. Если вы скажете, что у вас есть действительно веские причины, не объясняя их, или, в частности, расскажете нам о конечном эффекте, которого вы надеетесь достичь, вы получите обычный ответ: .... ... Если вы хотите пойти нетрадиционным путем, вы можете обобщите то, что мы сделали с DMS: присоедините свои микро-токены (как пробелы, так и комментарии) в виде последовательности к языковым токенам. - person Ira Baxter; 08.08.2011
comment
Да, это то, что я сделал, как я уже упоминал в вопросе, используя связанные списки, хотя в итоге я использовал двусвязный список. Однако потребление памяти все еще беспокоит меня, два дополнительных члена указателя для токенов - это довольно много, не так ли? Я не знаю, думаю, я закончу этот прототип и посмотрю, что из этого получится. - person Flavius; 08.08.2011
comment
Это может быть много, а может и нет; это зависит от статистических свойств языка, который вы обрабатываете. Если вы собираетесь работать с одной программой из 10 000 строк, а ваш синтаксический анализатор работает на ПК, никто, включая вас, не будет заботиться о его потреблении места. Если вы собираетесь обрабатывать 18 000 единиц компиляции (иногда мы делаем это с DMS), то пространство действительно ценно, и я бы очень усердно работал, чтобы не оставлять пробелы, потому что ИМХО они не вносят ничего такого, что вы не можете получить с другими методами Я предложил. - person Ira Baxter; 08.08.2011