Package pygccxml :: Package parser :: Module scanner

Source Code for Module pygccxml.parser.scanner

  1  # Copyright 2004-2008 Roman Yakovenko. 
  2  # Distributed under the Boost Software License, Version 1.0. (See 
  3  # accompanying file LICENSE_1_0.txt or copy at 
  4  # http://www.boost.org/LICENSE_1_0.txt) 
  5   
  6  import os 
  7  import types 
  8  import pprint 
  9  import xml.sax 
 10  import warnings 
 11  import xml.sax.handler 
 12  from pygccxml.declarations import * 
 13  from pygccxml import utils 
 14   
 15  ##convention 
 16  #XML_NN - XML Node Name 
 17  #XML_AN - XML Attribute Name 
 18  #also those constants are sorted for easy searching. 
 19  XML_AN_ABSTRACT = "abstract" 
 20  XML_AN_ACCESS = "access" 
 21  XML_AN_ALIGN = "align" 
 22  XML_AN_ARTIFICIAL = "artificial" 
 23  XML_AN_ATTRIBUTES = "attributes" 
 24  XML_AN_BASE_TYPE = "basetype" 
 25  XML_AN_BASES = "bases" 
 26  XML_AN_BITS = "bits" 
 27  XML_AN_CONST = "const" 
 28  XML_AN_CONTEXT = "context" 
 29  XML_AN_CVS_REVISION = "cvs_revision" 
 30  XML_AN_DEFAULT = "default" 
 31  XML_AN_DEMANGLED = "demangled" 
 32  XML_AN_EXTERN = "extern" 
 33  XML_AN_FILE = "file" 
 34  XML_AN_ID = "id" 
 35  XML_AN_INCOMPLETE = "incomplete" 
 36  XML_AN_INIT = "init" 
 37  XML_AN_LINE = "line" 
 38  XML_AN_MANGLED = "mangled" 
 39  XML_AN_MAX = "max" 
 40  XML_AN_MEMBERS = "members" 
 41  XML_AN_MUTABLE = "mutable" 
 42  XML_AN_NAME = "name" 
 43  XML_AN_OFFSET = "offset" 
 44  XML_AN_PURE_VIRTUAL = "pure_virtual" 
 45  XML_AN_RESTRICT = "restrict" 
 46  XML_AN_RETURNS = "returns" 
 47  XML_AN_SIZE = "size" 
 48  XML_AN_STATIC = "static" 
 49  XML_AN_THROW = "throw" 
 50  XML_AN_TYPE = "type" 
 51  XML_AN_VIRTUAL = "virtual" 
 52  XML_AN_VOLATILE = "volatile" 
 53  XML_NN_ARGUMENT = "Argument" 
 54  XML_NN_ARRAY_TYPE = "ArrayType" 
 55  XML_NN_CASTING_OPERATOR = "Converter" 
 56  XML_NN_CLASS = "Class" 
 57  XML_NN_CONSTRUCTOR = "Constructor" 
 58  XML_NN_CV_QUALIFIED_TYPE = "CvQualifiedType" 
 59  XML_NN_DESTRUCTOR = "Destructor" 
 60  XML_NN_ELLIPSIS = "Ellipsis" 
 61  XML_NN_ENUMERATION = "Enumeration" 
 62  XML_NN_ENUMERATION_VALUE = "EnumValue" 
 63  XML_NN_FIELD = "Field" 
 64  XML_NN_FILE = "File" 
 65  XML_NN_FUNCTION = "Function" 
 66  XML_NN_FUNCTION_TYPE = "FunctionType" 
 67  XML_NN_FUNDAMENTAL_TYPE = "FundamentalType" 
 68  XML_NN_FREE_OPERATOR = "OperatorFunction" 
 69  XML_NN_GCC_XML = "GCC_XML" 
 70  XML_NN_MEMBER_OPERATOR = "OperatorMethod" 
 71  XML_NN_METHOD = "Method" 
 72  XML_NN_METHOD_TYPE = "MethodType" 
 73  XML_NN_NAMESPACE = "Namespace" 
 74  XML_NN_OFFSET_TYPE = "OffsetType" 
 75  XML_NN_POINTER_TYPE = "PointerType" 
 76  XML_NN_REFERENCE_TYPE = "ReferenceType" 
 77  XML_NN_ROOT = "GCC_XML" 
 78  XML_NN_STRUCT = "Struct" 
 79  XML_NN_TYPEDEF = "Typedef" 
 80  XML_NN_UNION = "Union" 
 81  XML_NN_VARIABLE = "Variable" 
 82   
83 -class scanner_t( xml.sax.handler.ContentHandler ):
84 - def __init__(self, gccxml_file, decl_factory, *args ):
85 xml.sax.handler.ContentHandler.__init__(self, *args ) 86 self.logger = utils.loggers.gccxml 87 self.gccxml_file = gccxml_file 88 #defining parsing tables 89 self.__readers = { 90 XML_NN_FILE : self.__read_file 91 , XML_NN_NAMESPACE : self.__read_namespace 92 , XML_NN_ENUMERATION : self.__read_enumeration 93 , XML_NN_ENUMERATION_VALUE : self.__read_enumeration_value 94 , XML_NN_ARRAY_TYPE : self.__read_array_type 95 , XML_NN_CV_QUALIFIED_TYPE : self.__read_cv_qualified_type 96 , XML_NN_POINTER_TYPE : self.__read_pointer_type 97 , XML_NN_REFERENCE_TYPE : self.__read_reference_type 98 , XML_NN_FUNDAMENTAL_TYPE : self.__read_fundamental_type 99 , XML_NN_ARGUMENT : self.__read_argument 100 , XML_NN_FUNCTION_TYPE : self.__read_function_type 101 , XML_NN_METHOD_TYPE : self.__read_method_type 102 , XML_NN_OFFSET_TYPE : self.__read_offset_type 103 , XML_NN_TYPEDEF : self.__read_typedef 104 , XML_NN_VARIABLE : self.__read_variable 105 , XML_NN_CLASS : self.__read_class 106 , XML_NN_STRUCT : self.__read_struct 107 , XML_NN_UNION : self.__read_union 108 , XML_NN_FIELD : self.__read_field 109 , XML_NN_CASTING_OPERATOR : self.__read_casting_operator 110 , XML_NN_CONSTRUCTOR : self.__read_constructor 111 , XML_NN_DESTRUCTOR : self.__read_destructor 112 , XML_NN_FUNCTION : self.__read_function 113 , XML_NN_FREE_OPERATOR : self.__read_free_operator 114 , XML_NN_MEMBER_OPERATOR : self.__read_member_operator 115 , XML_NN_METHOD : self.__read_method 116 , XML_NN_GCC_XML : self.__read_version 117 , XML_NN_ELLIPSIS : self.__read_ellipsis 118 } 119 self.deep_declarations = [ 120 XML_NN_CASTING_OPERATOR 121 , XML_NN_CONSTRUCTOR 122 , XML_NN_DESTRUCTOR 123 , XML_NN_ENUMERATION 124 , XML_NN_FILE 125 , XML_NN_FUNCTION 126 , XML_NN_FREE_OPERATOR 127 , XML_NN_MEMBER_OPERATOR 128 , XML_NN_METHOD 129 , XML_NN_FUNCTION_TYPE 130 , XML_NN_METHOD_TYPE 131 ] 132 133 assert isinstance( decl_factory, decl_factory_t ) 134 self.__decl_factory = decl_factory 135 136 #mapping from id -> decl 137 self.__declarations = {} 138 #list of all read declarations 139 self.__calldefs = [] 140 #list of enums I need later 141 self.__enums = [] 142 #mapping from id -> type 143 self.__types = {} 144 #mapping from id -> file 145 self.__files = {} 146 #mapping between decl id -> access 147 self.__access = {} 148 #current object under construction 149 self.__inst = None 150 #mapping from id to members 151 self.__members = {} 152 153 self.__compiler = None
154
155 - def read( self ):
156 xml.sax.parse( self.gccxml_file, self )
157
158 - def endDocument( self ):
159 #updating membership 160 members_mapping = {} 161 for gccxml_id, members in self.__members.iteritems(): 162 decl = self.__declarations.get( gccxml_id, None ) 163 if not decl or not isinstance( decl, scopedef_t): 164 continue 165 members_mapping[ id( decl ) ] = members 166 self.__members = members_mapping
167
168 - def declarations(self):
169 return self.__declarations
170
171 - def calldefs( self ):
172 return self.__calldefs
173
174 - def enums(self):
175 return self.__enums
176
177 - def types(self):
178 return self.__types
179
180 - def files(self):
181 return self.__files
182
183 - def access(self):
184 return self.__access
185
186 - def members(self):
187 return self.__members
188
189 - def startElementNS(self, name, qname, attrs):
190 return self.startElement( name[1], attrs )
191
192 - def endElementNS(self, name, qname):
193 return self.endElement( name[1] )
194
195 - def startElement(self, name, attrs):
196 try: 197 if name not in self.__readers: 198 return 199 obj = self.__readers[name]( attrs ) 200 if not obj: 201 return #it means that we worked on internals 202 #for example EnumValue of function argument 203 if name in self.deep_declarations: 204 self.__inst = obj 205 self.__read_access( attrs ) 206 element_id = attrs.get(XML_AN_ID, None) 207 if isinstance( obj, declaration_t ): 208 obj.compiler = self.__compiler 209 self.__update_membership( attrs ) 210 self.__declarations[ element_id ] = obj 211 if not isinstance( obj, namespace_t ): 212 self.__read_location( obj, attrs ) 213 if isinstance( obj, class_t): 214 self.__read_bases( obj, attrs ) 215 self.__read_artificial(obj, attrs) 216 self.__read_mangled( obj, attrs) 217 self.__read_demangled( obj, attrs) 218 self.__read_attributes(obj, attrs) 219 220 elif isinstance( obj, type_t ): 221 self.__types[ element_id ] = obj 222 self.__read_byte_size(obj, attrs) 223 self.__read_byte_align(obj, attrs) 224 elif isinstance( obj, types.StringTypes ): 225 self.__files[ element_id ] = obj 226 else: 227 self.logger.warning( 'Unknown object type has been found.' 228 + ' Please report this bug to pygccxml development team.' ) 229 except Exception, error: 230 msg = 'error occured, while parsing element with name "%s" and attrs "%s".' 231 msg = msg + os.linesep + 'Error: %s.' % str( error ) 232 self.logger.error( msg % ( name, pprint.pformat( attrs.keys() ) ) ) 233 raise
234
235 - def endElement(self, name):
236 if name in self.deep_declarations: 237 self.__inst = None
238
239 - def __read_location(self, decl, attrs):
241
242 - def __update_membership(self, attrs):
243 parent = attrs.get( XML_AN_CONTEXT, None ) 244 if not parent: 245 return 246 if not self.__members.has_key( parent ): 247 self.__members[ parent ] = [] 248 self.__members[parent].append( attrs[XML_AN_ID] )
249
250 - def __read_members(self, decl, attrs ):
251 decl.declarations = attrs.get(XML_AN_MEMBERS, "")
252
253 - def __read_bases(self, decl, attrs ):
254 decl.bases = attrs.get( XML_AN_BASES, "" )
255
256 - def __read_artificial( self, decl, attrs ):
257 decl.is_artificial = attrs.get( XML_AN_ARTIFICIAL, False )
258
259 - def __read_mangled( self, decl, attrs ):
260 decl.mangled = attrs.get( XML_AN_MANGLED, None )
261
262 - def __read_demangled( self, decl, attrs ):
263 decl.demangled = attrs.get( XML_AN_DEMANGLED, None )
264
265 - def __read_attributes( self, decl, attrs ):
266 decl.attributes = attrs.get( XML_AN_ATTRIBUTES, None )
267
268 - def __read_access( self, attrs ):
269 self.__access[ attrs[XML_AN_ID] ] = attrs.get( XML_AN_ACCESS, ACCESS_TYPES.PUBLIC )
270
271 - def __read_byte_size (self, decl, attrs):
272 "Using duck typing to set the size instead of in constructor" 273 size = attrs.get(XML_AN_SIZE, 0) 274 decl.byte_size = int(size)/8 # Make sure the size is in bytes instead of bits
275
276 - def __read_byte_offset (self, decl, attrs):
277 "Using duck typing to set the offset instead of in constructor" 278 offset = attrs.get(XML_AN_OFFSET, 0) 279 decl.byte_offset = int(offset)/8 # Make sure the size is in bytes instead of bits
280
281 - def __read_byte_align (self, decl, attrs):
282 "Using duck typing to set the alignment" 283 align = attrs.get(XML_AN_ALIGN, 0) 284 decl.byte_align = int(align)/8 # Make sure the size is in bytes instead of bits
285
286 - def __read_root(self, attrs):
287 pass
288
289 - def __read_file( self, attrs ):
290 return attrs.get( XML_AN_NAME, '' )
291
292 - def __read_namespace(self, attrs):
293 ns_name = attrs.get( XML_AN_NAME, '' ) 294 if '.' in ns_name: 295 #if '.' in namespace then this is mangled namespace -> in c++ namespace{...} 296 #that is almost true: gcc mangale name using top file name. 297 #almost all files has '.' in name 298 ns_name = '' 299 return self.__decl_factory.create_namespace( name=ns_name )
300
301 - def __read_enumeration(self, attrs):
302 enum_name = attrs.get( XML_AN_NAME, '' ) 303 if '$_' in enum_name or '._' in enum_name: 304 #it means that this is unnamed enum. in c++ enum{ x }; 305 enum_name = '' 306 decl = self.__decl_factory.create_enumeration( name=enum_name ) 307 self.__read_byte_size(decl, attrs) 308 self.__read_byte_align(decl, attrs) 309 self.__enums.append( decl ) 310 return decl
311
312 - def __read_enumeration_value( self, attrs ):
313 name = attrs.get( XML_AN_NAME, '' ) 314 num = int(attrs[XML_AN_INIT]) 315 self.__inst.append_value(name, num)
316
317 - def __guess_int_value( self, value_as_str ):
318 #returns instance of int or None 319 #if gcc compiled the code, than it is correct! 320 numeric_suffix_letters = 'UuLlFf' 321 for s in numeric_suffix_letters: 322 value_as_str = value_as_str.replace( s, '' ) 323 try: 324 return int( value_as_str ) 325 except ValueError: 326 try: 327 return int( value_as_str, 16 ) 328 except ValueError: 329 return None
330
331 - def __read_array_type( self, attrs ):
332 type_ = attrs[ XML_AN_TYPE ] 333 size = self.__guess_int_value( attrs.get(XML_AN_MAX, '' ) ) 334 if size is None: 335 size = array_t.SIZE_UNKNOWN 336 msg = 'unable to find out array size from expression "%s"' % attrs[ XML_AN_MAX ] 337 warnings.warn( msg ) 338 return array_t( type_, size + 1 )
339
340 - def __read_cv_qualified_type( self, attrs ):
341 if attrs.has_key( XML_AN_CONST ): 342 return const_t( attrs[XML_AN_TYPE] ) 343 elif attrs.has_key( XML_AN_VOLATILE ): 344 return volatile_t( attrs[XML_AN_TYPE] ) 345 elif attrs.has_key( XML_AN_RESTRICT ): 346 return restrict_t( attrs[XML_AN_TYPE] ) 347 else: 348 assert 0
349
350 - def __read_pointer_type( self, attrs ):
351 return pointer_t( attrs[XML_AN_TYPE] )
352
353 - def __read_reference_type( self, attrs ):
354 return reference_t( attrs[XML_AN_TYPE] )
355
356 - def __read_fundamental_type(self, attrs ):
357 try: 358 return FUNDAMENTAL_TYPES[ attrs.get( XML_AN_NAME, '' ) ] 359 except KeyError: 360 raise RuntimeError( "pygccxml error: unable to find fundamental type with name '%s'." 361 % attrs.get( XML_AN_NAME, '' ) )
362
363 - def __read_offset_type( self,attrs ):
364 base = attrs[ XML_AN_BASE_TYPE ] 365 type_ = attrs[ XML_AN_TYPE ] 366 if '0.9' in self.__compiler: 367 return pointer_t( member_variable_type_t( class_inst=base, variable_type=type_ ) ) 368 else: 369 return member_variable_type_t( class_inst=base, variable_type=type_ )
370
371 - def __read_argument( self, attrs ):
372 if isinstance( self.__inst, calldef_type_t ): 373 self.__inst.arguments_types.append( attrs[XML_AN_TYPE] ) 374 else: 375 argument = argument_t() 376 argument.name = attrs.get( XML_AN_NAME, 'arg%d' % len(self.__inst.arguments) ) 377 argument.type = attrs[XML_AN_TYPE] 378 argument.default_value = attrs.get( XML_AN_DEFAULT, None ) 379 self.__read_attributes( argument, attrs ) 380 if argument.default_value == '<gccxml-cast-expr>': 381 argument.default_value = None 382 self.__inst.arguments.append( argument )
383
384 - def __read_ellipsis( self, attrs ):
385 if isinstance( self.__inst, calldef_type_t ): 386 self.__inst.arguments_types.append( '...' ) 387 else: 388 argument = argument_t( type='...' ) 389 self.__inst.arguments.append( argument )
390
391 - def __read_calldef( self, calldef, attrs, is_declaration ):
392 #destructor for example doesn't have return type 393 calldef.return_type = attrs.get( XML_AN_RETURNS, None ) 394 if is_declaration: 395 self.__calldefs.append( calldef ) 396 calldef.name = attrs.get(XML_AN_NAME, '') 397 calldef.has_extern = attrs.get( XML_AN_EXTERN, False ) 398 throw_stmt = attrs.get( XML_AN_THROW, None ) 399 if None is throw_stmt: 400 calldef.does_throw = True 401 calldef.exceptions = [] 402 elif "" == throw_stmt: 403 calldef.does_throw = False 404 calldef.exceptions = [] 405 else: 406 calldef.does_throw = True 407 calldef.exceptions = throw_stmt.split()
408
409 - def __read_member_function( self, calldef, attrs, is_declaration ):
410 self.__read_calldef( calldef, attrs, is_declaration ) 411 calldef.has_const = attrs.get( XML_AN_CONST, False ) 412 if is_declaration: 413 calldef.has_static = attrs.get( XML_AN_STATIC, False ) 414 if attrs.has_key( XML_AN_PURE_VIRTUAL ): 415 calldef.virtuality = VIRTUALITY_TYPES.PURE_VIRTUAL 416 elif attrs.has_key( XML_AN_VIRTUAL ): 417 calldef.virtuality = VIRTUALITY_TYPES.VIRTUAL 418 else: 419 calldef.virtuality = VIRTUALITY_TYPES.NOT_VIRTUAL 420 else: 421 calldef.class_inst = attrs[XML_AN_BASE_TYPE]
422
423 - def __read_function_type(self, attrs):
424 answer = free_function_type_t() 425 self.__read_calldef( answer, attrs, False ) 426 return answer
427
428 - def __read_method_type(self, attrs):
429 answer = member_function_type_t() 430 self.__read_member_function( answer, attrs, False ) 431 return answer
432
433 - def __read_typedef(self, attrs ):
434 return self.__decl_factory.create_typedef( name=attrs.get( XML_AN_NAME, '' ), type=attrs[XML_AN_TYPE])
435
436 - def __read_variable(self, attrs ):
437 type_qualifiers = type_qualifiers_t() 438 type_qualifiers.has_mutable = attrs.get(XML_AN_MUTABLE, False) 439 type_qualifiers.has_static = attrs.get(XML_AN_EXTERN, False) 440 bits = attrs.get( XML_AN_BITS, None ) 441 if bits: 442 bits = int( bits ) 443 decl = self.__decl_factory.create_variable( name=attrs.get( XML_AN_NAME, '' ) 444 , type=attrs[XML_AN_TYPE] 445 , type_qualifiers=type_qualifiers 446 , value=attrs.get( XML_AN_INIT, None ) 447 , bits=bits) 448 self.__read_byte_offset(decl, attrs) 449 return decl
450 451 __read_field = __read_variable #just a synonim 452
453 - def __read_class_impl(self, class_type, attrs):
454 decl = None 455 name = attrs.get(XML_AN_NAME, '') 456 if '$' in name or '.' in name: 457 name = '' 458 if attrs.has_key( XML_AN_INCOMPLETE ): 459 decl = self.__decl_factory.create_class_declaration(name=name) 460 else: 461 decl = self.__decl_factory.create_class( name=name, class_type=class_type ) 462 if attrs.get( XML_AN_ABSTRACT, False ): 463 decl.is_abstract = True 464 else: 465 decl.is_abstract = False 466 self.__read_byte_size(decl, attrs) 467 self.__read_byte_align(decl, attrs) 468 return decl
469
470 - def __read_class( self, attrs ):
471 return self.__read_class_impl( CLASS_TYPES.CLASS, attrs )
472
473 - def __read_struct( self, attrs ):
474 return self.__read_class_impl( CLASS_TYPES.STRUCT, attrs )
475
476 - def __read_union( self, attrs ):
477 return self.__read_class_impl( CLASS_TYPES.UNION, attrs )
478
479 - def __read_casting_operator(self, attrs ):
480 operator = self.__decl_factory.create_casting_operator() 481 self.__read_member_function( operator, attrs, True ) 482 return operator
483
484 - def __read_constructor( self, attrs ):
485 constructor = self.__decl_factory.create_constructor() 486 self.__read_member_function( constructor, attrs, True ) 487 return constructor
488
489 - def __read_function(self, attrs):
490 gfunction = self.__decl_factory.create_free_function() 491 self.__read_calldef( gfunction, attrs, True ) 492 return gfunction
493
494 - def __read_method(self, attrs):
495 mfunction = self.__decl_factory.create_member_function() 496 self.__read_member_function( mfunction, attrs, True ) 497 return mfunction
498
499 - def __read_destructor(self, attrs):
500 destructor = self.__decl_factory.create_destructor() 501 self.__read_member_function( destructor, attrs, True ) 502 destructor.name = '~' + destructor.name 503 return destructor
504
505 - def __read_free_operator(self, attrs ):
506 operator = self.__decl_factory.create_free_operator() 507 self.__read_member_function( operator, attrs, True ) 508 if 'new' in operator.name or 'delete' in operator.name: 509 operator.name = 'operator ' + operator.name 510 else: 511 operator.name = 'operator' + operator.name 512 return operator
513
514 - def __read_member_operator(self, attrs):
515 operator = self.__decl_factory.create_member_operator() 516 self.__read_member_function( operator, attrs, True ) 517 if 'new' in operator.name or 'delete' in operator.name: 518 operator.name = 'operator ' + operator.name 519 else: 520 operator.name = 'operator' + operator.name 521 return operator
522
523 - def __read_version(self, attrs):
524 logger = utils.loggers.cxx_parser 525 526 version = float( attrs.get(XML_AN_CVS_REVISION, 0.6) ) 527 if version is None: 528 logger.info ( 'GCCXML version - 0.6' ) 529 self.__compiler = compilers.GCC_XML_06 530 elif version <= 1.114: 531 logger.info ( 'GCCXML version - 0.7' ) 532 self.__compiler = compilers.GCC_XML_07 533 elif version in ( 1.115, 1.116, 1.117, 1.118, 1.119, 1.120, 1.121 ): 534 logger.info ( 'GCCXML version - 0.9 BUGGY' ) 535 self.__compiler = compilers.GCC_XML_09_BUGGY 536 else: 537 logger.info ( 'GCCXML version - 0.9' ) 538 self.__compiler = compilers.GCC_XML_09
539