Есть ли способ написать фронтэнд компилятора без использования синтаксически-ориентированного перевода?
Мой вопрос совпадает с названием. Я просто хочу знать, существуют ли какие-либо другие методы перевода, чтобы получить промежуточный код, который не основан на встраивании действий в синтаксический анализатор (то есть анализатор будет строго создавать абстрактное синтаксическое дерево, он не будет генерировать какой-либо код), Спасибо за любые ответы.
2 ответа
Если у вас есть синтаксический анализатор, то он должен сделать нечто большее, чем просто "распознать" входной поток как действительный экземпляр языка. Если вы хотите, чтобы компилятор производил что-либо, к действиям, в которых сопоставляются фрагменты языка, должны быть приложены какие-то действия. В некотором смысле, это не может быть что-либо, кроме "направленного синтаксиса"; на этапе разбора все, что у вас есть, это синтаксис.
По сути, действия по синтаксическому анализу должны создавать представление программы, которая является "более компилируемой". Я знаю только несколько основных методов:
- Создать набор инструкций виртуальной машины
- Создайте абстрактное синтаксическое дерево для передачи остальной части компилятора
- Создайте некоторое представление кода управления / потока данных (например, "тройки")
Все они в общих чертах в основном одинаковы: генерируемое парсером представление содержит связанные структуры, элементы которых имеют прямое семантическое понимание. Эти биты структуры с подразумеваемой семантикой - это то, что отключает остальная часть компилятора.
Теперь текст является представлением программы. Вы можете полностью избежать процесса "разбора" (своего рода), если решите реализовать свой компилятор как систему Post, набор правил перезаписи над строками. Они имеют вид "если вы видите эту строку, замените ее другой строкой". Почтовые системы способны провоцировать Turing, поэтому технически вы можете преобразовать свой исходный код в строку, представляющую вашу целевую программу, с достаточно умным набором правил переписывания строк. Никто из тех, кого я знаю, не создает настоящие компиляторы таким образом; Я уверен, что если вы будете копать достаточно сильно, вы сможете найти неясную техническую статью, которая это делает.
Можно разумно утверждать, что сопоставление строк, как того требует система Post, является своего рода синтаксическим анализом (например, распознавание интересной структуры), возвращая вас к исходному вопросу.
Интересно отметить, что системы трансформации программ (я создаю одну из них на коммерческой основе) обычно используют внешний интерфейс компилятора для создания AST, а затем применяют переписывание AST от дерева к дереву для достижения своей цели. Причина, по которой они построены таким образом, заключается в том, что они действительно представляют собой почтовые системы; любой AST для вашей программы может быть тривиально преобразован в строку (например, S-выражения), а древовидные преобразования могут быть преобразованы в эквивалентные строковые преобразования. Таким образом, система переписывания деревьев - это просто система Post, но это делает ее очень мощной. Конечно, можно объединить эту возможность с другими более традиционными методами компилятора, что мы и делаем с нашим продуктом. Это делает это более удобным; Вы не должны делать все как почтовую систему.
То, что вы описываете, на самом деле является стандартным дизайном компилятора. Можно написать однопроходные компиляторы, и, действительно, я это сделал, которые генерируют объектный код во время синтаксического анализа, но для синтаксического анализатора нормой является создание AST, а для последующего обхода AST - либо выходных данных, либо во многих случаях дополнительная промежуточная форма, такая как тройки, RTL и т. д.