李桑

李桑的博客

他的个人主页  他的博客

使用ply对PSDL/c++头文件解析

李桑  2009年08月13日 星期四 20:16 | 3796次浏览 | 7条评论

python ply cppheaderparser psdl c++头文件解析

  PSDL(Protocol Signature Description Language)--协议特征描述语言

最近需要对psdl文件及c++头文件进行解析,解出类、结构体、方法、属性等内容,在网上找到了ply( http://www.dabeaz.com/ply/ )及cppheaderparser( http://sourceforge.net/projects/cppheaderparser/ ),ply

是python实现lex and yacc的一个工具, cppheaderparser是一个使用ply对c++头文件进行解析的库。但是经过测试 cppheaderparser并不满足我的需求,它不支持内部类及结构体嵌套解析,不支持变量名字为数组,经过了winpdb的调试及代码的修改终于支持了!

首先,先安装ply,然后下载 cppheaderparser,修改CppHeaderParser.py文件为如下内容(不支持语法着色,晕那!)。

修改82行为

t_NAME = r'[<>A-Za-z_\[\]][A-Za-z0-9_\[\]]*'
修改371-483行为如下内容

   self.curClass = ""
        self.classes = {}
        self.nameStack = []
        self.lastClass = "" #2009-08-11 lisang save last class name
        self.curAccessSpecifier = 'private'
   
        if (len(self.headerFileName)):
            headerFileStr = "\n".join(open(self.headerFileName).readlines())
        self.braceDepth = 0
        lex.input(headerFileStr)
        curLine = 0
        curChar = 0
                if not tok:
                    break
                curLine = tok.lineno
                curChar = tok.lexpos
                if (tok.type == 'OPEN_BRACE'):
                    if len(self.nameStack) and not is_enum_namestack(self.nameStack):
                        if len(self.lastClass) == 0: #2009-08-11 lisang save last class name
                            self.lastClass = self.curClass
                        self.evaluateStack()
                    else:
                        self.nameStack.append(tok.value)
                    self.braceDepth += 1
                elif (tok.type == 'CLOSE_BRACE'):
                    if len(self.nameStack) and is_enum_namestack(self.nameStack):
                        self.nameStack.append(tok.value)
                    elif self.braceDepth > 0:
                        self.evaluateStack()
                    else:
                        self.nameStack = []
                    #self.braceDepth -= 1
                    #if (self.braceDepth == 0):
                    #    self.curClass = ""
                    self.curClass = self.lastClass #2009-08-11 lisang save last class name
                    self.lastClass = ""#2009-08-11 lisang reset last class name value
               
                if (tok.type == 'OPEN_PAREN'):
                    self.nameStack.append(tok.value)
                elif (tok.type == 'CLOSE_PAREN'):
                    self.nameStack.append(tok.value)
                elif (tok.type == 'EQUALS'):
                    self.nameStack.append(tok.value)
                    self.nameStack.append(tok.value)
                elif (tok.type == 'PLUS'):
                    self.nameStack.append(tok.value)
                elif (tok.type == 'STRING_LITERAL'):
                    self.nameStack.append(tok.value)
                elif (tok.type == 'NAME' or tok.type == 'AMPERSTAND' or tok.type == 'ASTERISK'):
                    if (tok.value == 'class' or tok.value == 'struct'):
                        self.nameStack.append(tok.value)
                    elif (tok.value in supportedAccessSpecifier):# and self.braceDepth == 1):
                        self.curAccessSpecifier = tok.value
                    else:
                        self.nameStack.append(tok.value)
                elif (tok.type == 'COLON'):
                    #Dont want colon to be first in stack
                    if len(self.nameStack) == 0:
                        continue
                    self.nameStack.append(tok.value)
                elif (tok.type == 'SEMI_COLON'):
                    #if (self.braceDepth < 2):
                        self.evaluateStack()
                elif (tok.value == 'PRECOMP_MACRO'):
                    pass
        except:
            raise CppParseError("Not able to parse %s on line %d evaluating \"%s\"\nError around: %s"
                                % (self.headerFileName, tok.lineno, tok.value, " ".join(self.nameStack)))
       
    def evaluateStack(self):
        """Evaluates the current name stack"""
        if (len(self.curClass)):
            if (debug): print "%s (%s) "%(self.curClass, self.curAccessSpecifier),
        if (len(self.nameStack) == 0):
            if (debug): print "(Empty Stack)"
            return
    #2009-08-11 lisang add struct type
        elif (self.nameStack[0] == "class" or self.nameStack[0] == "struct"):
            self.evaluateClassStack()
        elif (len(self.curClass) == 0):
            self.nameStack = []
            return
        elif (self.braceDepth < 1):
            #Ignore global stuff for now
            if (debug): print "Global stuff: ",  self.nameStack
            self.nameStack = []
            return
        #elif (self.braceDepth > 1):
        #    self.nameStack = []
        #    return
        elif is_enum_namestack(self.nameStack):
            #elif self.nameStack[0] == "enum":
            self.evaluateEnumStack()
        elif ('(' in self.nameStack):
            self.evaluateMethodStack()
        else:
            self.evaluatePropertyStack()
        self.nameStack = []
   
    def evaluateClassStack(self):
        """Create a Class out of the name stack (but not its parts)"""
        #dont support sub classes today
        if (debug): print 'self.nameStack',self.nameStack
       
        #2009-08-11 lisang support inner class embeded
        #if self.braceDepth != 0:
        #    return
        newClass = CppClass(self.nameStack)
        if len(newClass.keys()):
            self.curClass = newClass["name"]
            self.classes[self.curClass] = newClass
        else:
            self.curClass = ""

使用的c++头文件例子如下:

测试输出结果如下图所示:

 

后续可能还需要根据具体的需求进行修改,如对宏定义、命名空间、虚函数等进行支持,ply还真是不错,很方便!

评论

我的评论:

发表评论

请 登录 后发表评论。还没有在Zeuux哲思注册吗?现在 注册 !
王依依

回复 王依依  2009年08月14日 星期五 09:56

有个 ply 的大学课程

1条回复

赵斌

回复 赵斌  2009年08月14日 星期五 01:32

贴代码时可以到
"发芽"里刷一下,比较方便,贴过来就有高亮了
http://fayaa.com/code/

2条回复

  • 李桑

    回复 李桑  2009年08月14日 星期五 08:56

    格式化后数据太大,无法保存啊,把我的图都覆盖没了~

    1条回复

夏清然

回复 夏清然  2009年08月13日 星期四 20:18

留名,一会儿研究一下。

1条回复

暂时没有评论

Zeuux © 2023

京ICP备05028076号