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