Формальное построение графа потока управления

Я пишу компилятор для университетского проекта, и я хотел бы преобразовать свое абстрактное синтаксическое дерево в граф потока управления (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 -> _|_ 
}

CFG(dot) DotSrc

Кто-нибудь получил какие-либо подсказки о том, как сделать это немного более формально, чем 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, и основывается на базовых блоках. Тем не менее, отличный вклад!

26
задан sorin 3 September 2010 в 18:50
поделиться

2 ответа

Вы можете просто начать «запускать модули как автономные» немного по-другому:

Вместо:

python foo/bar.py

Использование:

python -mfoo.bar

Конечно, Должен присутствовать файл foo/__init__.py.

Также обратите внимание, что у вас есть циклическая зависимость между foo.py и bar.py — это не сработает. Я думаю, это просто ошибка в вашем примере.

Обновление: кажется, что это также отлично работает, если использовать его в качестве первой строки foo/bar.py:

#!/usr/bin/python -mfoo.bar

Затем вы можете выполнить скрипт непосредственно в системах POSIX.

22
ответ дан 28 November 2019 в 07:31
поделиться

Пока что единственным решением, которое я нашел, было вообще не использовать относительный импорт.

Из-за текущих ограничений мне интересно, когда кто-то должен использовать относительный импорт в python.

Во всех конфигурациях, которые я использовал, sys.path содержал текущий каталог в качестве первого аргумента, поэтому просто используйте import foo вместо from . import foo, потому что он сделает то же самое.

-2
ответ дан 28 November 2019 в 07:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: