1#------------------------------------------------------------------------- 2# CxxTest: A lightweight C++ unit testing library. 3# Copyright (c) 2008 Sandia Corporation. 4# This software is distributed under the LGPL License v2.1 5# For more information, see the COPYING file in the top CxxTest directory. 6# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, 7# the U.S. Government retains certain rights in this software. 8#------------------------------------------------------------------------- 9 10# vim: fileencoding=utf-8 11 12# 13# This is a PLY parser for the entire ANSI C++ grammar. This grammar was 14# adapted from the FOG grammar developed by E. D. Willink. See 15# 16# http://www.computing.surrey.ac.uk/research/dsrg/fog/ 17# 18# for further details. 19# 20# The goal of this grammar is to extract information about class, function and 21# class method declarations, along with their associated scope. Thus, this 22# grammar can be used to analyze classes in an inheritance heirarchy, and then 23# enumerate the methods in a derived class. 24# 25# This grammar parses blocks of <>, (), [] and {} in a generic manner. Thus, 26# There are several capabilities that this grammar does not support: 27# 28# 1. Ambiguous template specification. This grammar cannot parse template 29# specifications that do not have paired <>'s in their declaration. In 30# particular, ambiguous declarations like 31# 32# foo<A, c<3 >(); 33# 34# cannot be correctly parsed. 35# 36# 2. Template class specialization. Although the goal of this grammar is to 37# extract class information, specialization of templated classes is 38# not supported. When a template class definition is parsed, it's 39# declaration is archived without information about the template 40# parameters. Class specializations will be stored separately, and 41# thus they can be processed after the fact. However, this grammar 42# does not attempt to correctly process properties of class inheritence 43# when template class specialization is employed. 44# 45 46# 47# TODO: document usage of this file 48# 49 50 51 52import os 53import ply.lex as lex 54import ply.yacc as yacc 55import re 56try: 57 from collections import OrderedDict 58except ImportError: 59 from ordereddict import OrderedDict 60 61lexer = None 62scope_lineno = 0 63identifier_lineno = {} 64_parse_info=None 65_parsedata=None 66noExceptionLogic = True 67 68def ply_init(data): 69 global _parsedata 70 _parsedata=data 71 72 73class Scope(object): 74 75 def __init__(self,name,abs_name,scope_t,base_classes,lineno): 76 self.function=[] 77 self.name=name 78 self.scope_t=scope_t 79 self.sub_scopes=[] 80 self.base_classes=base_classes 81 self.abs_name=abs_name 82 self.lineno=lineno 83 84 def insert(self,scope): 85 self.sub_scopes.append(scope) 86 87 88class CppInfo(object): 89 90 def __init__(self, filter=None): 91 self.verbose=0 92 if filter is None: 93 self.filter=re.compile("[Tt][Ee][Ss][Tt]|createSuite|destroySuite") 94 else: 95 self.filter=filter 96 self.scopes=[""] 97 self.index=OrderedDict() 98 self.index[""]=Scope("","::","namespace",[],1) 99 self.function=[] 100 101 def push_scope(self,ns,scope_t,base_classes=[]): 102 name = self.scopes[-1]+"::"+ns 103 if self.verbose>=2: 104 print("-- Starting "+scope_t+" "+name) 105 self.scopes.append(name) 106 self.index[name] = Scope(ns,name,scope_t,base_classes,scope_lineno-1) 107 108 def pop_scope(self): 109 scope = self.scopes.pop() 110 if self.verbose>=2: 111 print("-- Stopping "+scope) 112 return scope 113 114 def add_function(self, fn): 115 fn = str(fn) 116 if self.filter.search(fn): 117 self.index[self.scopes[-1]].function.append((fn, identifier_lineno.get(fn,lexer.lineno-1))) 118 tmp = self.scopes[-1]+"::"+fn 119 if self.verbose==2: 120 print("-- Function declaration "+fn+" "+tmp) 121 elif self.verbose==1: 122 print("-- Function declaration "+tmp) 123 124 def get_functions(self,name,quiet=False): 125 if name == "::": 126 name = "" 127 scope = self.index[name] 128 fns=scope.function 129 for key in scope.base_classes: 130 cname = self.find_class(key,scope) 131 if cname is None: 132 if not quiet: 133 print("Defined classes: ",list(self.index.keys())) 134 print("WARNING: Unknown class "+key) 135 else: 136 fns += self.get_functions(cname,quiet) 137 return fns 138 139 def find_class(self,name,scope): 140 if ':' in name: 141 if name in self.index: 142 return name 143 else: 144 return None 145 tmp = scope.abs_name.split(':') 146 name1 = ":".join(tmp[:-1] + [name]) 147 if name1 in self.index: 148 return name1 149 name2 = "::"+name 150 if name2 in self.index: 151 return name2 152 return None 153 154 def __repr__(self): 155 return str(self) 156 157 def is_baseclass(self,cls,base): 158 '''Returns true if base is a base-class of cls''' 159 if cls in self.index: 160 bases = self.index[cls] 161 elif "::"+cls in self.index: 162 bases = self.index["::"+cls] 163 else: 164 return False 165 #raise IOError, "Unknown class "+cls 166 if base in bases.base_classes: 167 return True 168 for name in bases.base_classes: 169 if self.is_baseclass(name,base): 170 return True 171 return False 172 173 def __str__(self): 174 ans="" 175 keys = list(self.index.keys()) 176 keys.sort() 177 for key in keys: 178 scope = self.index[key] 179 ans += scope.scope_t+" "+scope.abs_name+"\n" 180 if scope.scope_t == "class": 181 ans += " Base Classes: "+str(scope.base_classes)+"\n" 182 for fn in self.get_functions(scope.abs_name): 183 ans += " "+fn+"\n" 184 else: 185 for fn in scope.function: 186 ans += " "+fn+"\n" 187 return ans 188 189 190def flatten(x): 191 """Flatten nested list""" 192 try: 193 strtypes = str 194 except: # for python3 etc 195 strtypes = (str, bytes) 196 197 result = [] 198 for el in x: 199 if hasattr(el, "__iter__") and not isinstance(el, strtypes): 200 result.extend(flatten(el)) 201 else: 202 result.append(el) 203 return result 204 205# 206# The lexer (and/or a preprocessor) is expected to identify the following 207# 208# Punctuation: 209# 210# 211literals = "+-*/%^&|~!<>=:()?.\'\"\\@$;," 212 213# 214reserved = { 215 'private' : 'PRIVATE', 216 'protected' : 'PROTECTED', 217 'public' : 'PUBLIC', 218 219 'bool' : 'BOOL', 220 'char' : 'CHAR', 221 'double' : 'DOUBLE', 222 'float' : 'FLOAT', 223 'int' : 'INT', 224 'long' : 'LONG', 225 'short' : 'SHORT', 226 'signed' : 'SIGNED', 227 'unsigned' : 'UNSIGNED', 228 'void' : 'VOID', 229 'wchar_t' : 'WCHAR_T', 230 231 'class' : 'CLASS', 232 'enum' : 'ENUM', 233 'namespace' : 'NAMESPACE', 234 'struct' : 'STRUCT', 235 'typename' : 'TYPENAME', 236 'union' : 'UNION', 237 238 'const' : 'CONST', 239 'volatile' : 'VOLATILE', 240 241 'auto' : 'AUTO', 242 'explicit' : 'EXPLICIT', 243 'export' : 'EXPORT', 244 'extern' : 'EXTERN', 245 '__extension__' : 'EXTENSION', 246 'friend' : 'FRIEND', 247 'inline' : 'INLINE', 248 'mutable' : 'MUTABLE', 249 'register' : 'REGISTER', 250 'static' : 'STATIC', 251 'template' : 'TEMPLATE', 252 'typedef' : 'TYPEDEF', 253 'using' : 'USING', 254 'virtual' : 'VIRTUAL', 255 256 'asm' : 'ASM', 257 'break' : 'BREAK', 258 'case' : 'CASE', 259 'catch' : 'CATCH', 260 'const_cast' : 'CONST_CAST', 261 'continue' : 'CONTINUE', 262 'default' : 'DEFAULT', 263 'delete' : 'DELETE', 264 'do' : 'DO', 265 'dynamic_cast' : 'DYNAMIC_CAST', 266 'else' : 'ELSE', 267 'false' : 'FALSE', 268 'for' : 'FOR', 269 'goto' : 'GOTO', 270 'if' : 'IF', 271 'new' : 'NEW', 272 'operator' : 'OPERATOR', 273 'reinterpret_cast' : 'REINTERPRET_CAST', 274 'return' : 'RETURN', 275 'sizeof' : 'SIZEOF', 276 'static_cast' : 'STATIC_CAST', 277 'switch' : 'SWITCH', 278 'this' : 'THIS', 279 'throw' : 'THROW', 280 'true' : 'TRUE', 281 'try' : 'TRY', 282 'typeid' : 'TYPEID', 283 'while' : 'WHILE', 284 '"C"' : 'CLiteral', 285 '"C++"' : 'CppLiteral', 286 287 '__attribute__' : 'ATTRIBUTE', 288 '__cdecl__' : 'CDECL', 289 '__typeof' : 'uTYPEOF', 290 'typeof' : 'TYPEOF', 291 292 'CXXTEST_STD' : 'CXXTEST_STD' 293} 294 295tokens = [ 296 "CharacterLiteral", 297 "FloatingLiteral", 298 "Identifier", 299 "IntegerLiteral", 300 "StringLiteral", 301 "RBRACE", 302 "LBRACE", 303 "RBRACKET", 304 "LBRACKET", 305 "ARROW", 306 "ARROW_STAR", 307 "DEC", 308 "EQ", 309 "GE", 310 "INC", 311 "LE", 312 "LOG_AND", 313 "LOG_OR", 314 "NE", 315 "SHL", 316 "SHR", 317 "ASS_ADD", 318 "ASS_AND", 319 "ASS_DIV", 320 "ASS_MOD", 321 "ASS_MUL", 322 "ASS_OR", 323 "ASS_SHL", 324 "ASS_SHR", 325 "ASS_SUB", 326 "ASS_XOR", 327 "DOT_STAR", 328 "ELLIPSIS", 329 "SCOPE", 330] + list(reserved.values()) 331 332t_ignore = " \t\r" 333 334t_LBRACE = r"(\{)|(<%)" 335t_RBRACE = r"(\})|(%>)" 336t_LBRACKET = r"(\[)|(<:)" 337t_RBRACKET = r"(\])|(:>)" 338t_ARROW = r"->" 339t_ARROW_STAR = r"->\*" 340t_DEC = r"--" 341t_EQ = r"==" 342t_GE = r">=" 343t_INC = r"\+\+" 344t_LE = r"<=" 345t_LOG_AND = r"&&" 346t_LOG_OR = r"\|\|" 347t_NE = r"!=" 348t_SHL = r"<<" 349t_SHR = r">>" 350t_ASS_ADD = r"\+=" 351t_ASS_AND = r"&=" 352t_ASS_DIV = r"/=" 353t_ASS_MOD = r"%=" 354t_ASS_MUL = r"\*=" 355t_ASS_OR = r"\|=" 356t_ASS_SHL = r"<<=" 357t_ASS_SHR = r">>=" 358t_ASS_SUB = r"-=" 359t_ASS_XOR = r"^=" 360t_DOT_STAR = r"\.\*" 361t_ELLIPSIS = r"\.\.\." 362t_SCOPE = r"::" 363 364# Discard comments 365def t_COMMENT(t): 366 r'(/\*(.|\n)*?\*/)|(//.*?\n)|(\#.*?\n)' 367 t.lexer.lineno += t.value.count("\n") 368 369t_IntegerLiteral = r'(0x[0-9A-F]+)|([0-9]+(L){0,1})' 370t_FloatingLiteral = r"[0-9]+[eE\.\+-]+[eE\.\+\-0-9]+" 371t_CharacterLiteral = r'\'([^\'\\]|\\.)*\'' 372#t_StringLiteral = r'"([^"\\]|\\.)*"' 373def t_StringLiteral(t): 374 r'"([^"\\]|\\.)*"' 375 t.type = reserved.get(t.value,'StringLiteral') 376 return t 377 378def t_Identifier(t): 379 r"[a-zA-Z_][a-zA-Z_0-9\.]*" 380 t.type = reserved.get(t.value,'Identifier') 381 return t 382 383 384def t_error(t): 385 print("Illegal character '%s'" % t.value[0]) 386 #raise IOError, "Parse error" 387 #t.lexer.skip() 388 389def t_newline(t): 390 r'[\n]+' 391 t.lexer.lineno += len(t.value) 392 393precedence = ( 394 ( 'right', 'SHIFT_THERE', 'REDUCE_HERE_MOSTLY', 'SCOPE'), 395 ( 'nonassoc', 'ELSE', 'INC', 'DEC', '+', '-', '*', '&', 'LBRACKET', 'LBRACE', '<', ':', ')') 396 ) 397 398start = 'translation_unit' 399 400# 401# The %prec resolves the 14.2-3 ambiguity: 402# Identifier '<' is forced to go through the is-it-a-template-name test 403# All names absorb TEMPLATE with the name, so that no template_test is 404# performed for them. This requires all potential declarations within an 405# expression to perpetuate this policy and thereby guarantee the ultimate 406# coverage of explicit_instantiation. 407# 408# The %prec also resolves a conflict in identifier : which is forced to be a 409# shift of a label for a labeled-statement rather than a reduction for the 410# name of a bit-field or generalised constructor. This is pretty dubious 411# syntactically but correct for all semantic possibilities. The shift is 412# only activated when the ambiguity exists at the start of a statement. 413# In this context a bit-field declaration or constructor definition are not 414# allowed. 415# 416 417def p_identifier(p): 418 '''identifier : Identifier 419 | CXXTEST_STD '(' Identifier ')' 420 ''' 421 if p[1][0] in ('t','T','c','d'): 422 identifier_lineno[p[1]] = p.lineno(1) 423 p[0] = p[1] 424 425def p_id(p): 426 '''id : identifier %prec SHIFT_THERE 427 | template_decl 428 | TEMPLATE id 429 ''' 430 p[0] = get_rest(p) 431 432def p_global_scope(p): 433 '''global_scope : SCOPE 434 ''' 435 p[0] = get_rest(p) 436 437def p_id_scope(p): 438 '''id_scope : id SCOPE''' 439 p[0] = get_rest(p) 440 441def p_id_scope_seq(p): 442 '''id_scope_seq : id_scope 443 | id_scope id_scope_seq 444 ''' 445 p[0] = get_rest(p) 446 447# 448# A :: B :: C; is ambiguous How much is type and how much name ? 449# The %prec maximises the (type) length which is the 7.1-2 semantic constraint. 450# 451def p_nested_id(p): 452 '''nested_id : id %prec SHIFT_THERE 453 | id_scope nested_id 454 ''' 455 p[0] = get_rest(p) 456 457def p_scoped_id(p): 458 '''scoped_id : nested_id 459 | global_scope nested_id 460 | id_scope_seq 461 | global_scope id_scope_seq 462 ''' 463 global scope_lineno 464 scope_lineno = lexer.lineno 465 data = flatten(get_rest(p)) 466 if data[0] != None: 467 p[0] = "".join(data) 468 469# 470# destructor_id has to be held back to avoid a conflict with a one's 471# complement as per 5.3.1-9, It gets put back only when scoped or in a 472# declarator_id, which is only used as an explicit member name. 473# Declarations of an unscoped destructor are always parsed as a one's 474# complement. 475# 476def p_destructor_id(p): 477 '''destructor_id : '~' id 478 | TEMPLATE destructor_id 479 ''' 480 p[0]=get_rest(p) 481 482#def p_template_id(p): 483# '''template_id : empty 484# | TEMPLATE 485# ''' 486# pass 487 488def p_template_decl(p): 489 '''template_decl : identifier '<' nonlgt_seq_opt '>' 490 ''' 491 # 492 # WEH: should we include the lt/gt symbols to indicate that this is a 493 # template class? How is that going to be used later??? 494 # 495 #p[0] = [p[1] ,"<",">"] 496 p[0] = p[1] 497 498def p_special_function_id(p): 499 '''special_function_id : conversion_function_id 500 | operator_function_id 501 | TEMPLATE special_function_id 502 ''' 503 p[0]=get_rest(p) 504 505def p_nested_special_function_id(p): 506 '''nested_special_function_id : special_function_id 507 | id_scope destructor_id 508 | id_scope nested_special_function_id 509 ''' 510 p[0]=get_rest(p) 511 512def p_scoped_special_function_id(p): 513 '''scoped_special_function_id : nested_special_function_id 514 | global_scope nested_special_function_id 515 ''' 516 p[0]=get_rest(p) 517 518# declarator-id is all names in all scopes, except reserved words 519def p_declarator_id(p): 520 '''declarator_id : scoped_id 521 | scoped_special_function_id 522 | destructor_id 523 ''' 524 p[0]=p[1] 525 526# 527# The standard defines pseudo-destructors in terms of type-name, which is 528# class/enum/typedef, of which class-name is covered by a normal destructor. 529# pseudo-destructors are supposed to support ~int() in templates, so the 530# grammar here covers built-in names. Other names are covered by the lack 531# of identifier/type discrimination. 532# 533def p_built_in_type_id(p): 534 '''built_in_type_id : built_in_type_specifier 535 | built_in_type_id built_in_type_specifier 536 ''' 537 pass 538 539def p_pseudo_destructor_id(p): 540 '''pseudo_destructor_id : built_in_type_id SCOPE '~' built_in_type_id 541 | '~' built_in_type_id 542 | TEMPLATE pseudo_destructor_id 543 ''' 544 pass 545 546def p_nested_pseudo_destructor_id(p): 547 '''nested_pseudo_destructor_id : pseudo_destructor_id 548 | id_scope nested_pseudo_destructor_id 549 ''' 550 pass 551 552def p_scoped_pseudo_destructor_id(p): 553 '''scoped_pseudo_destructor_id : nested_pseudo_destructor_id 554 | global_scope scoped_pseudo_destructor_id 555 ''' 556 pass 557 558#------------------------------------------------------------------------------- 559# A.2 Lexical conventions 560#------------------------------------------------------------------------------- 561# 562 563def p_literal(p): 564 '''literal : IntegerLiteral 565 | CharacterLiteral 566 | FloatingLiteral 567 | StringLiteral 568 | TRUE 569 | FALSE 570 ''' 571 pass 572 573#------------------------------------------------------------------------------- 574# A.3 Basic concepts 575#------------------------------------------------------------------------------- 576def p_translation_unit(p): 577 '''translation_unit : declaration_seq_opt 578 ''' 579 pass 580 581#------------------------------------------------------------------------------- 582# A.4 Expressions 583#------------------------------------------------------------------------------- 584# 585# primary_expression covers an arbitrary sequence of all names with the 586# exception of an unscoped destructor, which is parsed as its unary expression 587# which is the correct disambiguation (when ambiguous). This eliminates the 588# traditional A(B) meaning A B ambiguity, since we never have to tack an A 589# onto the front of something that might start with (. The name length got 590# maximised ab initio. The downside is that semantic interpretation must split 591# the names up again. 592# 593# Unification of the declaration and expression syntax means that unary and 594# binary pointer declarator operators: 595# int * * name 596# are parsed as binary and unary arithmetic operators (int) * (*name). Since 597# type information is not used 598# ambiguities resulting from a cast 599# (cast)*(value) 600# are resolved to favour the binary rather than the cast unary to ease AST 601# clean-up. The cast-call ambiguity must be resolved to the cast to ensure 602# that (a)(b)c can be parsed. 603# 604# The problem of the functional cast ambiguity 605# name(arg) 606# as call or declaration is avoided by maximising the name within the parsing 607# kernel. So primary_id_expression picks up 608# extern long int const var = 5; 609# as an assignment to the syntax parsed as "extern long int const var". The 610# presence of two names is parsed so that "extern long into const" is 611# distinguished from "var" considerably simplifying subsequent 612# semantic resolution. 613# 614# The generalised name is a concatenation of potential type-names (scoped 615# identifiers or built-in sequences) plus optionally one of the special names 616# such as an operator-function-id, conversion-function-id or destructor as the 617# final name. 618# 619 620def get_rest(p): 621 return [p[i] for i in range(1, len(p))] 622 623def p_primary_expression(p): 624 '''primary_expression : literal 625 | THIS 626 | suffix_decl_specified_ids 627 | abstract_expression %prec REDUCE_HERE_MOSTLY 628 ''' 629 p[0] = get_rest(p) 630 631# 632# Abstract-expression covers the () and [] of abstract-declarators. 633# 634def p_abstract_expression(p): 635 '''abstract_expression : parenthesis_clause 636 | LBRACKET bexpression_opt RBRACKET 637 | TEMPLATE abstract_expression 638 ''' 639 pass 640 641def p_postfix_expression(p): 642 '''postfix_expression : primary_expression 643 | postfix_expression parenthesis_clause 644 | postfix_expression LBRACKET bexpression_opt RBRACKET 645 | postfix_expression LBRACKET bexpression_opt RBRACKET attributes 646 | postfix_expression '.' declarator_id 647 | postfix_expression '.' scoped_pseudo_destructor_id 648 | postfix_expression ARROW declarator_id 649 | postfix_expression ARROW scoped_pseudo_destructor_id 650 | postfix_expression INC 651 | postfix_expression DEC 652 | DYNAMIC_CAST '<' nonlgt_seq_opt '>' '(' expression ')' 653 | STATIC_CAST '<' nonlgt_seq_opt '>' '(' expression ')' 654 | REINTERPRET_CAST '<' nonlgt_seq_opt '>' '(' expression ')' 655 | CONST_CAST '<' nonlgt_seq_opt '>' '(' expression ')' 656 | TYPEID parameters_clause 657 ''' 658 #print "HERE",str(p[1]) 659 p[0] = get_rest(p) 660 661def p_bexpression_opt(p): 662 '''bexpression_opt : empty 663 | bexpression 664 ''' 665 pass 666 667def p_bexpression(p): 668 '''bexpression : nonbracket_seq 669 | nonbracket_seq bexpression_seq bexpression_clause nonbracket_seq_opt 670 | bexpression_seq bexpression_clause nonbracket_seq_opt 671 ''' 672 pass 673 674def p_bexpression_seq(p): 675 '''bexpression_seq : empty 676 | bexpression_seq bexpression_clause nonbracket_seq_opt 677 ''' 678 pass 679 680def p_bexpression_clause(p): 681 '''bexpression_clause : LBRACKET bexpression_opt RBRACKET 682 ''' 683 pass 684 685 686 687def p_expression_list_opt(p): 688 '''expression_list_opt : empty 689 | expression_list 690 ''' 691 pass 692 693def p_expression_list(p): 694 '''expression_list : assignment_expression 695 | expression_list ',' assignment_expression 696 ''' 697 pass 698 699def p_unary_expression(p): 700 '''unary_expression : postfix_expression 701 | INC cast_expression 702 | DEC cast_expression 703 | ptr_operator cast_expression 704 | suffix_decl_specified_scope star_ptr_operator cast_expression 705 | '+' cast_expression 706 | '-' cast_expression 707 | '!' cast_expression 708 | '~' cast_expression 709 | SIZEOF unary_expression 710 | new_expression 711 | global_scope new_expression 712 | delete_expression 713 | global_scope delete_expression 714 ''' 715 p[0] = get_rest(p) 716 717def p_delete_expression(p): 718 '''delete_expression : DELETE cast_expression 719 ''' 720 pass 721 722def p_new_expression(p): 723 '''new_expression : NEW new_type_id new_initializer_opt 724 | NEW parameters_clause new_type_id new_initializer_opt 725 | NEW parameters_clause 726 | NEW parameters_clause parameters_clause new_initializer_opt 727 ''' 728 pass 729 730def p_new_type_id(p): 731 '''new_type_id : type_specifier ptr_operator_seq_opt 732 | type_specifier new_declarator 733 | type_specifier new_type_id 734 ''' 735 pass 736 737def p_new_declarator(p): 738 '''new_declarator : ptr_operator new_declarator 739 | direct_new_declarator 740 ''' 741 pass 742 743def p_direct_new_declarator(p): 744 '''direct_new_declarator : LBRACKET bexpression_opt RBRACKET 745 | direct_new_declarator LBRACKET bexpression RBRACKET 746 ''' 747 pass 748 749def p_new_initializer_opt(p): 750 '''new_initializer_opt : empty 751 | '(' expression_list_opt ')' 752 ''' 753 pass 754 755# 756# cast-expression is generalised to support a [] as well as a () prefix. This covers the omission of 757# DELETE[] which when followed by a parenthesised expression was ambiguous. It also covers the gcc 758# indexed array initialisation for free. 759# 760def p_cast_expression(p): 761 '''cast_expression : unary_expression 762 | abstract_expression cast_expression 763 ''' 764 p[0] = get_rest(p) 765 766def p_pm_expression(p): 767 '''pm_expression : cast_expression 768 | pm_expression DOT_STAR cast_expression 769 | pm_expression ARROW_STAR cast_expression 770 ''' 771 p[0] = get_rest(p) 772 773def p_multiplicative_expression(p): 774 '''multiplicative_expression : pm_expression 775 | multiplicative_expression star_ptr_operator pm_expression 776 | multiplicative_expression '/' pm_expression 777 | multiplicative_expression '%' pm_expression 778 ''' 779 p[0] = get_rest(p) 780 781def p_additive_expression(p): 782 '''additive_expression : multiplicative_expression 783 | additive_expression '+' multiplicative_expression 784 | additive_expression '-' multiplicative_expression 785 ''' 786 p[0] = get_rest(p) 787 788def p_shift_expression(p): 789 '''shift_expression : additive_expression 790 | shift_expression SHL additive_expression 791 | shift_expression SHR additive_expression 792 ''' 793 p[0] = get_rest(p) 794 795# | relational_expression '<' shift_expression 796# | relational_expression '>' shift_expression 797# | relational_expression LE shift_expression 798# | relational_expression GE shift_expression 799def p_relational_expression(p): 800 '''relational_expression : shift_expression 801 ''' 802 p[0] = get_rest(p) 803 804def p_equality_expression(p): 805 '''equality_expression : relational_expression 806 | equality_expression EQ relational_expression 807 | equality_expression NE relational_expression 808 ''' 809 p[0] = get_rest(p) 810 811def p_and_expression(p): 812 '''and_expression : equality_expression 813 | and_expression '&' equality_expression 814 ''' 815 p[0] = get_rest(p) 816 817def p_exclusive_or_expression(p): 818 '''exclusive_or_expression : and_expression 819 | exclusive_or_expression '^' and_expression 820 ''' 821 p[0] = get_rest(p) 822 823def p_inclusive_or_expression(p): 824 '''inclusive_or_expression : exclusive_or_expression 825 | inclusive_or_expression '|' exclusive_or_expression 826 ''' 827 p[0] = get_rest(p) 828 829def p_logical_and_expression(p): 830 '''logical_and_expression : inclusive_or_expression 831 | logical_and_expression LOG_AND inclusive_or_expression 832 ''' 833 p[0] = get_rest(p) 834 835def p_logical_or_expression(p): 836 '''logical_or_expression : logical_and_expression 837 | logical_or_expression LOG_OR logical_and_expression 838 ''' 839 p[0] = get_rest(p) 840 841def p_conditional_expression(p): 842 '''conditional_expression : logical_or_expression 843 | logical_or_expression '?' expression ':' assignment_expression 844 ''' 845 p[0] = get_rest(p) 846 847 848# 849# assignment-expression is generalised to cover the simple assignment of a braced initializer in order to 850# contribute to the coverage of parameter-declaration and init-declaration. 851# 852# | logical_or_expression assignment_operator assignment_expression 853def p_assignment_expression(p): 854 '''assignment_expression : conditional_expression 855 | logical_or_expression assignment_operator nonsemicolon_seq 856 | logical_or_expression '=' braced_initializer 857 | throw_expression 858 ''' 859 p[0]=get_rest(p) 860 861def p_assignment_operator(p): 862 '''assignment_operator : '=' 863 | ASS_ADD 864 | ASS_AND 865 | ASS_DIV 866 | ASS_MOD 867 | ASS_MUL 868 | ASS_OR 869 | ASS_SHL 870 | ASS_SHR 871 | ASS_SUB 872 | ASS_XOR 873 ''' 874 pass 875 876# 877# expression is widely used and usually single-element, so the reductions are arranged so that a 878# single-element expression is returned as is. Multi-element expressions are parsed as a list that 879# may then behave polymorphically as an element or be compacted to an element. 880# 881 882def p_expression(p): 883 '''expression : assignment_expression 884 | expression_list ',' assignment_expression 885 ''' 886 p[0] = get_rest(p) 887 888def p_constant_expression(p): 889 '''constant_expression : conditional_expression 890 ''' 891 pass 892 893#--------------------------------------------------------------------------------------------------- 894# A.5 Statements 895#--------------------------------------------------------------------------------------------------- 896# Parsing statements is easy once simple_declaration has been generalised to cover expression_statement. 897# 898# 899# The use of extern here is a hack. The 'extern "C" {}' block gets parsed 900# as a function, so when nested 'extern "C"' declarations exist, they don't 901# work because the block is viewed as a list of statements... :( 902# 903def p_statement(p): 904 '''statement : compound_statement 905 | declaration_statement 906 | try_block 907 | labeled_statement 908 | selection_statement 909 | iteration_statement 910 | jump_statement 911 ''' 912 pass 913 914def p_compound_statement(p): 915 '''compound_statement : LBRACE statement_seq_opt RBRACE 916 ''' 917 pass 918 919def p_statement_seq_opt(p): 920 '''statement_seq_opt : empty 921 | statement_seq_opt statement 922 ''' 923 pass 924 925# 926# The dangling else conflict is resolved to the innermost if. 927# 928def p_selection_statement(p): 929 '''selection_statement : IF '(' condition ')' statement %prec SHIFT_THERE 930 | IF '(' condition ')' statement ELSE statement 931 | SWITCH '(' condition ')' statement 932 ''' 933 pass 934 935def p_condition_opt(p): 936 '''condition_opt : empty 937 | condition 938 ''' 939 pass 940 941def p_condition(p): 942 '''condition : nonparen_seq 943 | nonparen_seq condition_seq parameters_clause nonparen_seq_opt 944 | condition_seq parameters_clause nonparen_seq_opt 945 ''' 946 pass 947 948def p_condition_seq(p): 949 '''condition_seq : empty 950 | condition_seq parameters_clause nonparen_seq_opt 951 ''' 952 pass 953 954def p_labeled_statement(p): 955 '''labeled_statement : identifier ':' statement 956 | CASE constant_expression ':' statement 957 | DEFAULT ':' statement 958 ''' 959 pass 960 961def p_try_block(p): 962 '''try_block : TRY compound_statement handler_seq 963 ''' 964 global noExceptionLogic 965 noExceptionLogic=False 966 967def p_jump_statement(p): 968 '''jump_statement : BREAK ';' 969 | CONTINUE ';' 970 | RETURN nonsemicolon_seq ';' 971 | GOTO identifier ';' 972 ''' 973 pass 974 975def p_iteration_statement(p): 976 '''iteration_statement : WHILE '(' condition ')' statement 977 | DO statement WHILE '(' expression ')' ';' 978 | FOR '(' nonparen_seq_opt ')' statement 979 ''' 980 pass 981 982def p_declaration_statement(p): 983 '''declaration_statement : block_declaration 984 ''' 985 pass 986 987#--------------------------------------------------------------------------------------------------- 988# A.6 Declarations 989#--------------------------------------------------------------------------------------------------- 990def p_compound_declaration(p): 991 '''compound_declaration : LBRACE declaration_seq_opt RBRACE 992 ''' 993 pass 994 995def p_declaration_seq_opt(p): 996 '''declaration_seq_opt : empty 997 | declaration_seq_opt declaration 998 ''' 999 pass 1000 1001def p_declaration(p): 1002 '''declaration : block_declaration 1003 | function_definition 1004 | template_declaration 1005 | explicit_specialization 1006 | specialised_declaration 1007 ''' 1008 pass 1009 1010def p_specialised_declaration(p): 1011 '''specialised_declaration : linkage_specification 1012 | namespace_definition 1013 | TEMPLATE specialised_declaration 1014 ''' 1015 pass 1016 1017def p_block_declaration(p): 1018 '''block_declaration : simple_declaration 1019 | specialised_block_declaration 1020 ''' 1021 pass 1022 1023def p_specialised_block_declaration(p): 1024 '''specialised_block_declaration : asm_definition 1025 | namespace_alias_definition 1026 | using_declaration 1027 | using_directive 1028 | TEMPLATE specialised_block_declaration 1029 ''' 1030 pass 1031 1032def p_simple_declaration(p): 1033 '''simple_declaration : ';' 1034 | init_declaration ';' 1035 | init_declarations ';' 1036 | decl_specifier_prefix simple_declaration 1037 ''' 1038 global _parse_info 1039 if len(p) == 3: 1040 if p[2] == ";": 1041 decl = p[1] 1042 else: 1043 decl = p[2] 1044 if decl is not None: 1045 fp = flatten(decl) 1046 if len(fp) >= 2 and fp[0] is not None and fp[0]!="operator" and fp[1] == '(': 1047 p[0] = fp[0] 1048 _parse_info.add_function(fp[0]) 1049 1050# 1051# A decl-specifier following a ptr_operator provokes a shift-reduce conflict for * const name which is resolved in favour of the pointer, and implemented by providing versions of decl-specifier guaranteed not to start with a cv_qualifier. decl-specifiers are implemented type-centrically. That is the semantic constraint that there must be a type is exploited to impose structure, but actually eliminate very little syntax. built-in types are multi-name and so need a different policy. 1052# 1053# non-type decl-specifiers are bound to the left-most type in a decl-specifier-seq, by parsing from the right and attaching suffixes to the right-hand type. Finally residual prefixes attach to the left. 1054# 1055def p_suffix_built_in_decl_specifier_raw(p): 1056 '''suffix_built_in_decl_specifier_raw : built_in_type_specifier 1057 | suffix_built_in_decl_specifier_raw built_in_type_specifier 1058 | suffix_built_in_decl_specifier_raw decl_specifier_suffix 1059 ''' 1060 pass 1061 1062def p_suffix_built_in_decl_specifier(p): 1063 '''suffix_built_in_decl_specifier : suffix_built_in_decl_specifier_raw 1064 | TEMPLATE suffix_built_in_decl_specifier 1065 ''' 1066 pass 1067 1068# | id_scope_seq 1069# | SCOPE id_scope_seq 1070def p_suffix_named_decl_specifier(p): 1071 '''suffix_named_decl_specifier : scoped_id 1072 | elaborate_type_specifier 1073 | suffix_named_decl_specifier decl_specifier_suffix 1074 ''' 1075 p[0]=get_rest(p) 1076 1077def p_suffix_named_decl_specifier_bi(p): 1078 '''suffix_named_decl_specifier_bi : suffix_named_decl_specifier 1079 | suffix_named_decl_specifier suffix_built_in_decl_specifier_raw 1080 ''' 1081 p[0] = get_rest(p) 1082 #print "HERE",get_rest(p) 1083 1084def p_suffix_named_decl_specifiers(p): 1085 '''suffix_named_decl_specifiers : suffix_named_decl_specifier_bi 1086 | suffix_named_decl_specifiers suffix_named_decl_specifier_bi 1087 ''' 1088 p[0] = get_rest(p) 1089 1090def p_suffix_named_decl_specifiers_sf(p): 1091 '''suffix_named_decl_specifiers_sf : scoped_special_function_id 1092 | suffix_named_decl_specifiers 1093 | suffix_named_decl_specifiers scoped_special_function_id 1094 ''' 1095 #print "HERE",get_rest(p) 1096 p[0] = get_rest(p) 1097 1098def p_suffix_decl_specified_ids(p): 1099 '''suffix_decl_specified_ids : suffix_built_in_decl_specifier 1100 | suffix_built_in_decl_specifier suffix_named_decl_specifiers_sf 1101 | suffix_named_decl_specifiers_sf 1102 ''' 1103 if len(p) == 3: 1104 p[0] = p[2] 1105 else: 1106 p[0] = p[1] 1107 1108def p_suffix_decl_specified_scope(p): 1109 '''suffix_decl_specified_scope : suffix_named_decl_specifiers SCOPE 1110 | suffix_built_in_decl_specifier suffix_named_decl_specifiers SCOPE 1111 | suffix_built_in_decl_specifier SCOPE 1112 ''' 1113 p[0] = get_rest(p) 1114 1115def p_decl_specifier_affix(p): 1116 '''decl_specifier_affix : storage_class_specifier 1117 | function_specifier 1118 | FRIEND 1119 | TYPEDEF 1120 | cv_qualifier 1121 ''' 1122 pass 1123 1124def p_decl_specifier_suffix(p): 1125 '''decl_specifier_suffix : decl_specifier_affix 1126 ''' 1127 pass 1128 1129def p_decl_specifier_prefix(p): 1130 '''decl_specifier_prefix : decl_specifier_affix 1131 | TEMPLATE decl_specifier_prefix 1132 ''' 1133 pass 1134 1135def p_storage_class_specifier(p): 1136 '''storage_class_specifier : REGISTER 1137 | STATIC 1138 | MUTABLE 1139 | EXTERN %prec SHIFT_THERE 1140 | EXTENSION 1141 | AUTO 1142 ''' 1143 pass 1144 1145def p_function_specifier(p): 1146 '''function_specifier : EXPLICIT 1147 | INLINE 1148 | VIRTUAL 1149 ''' 1150 pass 1151 1152def p_type_specifier(p): 1153 '''type_specifier : simple_type_specifier 1154 | elaborate_type_specifier 1155 | cv_qualifier 1156 ''' 1157 pass 1158 1159def p_elaborate_type_specifier(p): 1160 '''elaborate_type_specifier : class_specifier 1161 | enum_specifier 1162 | elaborated_type_specifier 1163 | TEMPLATE elaborate_type_specifier 1164 ''' 1165 pass 1166 1167def p_simple_type_specifier(p): 1168 '''simple_type_specifier : scoped_id 1169 | scoped_id attributes 1170 | built_in_type_specifier 1171 ''' 1172 p[0] = p[1] 1173 1174def p_built_in_type_specifier(p): 1175 '''built_in_type_specifier : Xbuilt_in_type_specifier 1176 | Xbuilt_in_type_specifier attributes 1177 ''' 1178 pass 1179 1180def p_attributes(p): 1181 '''attributes : attribute 1182 | attributes attribute 1183 ''' 1184 pass 1185 1186def p_attribute(p): 1187 '''attribute : ATTRIBUTE '(' parameters_clause ')' 1188 ''' 1189 1190def p_Xbuilt_in_type_specifier(p): 1191 '''Xbuilt_in_type_specifier : CHAR 1192 | WCHAR_T 1193 | BOOL 1194 | SHORT 1195 | INT 1196 | LONG 1197 | SIGNED 1198 | UNSIGNED 1199 | FLOAT 1200 | DOUBLE 1201 | VOID 1202 | uTYPEOF parameters_clause 1203 | TYPEOF parameters_clause 1204 ''' 1205 pass 1206 1207# 1208# The over-general use of declaration_expression to cover decl-specifier-seq_opt declarator in a function-definition means that 1209# class X { }; 1210# could be a function-definition or a class-specifier. 1211# enum X { }; 1212# could be a function-definition or an enum-specifier. 1213# The function-definition is not syntactically valid so resolving the false conflict in favour of the 1214# elaborated_type_specifier is correct. 1215# 1216def p_elaborated_type_specifier(p): 1217 '''elaborated_type_specifier : class_key scoped_id %prec SHIFT_THERE 1218 | elaborated_enum_specifier 1219 | TYPENAME scoped_id 1220 ''' 1221 pass 1222 1223def p_elaborated_enum_specifier(p): 1224 '''elaborated_enum_specifier : ENUM scoped_id %prec SHIFT_THERE 1225 ''' 1226 pass 1227 1228def p_enum_specifier(p): 1229 '''enum_specifier : ENUM scoped_id enumerator_clause 1230 | ENUM enumerator_clause 1231 ''' 1232 pass 1233 1234def p_enumerator_clause(p): 1235 '''enumerator_clause : LBRACE enumerator_list_ecarb 1236 | LBRACE enumerator_list enumerator_list_ecarb 1237 | LBRACE enumerator_list ',' enumerator_definition_ecarb 1238 ''' 1239 pass 1240 1241def p_enumerator_list_ecarb(p): 1242 '''enumerator_list_ecarb : RBRACE 1243 ''' 1244 pass 1245 1246def p_enumerator_definition_ecarb(p): 1247 '''enumerator_definition_ecarb : RBRACE 1248 ''' 1249 pass 1250 1251def p_enumerator_definition_filler(p): 1252 '''enumerator_definition_filler : empty 1253 ''' 1254 pass 1255 1256def p_enumerator_list_head(p): 1257 '''enumerator_list_head : enumerator_definition_filler 1258 | enumerator_list ',' enumerator_definition_filler 1259 ''' 1260 pass 1261 1262def p_enumerator_list(p): 1263 '''enumerator_list : enumerator_list_head enumerator_definition 1264 ''' 1265 pass 1266 1267def p_enumerator_definition(p): 1268 '''enumerator_definition : enumerator 1269 | enumerator '=' constant_expression 1270 ''' 1271 pass 1272 1273def p_enumerator(p): 1274 '''enumerator : identifier 1275 ''' 1276 pass 1277 1278def p_namespace_definition(p): 1279 '''namespace_definition : NAMESPACE scoped_id push_scope compound_declaration 1280 | NAMESPACE push_scope compound_declaration 1281 ''' 1282 global _parse_info 1283 scope = _parse_info.pop_scope() 1284 1285def p_namespace_alias_definition(p): 1286 '''namespace_alias_definition : NAMESPACE scoped_id '=' scoped_id ';' 1287 ''' 1288 pass 1289 1290def p_push_scope(p): 1291 '''push_scope : empty''' 1292 global _parse_info 1293 if p[-2] == "namespace": 1294 scope=p[-1] 1295 else: 1296 scope="" 1297 _parse_info.push_scope(scope,"namespace") 1298 1299def p_using_declaration(p): 1300 '''using_declaration : USING declarator_id ';' 1301 | USING TYPENAME declarator_id ';' 1302 ''' 1303 pass 1304 1305def p_using_directive(p): 1306 '''using_directive : USING NAMESPACE scoped_id ';' 1307 ''' 1308 pass 1309 1310# '''asm_definition : ASM '(' StringLiteral ')' ';' 1311def p_asm_definition(p): 1312 '''asm_definition : ASM '(' nonparen_seq_opt ')' ';' 1313 ''' 1314 pass 1315 1316def p_linkage_specification(p): 1317 '''linkage_specification : EXTERN CLiteral declaration 1318 | EXTERN CLiteral compound_declaration 1319 | EXTERN CppLiteral declaration 1320 | EXTERN CppLiteral compound_declaration 1321 ''' 1322 pass 1323 1324#--------------------------------------------------------------------------------------------------- 1325# A.7 Declarators 1326#--------------------------------------------------------------------------------------------------- 1327# 1328# init-declarator is named init_declaration to reflect the embedded decl-specifier-seq_opt 1329# 1330 1331def p_init_declarations(p): 1332 '''init_declarations : assignment_expression ',' init_declaration 1333 | init_declarations ',' init_declaration 1334 ''' 1335 p[0]=get_rest(p) 1336 1337def p_init_declaration(p): 1338 '''init_declaration : assignment_expression 1339 ''' 1340 p[0]=get_rest(p) 1341 1342def p_star_ptr_operator(p): 1343 '''star_ptr_operator : '*' 1344 | star_ptr_operator cv_qualifier 1345 ''' 1346 pass 1347 1348def p_nested_ptr_operator(p): 1349 '''nested_ptr_operator : star_ptr_operator 1350 | id_scope nested_ptr_operator 1351 ''' 1352 pass 1353 1354def p_ptr_operator(p): 1355 '''ptr_operator : '&' 1356 | nested_ptr_operator 1357 | global_scope nested_ptr_operator 1358 ''' 1359 pass 1360 1361def p_ptr_operator_seq(p): 1362 '''ptr_operator_seq : ptr_operator 1363 | ptr_operator ptr_operator_seq 1364 ''' 1365 pass 1366 1367# 1368# Independently coded to localise the shift-reduce conflict: sharing just needs another %prec 1369# 1370def p_ptr_operator_seq_opt(p): 1371 '''ptr_operator_seq_opt : empty %prec SHIFT_THERE 1372 | ptr_operator ptr_operator_seq_opt 1373 ''' 1374 pass 1375 1376def p_cv_qualifier_seq_opt(p): 1377 '''cv_qualifier_seq_opt : empty 1378 | cv_qualifier_seq_opt cv_qualifier 1379 ''' 1380 pass 1381 1382# TODO: verify that we should include attributes here 1383def p_cv_qualifier(p): 1384 '''cv_qualifier : CONST 1385 | VOLATILE 1386 | attributes 1387 ''' 1388 pass 1389 1390def p_type_id(p): 1391 '''type_id : type_specifier abstract_declarator_opt 1392 | type_specifier type_id 1393 ''' 1394 pass 1395 1396def p_abstract_declarator_opt(p): 1397 '''abstract_declarator_opt : empty 1398 | ptr_operator abstract_declarator_opt 1399 | direct_abstract_declarator 1400 ''' 1401 pass 1402 1403def p_direct_abstract_declarator_opt(p): 1404 '''direct_abstract_declarator_opt : empty 1405 | direct_abstract_declarator 1406 ''' 1407 pass 1408 1409def p_direct_abstract_declarator(p): 1410 '''direct_abstract_declarator : direct_abstract_declarator_opt parenthesis_clause 1411 | direct_abstract_declarator_opt LBRACKET RBRACKET 1412 | direct_abstract_declarator_opt LBRACKET bexpression RBRACKET 1413 ''' 1414 pass 1415 1416def p_parenthesis_clause(p): 1417 '''parenthesis_clause : parameters_clause cv_qualifier_seq_opt 1418 | parameters_clause cv_qualifier_seq_opt exception_specification 1419 ''' 1420 p[0] = ['(',')'] 1421 1422def p_parameters_clause(p): 1423 '''parameters_clause : '(' condition_opt ')' 1424 ''' 1425 p[0] = ['(',')'] 1426 1427# 1428# A typed abstract qualifier such as 1429# Class * ... 1430# looks like a multiply, so pointers are parsed as their binary operation equivalents that 1431# ultimately terminate with a degenerate right hand term. 1432# 1433def p_abstract_pointer_declaration(p): 1434 '''abstract_pointer_declaration : ptr_operator_seq 1435 | multiplicative_expression star_ptr_operator ptr_operator_seq_opt 1436 ''' 1437 pass 1438 1439def p_abstract_parameter_declaration(p): 1440 '''abstract_parameter_declaration : abstract_pointer_declaration 1441 | and_expression '&' 1442 | and_expression '&' abstract_pointer_declaration 1443 ''' 1444 pass 1445 1446def p_special_parameter_declaration(p): 1447 '''special_parameter_declaration : abstract_parameter_declaration 1448 | abstract_parameter_declaration '=' assignment_expression 1449 | ELLIPSIS 1450 ''' 1451 pass 1452 1453def p_parameter_declaration(p): 1454 '''parameter_declaration : assignment_expression 1455 | special_parameter_declaration 1456 | decl_specifier_prefix parameter_declaration 1457 ''' 1458 pass 1459 1460# 1461# function_definition includes constructor, destructor, implicit int definitions too. A local destructor is successfully parsed as a function-declaration but the ~ was treated as a unary operator. constructor_head is the prefix ambiguity between a constructor and a member-init-list starting with a bit-field. 1462# 1463def p_function_definition(p): 1464 '''function_definition : ctor_definition 1465 | func_definition 1466 ''' 1467 pass 1468 1469def p_func_definition(p): 1470 '''func_definition : assignment_expression function_try_block 1471 | assignment_expression function_body 1472 | decl_specifier_prefix func_definition 1473 ''' 1474 global _parse_info 1475 if p[2] is not None and p[2][0] == '{': 1476 decl = flatten(p[1]) 1477 #print "HERE",decl 1478 if decl[-1] == ')': 1479 decl=decl[-3] 1480 else: 1481 decl=decl[-1] 1482 p[0] = decl 1483 if decl != "operator": 1484 _parse_info.add_function(decl) 1485 else: 1486 p[0] = p[2] 1487 1488def p_ctor_definition(p): 1489 '''ctor_definition : constructor_head function_try_block 1490 | constructor_head function_body 1491 | decl_specifier_prefix ctor_definition 1492 ''' 1493 if p[2] is None or p[2][0] == "try" or p[2][0] == '{': 1494 p[0]=p[1] 1495 else: 1496 p[0]=p[1] 1497 1498def p_constructor_head(p): 1499 '''constructor_head : bit_field_init_declaration 1500 | constructor_head ',' assignment_expression 1501 ''' 1502 p[0]=p[1] 1503 1504def p_function_try_block(p): 1505 '''function_try_block : TRY function_block handler_seq 1506 ''' 1507 global noExceptionLogic 1508 noExceptionLogic=False 1509 p[0] = ['try'] 1510 1511def p_function_block(p): 1512 '''function_block : ctor_initializer_opt function_body 1513 ''' 1514 pass 1515 1516def p_function_body(p): 1517 '''function_body : LBRACE nonbrace_seq_opt RBRACE 1518 ''' 1519 p[0] = ['{','}'] 1520 1521def p_initializer_clause(p): 1522 '''initializer_clause : assignment_expression 1523 | braced_initializer 1524 ''' 1525 pass 1526 1527def p_braced_initializer(p): 1528 '''braced_initializer : LBRACE initializer_list RBRACE 1529 | LBRACE initializer_list ',' RBRACE 1530 | LBRACE RBRACE 1531 ''' 1532 pass 1533 1534def p_initializer_list(p): 1535 '''initializer_list : initializer_clause 1536 | initializer_list ',' initializer_clause 1537 ''' 1538 pass 1539 1540#--------------------------------------------------------------------------------------------------- 1541# A.8 Classes 1542#--------------------------------------------------------------------------------------------------- 1543# 1544# An anonymous bit-field declaration may look very like inheritance: 1545# const int B = 3; 1546# class A : B ; 1547# The two usages are too distant to try to create and enforce a common prefix so we have to resort to 1548# a parser hack by backtracking. Inheritance is much the most likely so we mark the input stream context 1549# and try to parse a base-clause. If we successfully reach a { the base-clause is ok and inheritance was 1550# the correct choice so we unmark and continue. If we fail to find the { an error token causes 1551# back-tracking to the alternative parse in elaborated_type_specifier which regenerates the : and 1552# declares unconditional success. 1553# 1554 1555def p_class_specifier_head(p): 1556 '''class_specifier_head : class_key scoped_id ':' base_specifier_list LBRACE 1557 | class_key ':' base_specifier_list LBRACE 1558 | class_key scoped_id LBRACE 1559 | class_key LBRACE 1560 ''' 1561 global _parse_info 1562 base_classes=[] 1563 if len(p) == 6: 1564 scope = p[2] 1565 base_classes = p[4] 1566 elif len(p) == 4: 1567 scope = p[2] 1568 elif len(p) == 5: 1569 base_classes = p[3] 1570 else: 1571 scope = "" 1572 _parse_info.push_scope(scope,p[1],base_classes) 1573 1574 1575def p_class_key(p): 1576 '''class_key : CLASS 1577 | STRUCT 1578 | UNION 1579 ''' 1580 p[0] = p[1] 1581 1582def p_class_specifier(p): 1583 '''class_specifier : class_specifier_head member_specification_opt RBRACE 1584 ''' 1585 scope = _parse_info.pop_scope() 1586 1587def p_member_specification_opt(p): 1588 '''member_specification_opt : empty 1589 | member_specification_opt member_declaration 1590 ''' 1591 pass 1592 1593def p_member_declaration(p): 1594 '''member_declaration : accessibility_specifier 1595 | simple_member_declaration 1596 | function_definition 1597 | using_declaration 1598 | template_declaration 1599 ''' 1600 p[0] = get_rest(p) 1601 #print "Decl",get_rest(p) 1602 1603# 1604# The generality of constructor names (there need be no parenthesised argument list) means that that 1605# name : f(g), h(i) 1606# could be the start of a constructor or the start of an anonymous bit-field. An ambiguity is avoided by 1607# parsing the ctor-initializer of a function_definition as a bit-field. 1608# 1609def p_simple_member_declaration(p): 1610 '''simple_member_declaration : ';' 1611 | assignment_expression ';' 1612 | constructor_head ';' 1613 | member_init_declarations ';' 1614 | decl_specifier_prefix simple_member_declaration 1615 ''' 1616 global _parse_info 1617 decl = flatten(get_rest(p)) 1618 if len(decl) >= 4 and decl[-3] == "(": 1619 _parse_info.add_function(decl[-4]) 1620 1621def p_member_init_declarations(p): 1622 '''member_init_declarations : assignment_expression ',' member_init_declaration 1623 | constructor_head ',' bit_field_init_declaration 1624 | member_init_declarations ',' member_init_declaration 1625 ''' 1626 pass 1627 1628def p_member_init_declaration(p): 1629 '''member_init_declaration : assignment_expression 1630 | bit_field_init_declaration 1631 ''' 1632 pass 1633 1634def p_accessibility_specifier(p): 1635 '''accessibility_specifier : access_specifier ':' 1636 ''' 1637 pass 1638 1639def p_bit_field_declaration(p): 1640 '''bit_field_declaration : assignment_expression ':' bit_field_width 1641 | ':' bit_field_width 1642 ''' 1643 if len(p) == 4: 1644 p[0]=p[1] 1645 1646def p_bit_field_width(p): 1647 '''bit_field_width : logical_or_expression 1648 | logical_or_expression '?' bit_field_width ':' bit_field_width 1649 ''' 1650 pass 1651 1652def p_bit_field_init_declaration(p): 1653 '''bit_field_init_declaration : bit_field_declaration 1654 | bit_field_declaration '=' initializer_clause 1655 ''' 1656 pass 1657 1658#--------------------------------------------------------------------------------------------------- 1659# A.9 Derived classes 1660#--------------------------------------------------------------------------------------------------- 1661def p_base_specifier_list(p): 1662 '''base_specifier_list : base_specifier 1663 | base_specifier_list ',' base_specifier 1664 ''' 1665 if len(p) == 2: 1666 p[0] = [p[1]] 1667 else: 1668 p[0] = p[1]+[p[3]] 1669 1670def p_base_specifier(p): 1671 '''base_specifier : scoped_id 1672 | access_specifier base_specifier 1673 | VIRTUAL base_specifier 1674 ''' 1675 if len(p) == 2: 1676 p[0] = p[1] 1677 else: 1678 p[0] = p[2] 1679 1680def p_access_specifier(p): 1681 '''access_specifier : PRIVATE 1682 | PROTECTED 1683 | PUBLIC 1684 ''' 1685 pass 1686 1687#--------------------------------------------------------------------------------------------------- 1688# A.10 Special member functions 1689#--------------------------------------------------------------------------------------------------- 1690def p_conversion_function_id(p): 1691 '''conversion_function_id : OPERATOR conversion_type_id 1692 ''' 1693 p[0] = ['operator'] 1694 1695def p_conversion_type_id(p): 1696 '''conversion_type_id : type_specifier ptr_operator_seq_opt 1697 | type_specifier conversion_type_id 1698 ''' 1699 pass 1700 1701# 1702# Ctor-initialisers can look like a bit field declaration, given the generalisation of names: 1703# Class(Type) : m1(1), m2(2) { } 1704# NonClass(bit_field) : int(2), second_variable, ... 1705# The grammar below is used within a function_try_block or function_definition. 1706# See simple_member_declaration for use in normal member function_definition. 1707# 1708def p_ctor_initializer_opt(p): 1709 '''ctor_initializer_opt : empty 1710 | ctor_initializer 1711 ''' 1712 pass 1713 1714def p_ctor_initializer(p): 1715 '''ctor_initializer : ':' mem_initializer_list 1716 ''' 1717 pass 1718 1719def p_mem_initializer_list(p): 1720 '''mem_initializer_list : mem_initializer 1721 | mem_initializer_list_head mem_initializer 1722 ''' 1723 pass 1724 1725def p_mem_initializer_list_head(p): 1726 '''mem_initializer_list_head : mem_initializer_list ',' 1727 ''' 1728 pass 1729 1730def p_mem_initializer(p): 1731 '''mem_initializer : mem_initializer_id '(' expression_list_opt ')' 1732 ''' 1733 pass 1734 1735def p_mem_initializer_id(p): 1736 '''mem_initializer_id : scoped_id 1737 ''' 1738 pass 1739 1740#--------------------------------------------------------------------------------------------------- 1741# A.11 Overloading 1742#--------------------------------------------------------------------------------------------------- 1743 1744def p_operator_function_id(p): 1745 '''operator_function_id : OPERATOR operator 1746 | OPERATOR '(' ')' 1747 | OPERATOR LBRACKET RBRACKET 1748 | OPERATOR '<' 1749 | OPERATOR '>' 1750 | OPERATOR operator '<' nonlgt_seq_opt '>' 1751 ''' 1752 p[0] = ["operator"] 1753 1754# 1755# It is not clear from the ANSI standard whether spaces are permitted in delete[]. If not then it can 1756# be recognised and returned as DELETE_ARRAY by the lexer. Assuming spaces are permitted there is an 1757# ambiguity created by the over generalised nature of expressions. operator new is a valid delarator-id 1758# which we may have an undimensioned array of. Semantic rubbish, but syntactically valid. Since the 1759# array form is covered by the declarator consideration we can exclude the operator here. The need 1760# for a semantic rescue can be eliminated at the expense of a couple of shift-reduce conflicts by 1761# removing the comments on the next four lines. 1762# 1763def p_operator(p): 1764 '''operator : NEW 1765 | DELETE 1766 | '+' 1767 | '-' 1768 | '*' 1769 | '/' 1770 | '%' 1771 | '^' 1772 | '&' 1773 | '|' 1774 | '~' 1775 | '!' 1776 | '=' 1777 | ASS_ADD 1778 | ASS_SUB 1779 | ASS_MUL 1780 | ASS_DIV 1781 | ASS_MOD 1782 | ASS_XOR 1783 | ASS_AND 1784 | ASS_OR 1785 | SHL 1786 | SHR 1787 | ASS_SHR 1788 | ASS_SHL 1789 | EQ 1790 | NE 1791 | LE 1792 | GE 1793 | LOG_AND 1794 | LOG_OR 1795 | INC 1796 | DEC 1797 | ',' 1798 | ARROW_STAR 1799 | ARROW 1800 ''' 1801 p[0]=p[1] 1802 1803# | IF 1804# | SWITCH 1805# | WHILE 1806# | FOR 1807# | DO 1808def p_reserved(p): 1809 '''reserved : PRIVATE 1810 | CLiteral 1811 | CppLiteral 1812 | IF 1813 | SWITCH 1814 | WHILE 1815 | FOR 1816 | DO 1817 | PROTECTED 1818 | PUBLIC 1819 | BOOL 1820 | CHAR 1821 | DOUBLE 1822 | FLOAT 1823 | INT 1824 | LONG 1825 | SHORT 1826 | SIGNED 1827 | UNSIGNED 1828 | VOID 1829 | WCHAR_T 1830 | CLASS 1831 | ENUM 1832 | NAMESPACE 1833 | STRUCT 1834 | TYPENAME 1835 | UNION 1836 | CONST 1837 | VOLATILE 1838 | AUTO 1839 | EXPLICIT 1840 | EXPORT 1841 | EXTERN 1842 | FRIEND 1843 | INLINE 1844 | MUTABLE 1845 | REGISTER 1846 | STATIC 1847 | TEMPLATE 1848 | TYPEDEF 1849 | USING 1850 | VIRTUAL 1851 | ASM 1852 | BREAK 1853 | CASE 1854 | CATCH 1855 | CONST_CAST 1856 | CONTINUE 1857 | DEFAULT 1858 | DYNAMIC_CAST 1859 | ELSE 1860 | FALSE 1861 | GOTO 1862 | OPERATOR 1863 | REINTERPRET_CAST 1864 | RETURN 1865 | SIZEOF 1866 | STATIC_CAST 1867 | THIS 1868 | THROW 1869 | TRUE 1870 | TRY 1871 | TYPEID 1872 | ATTRIBUTE 1873 | CDECL 1874 | TYPEOF 1875 | uTYPEOF 1876 ''' 1877 if p[1] in ('try', 'catch', 'throw'): 1878 global noExceptionLogic 1879 noExceptionLogic=False 1880 1881#--------------------------------------------------------------------------------------------------- 1882# A.12 Templates 1883#--------------------------------------------------------------------------------------------------- 1884def p_template_declaration(p): 1885 '''template_declaration : template_parameter_clause declaration 1886 | EXPORT template_declaration 1887 ''' 1888 pass 1889 1890def p_template_parameter_clause(p): 1891 '''template_parameter_clause : TEMPLATE '<' nonlgt_seq_opt '>' 1892 ''' 1893 pass 1894 1895# 1896# Generalised naming makes identifier a valid declaration, so TEMPLATE identifier is too. 1897# The TEMPLATE prefix is therefore folded into all names, parenthesis_clause and decl_specifier_prefix. 1898# 1899# explicit_instantiation: TEMPLATE declaration 1900# 1901def p_explicit_specialization(p): 1902 '''explicit_specialization : TEMPLATE '<' '>' declaration 1903 ''' 1904 pass 1905 1906#--------------------------------------------------------------------------------------------------- 1907# A.13 Exception Handling 1908#--------------------------------------------------------------------------------------------------- 1909def p_handler_seq(p): 1910 '''handler_seq : handler 1911 | handler handler_seq 1912 ''' 1913 pass 1914 1915def p_handler(p): 1916 '''handler : CATCH '(' exception_declaration ')' compound_statement 1917 ''' 1918 global noExceptionLogic 1919 noExceptionLogic=False 1920 1921def p_exception_declaration(p): 1922 '''exception_declaration : parameter_declaration 1923 ''' 1924 pass 1925 1926def p_throw_expression(p): 1927 '''throw_expression : THROW 1928 | THROW assignment_expression 1929 ''' 1930 global noExceptionLogic 1931 noExceptionLogic=False 1932 1933def p_exception_specification(p): 1934 '''exception_specification : THROW '(' ')' 1935 | THROW '(' type_id_list ')' 1936 ''' 1937 global noExceptionLogic 1938 noExceptionLogic=False 1939 1940def p_type_id_list(p): 1941 '''type_id_list : type_id 1942 | type_id_list ',' type_id 1943 ''' 1944 pass 1945 1946#--------------------------------------------------------------------------------------------------- 1947# Misc productions 1948#--------------------------------------------------------------------------------------------------- 1949def p_nonsemicolon_seq(p): 1950 '''nonsemicolon_seq : empty 1951 | nonsemicolon_seq nonsemicolon 1952 ''' 1953 pass 1954 1955def p_nonsemicolon(p): 1956 '''nonsemicolon : misc 1957 | '(' 1958 | ')' 1959 | '<' 1960 | '>' 1961 | LBRACKET nonbracket_seq_opt RBRACKET 1962 | LBRACE nonbrace_seq_opt RBRACE 1963 ''' 1964 pass 1965 1966def p_nonparen_seq_opt(p): 1967 '''nonparen_seq_opt : empty 1968 | nonparen_seq_opt nonparen 1969 ''' 1970 pass 1971 1972def p_nonparen_seq(p): 1973 '''nonparen_seq : nonparen 1974 | nonparen_seq nonparen 1975 ''' 1976 pass 1977 1978def p_nonparen(p): 1979 '''nonparen : misc 1980 | '<' 1981 | '>' 1982 | ';' 1983 | LBRACKET nonbracket_seq_opt RBRACKET 1984 | LBRACE nonbrace_seq_opt RBRACE 1985 ''' 1986 pass 1987 1988def p_nonbracket_seq_opt(p): 1989 '''nonbracket_seq_opt : empty 1990 | nonbracket_seq_opt nonbracket 1991 ''' 1992 pass 1993 1994def p_nonbracket_seq(p): 1995 '''nonbracket_seq : nonbracket 1996 | nonbracket_seq nonbracket 1997 ''' 1998 pass 1999 2000def p_nonbracket(p): 2001 '''nonbracket : misc 2002 | '<' 2003 | '>' 2004 | '(' 2005 | ')' 2006 | ';' 2007 | LBRACKET nonbracket_seq_opt RBRACKET 2008 | LBRACE nonbrace_seq_opt RBRACE 2009 ''' 2010 pass 2011 2012def p_nonbrace_seq_opt(p): 2013 '''nonbrace_seq_opt : empty 2014 | nonbrace_seq_opt nonbrace 2015 ''' 2016 pass 2017 2018def p_nonbrace(p): 2019 '''nonbrace : misc 2020 | '<' 2021 | '>' 2022 | '(' 2023 | ')' 2024 | ';' 2025 | LBRACKET nonbracket_seq_opt RBRACKET 2026 | LBRACE nonbrace_seq_opt RBRACE 2027 ''' 2028 pass 2029 2030def p_nonlgt_seq_opt(p): 2031 '''nonlgt_seq_opt : empty 2032 | nonlgt_seq_opt nonlgt 2033 ''' 2034 pass 2035 2036def p_nonlgt(p): 2037 '''nonlgt : misc 2038 | '(' 2039 | ')' 2040 | LBRACKET nonbracket_seq_opt RBRACKET 2041 | '<' nonlgt_seq_opt '>' 2042 | ';' 2043 ''' 2044 pass 2045 2046def p_misc(p): 2047 '''misc : operator 2048 | identifier 2049 | IntegerLiteral 2050 | CharacterLiteral 2051 | FloatingLiteral 2052 | StringLiteral 2053 | reserved 2054 | '?' 2055 | ':' 2056 | '.' 2057 | SCOPE 2058 | ELLIPSIS 2059 | EXTENSION 2060 ''' 2061 pass 2062 2063def p_empty(p): 2064 '''empty : ''' 2065 pass 2066 2067 2068 2069# 2070# Compute column. 2071# input is the input text string 2072# token is a token instance 2073# 2074def _find_column(input,token): 2075 ''' TODO ''' 2076 i = token.lexpos 2077 while i > 0: 2078 if input[i] == '\n': break 2079 i -= 1 2080 column = (token.lexpos - i)+1 2081 return column 2082 2083def p_error(p): 2084 if p is None: 2085 tmp = "Syntax error at end of file." 2086 else: 2087 tmp = "Syntax error at token " 2088 if p.type is "": 2089 tmp = tmp + "''" 2090 else: 2091 tmp = tmp + str(p.type) 2092 tmp = tmp + " with value '"+str(p.value)+"'" 2093 tmp = tmp + " in line " + str(lexer.lineno-1) 2094 tmp = tmp + " at column "+str(_find_column(_parsedata,p)) 2095 raise IOError( tmp ) 2096 2097 2098 2099# 2100# The function that performs the parsing 2101# 2102def parse_cpp(data=None, filename=None, debug=0, optimize=0, verbose=False, func_filter=None): 2103 if debug > 0: 2104 print("Debugging parse_cpp!") 2105 # 2106 # Always remove the parser.out file, which is generated to create debugging 2107 # 2108 if os.path.exists("parser.out"): 2109 os.remove("parser.out") 2110 # 2111 # Remove the parsetab.py* files. These apparently need to be removed 2112 # to ensure the creation of a parser.out file. 2113 # 2114 if os.path.exists("parsetab.py"): 2115 os.remove("parsetab.py") 2116 if os.path.exists("parsetab.pyc"): 2117 os.remove("parsetab.pyc") 2118 global debugging 2119 debugging=True 2120 # 2121 # Build lexer 2122 # 2123 global lexer 2124 lexer = lex.lex() 2125 # 2126 # Initialize parse object 2127 # 2128 global _parse_info 2129 _parse_info = CppInfo(filter=func_filter) 2130 _parse_info.verbose=verbose 2131 # 2132 # Build yaccer 2133 # 2134 write_table = not os.path.exists("parsetab.py") 2135 yacc.yacc(debug=debug, optimize=optimize, write_tables=write_table) 2136 # 2137 # Parse the file 2138 # 2139 global _parsedata 2140 if not data is None: 2141 _parsedata=data 2142 ply_init(_parsedata) 2143 yacc.parse(data,debug=debug) 2144 elif not filename is None: 2145 f = open(filename) 2146 data = f.read() 2147 f.close() 2148 _parsedata=data 2149 ply_init(_parsedata) 2150 yacc.parse(data, debug=debug) 2151 else: 2152 return None 2153 # 2154 if not noExceptionLogic: 2155 _parse_info.noExceptionLogic = False 2156 else: 2157 for key in identifier_lineno: 2158 if 'ASSERT_THROWS' in key: 2159 _parse_info.noExceptionLogic = False 2160 break 2161 _parse_info.noExceptionLogic = True 2162 # 2163 return _parse_info 2164 2165 2166 2167import sys 2168 2169if __name__ == '__main__': 2170 # 2171 # This MAIN routine parses a sequence of files provided at the command 2172 # line. If '-v' is included, then a verbose parsing output is 2173 # generated. 2174 # 2175 for arg in sys.argv[1:]: 2176 if arg == "-v": 2177 continue 2178 print("Parsing file '"+arg+"'") 2179 if '-v' in sys.argv: 2180 parse_cpp(filename=arg,debug=2,verbose=2) 2181 else: 2182 parse_cpp(filename=arg,verbose=2) 2183 # 2184 # Print the _parse_info object summary for this file. 2185 # This illustrates how class inheritance can be used to 2186 # deduce class members. 2187 # 2188 print(str(_parse_info)) 2189 2190