Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
c_parser.py2377 linesDownload Raw Back to pycparser
1# ------------------------------------------------------------------------------2# pycparser: c_parser.py3#4# Recursive-descent parser for the C language.5#6# Eli Bendersky [https://eli.thegreenplace.net/]7# License: BSD8# ------------------------------------------------------------------------------9from dataclasses import dataclass10from typing import (11    Any,12    Dict,13    List,14    Literal,15    NoReturn,16    Optional,17    Tuple,18    TypedDict,19    cast,20)21 22from . import c_ast23from .c_lexer import CLexer, _Token24from .ast_transforms import fix_switch_cases, fix_atomic_specifiers25 26 27@dataclass28class Coord:29    """Coordinates of a syntactic element. Consists of:30    - File name31    - Line number32    - Column number33    """34 35    file: str36    line: int37    column: Optional[int] = None38 39    def __str__(self) -> str:40        text = f"{self.file}:{self.line}"41        if self.column:42            text += f":{self.column}"43        return text44 45 46class ParseError(Exception):47    pass48 49 50class CParser:51    """Recursive-descent C parser.52 53    Usage:54        parser = CParser()55        ast = parser.parse(text, filename)56 57    The `lexer` parameter lets you inject a lexer class (defaults to CLexer).58    The parameters after `lexer` are accepted for backward compatibility with59    the old PLY-based parser and are otherwise unused.60    """61 62    def __init__(63        self,64        lex_optimize: bool = True,65        lexer: type[CLexer] = CLexer,66        lextab: str = "pycparser.lextab",67        yacc_optimize: bool = True,68        yacctab: str = "pycparser.yacctab",69        yacc_debug: bool = False,70        taboutputdir: str = "",71    ) -> None:72        self.clex: CLexer = lexer(73            error_func=self._lex_error_func,74            on_lbrace_func=self._lex_on_lbrace_func,75            on_rbrace_func=self._lex_on_rbrace_func,76            type_lookup_func=self._lex_type_lookup_func,77        )78 79        # Stack of scopes for keeping track of symbols. _scope_stack[-1] is80        # the current (topmost) scope. Each scope is a dictionary that81        # specifies whether a name is a type. If _scope_stack[n][name] is82        # True, 'name' is currently a type in the scope. If it's False,83        # 'name' is used in the scope but not as a type (for instance, if we84        # saw: int name;85        # If 'name' is not a key in _scope_stack[n] then 'name' was not defined86        # in this scope at all.87        self._scope_stack: List[Dict[str, bool]] = [dict()]88        self._tokens: _TokenStream = _TokenStream(self.clex)89 90    def parse(91        self, text: str, filename: str = "", debug: bool = False92    ) -> c_ast.FileAST:93        """Parses C code and returns an AST.94 95        text:96            A string containing the C source code97 98        filename:99            Name of the file being parsed (for meaningful100            error messages)101 102        debug:103            Deprecated debug flag (unused); for backwards compatibility.104        """105        self._scope_stack = [dict()]106        self.clex.input(text, filename)107        self._tokens = _TokenStream(self.clex)108 109        ast = self._parse_translation_unit_or_empty()110        tok = self._peek()111        if tok is not None:112            self._parse_error(f"before: {tok.value}", self._tok_coord(tok))113        return ast114 115    # ------------------------------------------------------------------116    # Scope and declaration helpers117    # ------------------------------------------------------------------118    def _coord(self, lineno: int, column: Optional[int] = None) -> Coord:119        return Coord(file=self.clex.filename, line=lineno, column=column)120 121    def _parse_error(self, msg: str, coord: Coord | str | None) -> NoReturn:122        raise ParseError(f"{coord}: {msg}")123 124    def _push_scope(self) -> None:125        self._scope_stack.append(dict())126 127    def _pop_scope(self) -> None:128        assert len(self._scope_stack) > 1129        self._scope_stack.pop()130 131    def _add_typedef_name(self, name: str, coord: Optional[Coord]) -> None:132        """Add a new typedef name (ie a TYPEID) to the current scope"""133        if not self._scope_stack[-1].get(name, True):134            self._parse_error(135                f"Typedef {name!r} previously declared as non-typedef in this scope",136                coord,137            )138        self._scope_stack[-1][name] = True139 140    def _add_identifier(self, name: str, coord: Optional[Coord]) -> None:141        """Add a new object, function, or enum member name (ie an ID) to the142        current scope143        """144        if self._scope_stack[-1].get(name, False):145            self._parse_error(146                f"Non-typedef {name!r} previously declared as typedef in this scope",147                coord,148            )149        self._scope_stack[-1][name] = False150 151    def _is_type_in_scope(self, name: str) -> bool:152        """Is *name* a typedef-name in the current scope?"""153        for scope in reversed(self._scope_stack):154            # If name is an identifier in this scope it shadows typedefs in155            # higher scopes.156            in_scope = scope.get(name)157            if in_scope is not None:158                return in_scope159        return False160 161    def _lex_error_func(self, msg: str, line: int, column: int) -> None:162        self._parse_error(msg, self._coord(line, column))163 164    def _lex_on_lbrace_func(self) -> None:165        self._push_scope()166 167    def _lex_on_rbrace_func(self) -> None:168        self._pop_scope()169 170    def _lex_type_lookup_func(self, name: str) -> bool:171        """Looks up types that were previously defined with172        typedef.173        Passed to the lexer for recognizing identifiers that174        are types.175        """176        return self._is_type_in_scope(name)177 178    # To understand what's going on here, read sections A.8.5 and179    # A.8.6 of K&R2 very carefully.180    #181    # A C type consists of a basic type declaration, with a list182    # of modifiers. For example:183    #184    # int *c[5];185    #186    # The basic declaration here is 'int c', and the pointer and187    # the array are the modifiers.188    #189    # Basic declarations are represented by TypeDecl (from module c_ast) and the190    # modifiers are FuncDecl, PtrDecl and ArrayDecl.191    #192    # The standard states that whenever a new modifier is parsed, it should be193    # added to the end of the list of modifiers. For example:194    #195    # K&R2 A.8.6.2: Array Declarators196    #197    # In a declaration T D where D has the form198    #   D1 [constant-expression-opt]199    # and the type of the identifier in the declaration T D1 is200    # "type-modifier T", the type of the201    # identifier of D is "type-modifier array of T"202    #203    # This is what this method does. The declarator it receives204    # can be a list of declarators ending with TypeDecl. It205    # tacks the modifier to the end of this list, just before206    # the TypeDecl.207    #208    # Additionally, the modifier may be a list itself. This is209    # useful for pointers, that can come as a chain from the rule210    # p_pointer. In this case, the whole modifier list is spliced211    # into the new location.212    def _type_modify_decl(self, decl: Any, modifier: Any) -> c_ast.Node:213        """Tacks a type modifier on a declarator, and returns214        the modified declarator.215 216        Note: the declarator and modifier may be modified217        """218        modifier_head = modifier219        modifier_tail = modifier220 221        # The modifier may be a nested list. Reach its tail.222        while modifier_tail.type:223            modifier_tail = modifier_tail.type224 225        # If the decl is a basic type, just tack the modifier onto it.226        if isinstance(decl, c_ast.TypeDecl):227            modifier_tail.type = decl228            return modifier229        else:230            # Otherwise, the decl is a list of modifiers. Reach231            # its tail and splice the modifier onto the tail,232            # pointing to the underlying basic type.233            decl_tail = decl234            while not isinstance(decl_tail.type, c_ast.TypeDecl):235                decl_tail = decl_tail.type236 237            modifier_tail.type = decl_tail.type238            decl_tail.type = modifier_head239            return decl240 241    # Due to the order in which declarators are constructed,242    # they have to be fixed in order to look like a normal AST.243    #244    # When a declaration arrives from syntax construction, it has245    # these problems:246    # * The innermost TypeDecl has no type (because the basic247    #   type is only known at the uppermost declaration level)248    # * The declaration has no variable name, since that is saved249    #   in the innermost TypeDecl250    # * The typename of the declaration is a list of type251    #   specifiers, and not a node. Here, basic identifier types252    #   should be separated from more complex types like enums253    #   and structs.254    #255    # This method fixes these problems.256    def _fix_decl_name_type(257        self,258        decl: c_ast.Decl | c_ast.Typedef | c_ast.Typename,259        typename: List[Any],260    ) -> c_ast.Decl | c_ast.Typedef | c_ast.Typename:261        """Fixes a declaration. Modifies decl."""262        # Reach the underlying basic type263        typ = decl264        while not isinstance(typ, c_ast.TypeDecl):265            typ = typ.type266 267        decl.name = typ.declname268        typ.quals = decl.quals[:]269 270        # The typename is a list of types. If any type in this271        # list isn't an IdentifierType, it must be the only272        # type in the list (it's illegal to declare "int enum ..")273        # If all the types are basic, they're collected in the274        # IdentifierType holder.275        for tn in typename:276            if not isinstance(tn, c_ast.IdentifierType):277                if len(typename) > 1:278                    self._parse_error("Invalid multiple types specified", tn.coord)279                else:280                    typ.type = tn281                    return decl282 283        if not typename:284            # Functions default to returning int285            if not isinstance(decl.type, c_ast.FuncDecl):286                self._parse_error("Missing type in declaration", decl.coord)287            typ.type = c_ast.IdentifierType(["int"], coord=decl.coord)288        else:289            # At this point, we know that typename is a list of IdentifierType290            # nodes. Concatenate all the names into a single list.291            typ.type = c_ast.IdentifierType(292                [name for id in typename for name in id.names], coord=typename[0].coord293            )294        return decl295 296    def _add_declaration_specifier(297        self,298        declspec: Optional["_DeclSpec"],299        newspec: Any,300        kind: "_DeclSpecKind",301        append: bool = False,302    ) -> "_DeclSpec":303        """See _DeclSpec for the specifier dictionary layout."""304        if declspec is None:305            spec: _DeclSpec = dict(306                qual=[], storage=[], type=[], function=[], alignment=[]307            )308        else:309            spec = declspec310 311        if append:312            spec[kind].append(newspec)313        else:314            spec[kind].insert(0, newspec)315 316        return spec317 318    def _build_declarations(319        self,320        spec: "_DeclSpec",321        decls: List["_DeclInfo"],322        typedef_namespace: bool = False,323    ) -> List[c_ast.Node]:324        """Builds a list of declarations all sharing the given specifiers.325        If typedef_namespace is true, each declared name is added326        to the "typedef namespace", which also includes objects,327        functions, and enum constants.328        """329        is_typedef = "typedef" in spec["storage"]330        declarations = []331 332        # Bit-fields are allowed to be unnamed.333        if decls[0].get("bitsize") is None:334            # When redeclaring typedef names as identifiers in inner scopes, a335            # problem can occur where the identifier gets grouped into336            # spec['type'], leaving decl as None.  This can only occur for the337            # first declarator.338            if decls[0]["decl"] is None:339                if (340                    len(spec["type"]) < 2341                    or len(spec["type"][-1].names) != 1342                    or not self._is_type_in_scope(spec["type"][-1].names[0])343                ):344                    coord = "?"345                    for t in spec["type"]:346                        if hasattr(t, "coord"):347                            coord = t.coord348                            break349                    self._parse_error("Invalid declaration", coord)350 351                # Make this look as if it came from "direct_declarator:ID"352                decls[0]["decl"] = c_ast.TypeDecl(353                    declname=spec["type"][-1].names[0],354                    type=None,355                    quals=None,356                    align=spec["alignment"],357                    coord=spec["type"][-1].coord,358                )359                # Remove the "new" type's name from the end of spec['type']360                del spec["type"][-1]361            # A similar problem can occur where the declaration ends up362            # looking like an abstract declarator.  Give it a name if this is363            # the case.364            elif not isinstance(365                decls[0]["decl"],366                (c_ast.Enum, c_ast.Struct, c_ast.Union, c_ast.IdentifierType),367            ):368                decls_0_tail = cast(Any, decls[0]["decl"])369                while not isinstance(decls_0_tail, c_ast.TypeDecl):370                    decls_0_tail = decls_0_tail.type371                if decls_0_tail.declname is None:372                    decls_0_tail.declname = spec["type"][-1].names[0]373                    del spec["type"][-1]374 375        for decl in decls:376            assert decl["decl"] is not None377            if is_typedef:378                declaration = c_ast.Typedef(379                    name=None,380                    quals=spec["qual"],381                    storage=spec["storage"],382                    type=decl["decl"],383                    coord=decl["decl"].coord,384                )385            else:386                declaration = c_ast.Decl(387                    name=None,388                    quals=spec["qual"],389                    align=spec["alignment"],390                    storage=spec["storage"],391                    funcspec=spec["function"],392                    type=decl["decl"],393                    init=decl.get("init"),394                    bitsize=decl.get("bitsize"),395                    coord=decl["decl"].coord,396                )397 398            if isinstance(399                declaration.type,400                (c_ast.Enum, c_ast.Struct, c_ast.Union, c_ast.IdentifierType),401            ):402                fixed_decl = declaration403            else:404                fixed_decl = self._fix_decl_name_type(declaration, spec["type"])405 406            # Add the type name defined by typedef to a407            # symbol table (for usage in the lexer)408            if typedef_namespace:409                if is_typedef:410                    self._add_typedef_name(fixed_decl.name, fixed_decl.coord)411                else:412                    self._add_identifier(fixed_decl.name, fixed_decl.coord)413 414            fixed_decl = fix_atomic_specifiers(415                cast(c_ast.Decl | c_ast.Typedef, fixed_decl)416            )417            declarations.append(fixed_decl)418 419        return declarations420 421    def _build_function_definition(422        self,423        spec: "_DeclSpec",424        decl: c_ast.Node,425        param_decls: Optional[List[c_ast.Node]],426        body: c_ast.Node,427    ) -> c_ast.Node:428        """Builds a function definition."""429        if "typedef" in spec["storage"]:430            self._parse_error("Invalid typedef", decl.coord)431 432        declaration = self._build_declarations(433            spec=spec,434            decls=[dict(decl=decl, init=None, bitsize=None)],435            typedef_namespace=True,436        )[0]437 438        return c_ast.FuncDef(439            decl=declaration, param_decls=param_decls, body=body, coord=decl.coord440        )441 442    def _select_struct_union_class(self, token: str) -> type:443        """Given a token (either STRUCT or UNION), selects the444        appropriate AST class.445        """446        if token == "struct":447            return c_ast.Struct448        else:449            return c_ast.Union450 451    # ------------------------------------------------------------------452    # Token helpers453    # ------------------------------------------------------------------454    def _peek(self, k: int = 1) -> Optional[_Token]:455        """Return the k-th next token without consuming it (1-based)."""456        return self._tokens.peek(k)457 458    def _peek_type(self, k: int = 1) -> Optional[str]:459        """Return the type of the k-th next token, or None if absent (1-based)."""460        tok = self._peek(k)461        return tok.type if tok is not None else None462 463    def _advance(self) -> _Token:464        tok = self._tokens.next()465        if tok is None:466            self._parse_error("At end of input", self.clex.filename)467        else:468            return tok469 470    def _accept(self, token_type: str) -> Optional[_Token]:471        """Conditionally consume next token, only if it's of token_type.472 473        If it is of the expected type, consume and return it.474        Otherwise, leaves the token intact and returns None.475        """476        tok = self._peek()477        if tok is not None and tok.type == token_type:478            return self._advance()479        return None480 481    def _expect(self, token_type: str) -> _Token:482        tok = self._advance()483        if tok.type != token_type:484            self._parse_error(f"before: {tok.value}", self._tok_coord(tok))485        return tok486 487    def _mark(self) -> int:488        return self._tokens.mark()489 490    def _reset(self, mark: int) -> None:491        self._tokens.reset(mark)492 493    def _tok_coord(self, tok: _Token) -> Coord:494        return self._coord(tok.lineno, tok.column)495 496    def _starts_declaration(self, tok: Optional[_Token] = None) -> bool:497        tok = tok or self._peek()498        if tok is None:499            return False500        return tok.type in _DECL_START501 502    def _starts_expression(self, tok: Optional[_Token] = None) -> bool:503        tok = tok or self._peek()504        if tok is None:505            return False506        return tok.type in _STARTS_EXPRESSION507 508    def _starts_statement(self) -> bool:509        tok_type = self._peek_type()510        if tok_type is None:511            return False512        if tok_type in _STARTS_STATEMENT:513            return True514        return self._starts_expression()515 516    def _starts_declarator(self, id_only: bool = False) -> bool:517        tok_type = self._peek_type()518        if tok_type is None:519            return False520        if tok_type in {"TIMES", "LPAREN"}:521            return True522        if id_only:523            return tok_type == "ID"524        return tok_type in {"ID", "TYPEID"}525 526    def _peek_declarator_name_info(self) -> Tuple[Optional[str], bool]:527        mark = self._mark()528        tok_type, saw_paren = self._scan_declarator_name_info()529        self._reset(mark)530        return tok_type, saw_paren531 532    def _parse_any_declarator(533        self, allow_abstract: bool = False, typeid_paren_as_abstract: bool = False534    ) -> Tuple[Optional[c_ast.Node], bool]:535        # C declarators are ambiguous without lookahead. For example:536        #   int foo(int (aa));   -> aa is a name (ID)537        #   typedef char TT;538        #   int bar(int (TT));   -> TT is a type (TYPEID) in parens539        name_type, saw_paren = self._peek_declarator_name_info()540        if name_type is None or (541            typeid_paren_as_abstract and name_type == "TYPEID" and saw_paren542        ):543            if not allow_abstract:544                tok = self._peek()545                coord = self._tok_coord(tok) if tok is not None else self.clex.filename546                self._parse_error("Invalid declarator", coord)547            decl = self._parse_abstract_declarator_opt()548            return decl, False549 550        if name_type == "TYPEID":551            if typeid_paren_as_abstract:552                decl = self._parse_typeid_noparen_declarator()553            else:554                decl = self._parse_typeid_declarator()555        else:556            decl = self._parse_id_declarator()557        return decl, True558 559    def _scan_declarator_name_info(self) -> Tuple[Optional[str], bool]:560        saw_paren = False561        while self._accept("TIMES"):562            while self._peek_type() in _TYPE_QUALIFIER:563                self._advance()564 565        tok = self._peek()566        if tok is None:567            return None, saw_paren568        if tok.type in {"ID", "TYPEID"}:569            self._advance()570            return tok.type, saw_paren571        if tok.type == "LPAREN":572            saw_paren = True573            self._advance()574            tok_type, nested_paren = self._scan_declarator_name_info()575            if nested_paren:576                saw_paren = True577            depth = 1578            while True:579                tok = self._peek()580                if tok is None:581                    return None, saw_paren582                if tok.type == "LPAREN":583                    depth += 1584                elif tok.type == "RPAREN":585                    depth -= 1586                    self._advance()587                    if depth == 0:588                        break589                    continue590                self._advance()591            return tok_type, saw_paren592        return None, saw_paren593 594    def _starts_direct_abstract_declarator(self) -> bool:595        return self._peek_type() in {"LPAREN", "LBRACKET"}596 597    def _is_assignment_op(self) -> bool:598        tok = self._peek()599        return tok is not None and tok.type in _ASSIGNMENT_OPS600 601    def _try_parse_paren_type_name(602        self,603    ) -> Optional[Tuple[c_ast.Typename, int, _Token]]:604        """Parse and return a parenthesized type name if present.605 606        Returns (typ, mark, lparen_tok) when the next tokens look like607        '(' type_name ')', where typ is the parsed type name, mark is the608        token-stream position before parsing, and lparen_tok is the LPAREN609        token. Returns None if no parenthesized type name is present.610        """611        mark = self._mark()612        lparen_tok = self._accept("LPAREN")613        if lparen_tok is None:614            return None615        if not self._starts_declaration():616            self._reset(mark)617            return None618        typ = self._parse_type_name()619        if self._accept("RPAREN") is None:620            self._reset(mark)621            return None622        return typ, mark, lparen_tok623 624    # ------------------------------------------------------------------625    # Top-level626    # ------------------------------------------------------------------627    # BNF: translation_unit_or_empty : translation_unit | empty628    def _parse_translation_unit_or_empty(self) -> c_ast.FileAST:629        if self._peek() is None:630            return c_ast.FileAST([])631        return c_ast.FileAST(self._parse_translation_unit())632 633    # BNF: translation_unit : external_declaration+634    def _parse_translation_unit(self) -> List[c_ast.Node]:635        ext = []636        while self._peek() is not None:637            ext.extend(self._parse_external_declaration())638        return ext639 640    # BNF: external_declaration : function_definition641    #                           | declaration642    #                           | pp_directive643    #                           | pppragma_directive644    #                           | static_assert645    #                           | ';'646    def _parse_external_declaration(self) -> List[c_ast.Node]:647        tok = self._peek()648        if tok is None:649            return []650        if tok.type == "PPHASH":651            self._parse_pp_directive()652            return []653        if tok.type in {"PPPRAGMA", "_PRAGMA"}:654            return [self._parse_pppragma_directive()]655        if self._accept("SEMI"):656            return []657        if tok.type == "_STATIC_ASSERT":658            return self._parse_static_assert()659 660        if not self._starts_declaration(tok):661            # Special handling for old-style function definitions that have an662            # implicit return type, e.g.663            #664            #   foo() {665            #    return 5;666            #   }667            #668            # These get an implicit 'int' return type.669            decl = self._parse_id_declarator()670            param_decls = None671            if self._peek_type() != "LBRACE":672                self._parse_error("Invalid function definition", decl.coord)673            spec: _DeclSpec = dict(674                qual=[],675                alignment=[],676                storage=[],677                type=[c_ast.IdentifierType(["int"], coord=decl.coord)],678                function=[],679            )680            func = self._build_function_definition(681                spec=spec,682                decl=decl,683                param_decls=param_decls,684                body=self._parse_compound_statement(),685            )686            return [func]687 688        # From here on, parsing a standard declatation/definition.689        spec, saw_type, spec_coord = self._parse_declaration_specifiers(690            allow_no_type=True691        )692 693        name_type, _ = self._peek_declarator_name_info()694        if name_type != "ID":695            decls = self._parse_decl_body_with_spec(spec, saw_type)696            self._expect("SEMI")697            return decls698 699        decl = self._parse_id_declarator()700 701        if self._peek_type() == "LBRACE" or self._starts_declaration():702            param_decls = None703            if self._starts_declaration():704                param_decls = self._parse_declaration_list()705            if self._peek_type() != "LBRACE":706                self._parse_error("Invalid function definition", decl.coord)707            if not spec["type"]:708                spec["type"] = [c_ast.IdentifierType(["int"], coord=spec_coord)]709            func = self._build_function_definition(710                spec=spec,711                decl=decl,712                param_decls=param_decls,713                body=self._parse_compound_statement(),714            )715            return [func]716 717        decl_dict: "_DeclInfo" = dict(decl=decl, init=None, bitsize=None)718        if self._accept("EQUALS"):719            decl_dict["init"] = self._parse_initializer()720        decls = self._parse_init_declarator_list(first=decl_dict)721        decls = self._build_declarations(spec=spec, decls=decls, typedef_namespace=True)722        self._expect("SEMI")723        return decls724 725    # ------------------------------------------------------------------726    # Declarations727    #728    # Declarations always come as lists (because they can be several in one729    # line). When returning parsed declarations, a list is always returned -730    # even if it contains a single element.731    # ------------------------------------------------------------------732    def _parse_declaration(self) -> List[c_ast.Node]:733        decls = self._parse_decl_body()734        self._expect("SEMI")735        return decls736 737    # BNF: decl_body : declaration_specifiers decl_body_with_spec738    def _parse_decl_body(self) -> List[c_ast.Node]:739        spec, saw_type, _ = self._parse_declaration_specifiers(allow_no_type=True)740        return self._parse_decl_body_with_spec(spec, saw_type)741 742    # BNF: decl_body_with_spec : init_declarator_list743    #                          | struct_or_union_or_enum_only744    def _parse_decl_body_with_spec(745        self, spec: "_DeclSpec", saw_type: bool746    ) -> List[c_ast.Node]:747        decls = None748        if saw_type:749            if self._starts_declarator():750                decls = self._parse_init_declarator_list()751        else:752            if self._starts_declarator(id_only=True):753                decls = self._parse_init_declarator_list(id_only=True)754 755        if decls is None:756            ty = spec["type"]757            s_u_or_e = (c_ast.Struct, c_ast.Union, c_ast.Enum)758            if len(ty) == 1 and isinstance(ty[0], s_u_or_e):759                decls = [760                    c_ast.Decl(761                        name=None,762                        quals=spec["qual"],763                        align=spec["alignment"],764                        storage=spec["storage"],765                        funcspec=spec["function"],766                        type=ty[0],767                        init=None,768                        bitsize=None,769                        coord=ty[0].coord,770                    )771                ]772            else:773                decls = self._build_declarations(774                    spec=spec,775                    decls=[dict(decl=None, init=None, bitsize=None)],776                    typedef_namespace=True,777                )778        else:779            decls = self._build_declarations(780                spec=spec, decls=decls, typedef_namespace=True781            )782 783        return decls784 785    # BNF: declaration_list : declaration+786    def _parse_declaration_list(self) -> List[c_ast.Node]:787        decls = []788        while self._starts_declaration():789            decls.extend(self._parse_declaration())790        return decls791 792    # BNF: declaration_specifiers   : (storage_class_specifier793    #                               | type_specifier794    #                               | type_qualifier795    #                               | function_specifier796    #                               | alignment_specifier)+797    def _parse_declaration_specifiers(798        self, allow_no_type: bool = False799    ) -> Tuple["_DeclSpec", bool, Optional[Coord]]:800        """Parse declaration-specifier sequence.801 802        allow_no_type:803            If True, allow a missing type specifier without error.804 805        Returns:806            (spec, saw_type, first_coord) where spec is a dict with807            qual/storage/type/function/alignment entries, saw_type is True808            if a type specifier was consumed, and first_coord is the coord809            of the first specifier token (used for diagnostics).810        """811        spec = None812        saw_type = False813        first_coord = None814 815        while True:816            tok = self._peek()817            if tok is None:818                break819 820            if tok.type == "_ALIGNAS":821                if first_coord is None:822                    first_coord = self._tok_coord(tok)823                spec = self._add_declaration_specifier(824                    spec, self._parse_alignment_specifier(), "alignment", append=True825                )826                continue827 828            if tok.type == "_ATOMIC" and self._peek_type(2) == "LPAREN":829                if first_coord is None:830                    first_coord = self._tok_coord(tok)831                spec = self._add_declaration_specifier(832                    spec, self._parse_atomic_specifier(), "type", append=True833                )834                saw_type = True835                continue836 837            if tok.type in _TYPE_QUALIFIER:838                if first_coord is None:839                    first_coord = self._tok_coord(tok)840                spec = self._add_declaration_specifier(841                    spec, self._advance().value, "qual", append=True842                )843                continue844 845            if tok.type in _STORAGE_CLASS:846                if first_coord is None:847                    first_coord = self._tok_coord(tok)848                spec = self._add_declaration_specifier(849                    spec, self._advance().value, "storage", append=True850                )851                continue852 853            if tok.type in _FUNCTION_SPEC:854                if first_coord is None:855                    first_coord = self._tok_coord(tok)856                spec = self._add_declaration_specifier(857                    spec, self._advance().value, "function", append=True858                )859                continue860 861            if tok.type in _TYPE_SPEC_SIMPLE:862                if first_coord is None:863                    first_coord = self._tok_coord(tok)864                tok = self._advance()865                spec = self._add_declaration_specifier(866                    spec,867                    c_ast.IdentifierType([tok.value], coord=self._tok_coord(tok)),868                    "type",869                    append=True,870                )871                saw_type = True872                continue873 874            if tok.type == "TYPEID":875                if saw_type:876                    break877                if first_coord is None:878                    first_coord = self._tok_coord(tok)879                tok = self._advance()880                spec = self._add_declaration_specifier(881                    spec,882                    c_ast.IdentifierType([tok.value], coord=self._tok_coord(tok)),883                    "type",884                    append=True,885                )886                saw_type = True887                continue888 889            if tok.type in {"STRUCT", "UNION"}:890                if first_coord is None:891                    first_coord = self._tok_coord(tok)892                spec = self._add_declaration_specifier(893                    spec, self._parse_struct_or_union_specifier(), "type", append=True894                )895                saw_type = True896                continue897 898            if tok.type == "ENUM":899                if first_coord is None:900                    first_coord = self._tok_coord(tok)901                spec = self._add_declaration_specifier(902                    spec, self._parse_enum_specifier(), "type", append=True903                )904                saw_type = True905                continue906 907            break908 909        if spec is None:910            self._parse_error("Invalid declaration", self.clex.filename)911 912        if not saw_type and not allow_no_type:913            self._parse_error("Missing type in declaration", first_coord)914 915        return spec, saw_type, first_coord916 917    # BNF: specifier_qualifier_list : (type_specifier918    #                               | type_qualifier919    #                               | alignment_specifier)+920    def _parse_specifier_qualifier_list(self) -> "_DeclSpec":921        spec = None922        saw_type = False923        saw_alignment = False924        first_coord = None925 926        while True:927            tok = self._peek()928            if tok is None:929                break930 931            if tok.type == "_ALIGNAS":932                if first_coord is None:933                    first_coord = self._tok_coord(tok)934                spec = self._add_declaration_specifier(935                    spec, self._parse_alignment_specifier(), "alignment", append=True936                )937                saw_alignment = True938                continue939 940            if tok.type == "_ATOMIC" and self._peek_type(2) == "LPAREN":941                if first_coord is None:942                    first_coord = self._tok_coord(tok)943                spec = self._add_declaration_specifier(944                    spec, self._parse_atomic_specifier(), "type", append=True945                )946                saw_type = True947                continue948 949            if tok.type in _TYPE_QUALIFIER:950                if first_coord is None:951                    first_coord = self._tok_coord(tok)952                spec = self._add_declaration_specifier(953                    spec, self._advance().value, "qual", append=True954                )955                continue956 957            if tok.type in _TYPE_SPEC_SIMPLE:958                if first_coord is None:959                    first_coord = self._tok_coord(tok)960                tok = self._advance()961                spec = self._add_declaration_specifier(962                    spec,963                    c_ast.IdentifierType([tok.value], coord=self._tok_coord(tok)),964                    "type",965                    append=True,966                )967                saw_type = True968                continue969 970            if tok.type == "TYPEID":971                if saw_type:972                    break973                if first_coord is None:974                    first_coord = self._tok_coord(tok)975                tok = self._advance()976                spec = self._add_declaration_specifier(977                    spec,978                    c_ast.IdentifierType([tok.value], coord=self._tok_coord(tok)),979                    "type",980                    append=True,981                )982                saw_type = True983                continue984 985            if tok.type in {"STRUCT", "UNION"}:986                if first_coord is None:987                    first_coord = self._tok_coord(tok)988                spec = self._add_declaration_specifier(989                    spec, self._parse_struct_or_union_specifier(), "type", append=True990                )991                saw_type = True992                continue993 994            if tok.type == "ENUM":995                if first_coord is None:996                    first_coord = self._tok_coord(tok)997                spec = self._add_declaration_specifier(998                    spec, self._parse_enum_specifier(), "type", append=True999                )1000                saw_type = True1001                continue1002 1003            break1004 1005        if spec is None:1006            self._parse_error("Invalid specifier list", self.clex.filename)1007 1008        if not saw_type and not saw_alignment:1009            self._parse_error("Missing type in declaration", first_coord)1010 1011        if spec.get("storage") is None:1012            spec["storage"] = []1013        if spec.get("function") is None:1014            spec["function"] = []1015 1016        return spec1017 1018    # BNF: type_qualifier_list : type_qualifier+1019    def _parse_type_qualifier_list(self) -> List[str]:1020        quals = []1021        while self._peek_type() in _TYPE_QUALIFIER:1022            quals.append(self._advance().value)1023        return quals1024 1025    # BNF: alignment_specifier : _ALIGNAS '(' type_name | constant_expression ')'1026    def _parse_alignment_specifier(self) -> c_ast.Node:1027        tok = self._expect("_ALIGNAS")1028        self._expect("LPAREN")1029 1030        if self._starts_declaration():1031            typ = self._parse_type_name()1032            self._expect("RPAREN")1033            return c_ast.Alignas(typ, self._tok_coord(tok))1034 1035        expr = self._parse_constant_expression()1036        self._expect("RPAREN")1037        return c_ast.Alignas(expr, self._tok_coord(tok))1038 1039    # BNF: atomic_specifier : _ATOMIC '(' type_name ')'1040    def _parse_atomic_specifier(self) -> c_ast.Node:1041        self._expect("_ATOMIC")1042        self._expect("LPAREN")1043        typ = self._parse_type_name()1044        self._expect("RPAREN")1045        typ.quals.append("_Atomic")1046        return typ1047 1048    # BNF: init_declarator_list : init_declarator (',' init_declarator)*1049    def _parse_init_declarator_list(1050        self, first: Optional["_DeclInfo"] = None, id_only: bool = False1051    ) -> List["_DeclInfo"]:1052        decls = (1053            [first]1054            if first is not None1055            else [self._parse_init_declarator(id_only=id_only)]1056        )1057 1058        while self._accept("COMMA"):1059            decls.append(self._parse_init_declarator(id_only=id_only))1060        return decls1061 1062    # BNF: init_declarator : declarator ('=' initializer)?1063    def _parse_init_declarator(self, id_only: bool = False) -> "_DeclInfo":1064        decl = self._parse_id_declarator() if id_only else self._parse_declarator()1065        init = None1066        if self._accept("EQUALS"):1067            init = self._parse_initializer()1068        return dict(decl=decl, init=init, bitsize=None)1069 1070    # ------------------------------------------------------------------1071    # Structs/unions/enums1072    # ------------------------------------------------------------------1073    # BNF: struct_or_union_specifier : struct_or_union ID? '{' struct_declaration_list? '}'1074    #                                | struct_or_union ID1075    def _parse_struct_or_union_specifier(self) -> c_ast.Node:1076        tok = self._advance()1077        klass = self._select_struct_union_class(tok.value)1078 1079        if self._peek_type() in {"ID", "TYPEID"}:1080            name_tok = self._advance()1081            if self._peek_type() == "LBRACE":1082                self._advance()1083                if self._accept("RBRACE"):1084                    return klass(1085                        name=name_tok.value, decls=[], coord=self._tok_coord(name_tok)1086                    )1087                decls = self._parse_struct_declaration_list()1088                self._expect("RBRACE")1089                return klass(1090                    name=name_tok.value, decls=decls, coord=self._tok_coord(name_tok)1091                )1092 1093            return klass(1094                name=name_tok.value, decls=None, coord=self._tok_coord(name_tok)1095            )1096 1097        if self._peek_type() == "LBRACE":1098            brace_tok = self._advance()1099            if self._accept("RBRACE"):1100                return klass(name=None, decls=[], coord=self._tok_coord(brace_tok))1101            decls = self._parse_struct_declaration_list()1102            self._expect("RBRACE")1103            return klass(name=None, decls=decls, coord=self._tok_coord(brace_tok))1104 1105        self._parse_error("Invalid struct/union declaration", self._tok_coord(tok))1106 1107    # BNF: struct_declaration_list : struct_declaration+1108    def _parse_struct_declaration_list(self) -> List[c_ast.Node]:1109        decls = []1110        while self._peek_type() not in {None, "RBRACE"}:1111            items = self._parse_struct_declaration()1112            if items is None:1113                continue1114            decls.extend(items)1115        return decls1116 1117    # BNF: struct_declaration   : specifier_qualifier_list struct_declarator_list? ';'1118    #                           | static_assert1119    #                           | pppragma_directive1120    def _parse_struct_declaration(self) -> Optional[List[c_ast.Node]]:1121        if self._peek_type() == "SEMI":1122            self._advance()1123            return None1124        if self._peek_type() in {"PPPRAGMA", "_PRAGMA"}:1125            return [self._parse_pppragma_directive()]1126 1127        spec = self._parse_specifier_qualifier_list()1128        assert "typedef" not in spec.get("storage", [])1129 1130        decls = None1131        if self._starts_declarator() or self._peek_type() == "COLON":1132            decls = self._parse_struct_declarator_list()1133        if decls is not None:1134            self._expect("SEMI")1135            return self._build_declarations(spec=spec, decls=decls)1136 1137        if len(spec["type"]) == 1:1138            node = spec["type"][0]1139            if isinstance(node, c_ast.Node):1140                decl_type = node1141            else:1142                decl_type = c_ast.IdentifierType(node)1143            self._expect("SEMI")1144            return self._build_declarations(1145                spec=spec, decls=[dict(decl=decl_type, init=None, bitsize=None)]1146            )1147 1148        self._expect("SEMI")1149        return self._build_declarations(1150            spec=spec, decls=[dict(decl=None, init=None, bitsize=None)]1151        )1152 1153    # BNF: struct_declarator_list : struct_declarator (',' struct_declarator)*1154    def _parse_struct_declarator_list(self) -> List["_DeclInfo"]:1155        decls = [self._parse_struct_declarator()]1156        while self._accept("COMMA"):1157            decls.append(self._parse_struct_declarator())1158        return decls1159 1160    # BNF: struct_declarator : declarator? ':' constant_expression1161    #                        | declarator (':' constant_expression)?1162    def _parse_struct_declarator(self) -> "_DeclInfo":1163        if self._accept("COLON"):1164            bitsize = self._parse_constant_expression()1165            return {1166                "decl": c_ast.TypeDecl(None, None, None, None),1167                "init": None,1168                "bitsize": bitsize,1169            }1170 1171        decl = self._parse_declarator()1172        if self._accept("COLON"):1173            bitsize = self._parse_constant_expression()1174            return {"decl": decl, "init": None, "bitsize": bitsize}1175 1176        return {"decl": decl, "init": None, "bitsize": None}1177 1178    # BNF: enum_specifier : ENUM ID? '{' enumerator_list? '}'1179    #                     | ENUM ID1180    def _parse_enum_specifier(self) -> c_ast.Node:1181        tok = self._expect("ENUM")1182        if self._peek_type() in {"ID", "TYPEID"}:1183            name_tok = self._advance()1184            if self._peek_type() == "LBRACE":1185                self._advance()1186                enums = self._parse_enumerator_list()1187                self._expect("RBRACE")1188                return c_ast.Enum(name_tok.value, enums, self._tok_coord(tok))1189            return c_ast.Enum(name_tok.value, None, self._tok_coord(tok))1190 1191        self._expect("LBRACE")1192        enums = self._parse_enumerator_list()1193        self._expect("RBRACE")1194        return c_ast.Enum(None, enums, self._tok_coord(tok))1195 1196    # BNF: enumerator_list : enumerator (',' enumerator)* ','?1197    def _parse_enumerator_list(self) -> c_ast.Node:1198        enum = self._parse_enumerator()1199        enum_list = c_ast.EnumeratorList([enum], enum.coord)1200        while self._accept("COMMA"):

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

codekingpro/portable-devtools · Team Ai