В настоящее время я изучаю разработку компилятора, который преобразует его AST в несколько этапов. Идея состоит в том, что, начиная с дерева синтаксического анализа, каждый проход преобразует дерево до тех пор, пока полученный AST не будет оптимизирован и не будет содержать всю необходимую информацию в каждом node дерева, необходимого для генерации промежуточного кода (в этом случае LLVM ИК). Проход над деревом может значительно изменить его структуру, например, изменить список операторов и операндов в иерархию упорядоченных операций с помощью синтаксического анализа приоритета оператора. Обратите внимание, что проход может оставить части структуры полностью неизменными.
Итак, мой вопрос: насколько я лучше всего (читайте: проще всего, с минимальным повторением) представляют собой AST, который имеет несколько промежуточных представлений в С++? Я бы хотел, чтобы типы node из каждой фазовой версии АСТ учитывали их несовместимость во время компиляции. Я считаю, что ключевая проблема заключается в том, как я должен представлять части структуры, которые не меняются между проходами, избегая повторного кода? Я полагаю, что это проблема, которую много раз решали авторами компилятора в прошлом.
Обратите внимание, что в настоящее время я использую Boost Variant вместо обычного полиморфизма времени выполнения в моем AST и хотел бы, чтобы решение было совместимо с ним.