Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
c_parser.py1951 linesDownload Raw Back to pycparser
1#------------------------------------------------------------------------------2# pycparser: c_parser.py3#4# CParser class: Parser and AST builder for the C language5#6# Eli Bendersky [https://eli.thegreenplace.net/]7# License: BSD8#------------------------------------------------------------------------------9from .ply import yacc10 11from . import c_ast12from .c_lexer import CLexer13from .plyparser import PLYParser, ParseError, parameterized, template14from .ast_transforms import fix_switch_cases, fix_atomic_specifiers15 16 17@template18class CParser(PLYParser):19    def __init__(20            self,21            lex_optimize=True,22            lexer=CLexer,23            lextab='pycparser.lextab',24            yacc_optimize=True,25            yacctab='pycparser.yacctab',26            yacc_debug=False,27            taboutputdir=''):28        """ Create a new CParser.29 30            Some arguments for controlling the debug/optimization31            level of the parser are provided. The defaults are32            tuned for release/performance mode.33            The simple rules for using them are:34            *) When tweaking CParser/CLexer, set these to False35            *) When releasing a stable parser, set to True36 37            lex_optimize:38                Set to False when you're modifying the lexer.39                Otherwise, changes in the lexer won't be used, if40                some lextab.py file exists.41                When releasing with a stable lexer, set to True42                to save the re-generation of the lexer table on43                each run.44 45            lexer:46                Set this parameter to define the lexer to use if47                you're not using the default CLexer.48 49            lextab:50                Points to the lex table that's used for optimized51                mode. Only if you're modifying the lexer and want52                some tests to avoid re-generating the table, make53                this point to a local lex table file (that's been54                earlier generated with lex_optimize=True)55 56            yacc_optimize:57                Set to False when you're modifying the parser.58                Otherwise, changes in the parser won't be used, if59                some parsetab.py file exists.60                When releasing with a stable parser, set to True61                to save the re-generation of the parser table on62                each run.63 64            yacctab:65                Points to the yacc table that's used for optimized66                mode. Only if you're modifying the parser, make67                this point to a local yacc table file68 69            yacc_debug:70                Generate a parser.out file that explains how yacc71                built the parsing table from the grammar.72 73            taboutputdir:74                Set this parameter to control the location of generated75                lextab and yacctab files.76        """77        self.clex = lexer(78            error_func=self._lex_error_func,79            on_lbrace_func=self._lex_on_lbrace_func,80            on_rbrace_func=self._lex_on_rbrace_func,81            type_lookup_func=self._lex_type_lookup_func)82 83        self.clex.build(84            optimize=lex_optimize,85            lextab=lextab,86            outputdir=taboutputdir)87        self.tokens = self.clex.tokens88 89        rules_with_opt = [90            'abstract_declarator',91            'assignment_expression',92            'declaration_list',93            'declaration_specifiers_no_type',94            'designation',95            'expression',96            'identifier_list',97            'init_declarator_list',98            'id_init_declarator_list',99            'initializer_list',100            'parameter_type_list',101            'block_item_list',102            'type_qualifier_list',103            'struct_declarator_list'104        ]105 106        for rule in rules_with_opt:107            self._create_opt_rule(rule)108 109        self.cparser = yacc.yacc(110            module=self,111            start='translation_unit_or_empty',112            debug=yacc_debug,113            optimize=yacc_optimize,114            tabmodule=yacctab,115            outputdir=taboutputdir)116 117        # Stack of scopes for keeping track of symbols. _scope_stack[-1] is118        # the current (topmost) scope. Each scope is a dictionary that119        # specifies whether a name is a type. If _scope_stack[n][name] is120        # True, 'name' is currently a type in the scope. If it's False,121        # 'name' is used in the scope but not as a type (for instance, if we122        # saw: int name;123        # If 'name' is not a key in _scope_stack[n] then 'name' was not defined124        # in this scope at all.125        self._scope_stack = [dict()]126 127        # Keeps track of the last token given to yacc (the lookahead token)128        self._last_yielded_token = None129 130    def parse(self, text, filename='', debug=False):131        """ Parses C code and returns an AST.132 133            text:134                A string containing the C source code135 136            filename:137                Name of the file being parsed (for meaningful138                error messages)139 140            debug:141                Debug flag to YACC142        """143        self.clex.filename = filename144        self.clex.reset_lineno()145        self._scope_stack = [dict()]146        self._last_yielded_token = None147        return self.cparser.parse(148                input=text,149                lexer=self.clex,150                debug=debug)151 152    ######################--   PRIVATE   --######################153 154    def _push_scope(self):155        self._scope_stack.append(dict())156 157    def _pop_scope(self):158        assert len(self._scope_stack) > 1159        self._scope_stack.pop()160 161    def _add_typedef_name(self, name, coord):162        """ Add a new typedef name (ie a TYPEID) to the current scope163        """164        if not self._scope_stack[-1].get(name, True):165            self._parse_error(166                "Typedef %r previously declared as non-typedef "167                "in this scope" % name, coord)168        self._scope_stack[-1][name] = True169 170    def _add_identifier(self, name, coord):171        """ Add a new object, function, or enum member name (ie an ID) to the172            current scope173        """174        if self._scope_stack[-1].get(name, False):175            self._parse_error(176                "Non-typedef %r previously declared as typedef "177                "in this scope" % name, coord)178        self._scope_stack[-1][name] = False179 180    def _is_type_in_scope(self, name):181        """ Is *name* a typedef-name in the current scope?182        """183        for scope in reversed(self._scope_stack):184            # If name is an identifier in this scope it shadows typedefs in185            # higher scopes.186            in_scope = scope.get(name)187            if in_scope is not None: return in_scope188        return False189 190    def _lex_error_func(self, msg, line, column):191        self._parse_error(msg, self._coord(line, column))192 193    def _lex_on_lbrace_func(self):194        self._push_scope()195 196    def _lex_on_rbrace_func(self):197        self._pop_scope()198 199    def _lex_type_lookup_func(self, name):200        """ Looks up types that were previously defined with201            typedef.202            Passed to the lexer for recognizing identifiers that203            are types.204        """205        is_type = self._is_type_in_scope(name)206        return is_type207 208    def _get_yacc_lookahead_token(self):209        """ We need access to yacc's lookahead token in certain cases.210            This is the last token yacc requested from the lexer, so we211            ask the lexer.212        """213        return self.clex.last_token214 215    # To understand what's going on here, read sections A.8.5 and216    # A.8.6 of K&R2 very carefully.217    #218    # A C type consists of a basic type declaration, with a list219    # of modifiers. For example:220    #221    # int *c[5];222    #223    # The basic declaration here is 'int c', and the pointer and224    # the array are the modifiers.225    #226    # Basic declarations are represented by TypeDecl (from module c_ast) and the227    # modifiers are FuncDecl, PtrDecl and ArrayDecl.228    #229    # The standard states that whenever a new modifier is parsed, it should be230    # added to the end of the list of modifiers. For example:231    #232    # K&R2 A.8.6.2: Array Declarators233    #234    # In a declaration T D where D has the form235    #   D1 [constant-expression-opt]236    # and the type of the identifier in the declaration T D1 is237    # "type-modifier T", the type of the238    # identifier of D is "type-modifier array of T"239    #240    # This is what this method does. The declarator it receives241    # can be a list of declarators ending with TypeDecl. It242    # tacks the modifier to the end of this list, just before243    # the TypeDecl.244    #245    # Additionally, the modifier may be a list itself. This is246    # useful for pointers, that can come as a chain from the rule247    # p_pointer. In this case, the whole modifier list is spliced248    # into the new location.249    def _type_modify_decl(self, decl, modifier):250        """ Tacks a type modifier on a declarator, and returns251            the modified declarator.252 253            Note: the declarator and modifier may be modified254        """255        #~ print '****'256        #~ decl.show(offset=3)257        #~ modifier.show(offset=3)258        #~ print '****'259 260        modifier_head = modifier261        modifier_tail = modifier262 263        # The modifier may be a nested list. Reach its tail.264        while modifier_tail.type:265            modifier_tail = modifier_tail.type266 267        # If the decl is a basic type, just tack the modifier onto it.268        if isinstance(decl, c_ast.TypeDecl):269            modifier_tail.type = decl270            return modifier271        else:272            # Otherwise, the decl is a list of modifiers. Reach273            # its tail and splice the modifier onto the tail,274            # pointing to the underlying basic type.275            decl_tail = decl276 277            while not isinstance(decl_tail.type, c_ast.TypeDecl):278                decl_tail = decl_tail.type279 280            modifier_tail.type = decl_tail.type281            decl_tail.type = modifier_head282            return decl283 284    # Due to the order in which declarators are constructed,285    # they have to be fixed in order to look like a normal AST.286    #287    # When a declaration arrives from syntax construction, it has288    # these problems:289    # * The innermost TypeDecl has no type (because the basic290    #   type is only known at the uppermost declaration level)291    # * The declaration has no variable name, since that is saved292    #   in the innermost TypeDecl293    # * The typename of the declaration is a list of type294    #   specifiers, and not a node. Here, basic identifier types295    #   should be separated from more complex types like enums296    #   and structs.297    #298    # This method fixes these problems.299    def _fix_decl_name_type(self, decl, typename):300        """ Fixes a declaration. Modifies decl.301        """302        # Reach the underlying basic type303        #304        type = decl305        while not isinstance(type, c_ast.TypeDecl):306            type = type.type307 308        decl.name = type.declname309        type.quals = decl.quals[:]310 311        # The typename is a list of types. If any type in this312        # list isn't an IdentifierType, it must be the only313        # type in the list (it's illegal to declare "int enum ..")314        # If all the types are basic, they're collected in the315        # IdentifierType holder.316        for tn in typename:317            if not isinstance(tn, c_ast.IdentifierType):318                if len(typename) > 1:319                    self._parse_error(320                        "Invalid multiple types specified", tn.coord)321                else:322                    type.type = tn323                    return decl324 325        if not typename:326            # Functions default to returning int327            #328            if not isinstance(decl.type, c_ast.FuncDecl):329                self._parse_error(330                        "Missing type in declaration", decl.coord)331            type.type = c_ast.IdentifierType(332                    ['int'],333                    coord=decl.coord)334        else:335            # At this point, we know that typename is a list of IdentifierType336            # nodes. Concatenate all the names into a single list.337            #338            type.type = c_ast.IdentifierType(339                [name for id in typename for name in id.names],340                coord=typename[0].coord)341        return decl342 343    def _add_declaration_specifier(self, declspec, newspec, kind, append=False):344        """ Declaration specifiers are represented by a dictionary345            with the entries:346            * qual: a list of type qualifiers347            * storage: a list of storage type qualifiers348            * type: a list of type specifiers349            * function: a list of function specifiers350            * alignment: a list of alignment specifiers351 352            This method is given a declaration specifier, and a353            new specifier of a given kind.354            If `append` is True, the new specifier is added to the end of355            the specifiers list, otherwise it's added at the beginning.356            Returns the declaration specifier, with the new357            specifier incorporated.358        """359        spec = declspec or dict(qual=[], storage=[], type=[], function=[], alignment=[])360 361        if append:362            spec[kind].append(newspec)363        else:364            spec[kind].insert(0, newspec)365 366        return spec367 368    def _build_declarations(self, spec, decls, typedef_namespace=False):369        """ Builds a list of declarations all sharing the given specifiers.370            If typedef_namespace is true, each declared name is added371            to the "typedef namespace", which also includes objects,372            functions, and enum constants.373        """374        is_typedef = 'typedef' in spec['storage']375        declarations = []376 377        # Bit-fields are allowed to be unnamed.378        if decls[0].get('bitsize') is not None:379            pass380 381        # When redeclaring typedef names as identifiers in inner scopes, a382        # problem can occur where the identifier gets grouped into383        # spec['type'], leaving decl as None.  This can only occur for the384        # first declarator.385        elif decls[0]['decl'] is None:386            if len(spec['type']) < 2 or len(spec['type'][-1].names) != 1 or \387                    not self._is_type_in_scope(spec['type'][-1].names[0]):388                coord = '?'389                for t in spec['type']:390                    if hasattr(t, 'coord'):391                        coord = t.coord392                        break393                self._parse_error('Invalid declaration', coord)394 395            # Make this look as if it came from "direct_declarator:ID"396            decls[0]['decl'] = c_ast.TypeDecl(397                declname=spec['type'][-1].names[0],398                type=None,399                quals=None,400                align=spec['alignment'],401                coord=spec['type'][-1].coord)402            # Remove the "new" type's name from the end of spec['type']403            del spec['type'][-1]404 405        # A similar problem can occur where the declaration ends up looking406        # like an abstract declarator.  Give it a name if this is the case.407        elif not isinstance(decls[0]['decl'], (408                c_ast.Enum, c_ast.Struct, c_ast.Union, c_ast.IdentifierType)):409            decls_0_tail = decls[0]['decl']410            while not isinstance(decls_0_tail, c_ast.TypeDecl):411                decls_0_tail = decls_0_tail.type412            if decls_0_tail.declname is None:413                decls_0_tail.declname = spec['type'][-1].names[0]414                del spec['type'][-1]415 416        for decl in decls:417            assert decl['decl'] is not None418            if is_typedef:419                declaration = c_ast.Typedef(420                    name=None,421                    quals=spec['qual'],422                    storage=spec['storage'],423                    type=decl['decl'],424                    coord=decl['decl'].coord)425            else:426                declaration = c_ast.Decl(427                    name=None,428                    quals=spec['qual'],429                    align=spec['alignment'],430                    storage=spec['storage'],431                    funcspec=spec['function'],432                    type=decl['decl'],433                    init=decl.get('init'),434                    bitsize=decl.get('bitsize'),435                    coord=decl['decl'].coord)436 437            if isinstance(declaration.type, (438                    c_ast.Enum, c_ast.Struct, c_ast.Union,439                    c_ast.IdentifierType)):440                fixed_decl = declaration441            else:442                fixed_decl = self._fix_decl_name_type(declaration, spec['type'])443 444            # Add the type name defined by typedef to a445            # symbol table (for usage in the lexer)446            if typedef_namespace:447                if is_typedef:448                    self._add_typedef_name(fixed_decl.name, fixed_decl.coord)449                else:450                    self._add_identifier(fixed_decl.name, fixed_decl.coord)451 452            fixed_decl = fix_atomic_specifiers(fixed_decl)453            declarations.append(fixed_decl)454 455        return declarations456 457    def _build_function_definition(self, spec, decl, param_decls, body):458        """ Builds a function definition.459        """460        if 'typedef' in spec['storage']:461            self._parse_error("Invalid typedef", decl.coord)462 463        declaration = self._build_declarations(464            spec=spec,465            decls=[dict(decl=decl, init=None)],466            typedef_namespace=True)[0]467 468        return c_ast.FuncDef(469            decl=declaration,470            param_decls=param_decls,471            body=body,472            coord=decl.coord)473 474    def _select_struct_union_class(self, token):475        """ Given a token (either STRUCT or UNION), selects the476            appropriate AST class.477        """478        if token == 'struct':479            return c_ast.Struct480        else:481            return c_ast.Union482 483    ##484    ## Precedence and associativity of operators485    ##486    # If this changes, c_generator.CGenerator.precedence_map needs to change as487    # well488    precedence = (489        ('left', 'LOR'),490        ('left', 'LAND'),491        ('left', 'OR'),492        ('left', 'XOR'),493        ('left', 'AND'),494        ('left', 'EQ', 'NE'),495        ('left', 'GT', 'GE', 'LT', 'LE'),496        ('left', 'RSHIFT', 'LSHIFT'),497        ('left', 'PLUS', 'MINUS'),498        ('left', 'TIMES', 'DIVIDE', 'MOD')499    )500 501    ##502    ## Grammar productions503    ## Implementation of the BNF defined in K&R2 A.13504    ##505 506    # Wrapper around a translation unit, to allow for empty input.507    # Not strictly part of the C99 Grammar, but useful in practice.508    def p_translation_unit_or_empty(self, p):509        """ translation_unit_or_empty   : translation_unit510                                        | empty511        """512        if p[1] is None:513            p[0] = c_ast.FileAST([])514        else:515            p[0] = c_ast.FileAST(p[1])516 517    def p_translation_unit_1(self, p):518        """ translation_unit    : external_declaration519        """520        # Note: external_declaration is already a list521        p[0] = p[1]522 523    def p_translation_unit_2(self, p):524        """ translation_unit    : translation_unit external_declaration525        """526        p[1].extend(p[2])527        p[0] = p[1]528 529    # Declarations always come as lists (because they can be530    # several in one line), so we wrap the function definition531    # into a list as well, to make the return value of532    # external_declaration homogeneous.533    def p_external_declaration_1(self, p):534        """ external_declaration    : function_definition535        """536        p[0] = [p[1]]537 538    def p_external_declaration_2(self, p):539        """ external_declaration    : declaration540        """541        p[0] = p[1]542 543    def p_external_declaration_3(self, p):544        """ external_declaration    : pp_directive545                                    | pppragma_directive546        """547        p[0] = [p[1]]548 549    def p_external_declaration_4(self, p):550        """ external_declaration    : SEMI551        """552        p[0] = []553 554    def p_external_declaration_5(self, p):555        """ external_declaration    : static_assert556        """557        p[0] = p[1]558 559    def p_static_assert_declaration(self, p):560        """ static_assert           : _STATIC_ASSERT LPAREN constant_expression COMMA unified_string_literal RPAREN561                                    | _STATIC_ASSERT LPAREN constant_expression RPAREN562        """563        if len(p) == 5:564            p[0] = [c_ast.StaticAssert(p[3], None, self._token_coord(p, 1))]565        else:566            p[0] = [c_ast.StaticAssert(p[3], p[5], self._token_coord(p, 1))]567 568    def p_pp_directive(self, p):569        """ pp_directive  : PPHASH570        """571        self._parse_error('Directives not supported yet',572                          self._token_coord(p, 1))573 574    # This encompasses two types of C99-compatible pragmas:575    # - The #pragma directive:576    #       # pragma character_sequence577    # - The _Pragma unary operator:578    #       _Pragma ( " string_literal " )579    def p_pppragma_directive(self, p):580        """ pppragma_directive      : PPPRAGMA581                                    | PPPRAGMA PPPRAGMASTR582                                    | _PRAGMA LPAREN unified_string_literal RPAREN583        """584        if len(p) == 5:585            p[0] = c_ast.Pragma(p[3], self._token_coord(p, 2))586        elif len(p) == 3:587            p[0] = c_ast.Pragma(p[2], self._token_coord(p, 2))588        else:589            p[0] = c_ast.Pragma("", self._token_coord(p, 1))590 591    def p_pppragma_directive_list(self, p):592        """ pppragma_directive_list : pppragma_directive593                                    | pppragma_directive_list pppragma_directive594        """595        p[0] = [p[1]] if len(p) == 2 else p[1] + [p[2]]596 597    # In function definitions, the declarator can be followed by598    # a declaration list, for old "K&R style" function definitios.599    def p_function_definition_1(self, p):600        """ function_definition : id_declarator declaration_list_opt compound_statement601        """602        # no declaration specifiers - 'int' becomes the default type603        spec = dict(604            qual=[],605            alignment=[],606            storage=[],607            type=[c_ast.IdentifierType(['int'],608                                       coord=self._token_coord(p, 1))],609            function=[])610 611        p[0] = self._build_function_definition(612            spec=spec,613            decl=p[1],614            param_decls=p[2],615            body=p[3])616 617    def p_function_definition_2(self, p):618        """ function_definition : declaration_specifiers id_declarator declaration_list_opt compound_statement619        """620        spec = p[1]621 622        p[0] = self._build_function_definition(623            spec=spec,624            decl=p[2],625            param_decls=p[3],626            body=p[4])627 628    # Note, according to C18 A.2.2 6.7.10 static_assert-declaration _Static_assert629    # is a declaration, not a statement. We additionally recognise it as a statement630    # to fix parsing of _Static_assert inside the functions.631    #632    def p_statement(self, p):633        """ statement   : labeled_statement634                        | expression_statement635                        | compound_statement636                        | selection_statement637                        | iteration_statement638                        | jump_statement639                        | pppragma_directive640                        | static_assert641        """642        p[0] = p[1]643 644    # A pragma is generally considered a decorator rather than an actual645    # statement. Still, for the purposes of analyzing an abstract syntax tree of646    # C code, pragma's should not be ignored and were previously treated as a647    # statement. This presents a problem for constructs that take a statement648    # such as labeled_statements, selection_statements, and649    # iteration_statements, causing a misleading structure in the AST. For650    # example, consider the following C code.651    #652    #   for (int i = 0; i < 3; i++)653    #       #pragma omp critical654    #       sum += 1;655    #656    # This code will compile and execute "sum += 1;" as the body of the for657    # loop. Previous implementations of PyCParser would render the AST for this658    # block of code as follows:659    #660    #   For:661    #     DeclList:662    #       Decl: i, [], [], []663    #         TypeDecl: i, []664    #           IdentifierType: ['int']665    #         Constant: int, 0666    #     BinaryOp: <667    #       ID: i668    #       Constant: int, 3669    #     UnaryOp: p++670    #       ID: i671    #     Pragma: omp critical672    #   Assignment: +=673    #     ID: sum674    #     Constant: int, 1675    #676    # This AST misleadingly takes the Pragma as the body of the loop and the677    # assignment then becomes a sibling of the loop.678    #679    # To solve edge cases like these, the pragmacomp_or_statement rule groups680    # a pragma and its following statement (which would otherwise be orphaned)681    # using a compound block, effectively turning the above code into:682    #683    #   for (int i = 0; i < 3; i++) {684    #       #pragma omp critical685    #       sum += 1;686    #   }687    def p_pragmacomp_or_statement(self, p):688        """ pragmacomp_or_statement     : pppragma_directive_list statement689                                        | statement690        """691        if len(p) == 3:692            p[0] = c_ast.Compound(693                block_items=p[1]+[p[2]],694                coord=self._token_coord(p, 1))695        else:696            p[0] = p[1]697 698    # In C, declarations can come several in a line:699    #   int x, *px, romulo = 5;700    #701    # However, for the AST, we will split them to separate Decl702    # nodes.703    #704    # This rule splits its declarations and always returns a list705    # of Decl nodes, even if it's one element long.706    #707    def p_decl_body(self, p):708        """ decl_body : declaration_specifiers init_declarator_list_opt709                      | declaration_specifiers_no_type id_init_declarator_list_opt710        """711        spec = p[1]712 713        # p[2] (init_declarator_list_opt) is either a list or None714        #715        if p[2] is None:716            # By the standard, you must have at least one declarator unless717            # declaring a structure tag, a union tag, or the members of an718            # enumeration.719            #720            ty = spec['type']721            s_u_or_e = (c_ast.Struct, c_ast.Union, c_ast.Enum)722            if len(ty) == 1 and isinstance(ty[0], s_u_or_e):723                decls = [c_ast.Decl(724                    name=None,725                    quals=spec['qual'],726                    align=spec['alignment'],727                    storage=spec['storage'],728                    funcspec=spec['function'],729                    type=ty[0],730                    init=None,731                    bitsize=None,732                    coord=ty[0].coord)]733 734            # However, this case can also occur on redeclared identifiers in735            # an inner scope.  The trouble is that the redeclared type's name736            # gets grouped into declaration_specifiers; _build_declarations737            # compensates for this.738            #739            else:740                decls = self._build_declarations(741                    spec=spec,742                    decls=[dict(decl=None, init=None)],743                    typedef_namespace=True)744 745        else:746            decls = self._build_declarations(747                spec=spec,748                decls=p[2],749                typedef_namespace=True)750 751        p[0] = decls752 753    # The declaration has been split to a decl_body sub-rule and754    # SEMI, because having them in a single rule created a problem755    # for defining typedefs.756    #757    # If a typedef line was directly followed by a line using the758    # type defined with the typedef, the type would not be759    # recognized. This is because to reduce the declaration rule,760    # the parser's lookahead asked for the token after SEMI, which761    # was the type from the next line, and the lexer had no chance762    # to see the updated type symbol table.763    #764    # Splitting solves this problem, because after seeing SEMI,765    # the parser reduces decl_body, which actually adds the new766    # type into the table to be seen by the lexer before the next767    # line is reached.768    def p_declaration(self, p):769        """ declaration : decl_body SEMI770        """771        p[0] = p[1]772 773    # Since each declaration is a list of declarations, this774    # rule will combine all the declarations and return a single775    # list776    #777    def p_declaration_list(self, p):778        """ declaration_list    : declaration779                                | declaration_list declaration780        """781        p[0] = p[1] if len(p) == 2 else p[1] + p[2]782 783    # To know when declaration-specifiers end and declarators begin,784    # we require declaration-specifiers to have at least one785    # type-specifier, and disallow typedef-names after we've seen any786    # type-specifier. These are both required by the spec.787    #788    def p_declaration_specifiers_no_type_1(self, p):789        """ declaration_specifiers_no_type  : type_qualifier declaration_specifiers_no_type_opt790        """791        p[0] = self._add_declaration_specifier(p[2], p[1], 'qual')792 793    def p_declaration_specifiers_no_type_2(self, p):794        """ declaration_specifiers_no_type  : storage_class_specifier declaration_specifiers_no_type_opt795        """796        p[0] = self._add_declaration_specifier(p[2], p[1], 'storage')797 798    def p_declaration_specifiers_no_type_3(self, p):799        """ declaration_specifiers_no_type  : function_specifier declaration_specifiers_no_type_opt800        """801        p[0] = self._add_declaration_specifier(p[2], p[1], 'function')802 803    # Without this, `typedef _Atomic(T) U` will parse incorrectly because the804    # _Atomic qualifier will match, instead of the specifier.805    def p_declaration_specifiers_no_type_4(self, p):806        """ declaration_specifiers_no_type  : atomic_specifier declaration_specifiers_no_type_opt807        """808        p[0] = self._add_declaration_specifier(p[2], p[1], 'type')809 810    def p_declaration_specifiers_no_type_5(self, p):811        """ declaration_specifiers_no_type  : alignment_specifier declaration_specifiers_no_type_opt812        """813        p[0] = self._add_declaration_specifier(p[2], p[1], 'alignment')814 815    def p_declaration_specifiers_1(self, p):816        """ declaration_specifiers  : declaration_specifiers type_qualifier817        """818        p[0] = self._add_declaration_specifier(p[1], p[2], 'qual', append=True)819 820    def p_declaration_specifiers_2(self, p):821        """ declaration_specifiers  : declaration_specifiers storage_class_specifier822        """823        p[0] = self._add_declaration_specifier(p[1], p[2], 'storage', append=True)824 825    def p_declaration_specifiers_3(self, p):826        """ declaration_specifiers  : declaration_specifiers function_specifier827        """828        p[0] = self._add_declaration_specifier(p[1], p[2], 'function', append=True)829 830    def p_declaration_specifiers_4(self, p):831        """ declaration_specifiers  : declaration_specifiers type_specifier_no_typeid832        """833        p[0] = self._add_declaration_specifier(p[1], p[2], 'type', append=True)834 835    def p_declaration_specifiers_5(self, p):836        """ declaration_specifiers  : type_specifier837        """838        p[0] = self._add_declaration_specifier(None, p[1], 'type')839 840    def p_declaration_specifiers_6(self, p):841        """ declaration_specifiers  : declaration_specifiers_no_type type_specifier842        """843        p[0] = self._add_declaration_specifier(p[1], p[2], 'type', append=True)844 845    def p_declaration_specifiers_7(self, p):846        """ declaration_specifiers  : declaration_specifiers alignment_specifier847        """848        p[0] = self._add_declaration_specifier(p[1], p[2], 'alignment', append=True)849 850    def p_storage_class_specifier(self, p):851        """ storage_class_specifier : AUTO852                                    | REGISTER853                                    | STATIC854                                    | EXTERN855                                    | TYPEDEF856                                    | _THREAD_LOCAL857        """858        p[0] = p[1]859 860    def p_function_specifier(self, p):861        """ function_specifier  : INLINE862                                | _NORETURN863        """864        p[0] = p[1]865 866    def p_type_specifier_no_typeid(self, p):867        """ type_specifier_no_typeid  : VOID868                                      | _BOOL869                                      | CHAR870                                      | SHORT871                                      | INT872                                      | LONG873                                      | FLOAT874                                      | DOUBLE875                                      | _COMPLEX876                                      | SIGNED877                                      | UNSIGNED878                                      | __INT128879        """880        p[0] = c_ast.IdentifierType([p[1]], coord=self._token_coord(p, 1))881 882    def p_type_specifier(self, p):883        """ type_specifier  : typedef_name884                            | enum_specifier885                            | struct_or_union_specifier886                            | type_specifier_no_typeid887                            | atomic_specifier888        """889        p[0] = p[1]890 891    # See section 6.7.2.4 of the C11 standard.892    def p_atomic_specifier(self, p):893        """ atomic_specifier  : _ATOMIC LPAREN type_name RPAREN894        """895        typ = p[3]896        typ.quals.append('_Atomic')897        p[0] = typ898 899    def p_type_qualifier(self, p):900        """ type_qualifier  : CONST901                            | RESTRICT902                            | VOLATILE903                            | _ATOMIC904        """905        p[0] = p[1]906 907    def p_init_declarator_list(self, p):908        """ init_declarator_list    : init_declarator909                                    | init_declarator_list COMMA init_declarator910        """911        p[0] = p[1] + [p[3]] if len(p) == 4 else [p[1]]912 913    # Returns a {decl=<declarator> : init=<initializer>} dictionary914    # If there's no initializer, uses None915    #916    def p_init_declarator(self, p):917        """ init_declarator : declarator918                            | declarator EQUALS initializer919        """920        p[0] = dict(decl=p[1], init=(p[3] if len(p) > 2 else None))921 922    def p_id_init_declarator_list(self, p):923        """ id_init_declarator_list    : id_init_declarator924                                       | id_init_declarator_list COMMA init_declarator925        """926        p[0] = p[1] + [p[3]] if len(p) == 4 else [p[1]]927 928    def p_id_init_declarator(self, p):929        """ id_init_declarator : id_declarator930                               | id_declarator EQUALS initializer931        """932        p[0] = dict(decl=p[1], init=(p[3] if len(p) > 2 else None))933 934    # Require at least one type specifier in a specifier-qualifier-list935    #936    def p_specifier_qualifier_list_1(self, p):937        """ specifier_qualifier_list    : specifier_qualifier_list type_specifier_no_typeid938        """939        p[0] = self._add_declaration_specifier(p[1], p[2], 'type', append=True)940 941    def p_specifier_qualifier_list_2(self, p):942        """ specifier_qualifier_list    : specifier_qualifier_list type_qualifier943        """944        p[0] = self._add_declaration_specifier(p[1], p[2], 'qual', append=True)945 946    def p_specifier_qualifier_list_3(self, p):947        """ specifier_qualifier_list  : type_specifier948        """949        p[0] = self._add_declaration_specifier(None, p[1], 'type')950 951    def p_specifier_qualifier_list_4(self, p):952        """ specifier_qualifier_list  : type_qualifier_list type_specifier953        """954        p[0] = dict(qual=p[1], alignment=[], storage=[], type=[p[2]], function=[])955 956    def p_specifier_qualifier_list_5(self, p):957        """ specifier_qualifier_list  : alignment_specifier958        """959        p[0] = dict(qual=[], alignment=[p[1]], storage=[], type=[], function=[])960 961    def p_specifier_qualifier_list_6(self, p):962        """ specifier_qualifier_list  : specifier_qualifier_list alignment_specifier963        """964        p[0] = self._add_declaration_specifier(p[1], p[2], 'alignment')965 966    # TYPEID is allowed here (and in other struct/enum related tag names), because967    # struct/enum tags reside in their own namespace and can be named the same as types968    #969    def p_struct_or_union_specifier_1(self, p):970        """ struct_or_union_specifier   : struct_or_union ID971                                        | struct_or_union TYPEID972        """973        klass = self._select_struct_union_class(p[1])974        # None means no list of members975        p[0] = klass(976            name=p[2],977            decls=None,978            coord=self._token_coord(p, 2))979 980    def p_struct_or_union_specifier_2(self, p):981        """ struct_or_union_specifier : struct_or_union brace_open struct_declaration_list brace_close982                                      | struct_or_union brace_open brace_close983        """984        klass = self._select_struct_union_class(p[1])985        if len(p) == 4:986            # Empty sequence means an empty list of members987            p[0] = klass(988                name=None,989                decls=[],990                coord=self._token_coord(p, 2))991        else:992            p[0] = klass(993                name=None,994                decls=p[3],995                coord=self._token_coord(p, 2))996 997 998    def p_struct_or_union_specifier_3(self, p):999        """ struct_or_union_specifier   : struct_or_union ID brace_open struct_declaration_list brace_close1000                                        | struct_or_union ID brace_open brace_close1001                                        | struct_or_union TYPEID brace_open struct_declaration_list brace_close1002                                        | struct_or_union TYPEID brace_open brace_close1003        """1004        klass = self._select_struct_union_class(p[1])1005        if len(p) == 5:1006            # Empty sequence means an empty list of members1007            p[0] = klass(1008                name=p[2],1009                decls=[],1010                coord=self._token_coord(p, 2))1011        else:1012            p[0] = klass(1013                name=p[2],1014                decls=p[4],1015                coord=self._token_coord(p, 2))1016 1017    def p_struct_or_union(self, p):1018        """ struct_or_union : STRUCT1019                            | UNION1020        """1021        p[0] = p[1]1022 1023    # Combine all declarations into a single list1024    #1025    def p_struct_declaration_list(self, p):1026        """ struct_declaration_list     : struct_declaration1027                                        | struct_declaration_list struct_declaration1028        """1029        if len(p) == 2:1030            p[0] = p[1] or []1031        else:1032            p[0] = p[1] + (p[2] or [])1033 1034    def p_struct_declaration_1(self, p):1035        """ struct_declaration : specifier_qualifier_list struct_declarator_list_opt SEMI1036        """1037        spec = p[1]1038        assert 'typedef' not in spec['storage']1039 1040        if p[2] is not None:1041            decls = self._build_declarations(1042                spec=spec,1043                decls=p[2])1044 1045        elif len(spec['type']) == 1:1046            # Anonymous struct/union, gcc extension, C1x feature.1047            # Although the standard only allows structs/unions here, I see no1048            # reason to disallow other types since some compilers have typedefs1049            # here, and pycparser isn't about rejecting all invalid code.1050            #1051            node = spec['type'][0]1052            if isinstance(node, c_ast.Node):1053                decl_type = node1054            else:1055                decl_type = c_ast.IdentifierType(node)1056 1057            decls = self._build_declarations(1058                spec=spec,1059                decls=[dict(decl=decl_type)])1060 1061        else:1062            # Structure/union members can have the same names as typedefs.1063            # The trouble is that the member's name gets grouped into1064            # specifier_qualifier_list; _build_declarations compensates.1065            #1066            decls = self._build_declarations(1067                spec=spec,1068                decls=[dict(decl=None, init=None)])1069 1070        p[0] = decls1071 1072    def p_struct_declaration_2(self, p):1073        """ struct_declaration : SEMI1074        """1075        p[0] = None1076 1077    def p_struct_declaration_3(self, p):1078        """ struct_declaration : pppragma_directive1079        """1080        p[0] = [p[1]]1081 1082    def p_struct_declarator_list(self, p):1083        """ struct_declarator_list  : struct_declarator1084                                    | struct_declarator_list COMMA struct_declarator1085        """1086        p[0] = p[1] + [p[3]] if len(p) == 4 else [p[1]]1087 1088    # struct_declarator passes up a dict with the keys: decl (for1089    # the underlying declarator) and bitsize (for the bitsize)1090    #1091    def p_struct_declarator_1(self, p):1092        """ struct_declarator : declarator1093        """1094        p[0] = {'decl': p[1], 'bitsize': None}1095 1096    def p_struct_declarator_2(self, p):1097        """ struct_declarator   : declarator COLON constant_expression1098                                | COLON constant_expression1099        """1100        if len(p) > 3:1101            p[0] = {'decl': p[1], 'bitsize': p[3]}1102        else:1103            p[0] = {'decl': c_ast.TypeDecl(None, None, None, None), 'bitsize': p[2]}1104 1105    def p_enum_specifier_1(self, p):1106        """ enum_specifier  : ENUM ID1107                            | ENUM TYPEID1108        """1109        p[0] = c_ast.Enum(p[2], None, self._token_coord(p, 1))1110 1111    def p_enum_specifier_2(self, p):1112        """ enum_specifier  : ENUM brace_open enumerator_list brace_close1113        """1114        p[0] = c_ast.Enum(None, p[3], self._token_coord(p, 1))1115 1116    def p_enum_specifier_3(self, p):1117        """ enum_specifier  : ENUM ID brace_open enumerator_list brace_close1118                            | ENUM TYPEID brace_open enumerator_list brace_close1119        """1120        p[0] = c_ast.Enum(p[2], p[4], self._token_coord(p, 1))1121 1122    def p_enumerator_list(self, p):1123        """ enumerator_list : enumerator1124                            | enumerator_list COMMA1125                            | enumerator_list COMMA enumerator1126        """1127        if len(p) == 2:1128            p[0] = c_ast.EnumeratorList([p[1]], p[1].coord)1129        elif len(p) == 3:1130            p[0] = p[1]1131        else:1132            p[1].enumerators.append(p[3])1133            p[0] = p[1]1134 1135    def p_alignment_specifier(self, p):1136        """ alignment_specifier  : _ALIGNAS LPAREN type_name RPAREN1137                                 | _ALIGNAS LPAREN constant_expression RPAREN1138        """1139        p[0] = c_ast.Alignas(p[3], self._token_coord(p, 1))1140 1141    def p_enumerator(self, p):1142        """ enumerator  : ID1143                        | ID EQUALS constant_expression1144        """1145        if len(p) == 2:1146            enumerator = c_ast.Enumerator(1147                        p[1], None,1148                        self._token_coord(p, 1))1149        else:1150            enumerator = c_ast.Enumerator(1151                        p[1], p[3],1152                        self._token_coord(p, 1))1153        self._add_identifier(enumerator.name, enumerator.coord)1154 1155        p[0] = enumerator1156 1157    def p_declarator(self, p):1158        """ declarator  : id_declarator1159                        | typeid_declarator1160        """1161        p[0] = p[1]1162 1163    @parameterized(('id', 'ID'), ('typeid', 'TYPEID'), ('typeid_noparen', 'TYPEID'))1164    def p_xxx_declarator_1(self, p):1165        """ xxx_declarator  : direct_xxx_declarator1166        """1167        p[0] = p[1]1168 1169    @parameterized(('id', 'ID'), ('typeid', 'TYPEID'), ('typeid_noparen', 'TYPEID'))1170    def p_xxx_declarator_2(self, p):1171        """ xxx_declarator  : pointer direct_xxx_declarator1172        """1173        p[0] = self._type_modify_decl(p[2], p[1])1174 1175    @parameterized(('id', 'ID'), ('typeid', 'TYPEID'), ('typeid_noparen', 'TYPEID'))1176    def p_direct_xxx_declarator_1(self, p):1177        """ direct_xxx_declarator   : yyy1178        """1179        p[0] = c_ast.TypeDecl(1180            declname=p[1],1181            type=None,1182            quals=None,1183            align=None,1184            coord=self._token_coord(p, 1))1185 1186    @parameterized(('id', 'ID'), ('typeid', 'TYPEID'))1187    def p_direct_xxx_declarator_2(self, p):1188        """ direct_xxx_declarator   : LPAREN xxx_declarator RPAREN1189        """1190        p[0] = p[2]1191 1192    @parameterized(('id', 'ID'), ('typeid', 'TYPEID'), ('typeid_noparen', 'TYPEID'))1193    def p_direct_xxx_declarator_3(self, p):1194        """ direct_xxx_declarator   : direct_xxx_declarator LBRACKET type_qualifier_list_opt assignment_expression_opt RBRACKET1195        """1196        quals = (p[3] if len(p) > 5 else []) or []1197        # Accept dimension qualifiers1198        # Per C99 6.7.5.3 p71199        arr = c_ast.ArrayDecl(1200            type=None,

Showing the first 1,200 of 1951 lines. Download the file for the rest.

codekingpro/portable-devtools · Team Ai