python解析c语言抽象语法树,关于解析:如何在Python中编写抽象语法树的访问者模式?...

我的同事建议我写一个访客模式来导航AST。有人能告诉我更多我该怎么开始写吗?

据我所知,ast中的每个节点都有visit()方法(?)不知何故(从哪里)会被呼叫?我的理解到此为止。

为了简化一切,假设我有节点Root、Expression、Number、Op,树如下:

Root

|

Op(+)

/   \

/     \

Number(5)  \

Op(*)

/   \

/     \

/       \

Number(2)   Number(444)

有人能想到访问者模式将如何访问此树以生成输出:

5 + 2 * 444

谢谢,博达·赛多。

添加了python标记

维基百科对访问者模式的工作有很大的了解,尽管他们使用的示例实现是在Java中。不过,您可以很容易地将其移植到Python,不是吗?

基本上,您希望实现一个双调度机制。AST中的每个节点都需要实现一个accept()方法(而不是visit()方法)。该方法将访问者对象作为参数。在实现此EDCOX1×1的方法中,您调用Eclipse对象的EDCOX1×2的方法(每个AST节点类型都有一个;在Java中,您将使用参数重载,在Python中,假设您可以使用不同的EDCOX1和5个方法)。然后,将使用正确的节点类型作为参数调度正确的访问者。

参见ast.NodeVisitor的文档,例如,粗略的可能性可能是:

import ast

class MyVisitor(ast.NodeVisitor):

def visit_BinaryOp(self, node):

self.visit(node.left)

print node.op,

self.visit(node.right)

def visit_Num(self, node):

print node.n,

当然,即使在需要的地方,这也不会发出括号,所以实际上还有更多的工作要做,但是,这是一个开始;-)。

我在互联网上最常遇到的两种在python中实现访问者模式的变体:

gamma等人从desigh patterns书中一对一地翻译示例。

使用附加模块进行双调度

从设计模式书翻译的例子

这种变体在数据结构类中使用accept()方法,在访问者中使用相应的visit_Type()方法。

数据结构

class Operation(object):

def __init__(self, op, arg1, arg2):

self.op = op

self.arg1 = arg1

self.arg2 = arg2

def accept(self, visitor):

visitor.visitOperation(self)

class Integer(object):

def __init__(self, num):

self.num = num

def accept(self, visitor):

visitor.visitInteger(self)

class Float(object):

def __init__(self, num):

self.num = num

def accept(self, visitor):

visitor.visitFloat(self)

expression = Operation('+', Integer('5'),

Operation('*', Integer('2'), Float('444.1')))

中缀打印访问者

class InfixPrintVisitor(object):

def __init__(self):

self.expression_string = ''

def visitOperation(self, operation):

operation.arg1.accept(self)

self.expression_string += ' ' + operation.op + ' '

operation.arg2.accept(self)

def visitInteger(self, number):

self.expression_string += number.num

def visitFloat(self, number):

self.expression_string += number.num

前缀打印访问者

class PrefixPrintVisitor(object):

def __init__(self):

self.expression_string = ''

def visitOperation(self, operation):

self.expression_string  += operation.op + ' '

operation.arg1.accept(self)

self.expression_string  += ' '

operation.arg2.accept(self)

def visitInteger(self, number):

self.expression_string += number.num

def visitFloat(self, number):

self.expression_string += number.num

试验

infixPrintVisitor = InfixPrintVisitor()

expression.accept(infixPrintVisitor)

print(infixPrintVisitor.expression_string)

prefixPrintVisitor = PrefixPrintVisitor()

expression.accept(prefixPrintVisitor)

print(prefixPrintVisitor.expression_string)

产量

5 + 2 * 444.1

+ 5 * 2 444.1

。使用其他模块

此变体使用@functools.singledispatch()修饰器(自python v3.4以来在python标准库中提供)。

数据结构

class Operation(object):

def __init__(self, op, arg1, arg2):

self.op = op

self.arg1 = arg1

self.arg2 = arg2

class Integer(object):

def __init__(self, num):

self.num = num

class Float(object):

def __init__(self, num):

self.num = num

expression = Operation('+', Integer('5'),

Operation('*', Integer('2'), Float('444.1')))

中缀打印访问者

from functools import singledispatch

@singledispatch

def visitor_print_infix(obj):

pass

@visitor_print_infix.register(Operation)

def __(operation):

return visitor_print_infix(operation.arg1) + ' ' \

+ operation.op + ' ' \

+ visitor_print_infix(operation.arg2)

@visitor_print_infix.register(Integer)

@visitor_print_infix.register(Float)

def __(number):

return number.num

前缀打印访问者

from functools import singledispatch

@singledispatch

def visitor_print_prefix(obj):

pass

@visitor_print_prefix.register(Operation)

def __(operation):

return operation.op + ' ' \

+ visitor_print_prefix(operation.arg1) + ' ' \

+ visitor_print_prefix(operation.arg2)

@visitor_print_prefix.register(Integer)

@visitor_print_prefix.register(Float)

def __(number):

return number.num

试验

print(visitor_print_infix(expression))

print(visitor_print_prefix(expression))

产量

5 + 2 * 444.1

+ 5 * 2 444.1

我之所以喜欢这种变体,是因为它消除了accept()方法,并将数据结构与访问者中实现的操作完全分离。使用新元素扩展数据结构不需要更改访问者。访问者默认忽略未知的元素类型(参见使用pass关键字的定义)。这种方法的一个缺点是,singledispatchdecorator不能直接与实例方法一起使用,尽管有一些方法可以使它工作。

对于3.4版之前的python,可以使用类似于singledispatch修饰符的多方法模块。多方法模块的一个缺点是,应用于给定数据结构元素的Visitor方法不仅基于元素的类型,而且基于方法的声明顺序进行选择。对于具有复杂继承层次结构的数据结构,将方法定义保持在正确的顺序可能很麻烦,而且容易出错。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值