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