Я написал простой компилятор на C ++ и хочу визуализировать абстрактное синтаксическое дерево, которое оно создает. В настоящее время я выкидываю AST в супер длинную строку, похожую на что-то ниже:
Program(decls=[ConstDecl(type=BasicTypeKind::Int, value=Num(n=1, loc=Location(1, 21)), name=positive, loc=Location(1, 10)), ConstDecl(type=BasicTypeKind::Int, value=Num(n=-1, loc=Location(2, 21)), name=negative, loc=Location(2, 10)), ConstDecl(type=BasicTypeKind::Int, value=Num(n=100, loc=Location(3, 26)), name=max_heap_size, loc=Location(3, 10)), ConstDecl(type=BasicTypeKind::Character, value=Char(c=99, loc=Location(4, 23)), name=...
Как видите, этот дамп не очень удобен для человека с точки зрения визуализации. Нельзя естественно связать понятие дерево до такой длинной строки. Я попробовал подход, чтобы красиво распечатать AST и нашел astpretty, который для Python. Он нацелен на отладку, но что, если я хочу иллюстрацию AST? Графический формат, безусловно, подходит лучше.
На самом деле у меня есть картина о том, какой выход я с нетерпением жду. Graphviz
делает большую работу в этой области и различных графиков инструмент документа C ++ Doxygen
концептуально очень близки к моей цели.
Собирая их вместе, я хочу, чтобы способ превращать AST в памяти как объекты C ++ в приличный графический вывод (статический в порядке). Есть хорошая отправная точка?
Редактировать: как сказано в комментариях, сбрасывает мой AST в формате Graphviz
признает это хорошая отправная точка. Я постараюсь сделать это так, пока не возникнут новые и более конкретные проблемы. Спасибо, парни.
Я нашел решение, которое было бы быстрым и приемлемым. LLVM-8 включает в себя возможность визуализации графика потока управления (CFG) путем создания из него файла точечного формата. В основном это работает для более общих структур графов, если вы специализируете llvm::GraphTraits
а также llvm::DOTGraphTraits
шаблоны (с небольшой работой вокруг) и llvm::WriteGraph()
будет работать на вас. Вот результат без особой подстройки:
учитывая C-подобный фрагмент:
const int IntConstant = 1;
int Array[2];
void main() {
Printf("hello");
}
Этот язык является упрощением языка Си и нечувствителен к регистру. Printf()
представлен Write
Заявление в качестве узла на изображении. ConstDecl
средства постоянная декларация. VarDecl
средства объявление переменной а также FuncDef
средства определение функции. Другие вещи довольно просты.
Прежде чем объяснить магию, я хотел бы указать вам на эти документы, которые действительно помогают использовать задействованный APT llvm.
WriteGraph
требует вашего кода.GraphTraits
Теперь с этими базами знаний, вам просто нужно собрать их вместе. На самом деле, выполните следующие действия:
nodes_iterator
реализация.ChildIteratorType
реализация.getNodeLabel()
а также getNodeDescription()
вашей DOTGraphTraits
,NodeRef
тип GraphTraits
должен быть указателем! знание этого заранее может сэкономить вам день. Это верно для последней версии. Возможно, в будущем они снимают ограничения.Моя текущая реализация включает в себя только имя класса узла в качестве его метки и понятную строку в качестве его описания без какой-либо тонкой настройки. Если вы хотите больше эффектов, например, цвета, формы и т. Д., Вы можете сделать это в своем DOTGraphTraits
,
Других решений пока нет …