gccxmlparser.py
来自「Boost provides free peer-reviewed portab」· Python 代码 · 共 475 行 · 第 1/2 页
PY
475 行
# Copyright Bruno da Silva de Oliveira 2003. Use, modification and # distribution is subject to the Boost Software License, Version 1.0.# (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt)from declarations import *# try to use cElementTree if avaiabletry: from cElementTree import ElementTree except ImportError: # fall back to the normal elementtree from elementtree.ElementTree import ElementTreefrom xml.parsers.expat import ExpatErrorfrom copy import deepcopyfrom utils import enumerate#==============================================================================# Exceptions#==============================================================================class InvalidXMLError(Exception): passclass ParserError(Exception): passclass InvalidContextError(ParserError): pass#==============================================================================# GCCXMLParser#==============================================================================class GCCXMLParser(object): 'Parse a GCC_XML file and extract the top-level declarations.' interested_tags = {'Class':0, 'Function':0, 'Variable':0, 'Enumeration':0} def Parse(self, filename): self.elements = self.GetElementsFromXML(filename) # high level declarations self.declarations = [] self._names = {} # parse the elements for id in self.elements: element, decl = self.elements[id] if decl is None: try: self.ParseElement(id, element) except InvalidContextError: pass # ignore those nodes with invalid context # (workaround gccxml bug) def Declarations(self): return self.declarations def AddDecl(self, decl): if decl.FullName() in self._names: decl.is_unique= False for d in self.declarations: if d.FullName() == decl.FullName(): d.is_unique = False self._names[decl.FullName()] = 0 self.declarations.append(decl) def ParseElement(self, id, element): method = 'Parse' + element.tag if hasattr(self, method): func = getattr(self, method) func(id, element) else: self.ParseUnknown(id, element) def GetElementsFromXML(self,filename): 'Extracts a dictionary of elements from the gcc_xml file.' tree = ElementTree() try: tree.parse(filename) except ExpatError: raise InvalidXMLError, 'Not a XML file: %s' % filename root = tree.getroot() if root.tag != 'GCC_XML': raise InvalidXMLError, 'Not a valid GCC_XML file' # build a dictionary of id -> element, None elementlist = root.getchildren() elements = {} for element in elementlist: id = element.get('id') if id: elements[id] = element, None return elements def GetDecl(self, id): if id not in self.elements: if id == '_0': raise InvalidContextError, 'Invalid context found in the xml file.' else: msg = 'ID not found in elements: %s' % id raise ParserError, msg elem, decl = self.elements[id] if decl is None: self.ParseElement(id, elem) elem, decl = self.elements[id] if decl is None: raise ParserError, 'Could not parse element: %s' % elem.tag return decl def GetType(self, id): def Check(id, feature): pos = id.find(feature) if pos != -1: id = id[:pos] + id[pos+1:] return True, id else: return False, id const, id = Check(id, 'c') volatile, id = Check(id, 'v') restricted, id = Check(id, 'r') decl = self.GetDecl(id) if isinstance(decl, Type): res = deepcopy(decl) if const: res.const = const if volatile: res.volatile = volatile if restricted: res.restricted = restricted else: res = Type(decl.FullName(), const) res.volatile = volatile res.restricted = restricted return res def GetLocation(self, location): file, line = location.split(':') file = self.GetDecl(file) return file, int(line) def Update(self, id, decl): element, _ = self.elements[id] self.elements[id] = element, decl def ParseUnknown(self, id, element): name = '__Unknown_Element_%s' % id decl = Unknown(name) self.Update(id, decl) def ParseNamespace(self, id, element): namespace = element.get('name') context = element.get('context') if context: outer = self.GetDecl(context) if not outer.endswith('::'): outer += '::' namespace = outer + namespace if namespace.startswith('::'): namespace = namespace[2:] self.Update(id, namespace) def ParseFile(self, id, element): filename = element.get('name') self.Update(id, filename) def ParseVariable(self, id, element): # in gcc_xml, a static Field is declared as a Variable, so we check # this and call the Field parser. context = self.GetDecl(element.get('context')) if isinstance(context, Class): self.ParseField(id, element) elem, decl = self.elements[id] decl.static = True else: namespace = context name = element.get('name') type_ = self.GetType(element.get('type')) location = self.GetLocation(element.get('location')) variable = Variable(type_, name, namespace) variable.location = location self.AddDecl(variable) self.Update(id, variable) def GetArguments(self, element): args = [] for child in element: if child.tag == 'Argument': type = self.GetType(child.get('type')) type.default = child.get('default') args.append(type) return args def GetExceptions(self, exception_list): if exception_list is None: return None exceptions = [] for t in exception_list.split(): exceptions.append(self.GetType(t)) return exceptions def ParseFunction(self, id, element, functionType=Function): '''functionType is used because a Operator is identical to a normal function, only the type of the function changes.''' name = element.get('name') returns = self.GetType(element.get('returns')) namespace = self.GetDecl(element.get('context')) location = self.GetLocation(element.get('location')) params = self.GetArguments(element) incomplete = bool(int(element.get('incomplete', 0))) throws = self.GetExceptions(element.get('throw', None)) function = functionType(name, namespace, returns, params, throws) function.location = location self.AddDecl(function) self.Update(id, function) def ParseOperatorFunction(self, id, element): self.ParseFunction(id, element, Operator) def GetHierarchy(self, bases): '''Parses the string "bases" from the xml into a list of tuples of Base
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?