Я пишу компилятор для университетского проекта, и я хотел бы преобразовать свое абстрактное синтаксическое дерево в граф потока управления (CFG).
Я думаю, что узлы ( V
) в CFG должны быть узлами из AST. Я знаю алгоритмически, как построить набор ребер ( G = (V, E)
), но мне трудно написать процесс более формально
Я создал это сопоставление с шаблоном в стиле scala (Псевдо):
def edges(n:Node)(nestedin_next: Node) : List[(Node,Node)] =
n match {
case (c_1 :: c_2::tl) => (c1,c2) :: edges(c2::tl)(nestedin_next)++
edges(c_1)(c_2)//recurse
case c_1 :: Nil => (c_1,nestedin_next)::Nil
case i@ IF(_,c1,c2) => (i,c1)::(i,c2)::edges(c1)(nestedin_next)++
edges(c2)(nestedin_next)
case _ => Nil
}
, которое должно соответствовать структуре AST, например:
( IF(1,
ASSIGN(x,1), // ia1
ASSIGN(x,2) // ia2
) :: // i1
ASSIGN(y,2) :: // a1
ASSIGN(z,ADD(x,y)) :: //a2
IF(z,
RET(z), //i2r1
assign(z,0):: // i2a1
ret(z) // i2r2
) :://i2
Nil
)
и предоставить набор ребер, например:
{ i1 -> ia1,
i1 -> ia2,
ia1 -> a1,
ia2 -> a1,
a1 -> a2,
a2 -> i2,
i2 -> i2r1
i2-> i2a1
i2a1 -> i2r2
i2r2 -> _|_
i2r1 -> _|_
}
Кто-нибудь получил какие-либо подсказки о том, как сделать это немного более формально, чем scala «псевдокод»?
Я думаю, что-то индуктивное, например:
e[[ IF(_,b1,b2) ]] = (if -> b1) + (if -> b2) \cup e[[ b1 ]] \cup e[[ b2 ]]
e[[ b1, b2 ]] = e[[b1]] \cup e[[b2]]
(приведенное выше дает только дерево, а не граф. Например, нет ребра от края then-ветвления до следующего оператора)
EDIT:
Я читал kiama и потоки данных для scala, и я как и подходы «succ» и «follow», которые они используют. Тем не менее, мне трудно свести это к более формальному описанию, в основном из-за изящных childAttr
, s. next
, который скрывает некоторые детали, которые становятся уродливыми, когда я пытаюсь указать это формально.
EDIT2:
Я прошел через Dragon Book и «Современную реализацию компилятора в ML», а также некоторые из другой материал из Обучение написанию компилятора и некоторые / большинство упоминают поток данных и поток управления, но никогда особо не затрагивают КАК создать CFG каким-либо формальным способом.
EDIT3:
Via Киама автор, доцент доктор Тони Слоан Я получил несколько дополнительных ссылок на книги, которые нужно найти .
Насколько я могу видеть «путь к do it »согласно этим книгам, основывается на« на каждый оператор »программы больше, чем на AST, и основывается на базовых блоках. Тем не менее, отличный вклад!
Вы можете просто начать «запускать модули как автономные» немного по-другому:
Вместо:
python foo/bar.py
Использование:
python -mfoo.bar
Конечно, Должен присутствовать файл foo/__init__.py
.
Также обратите внимание, что у вас есть циклическая зависимость между foo.py
и bar.py
— это не сработает. Я думаю, это просто ошибка в вашем примере.
Обновление: кажется, что это также отлично работает, если использовать его в качестве первой строки foo/bar.py
:
#!/usr/bin/python -mfoo.bar
Затем вы можете выполнить скрипт непосредственно в системах POSIX.
Пока что единственным решением, которое я нашел, было вообще не использовать относительный импорт.
Из-за текущих ограничений мне интересно, когда кто-то должен использовать относительный импорт в python.
Во всех конфигурациях, которые я использовал, sys.path
содержал текущий каталог в качестве первого аргумента, поэтому просто используйте import foo
вместо from . import foo
, потому что он сделает то же самое.