Not a kernel guy

… in the Windows kernel team

Sunday, September 16, 2007

Отладка абстрактного синтаксического дерева (AST).

Во время работы над парсером постоянно возникала необходимость посмотреть как выглядит тот или иной кусок дерева или все дерево целиком. Недолго думая, я попробовал выводить его в виде XML, - получилось довольно неплохо.

Исходный код на C:

typedef void *LPVOID;

Дерево, полученное после синтаксического разбора:

<translation_unit>
 <external_declaration>
  <declaration>
   <init_list_declaration>
    <declaration_specifiers>
     <declaration_specifier>
      <storage_class_specifier>
       typedef
      </storage_class_specifier>
     </declaration_specifier>
     <declaration_specifier>
      <type_specifier>
       <builtin_type>
        void
       </builtin_type>
      </type_specifier>
     </declaration_specifier>
    </declaration_specifiers>
    <init_declarator>
     <declarator>
      <pointer>
       *
      </pointer>
      <direct_declarator>
       LPVOID
      </direct_declarator>
     </declarator>
    </init_declarator>
   </init_list_declaration>
   ;
  </declaration>
 </external_declaration>
</translation_unit>

Что особенно приятно, так это то, что на Python такие вещи делаются одной левой. Исходный класс Node, представляющий узел дерева, дополняется методом “__str__”:

exclude_attrs = set(['type', 'children'])

class Node:
    def __init__(self, type, children):
        self.type = type
        self.children = children

    def __str__(self):
        s = '<%s' % self.type

        # Представляем переменные объекта как XML аттрибуты
        for attr in self.__dict__:
            if not attr in exclude_attrs:
                s += ' %s="%s"' % (attr, self.__dict__[attr])

        # Рекурсивно генерируем все подузлы, не забывая про отступы
        if len(self.children):
            s += '>\n'
            for i in self.children:
                s += ' %s\n' % str(i).replace('\n', '\n ')
            s += '</%s>' % self.type
        else:
            s += '/>'

        return s

# Получаем AST
node = parse_source()

# Выводим его в stdout
print node

Небольшого пояснения требует комментарий про то, что переменные объекта выводятся в виде XML атрибутов, поскольку в примере выше никаких атрибутов нет. Каждый из узлов дерева, использованного в примере, содержит только две переменные: “type” – тип узла и “children” – список всех детей. Поскольку и то и другое включаются в XML “естественным” путем, то и показывать их как атрибуты не следует. Для их исключения используется список “exclude_attrs”.
А вот, например, такой объект будет показан по-другому:

node = Node(“test”, [])
node.value = “FooBar”
print node
<test value="FooBar"/>

Эта возможность будет очень полезна позднее, когда в AST будут включаться не только экземпляры класса Node, но и более сложные классы.

Posted at 9:19 pm •

RSS feed | Trackback URI

4 Comments »

Trackback by Зеркало: Not a kernel guy — September 16, 2007 @ 9:36 pm

Отладка абстрактного синтаксического дерева (AST)….

Во время работы над парсером постоянно возникала необходимость посмотреть как вы…

 
Comment by iv — September 17, 2007 @ 11:47 pm

А в чем питоновский код редактируешь и отлаживаешь?

Comment by Not a kernel guy — September 18, 2007 @ 9:35 am

Редактирую - немного подправленным вариантом Notepad 2, отлаживаю - print в нужных местах.

 
 

[...] навигация по дереву. После давешнего эксперимента с отображением дерева в виде XML, использование XPath для навигации по дереву просто [...]

 

Your Comment (smaller | larger)

You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Powered by WordPress