Как визуализировать абстрактное синтаксическое дерево графически? - PullRequest
0 голосов
/ 02 декабря 2018

Я написал простой компилятор на 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 признает хорошей отправной точкой.Я постараюсь сделать это так, пока не возникнут новые и более конкретные проблемы.Спасибо, ребята.

1 Ответ

0 голосов
/ 04 декабря 2018

Я нашел быстрое и приемлемое решение.LLVM-8 включает в себя возможность визуализации графика потока управления (CFG) путем создания из него файла точечного формата.В основном это работает для более общих структур графов, если вы специализируете шаблоны llvm::GraphTraits и llvm::DOTGraphTraits (с небольшим обходом) и llvm::WriteGraph() будет работать для вас.Вот результат без особых настроек:

enter image description here

с учетом C-подобного фрагмента:

const int IntConstant = 1;
int Array[2];

void main() {
  Printf("hello");
}

Этот языкупрощение C, и это без учета регистра.Printf() представляется оператором Write в качестве узла на изображении.ConstDecl означает объявление константы .VarDecl означает объявление переменной и FuncDef означает определение функции .Другие вещи довольно просты.

Прежде чем объяснить магию, я бы хотел указать вам на эти документы, которые действительно помогают использовать задействованный APT llvm.

  • GraphTraits чтобы узнать, какую подпись должен иметь ваш код.
  • WriteGraph чтобы узнать, чего требует WriteGraph от вашего кода.
  • CFGPrinter знать, как специализировать ваши GraphTraits
  • DOTGraphTraits , чтобы знать, как сделать вашу иллюстрацию значимой, давая метки и описания узлам.
  • iterator_facade_base чтобы знать, как безболезненно писать работающие итераторы.

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

  1. подумайте, как выполнить итерацию по каждому узлу в AST, и специализируйте реализацию nodes_iterator.
  2. подумайте, как выполнить итерацию по всем потомкамзаданный узел и специализируйте реализацию ChildIteratorType.
  3. подумайте, как извлечь полезную информацию из ваших узлов и специализируйте getNodeLabel() и getNodeDescription() вашей DOTGraphTraits.
  4. заметки.шахта: NodeRef тип GraphTraits должен быть указателем!знание этого заранее может сэкономить вам день.Это верно для последней версии.Возможно, в будущем они уберут ограничение.

Моя текущая реализация включает в себя только имя класса узла в качестве его метки и поясняющую строку в качестве описания без какой-либо тонкой настройки.Если вам нужны дополнительные эффекты, например, цвет, форма и т. Д., Вы можете сделать это в вашем DOTGraphTraits.

...