Как создать поток управления AST (представленный в XML) с использованием Python? - PullRequest
3 голосов
/ 16 февраля 2012

У меня есть язык AST of WHILE (http://www.program -analysis.com / while.html) в формате XML.В настоящее время я не обрабатываю вызовы функций или рекурсию.Мне нужно сгенерировать поток управления для этой программы.

Пример программы (цифры после // указывают метки, сгенерированные анализатором):

begin

x:=1;        // 1
z:= 2+x;     // 2
x  := x+z;   // 3
y:=z-x+z;    // 4
w:=x+y+z;    // 5

while(not (y<z)) {   // 12
    x:=x+1;          // 6
    if (w <=x) {     // 9
        w:= w-x; // 7
    }
    else {
        w:=w+x;   // 8
    }
    z:=z-1;          // 10
    y:=y+1;          // 11
}

x:=z+y;              // 13
w:=x;                // 14

end

AST для вышеупомянутогоПрограмма представлена ​​как:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<program>
    <assignment label="1" variable="x">
        <value>
            <number value="1"/>
        </value>
    </assignment>
    <assignment label="2" variable="z">
        <value>
            <binary operator="+">
                <left>
                    <number value="2"/>
                </left>
                <right>
                    <variable name="x"/>
                </right>
            </binary>
        </value>
    </assignment>
    <assignment label="3" variable="x">
        <value>
            <binary operator="+">
                <left>
                    <variable name="x"/>
                </left>
                <right>
                    <variable name="z"/>
                </right>
            </binary>
        </value>
    </assignment>
    <assignment label="4" variable="y">
        <value>
            <binary operator="+">
                <left>
                    <binary operator="-">
                        <left>
                            <variable name="z"/>
                        </left>
                        <right>
                            <variable name="x"/>
                        </right>
                    </binary>
                </left>
                <right>
                    <variable name="z"/>
                </right>
            </binary>
        </value>
    </assignment>
    <assignment label="5" variable="w">
        <value>
            <binary operator="+">
                <left>
                    <binary operator="+">
                        <left>
                            <variable name="x"/>
                        </left>
                        <right>
                            <variable name="y"/>
                        </right>
                    </binary>
                </left>
                <right>
                    <variable name="z"/>
                </right>
            </binary>
        </value>
    </assignment>
    <while condition-label="12">
        <condition>
            <not>
                <binary operator="&lt;">
                    <left>
                        <variable name="y"/>
                    </left>
                    <right>
                        <variable name="z"/>
                    </right>
                </binary>
            </not>
        </condition>
        <body>
            <assignment label="6" variable="x">
                <value>
                    <binary operator="+">
                        <left>
                            <variable name="x"/>
                        </left>
                        <right>
                            <number value="1"/>
                        </right>
                    </binary>
                </value>
            </assignment>
            <if condition-label="9">
                <condition>
                    <binary operator="&lt;=">
                        <left>
                            <variable name="w"/>
                        </left>
                        <right>
                            <variable name="x"/>
                        </right>
                    </binary>
                </condition>
                <true-branch>
                    <assignment label="7" variable="w">
                        <value>
                            <binary operator="-">
                                <left>
                                    <variable name="w"/>
                                </left>
                                <right>
                                    <variable name="x"/>
                                </right>
                            </binary>
                        </value>
                    </assignment>
                </true-branch>
                <false-branch>
                    <assignment label="8" variable="w">
                        <value>
                            <binary operator="+">
                                <left>
                                    <variable name="w"/>
                                </left>
                                <right>
                                    <variable name="x"/>
                                </right>
                            </binary>
                        </value>
                    </assignment>
                </false-branch>
            </if>
            <assignment label="10" variable="z">
                <value>
                    <binary operator="-">
                        <left>
                            <variable name="z"/>
                        </left>
                        <right>
                            <number value="1"/>
                        </right>
                    </binary>
                </value>
            </assignment>
            <assignment label="11" variable="y">
                <value>
                    <binary operator="+">
                        <left>
                            <variable name="y"/>
                        </left>
                        <right>
                            <number value="1"/>
                        </right>
                    </binary>
                </value>
            </assignment>
        </body>
    </while>
    <assignment label="13" variable="x">
        <value>
            <binary operator="+">
                <left>
                    <variable name="z"/>
                </left>
                <right>
                    <variable name="y"/>
                </right>
            </binary>
        </value>
    </assignment>
    <assignment label="14" variable="w">
        <value>
            <variable name="x"/>
        </value>
    </assignment>
</program>

Мне нужно сгенерировать поток управления программы.

Поток управления для вышеупомянутой программы выглядит так:

1->2,
2->3,
3->4,
4->5,
5->12,
12->6,
12->13,
11->12,
6->9 ,
9->7,
9->8,
7->10,
8->10,
10->11,
13->14.

Примечание: while может иметь вложенные операторы if и while в нем и наоборот.Я предпочтительно ищу универсальное решение на Python / Java / C.

Заранее спасибо, Рой

Ответы [ 3 ]

3 голосов
/ 16 февраля 2012

Вот одно из возможных решений.Он возвращает дуги в несколько ином порядке к вашему примеру, но это не должно иметь значения.

from xml.dom import minidom
dom = minidom.parse('test1.wl.xml')


def print_arcs(from_list, to_list):
    '''
    Print arcs from every member of the from list, to every member of
    the to list
    '''
    for source in from_list:
        for target in to_list:
            print "%s -> %s" % (source, target)

def parse(node, came_from):
    '''
    Descend an XML structure representing an AST
    '''
    if not node:
        return came_from

    if node.nodeName=="#text":
        return parse(node.nextSibling, came_from)

    if node.nodeName=="program":
        return parse(node.firstChild, came_from)

    if node.nodeName=="assignment":
        this = node.getAttribute('label')
        print_arcs(came_from, [this])
        return parse(node.nextSibling, [this])

    if node.nodeName=="while":
        loop_start = node.getAttribute('condition-label')
        print_arcs(came_from, [loop_start])
        next = [loop_start]
        for s in node.childNodes:
            if s.nodeName=="body":
                loop_end = parse(s, [loop_start])
                print_arcs(loop_end, [loop_start])
        return parse(node.nextSibling, next)

    if node.nodeName=="if":
        if_start = node.getAttribute('condition-label')
        print_arcs(came_from, [if_start])
        next = []
        for s in node.childNodes:
            if s.nodeName=="#text":
                continue
            item = parse(s, [if_start])
            if item:
                next.extend(item)
        return parse(node.nextSibling, next)

    if node.nodeName=="condition":
        return None

    if node.nodeName=="true-branch":
        return parse(node.firstChild, came_from)

    if node.nodeName=="false-branch":
        return parse(node.firstChild, came_from)

    if node.nodeName=="body":
        return parse(node.firstChild, came_from)


parse(dom.firstChild, [])

Это повторяется через структуру AST, и его вывод зависит от типа встреченного узла.Присвоение просто выводит дуги из предыдущего узла (ов) в текущий узел;if нужны дуги для двух возможностей, а while нужны дуги, представляющие цикл и возможный провал.Данный код хранит список того, откуда могло произойти выполнение, чтобы в конечном итоге оказаться в текущем местоположении.Функция parse возвращает местоположение, в котором заканчивается текущий блок.

Обратите внимание, что реализация как while, так и if здесь немного ошибочна, и она может упасть при определенных синтаксических ошибках..

0 голосов
/ 16 февраля 2012

Вам не нужно реализовывать полную виртуальную машину для выполнения анализа потока управления.Вам нужно пройти через АСТ.Действительно, книга, упомянутая сайтом, на который вы ссылаетесь ( Принципы анализа программ ), объясняет, как это сделать.Подумайте о том, как каждое утверждение на вашем языке имеет точки входа и выхода.На процедурном языке оператор if/else if/else может быть введен из предшествующего ему оператора и может иметь несколько точек выхода (по одной для каждой ветви if/else if/else).У оператора while есть точка входа из оператора, предшествующего ему, и две точки выхода - одна точка выхода зацикливается на вершину while, а другая выходит из while и переходит к следующей инструкции.Операторы назначения имеют одну запись из оператора, предшествующего назначению, и одну точку выхода, которая ведет к последующим операторам.

Это ориентированный граф, который вам нужно нарисовать.Итак, вы хотите перебрать XML, который у вас есть, «испуская» узлы в вашем CFG.Самый простой способ сделать это, IMO, это использовать шаблон посетителя , поскольку вы пишете на языке OO.

Например, эта программа:

begin
    x := 10          // 1
    if x < 100 {     // 2
        print "foo"  // 3
    }
    else {
        print "bar"  // 4
    }
end

будет иметь следующий CFG:

CFG

0 голосов
/ 16 февраля 2012

Вам потребуется внедрить виртуальную машину для выполнения этого кода. К счастью, все, что вам нужно иметь в этом коде, это операторы присваивания, if и while. Вам также понадобится ваша виртуальная машина для ведения реестра имен переменных, что можно просто сделать с помощью Python dict. Начните с первого оператора, назначения просто выполняются и переходите к следующему. если операторы должны оценивать условие, а затем переходить соответственно. while аналогичен if, но вам потребуется стек адресов для выхода, когда условие оценивает false (используйте стек для обработки вложенных while). И следите за номерами этикеток по ходу дела.

...