Когда использовать абстрактное или конкретное синтаксическое дерево? - PullRequest
5 голосов
/ 26 февраля 2012

Я занимаюсь исследованием компиляторов. Лексер кажется очень прямым: возьмите «предложение» и разбейте его на слова (или жетоны). Для обеспечения правильной грамматики необходим синтаксический анализатор. Парсер обычно берет токены и строит дерево, которое приводит к корневому узлу (слова в предложениях, абзацы, страницы и т. Д.).

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

Но как насчет преобразования кода с одного языка на другой? Взять выдуманный язык (грамматику) или существующую грамматику и преобразовать ее в другой, где правила приоритета операторов могут отличаться или не различаться? Приоритет оператора также встроен в CST?

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

Так что для языкового перевода CST будет лучше? Обычно приоритет оператора встроен в CST? Есть что-нибудь промежуточное? Есть ли примеры, сравнивающие оба дерева с простым уравнением алгебры? Какие-нибудь примеры, иллюстрирующие троичный оператор?

(Является ли «транскодирование» правильным термином для «перевода на язык программирования»? Поиск в Google выводит конвертирующие медиа.)

То, что я пытаюсь выяснить, это: когда более уместно использовать один над другим?

1 Ответ

7 голосов
/ 27 февраля 2012

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

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

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

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

Если проблема с генерацией кода более сложная, обычно происходит следующее:AST используется для генерации того, что составляет модель потока данных вычислений, состоящая из операторов, которые производят результаты и используют результаты предыдущих операторов, основываясь на «операторах», которые выбирают значения и константы переменных.Затем выполняется представление потока данных для генерации кода;Преимущество этого заключается в том, что вы можете выбрать оператор в представлении потока данных, найти соответствующую кодовую последовательность на целевом языке, сгенерировать ее, а затем беспокоиться о том, как собираются операнды.Более совершенные схемы сопоставляют подграфы потока данных (представляющие эквивалентные составные конструкции целевого языка) с созданным графом потока данных;это может дать значительно лучший код.Часто можно применять специфические оптимизации для целевого языка после генерации исходного кода, чтобы получить еще лучший код.В обоих случаях вам нужно беспокоиться об управлении результатами оператора;могут ли они быть переданы непосредственно следующему оператору целевого языка, или они должны войти в какое-то временное хранилище (для машинного кода это может быть другой регистр или ячейка памяти).Делать все это не легко;опять же, именно поэтому книги по компиляторам не такие уж и тонкие.

Разновидностью этой идеи являются преобразования программ из исходного кода в исходный.Это сопоставляет конструкции в исходном коде «напрямую» с конструкциями в целевом коде, хотя это обычно делается за кулисами при работе с AST, поскольку трудно разбирать текст на непарсированном языке программирования.Наш DMS Software Reengineering Toolkit является примером такой системы.С помощью такого инструмента вы пишете шаблоны на исходном языке (которые неявно совпадают с деревом разбора) и соответствующие шаблоны на целевом языке (неявно производя AST на целевом языке).Вы можете написать сложные исходные или целевые конструкции, дающие большую часть эффекта сопоставления графа потока данных выше.Оптимизация после генерации состоит из большего количества правил переписывания, которые преобразуют целевой код в целевой код.

Итог: наличие AST на самом деле недостаточно, если ваш перевод не является действительно тривиальным.Вы можете прочитать больше о том, что вам нужно, в этом SO-ответе: https://stackoverflow.com/a/3460977/120163

ВНИМАНИЕ: следует громкое мнение.

Re "Транскодер": я очень предпочитаю термины "компиляция", "перевод" или "источник к источнику" компилятор.Я создавал инструменты анализа и манипулирования программами почти 40 лет.Я никогда не слышал термин «транскодер», пока не столкнулся с таким вопросом: Опыт миграции устаревшего Cobol / PL1 на Java и ответ, описывающий IMHO действительно ужасную схему перевода кода под названием NACA.С тех пор я слышал, что этот термин набирает силу;Я не понимаю, почему мы должны были изобрести другой термин, когда у нас есть совершенно адекватные.Обычно это признак того, что кто-то изобретает первосвященство;«Давайте изобретем новый блестящий термин, чтобы люди не понимали, что мы делаем».Я счастлив оставить этот термин в таких по-настоящему ужасных переводах.

...