Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/pycparser/c_parser.py: 88%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# ------------------------------------------------------------------------------
2# pycparser: c_parser.py
3#
4# Recursive-descent parser for the C language.
5#
6# Eli Bendersky [https://eli.thegreenplace.net/]
7# License: BSD
8# ------------------------------------------------------------------------------
9from dataclasses import dataclass
10from typing import (
11 Any,
12 Dict,
13 List,
14 Literal,
15 NoReturn,
16 Optional,
17 Tuple,
18 TypedDict,
19 cast,
20)
22from . import c_ast
23from .c_lexer import CLexer, Token
24from .ast_transforms import fix_switch_cases, fix_atomic_specifiers
27@dataclass
28class Coord:
29 """Coordinates of a syntactic element. Consists of:
30 - File name
31 - Line number
32 - Column number
33 """
35 file: str
36 line: int
37 column: Optional[int] = None
39 def __str__(self) -> str:
40 text = f"{self.file}:{self.line}"
41 if self.column is not None:
42 text += f":{self.column}"
43 return text
46class ParseError(Exception):
47 pass
50class CParser:
51 """Recursive-descent C parser.
53 Usage:
54 parser = CParser()
55 ast = parser.parse(text, filename)
57 The `lexer` parameter lets you inject a lexer class (defaults to CLexer).
58 The parameters after `lexer` are accepted for backward compatibility with
59 the old PLY-based parser and are otherwise unused.
60 """
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 )
79 # Stack of scopes for keeping track of symbols. _scope_stack[-1] is
80 # the current (topmost) scope. Each scope is a dictionary that
81 # specifies whether a name is a type. If _scope_stack[n][name] is
82 # True, 'name' is currently a type in the scope. If it's False,
83 # 'name' is defined in the scope but not as a type (for instance, if we
84 # saw: int name;)
85 # If 'name' is not a key in _scope_stack[n] then 'name' was not defined
86 # in this scope at all.
87 self._scope_stack: List[Dict[str, bool]] = [dict()]
88 self._tokens: _TokenStream = _TokenStream(self.clex)
90 def parse(
91 self, text: str, filename: str = "", debug: bool = False
92 ) -> c_ast.FileAST:
93 """Parses C code and returns an AST.
95 text:
96 A string containing the C source code
98 filename:
99 Name of the file being parsed (for meaningful error messages)
101 debug:
102 Deprecated debug flag (unused); for backwards compatibility.
103 """
104 self._scope_stack = [dict()]
105 self.clex.input(text, filename)
106 self._tokens = _TokenStream(self.clex)
108 ast = self._parse_translation_unit_or_empty()
109 tok = self._peek()
110 if tok is not None:
111 self._parse_error(f"before: {tok.value}", self._tok_coord(tok))
112 return ast
114 # ------------------------------------------------------------------
115 # Scope and declaration helpers
116 # ------------------------------------------------------------------
117 def _coord(self, lineno: int, column: Optional[int] = None) -> Coord:
118 return Coord(file=self.clex.filename, line=lineno, column=column)
120 def _parse_error(self, msg: str, coord: Coord | str | None) -> NoReturn:
121 raise ParseError(f"{coord}: {msg}")
123 def _push_scope(self) -> None:
124 self._scope_stack.append(dict())
126 def _pop_scope(self) -> None:
127 if len(self._scope_stack) <= 1:
128 raise ParseError("Unmatched '}'")
129 self._scope_stack.pop()
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] = True
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 the
142 current scope
143 """
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] = False
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 in
155 # higher scopes.
156 if name in scope:
157 return scope[name]
158 return False
160 def _lex_error_func(self, msg: str, line: int, column: int) -> None:
161 self._parse_error(msg, self._coord(line, column))
163 def _lex_on_lbrace_func(self) -> None:
164 self._push_scope()
166 def _lex_on_rbrace_func(self) -> None:
167 self._pop_scope()
169 def _lex_type_lookup_func(self, name: str) -> bool:
170 """Looks up types that were previously defined with typedef.
172 Passed to the lexer for recognizing identifiers that are types.
173 """
174 return self._is_type_in_scope(name)
176 # To understand what's going on here, read sections A.8.5 and
177 # A.8.6 of K&R2 very carefully.
178 #
179 # A C type consists of a basic type declaration, with a list
180 # of modifiers. For example:
181 #
182 # int *c[5];
183 #
184 # The basic declaration here is 'int c', and the pointer and
185 # the array are the modifiers.
186 #
187 # Basic declarations are represented by TypeDecl (from module c_ast) and the
188 # modifiers are FuncDecl, PtrDecl and ArrayDecl.
189 #
190 # The standard states that whenever a new modifier is parsed, it should be
191 # added to the end of the list of modifiers. For example:
192 #
193 # K&R2 A.8.6.2: Array Declarators
194 #
195 # In a declaration T D where D has the form
196 # D1 [constant-expression-opt]
197 # and the type of the identifier in the declaration T D1 is
198 # "type-modifier T", the type of the
199 # identifier of D is "type-modifier array of T"
200 #
201 # This is what this method does. The declarator it receives
202 # can be a list of declarators ending with TypeDecl. It
203 # tacks the modifier to the end of this list, just before
204 # the TypeDecl.
205 #
206 # Additionally, the modifier may be a list itself. This is
207 # useful for pointers, that can come as a chain from the rule
208 # p_pointer. In this case, the whole modifier list is spliced
209 # into the new location.
210 def _type_modify_decl(self, decl: Any, modifier: Any) -> c_ast.Node:
211 """Tacks a type modifier on a declarator, and returns
212 the modified declarator.
214 Note: the declarator and modifier may be modified
215 """
216 modifier_head = modifier
217 modifier_tail = modifier
219 # The modifier may be a nested list. Reach its tail.
220 while modifier_tail.type:
221 modifier_tail = modifier_tail.type
223 # If the decl is a basic type, just tack the modifier onto it.
224 if isinstance(decl, c_ast.TypeDecl):
225 modifier_tail.type = decl
226 return modifier
227 else:
228 # Otherwise, the decl is a list of modifiers. Reach
229 # its tail and splice the modifier onto the tail,
230 # pointing to the underlying basic type.
231 decl_tail = decl
232 while not isinstance(decl_tail.type, c_ast.TypeDecl):
233 decl_tail = decl_tail.type
235 modifier_tail.type = decl_tail.type
236 decl_tail.type = modifier_head
237 return decl
239 # Due to the order in which declarators are constructed,
240 # they have to be fixed in order to look like a normal AST.
241 #
242 # When a declaration arrives from syntax construction, it has
243 # these problems:
244 # * The innermost TypeDecl has no type (because the basic
245 # type is only known at the uppermost declaration level)
246 # * The declaration has no variable name, since that is saved
247 # in the innermost TypeDecl
248 # * The typename of the declaration is a list of type
249 # specifiers, and not a node. Here, basic identifier types
250 # should be separated from more complex types like enums
251 # and structs.
252 #
253 # This method fixes these problems.
254 def _fix_decl_name_type(
255 self,
256 decl: c_ast.Decl | c_ast.Typedef | c_ast.Typename,
257 typename: List[Any],
258 ) -> c_ast.Decl | c_ast.Typedef | c_ast.Typename:
259 """Fixes a declaration. Modifies decl."""
260 # Reach the underlying basic type
261 typ = decl
262 while not isinstance(typ, c_ast.TypeDecl):
263 typ = typ.type
265 decl.name = typ.declname
266 typ.quals = decl.quals[:]
268 # The typename is a list of types. If any type in this
269 # list isn't an IdentifierType, it must be the only
270 # type in the list (it's illegal to declare "int enum ..")
271 # If all the types are basic, they're collected in the
272 # IdentifierType holder.
273 for tn in typename:
274 if not isinstance(tn, c_ast.IdentifierType):
275 if len(typename) > 1:
276 self._parse_error("Invalid multiple types specified", tn.coord)
277 else:
278 typ.type = tn
279 return decl
281 if not typename:
282 # Functions default to returning int
283 if not isinstance(decl.type, c_ast.FuncDecl):
284 self._parse_error("Missing type in declaration", decl.coord)
285 typ.type = c_ast.IdentifierType(["int"], coord=decl.coord)
286 else:
287 # At this point, we know that typename is a list of IdentifierType
288 # nodes. Concatenate all the names into a single list.
289 typ.type = c_ast.IdentifierType(
290 [name for id in typename for name in id.names], coord=typename[0].coord
291 )
292 return decl
294 def _add_declaration_specifier(
295 self,
296 declspec: Optional["_DeclSpec"],
297 newspec: Any,
298 kind: "_DeclSpecKind",
299 append: bool = False,
300 ) -> "_DeclSpec":
301 """See _DeclSpec for the specifier dictionary layout."""
302 if declspec is None:
303 spec: _DeclSpec = dict(
304 qual=[], storage=[], type=[], function=[], alignment=[]
305 )
306 else:
307 spec = declspec
309 if append:
310 spec[kind].append(newspec)
311 else:
312 spec[kind].insert(0, newspec)
314 return spec
316 def _build_declarations(
317 self,
318 spec: "_DeclSpec",
319 decls: List["_DeclInfo"],
320 typedef_namespace: bool = False,
321 ) -> List[c_ast.Node]:
322 """Builds a list of declarations all sharing the given specifiers.
323 If typedef_namespace is true, each declared name is added
324 to the "typedef namespace", which also includes objects,
325 functions, and enum constants.
326 """
327 is_typedef = "typedef" in spec["storage"]
328 declarations = []
330 # Bit-fields are allowed to be unnamed.
331 if decls[0].get("bitsize") is None:
332 # When redeclaring typedef names as identifiers in inner scopes, a
333 # problem can occur where the identifier gets grouped into
334 # spec['type'], leaving decl as None. This can only occur for the
335 # first declarator.
336 if decls[0]["decl"] is None:
337 if (
338 len(spec["type"]) < 2
339 or len(spec["type"][-1].names) != 1
340 or not self._is_type_in_scope(spec["type"][-1].names[0])
341 ):
342 coord = "?"
343 for t in spec["type"]:
344 if hasattr(t, "coord"):
345 coord = t.coord
346 break
347 self._parse_error("Invalid declaration", coord)
349 # Make this look as if it came from "direct_declarator:ID"
350 decls[0]["decl"] = c_ast.TypeDecl(
351 declname=spec["type"][-1].names[0],
352 type=None,
353 quals=None,
354 align=spec["alignment"],
355 coord=spec["type"][-1].coord,
356 )
357 # Remove the "new" type's name from the end of spec['type']
358 del spec["type"][-1]
359 # A similar problem can occur where the declaration ends up
360 # looking like an abstract declarator. Give it a name if this is
361 # the case.
362 elif not isinstance(
363 decls[0]["decl"],
364 (c_ast.Enum, c_ast.Struct, c_ast.Union, c_ast.IdentifierType),
365 ):
366 decls_0_tail = cast(Any, decls[0]["decl"])
367 while not isinstance(decls_0_tail, c_ast.TypeDecl):
368 decls_0_tail = decls_0_tail.type
369 if decls_0_tail.declname is None:
370 decls_0_tail.declname = spec["type"][-1].names[0]
371 del spec["type"][-1]
373 for decl in decls:
374 assert decl["decl"] is not None
375 if is_typedef:
376 declaration = c_ast.Typedef(
377 name=None,
378 quals=spec["qual"],
379 storage=spec["storage"],
380 type=decl["decl"],
381 coord=decl["decl"].coord,
382 )
383 else:
384 declaration = c_ast.Decl(
385 name=None,
386 quals=spec["qual"],
387 align=spec["alignment"],
388 storage=spec["storage"],
389 funcspec=spec["function"],
390 type=decl["decl"],
391 init=decl.get("init"),
392 bitsize=decl.get("bitsize"),
393 coord=decl["decl"].coord,
394 )
396 if isinstance(
397 declaration.type,
398 (c_ast.Enum, c_ast.Struct, c_ast.Union, c_ast.IdentifierType),
399 ):
400 fixed_decl = declaration
401 else:
402 fixed_decl = self._fix_decl_name_type(declaration, spec["type"])
404 # Add the type name defined by typedef to a
405 # symbol table (for usage in the lexer)
406 if typedef_namespace:
407 if is_typedef:
408 self._add_typedef_name(fixed_decl.name, fixed_decl.coord)
409 else:
410 self._add_identifier(fixed_decl.name, fixed_decl.coord)
412 fixed_decl = fix_atomic_specifiers(
413 cast(c_ast.Decl | c_ast.Typedef, fixed_decl)
414 )
415 declarations.append(fixed_decl)
417 return declarations
419 def _build_function_definition(
420 self,
421 spec: "_DeclSpec",
422 decl: c_ast.Node,
423 param_decls: Optional[List[c_ast.Node]],
424 body: c_ast.Node,
425 ) -> c_ast.Node:
426 """Builds a function definition."""
427 if "typedef" in spec["storage"]:
428 self._parse_error("Invalid typedef", decl.coord)
430 declaration = self._build_declarations(
431 spec=spec,
432 decls=[dict(decl=decl, init=None, bitsize=None)],
433 typedef_namespace=True,
434 )[0]
436 return c_ast.FuncDef(
437 decl=declaration, param_decls=param_decls, body=body, coord=decl.coord
438 )
440 def _select_struct_union_class(self, token: str) -> type:
441 """Given a token (either STRUCT or UNION), selects the
442 appropriate AST class.
443 """
444 if token == "struct":
445 return c_ast.Struct
446 else:
447 return c_ast.Union
449 # ------------------------------------------------------------------
450 # Token helpers
451 # ------------------------------------------------------------------
452 def _peek(self, k: int = 1) -> Optional[Token]:
453 """Return the k-th next token without consuming it (1-based)."""
454 return self._tokens.peek(k)
456 def _peek_type(self, k: int = 1) -> Optional[str]:
457 """Return the type of the k-th next token, or None if absent (1-based)."""
458 tok = self._peek(k)
459 return tok.type if tok is not None else None
461 def _advance(self) -> Token:
462 tok = self._tokens.next()
463 if tok is None:
464 self._parse_error("At end of input", self.clex.filename)
465 else:
466 return tok
468 def _accept(self, token_type: str) -> Optional[Token]:
469 """Conditionally consume next token, only if it's of token_type.
471 If it is of the expected type, consume and return it.
472 Otherwise, leaves the token intact and returns None.
473 """
474 tok = self._peek()
475 if tok is not None and tok.type == token_type:
476 return self._advance()
477 return None
479 def _expect(self, token_type: str) -> Token:
480 tok = self._advance()
481 if tok.type != token_type:
482 self._parse_error(f"before: {tok.value}", self._tok_coord(tok))
483 return tok
485 def _mark(self) -> int:
486 return self._tokens.mark()
488 def _reset(self, mark: int) -> None:
489 self._tokens.reset(mark)
491 def _tok_coord(self, tok: Token) -> Coord:
492 return self._coord(tok.lineno, tok.column)
494 def _starts_declaration(self, tok: Optional[Token] = None) -> bool:
495 tok = tok or self._peek()
496 if tok is None:
497 return False
498 return tok.type in _DECL_START
500 def _starts_expression(self, tok: Optional[Token] = None) -> bool:
501 tok = tok or self._peek()
502 if tok is None:
503 return False
504 return tok.type in _STARTS_EXPRESSION
506 def _starts_statement(self) -> bool:
507 tok_type = self._peek_type()
508 if tok_type is None:
509 return False
510 if tok_type in _STARTS_STATEMENT:
511 return True
512 return self._starts_expression()
514 def _starts_declarator(self, id_only: bool = False) -> bool:
515 tok_type = self._peek_type()
516 if tok_type is None:
517 return False
518 if tok_type in {"TIMES", "LPAREN"}:
519 return True
520 if id_only:
521 return tok_type == "ID"
522 return tok_type in {"ID", "TYPEID"}
524 def _peek_declarator_name_info(self) -> Tuple[Optional[str], bool]:
525 mark = self._mark()
526 tok_type, saw_paren = self._scan_declarator_name_info()
527 self._reset(mark)
528 return tok_type, saw_paren
530 def _parse_any_declarator(
531 self, allow_abstract: bool = False, typeid_paren_as_abstract: bool = False
532 ) -> Tuple[Optional[c_ast.Node], bool]:
533 # C declarators are ambiguous without lookahead. For example:
534 # int foo(int (aa)); -> aa is a name (ID)
535 # typedef char TT;
536 # int bar(int (TT)); -> TT is a type (TYPEID) in parens
537 name_type, saw_paren = self._peek_declarator_name_info()
538 if name_type is None or (
539 typeid_paren_as_abstract and name_type == "TYPEID" and saw_paren
540 ):
541 if not allow_abstract:
542 tok = self._peek()
543 coord = self._tok_coord(tok) if tok is not None else self.clex.filename
544 self._parse_error("Invalid declarator", coord)
545 decl = self._parse_abstract_declarator_opt()
546 return decl, False
548 if name_type == "TYPEID":
549 if typeid_paren_as_abstract:
550 decl = self._parse_typeid_noparen_declarator()
551 else:
552 decl = self._parse_typeid_declarator()
553 else:
554 decl = self._parse_id_declarator()
555 return decl, True
557 def _scan_declarator_name_info(self) -> Tuple[Optional[str], bool]:
558 saw_paren = False
559 while self._accept("TIMES"):
560 while self._peek_type() in _TYPE_QUALIFIER:
561 self._advance()
563 tok = self._peek()
564 if tok is None:
565 return None, saw_paren
566 if tok.type in {"ID", "TYPEID"}:
567 self._advance()
568 return tok.type, saw_paren
569 if tok.type == "LPAREN":
570 saw_paren = True
571 self._advance()
572 tok_type, nested_paren = self._scan_declarator_name_info()
573 if nested_paren:
574 saw_paren = True
575 depth = 1
576 while True:
577 tok = self._peek()
578 if tok is None:
579 return None, saw_paren
580 if tok.type == "LPAREN":
581 depth += 1
582 elif tok.type == "RPAREN":
583 depth -= 1
584 self._advance()
585 if depth == 0:
586 break
587 continue
588 self._advance()
589 return tok_type, saw_paren
590 return None, saw_paren
592 def _starts_direct_abstract_declarator(self) -> bool:
593 return self._peek_type() in {"LPAREN", "LBRACKET"}
595 def _is_assignment_op(self) -> bool:
596 tok = self._peek()
597 return tok is not None and tok.type in _ASSIGNMENT_OPS
599 def _try_parse_paren_type_name(
600 self,
601 ) -> Optional[Tuple[c_ast.Typename, int, Token]]:
602 """Parse and return a parenthesized type name if present.
604 Returns (typ, mark, lparen_tok) when the next tokens look like
605 '(' type_name ')', where typ is the parsed type name, mark is the
606 token-stream position before parsing, and lparen_tok is the LPAREN
607 token. Returns None if no parenthesized type name is present.
608 """
609 mark = self._mark()
610 lparen_tok = self._accept("LPAREN")
611 if lparen_tok is None:
612 return None
613 if not self._starts_declaration():
614 self._reset(mark)
615 return None
616 typ = self._parse_type_name()
617 if self._accept("RPAREN") is None:
618 self._reset(mark)
619 return None
620 return typ, mark, lparen_tok
622 # ------------------------------------------------------------------
623 # Top-level
624 # ------------------------------------------------------------------
625 # BNF: translation_unit_or_empty : translation_unit | empty
626 def _parse_translation_unit_or_empty(self) -> c_ast.FileAST:
627 if self._peek() is None:
628 return c_ast.FileAST([])
629 return c_ast.FileAST(self._parse_translation_unit())
631 # BNF: translation_unit : external_declaration+
632 def _parse_translation_unit(self) -> List[c_ast.Node]:
633 ext = []
634 while self._peek() is not None:
635 ext.extend(self._parse_external_declaration())
636 return ext
638 # BNF: external_declaration : function_definition
639 # | declaration
640 # | pp_directive
641 # | pppragma_directive
642 # | static_assert
643 # | ';'
644 def _parse_external_declaration(self) -> List[c_ast.Node]:
645 tok = self._peek()
646 if tok is None:
647 return []
648 if tok.type == "PPHASH":
649 self._parse_pp_directive()
650 return []
651 if tok.type in {"PPPRAGMA", "_PRAGMA"}:
652 return [self._parse_pppragma_directive()]
653 if self._accept("SEMI"):
654 return []
655 if tok.type == "_STATIC_ASSERT":
656 return self._parse_static_assert()
658 if not self._starts_declaration(tok):
659 # Special handling for old-style function definitions that have an
660 # implicit return type, e.g.
661 #
662 # foo() {
663 # return 5;
664 # }
665 #
666 # These get an implicit 'int' return type.
667 decl = self._parse_id_declarator()
668 param_decls = None
669 if self._peek_type() != "LBRACE":
670 self._parse_error("Invalid function definition", decl.coord)
671 spec: _DeclSpec = dict(
672 qual=[],
673 alignment=[],
674 storage=[],
675 type=[c_ast.IdentifierType(["int"], coord=decl.coord)],
676 function=[],
677 )
678 func = self._build_function_definition(
679 spec=spec,
680 decl=decl,
681 param_decls=param_decls,
682 body=self._parse_compound_statement(),
683 )
684 return [func]
686 # From here on, parsing a standard declatation/definition.
687 spec, saw_type, spec_coord = self._parse_declaration_specifiers(
688 allow_no_type=True
689 )
691 name_type, _ = self._peek_declarator_name_info()
692 if name_type != "ID":
693 decls = self._parse_decl_body_with_spec(spec, saw_type)
694 self._expect("SEMI")
695 return decls
697 decl = self._parse_id_declarator()
699 if self._peek_type() == "LBRACE" or self._starts_declaration():
700 param_decls = None
701 if self._starts_declaration():
702 param_decls = self._parse_declaration_list()
703 if self._peek_type() != "LBRACE":
704 self._parse_error("Invalid function definition", decl.coord)
705 if not spec["type"]:
706 spec["type"] = [c_ast.IdentifierType(["int"], coord=spec_coord)]
707 func = self._build_function_definition(
708 spec=spec,
709 decl=decl,
710 param_decls=param_decls,
711 body=self._parse_compound_statement(),
712 )
713 return [func]
715 decl_dict: "_DeclInfo" = dict(decl=decl, init=None, bitsize=None)
716 if self._accept("EQUALS"):
717 decl_dict["init"] = self._parse_initializer()
718 decls = self._parse_init_declarator_list(first=decl_dict)
719 decls = self._build_declarations(spec=spec, decls=decls, typedef_namespace=True)
720 self._expect("SEMI")
721 return decls
723 # ------------------------------------------------------------------
724 # Declarations
725 #
726 # Declarations always come as lists (because they can be several in one
727 # line). When returning parsed declarations, a list is always returned -
728 # even if it contains a single element.
729 # ------------------------------------------------------------------
730 def _parse_declaration(self) -> List[c_ast.Node]:
731 decls = self._parse_decl_body()
732 self._expect("SEMI")
733 return decls
735 # BNF: decl_body : declaration_specifiers decl_body_with_spec
736 def _parse_decl_body(self) -> List[c_ast.Node]:
737 spec, saw_type, _ = self._parse_declaration_specifiers(allow_no_type=True)
738 return self._parse_decl_body_with_spec(spec, saw_type)
740 # BNF: decl_body_with_spec : init_declarator_list
741 # | struct_or_union_or_enum_only
742 def _parse_decl_body_with_spec(
743 self, spec: "_DeclSpec", saw_type: bool
744 ) -> List[c_ast.Node]:
745 # saw_type is True if the specifiers included an actual type (as
746 # opposed to only storage/function/qualifiers).
747 decl_infos: Optional[List["_DeclInfo"]] = None
748 if saw_type:
749 if self._starts_declarator():
750 decl_infos = self._parse_init_declarator_list()
751 else:
752 if self._starts_declarator(id_only=True):
753 decl_infos = self._parse_init_declarator_list(id_only=True)
755 decls: List[c_ast.Node]
756 if decl_infos is None:
757 ty = spec["type"]
758 s_u_or_e = (c_ast.Struct, c_ast.Union, c_ast.Enum)
759 if len(ty) == 1 and isinstance(ty[0], s_u_or_e):
760 decls = [
761 c_ast.Decl(
762 name=None,
763 quals=spec["qual"],
764 align=spec["alignment"],
765 storage=spec["storage"],
766 funcspec=spec["function"],
767 type=ty[0],
768 init=None,
769 bitsize=None,
770 coord=ty[0].coord,
771 )
772 ]
773 else:
774 decls = self._build_declarations(
775 spec=spec,
776 decls=[dict(decl=None, init=None, bitsize=None)],
777 typedef_namespace=True,
778 )
779 else:
780 decls = self._build_declarations(
781 spec=spec, decls=decl_infos, typedef_namespace=True
782 )
784 return decls
786 # BNF: declaration_list : declaration+
787 def _parse_declaration_list(self) -> List[c_ast.Node]:
788 decls = []
789 while self._starts_declaration():
790 decls.extend(self._parse_declaration())
791 return decls
793 # BNF: declaration_specifiers : (storage_class_specifier
794 # | type_specifier
795 # | type_qualifier
796 # | function_specifier
797 # | alignment_specifier)+
798 def _parse_declaration_specifiers(
799 self, allow_no_type: bool = False
800 ) -> Tuple["_DeclSpec", bool, Optional[Coord]]:
801 """Parse declaration-specifier sequence.
803 allow_no_type:
804 If True, allow a missing type specifier without error.
806 Returns:
807 (spec, saw_type, first_coord) where spec is a dict with
808 qual/storage/type/function/alignment entries, saw_type is True
809 if a type specifier was consumed, and first_coord is the coord
810 of the first specifier token (used for diagnostics).
811 """
812 spec = None
813 saw_type = False
814 first_coord = None
816 while True:
817 tok = self._peek()
818 if tok is None:
819 break
821 if tok.type == "_ALIGNAS":
822 if first_coord is None:
823 first_coord = self._tok_coord(tok)
824 spec = self._add_declaration_specifier(
825 spec, self._parse_alignment_specifier(), "alignment", append=True
826 )
827 continue
829 if tok.type == "_ATOMIC" and self._peek_type(2) == "LPAREN":
830 if first_coord is None:
831 first_coord = self._tok_coord(tok)
832 spec = self._add_declaration_specifier(
833 spec, self._parse_atomic_specifier(), "type", append=True
834 )
835 saw_type = True
836 continue
838 if tok.type in _TYPE_QUALIFIER:
839 if first_coord is None:
840 first_coord = self._tok_coord(tok)
841 spec = self._add_declaration_specifier(
842 spec, self._advance().value, "qual", append=True
843 )
844 continue
846 if tok.type in _STORAGE_CLASS:
847 if first_coord is None:
848 first_coord = self._tok_coord(tok)
849 spec = self._add_declaration_specifier(
850 spec, self._advance().value, "storage", append=True
851 )
852 continue
854 if tok.type in _FUNCTION_SPEC:
855 if first_coord is None:
856 first_coord = self._tok_coord(tok)
857 spec = self._add_declaration_specifier(
858 spec, self._advance().value, "function", append=True
859 )
860 continue
862 if tok.type in _TYPE_SPEC_SIMPLE:
863 if first_coord is None:
864 first_coord = self._tok_coord(tok)
865 tok = self._advance()
866 spec = self._add_declaration_specifier(
867 spec,
868 c_ast.IdentifierType([tok.value], coord=self._tok_coord(tok)),
869 "type",
870 append=True,
871 )
872 saw_type = True
873 continue
875 if tok.type == "TYPEID":
876 if saw_type:
877 break
878 if first_coord is None:
879 first_coord = self._tok_coord(tok)
880 tok = self._advance()
881 spec = self._add_declaration_specifier(
882 spec,
883 c_ast.IdentifierType([tok.value], coord=self._tok_coord(tok)),
884 "type",
885 append=True,
886 )
887 saw_type = True
888 continue
890 if tok.type in {"STRUCT", "UNION"}:
891 if first_coord is None:
892 first_coord = self._tok_coord(tok)
893 spec = self._add_declaration_specifier(
894 spec, self._parse_struct_or_union_specifier(), "type", append=True
895 )
896 saw_type = True
897 continue
899 if tok.type == "ENUM":
900 if first_coord is None:
901 first_coord = self._tok_coord(tok)
902 spec = self._add_declaration_specifier(
903 spec, self._parse_enum_specifier(), "type", append=True
904 )
905 saw_type = True
906 continue
908 break
910 if spec is None:
911 self._parse_error("Invalid declaration", self.clex.filename)
913 if not saw_type and not allow_no_type:
914 self._parse_error("Missing type in declaration", first_coord)
916 return spec, saw_type, first_coord
918 # BNF: specifier_qualifier_list : (type_specifier
919 # | type_qualifier
920 # | alignment_specifier)+
921 def _parse_specifier_qualifier_list(self) -> "_DeclSpec":
922 spec = None
923 saw_type = False
924 saw_alignment = False
925 first_coord = None
927 while True:
928 tok = self._peek()
929 if tok is None:
930 break
932 if tok.type == "_ALIGNAS":
933 if first_coord is None:
934 first_coord = self._tok_coord(tok)
935 spec = self._add_declaration_specifier(
936 spec, self._parse_alignment_specifier(), "alignment", append=True
937 )
938 saw_alignment = True
939 continue
941 if tok.type == "_ATOMIC" and self._peek_type(2) == "LPAREN":
942 if first_coord is None:
943 first_coord = self._tok_coord(tok)
944 spec = self._add_declaration_specifier(
945 spec, self._parse_atomic_specifier(), "type", append=True
946 )
947 saw_type = True
948 continue
950 if tok.type in _TYPE_QUALIFIER:
951 if first_coord is None:
952 first_coord = self._tok_coord(tok)
953 spec = self._add_declaration_specifier(
954 spec, self._advance().value, "qual", append=True
955 )
956 continue
958 if tok.type in _TYPE_SPEC_SIMPLE:
959 if first_coord is None:
960 first_coord = self._tok_coord(tok)
961 tok = self._advance()
962 spec = self._add_declaration_specifier(
963 spec,
964 c_ast.IdentifierType([tok.value], coord=self._tok_coord(tok)),
965 "type",
966 append=True,
967 )
968 saw_type = True
969 continue
971 if tok.type == "TYPEID":
972 if saw_type:
973 break
974 if first_coord is None:
975 first_coord = self._tok_coord(tok)
976 tok = self._advance()
977 spec = self._add_declaration_specifier(
978 spec,
979 c_ast.IdentifierType([tok.value], coord=self._tok_coord(tok)),
980 "type",
981 append=True,
982 )
983 saw_type = True
984 continue
986 if tok.type in {"STRUCT", "UNION"}:
987 if first_coord is None:
988 first_coord = self._tok_coord(tok)
989 spec = self._add_declaration_specifier(
990 spec, self._parse_struct_or_union_specifier(), "type", append=True
991 )
992 saw_type = True
993 continue
995 if tok.type == "ENUM":
996 if first_coord is None:
997 first_coord = self._tok_coord(tok)
998 spec = self._add_declaration_specifier(
999 spec, self._parse_enum_specifier(), "type", append=True
1000 )
1001 saw_type = True
1002 continue
1004 break
1006 if spec is None:
1007 self._parse_error("Invalid specifier list", self.clex.filename)
1009 if not saw_type and not saw_alignment:
1010 self._parse_error("Missing type in declaration", first_coord)
1012 if spec.get("storage") is None:
1013 spec["storage"] = []
1014 if spec.get("function") is None:
1015 spec["function"] = []
1017 return spec
1019 # BNF: type_qualifier_list : type_qualifier+
1020 def _parse_type_qualifier_list(self) -> List[str]:
1021 quals = []
1022 while self._peek_type() in _TYPE_QUALIFIER:
1023 quals.append(self._advance().value)
1024 return quals
1026 # BNF: alignment_specifier : _ALIGNAS '(' type_name | constant_expression ')'
1027 def _parse_alignment_specifier(self) -> c_ast.Node:
1028 tok = self._expect("_ALIGNAS")
1029 self._expect("LPAREN")
1031 if self._starts_declaration():
1032 typ = self._parse_type_name()
1033 self._expect("RPAREN")
1034 return c_ast.Alignas(typ, self._tok_coord(tok))
1036 expr = self._parse_constant_expression()
1037 self._expect("RPAREN")
1038 return c_ast.Alignas(expr, self._tok_coord(tok))
1040 # BNF: atomic_specifier : _ATOMIC '(' type_name ')'
1041 def _parse_atomic_specifier(self) -> c_ast.Node:
1042 self._expect("_ATOMIC")
1043 self._expect("LPAREN")
1044 typ = self._parse_type_name()
1045 self._expect("RPAREN")
1046 typ.quals.append("_Atomic")
1047 return typ
1049 # BNF: init_declarator_list : init_declarator (',' init_declarator)*
1050 def _parse_init_declarator_list(
1051 self, first: Optional["_DeclInfo"] = None, id_only: bool = False
1052 ) -> List["_DeclInfo"]:
1053 decls = (
1054 [first]
1055 if first is not None
1056 else [self._parse_init_declarator(id_only=id_only)]
1057 )
1059 while self._accept("COMMA"):
1060 decls.append(self._parse_init_declarator(id_only=id_only))
1061 return decls
1063 # BNF: init_declarator : declarator ('=' initializer)?
1064 def _parse_init_declarator(self, id_only: bool = False) -> "_DeclInfo":
1065 decl = self._parse_id_declarator() if id_only else self._parse_declarator()
1066 init = None
1067 if self._accept("EQUALS"):
1068 init = self._parse_initializer()
1069 return dict(decl=decl, init=init, bitsize=None)
1071 # ------------------------------------------------------------------
1072 # Structs/unions/enums
1073 # ------------------------------------------------------------------
1074 # BNF: struct_or_union_specifier : struct_or_union ID? '{' struct_declaration_list? '}'
1075 # | struct_or_union ID
1076 def _parse_struct_or_union_specifier(self) -> c_ast.Node:
1077 tok = self._advance()
1078 klass = self._select_struct_union_class(tok.value)
1080 if self._peek_type() in {"ID", "TYPEID"}:
1081 name_tok = self._advance()
1082 if self._peek_type() == "LBRACE":
1083 self._advance()
1084 if self._accept("RBRACE"):
1085 return klass(
1086 name=name_tok.value, decls=[], coord=self._tok_coord(name_tok)
1087 )
1088 decls = self._parse_struct_declaration_list()
1089 self._expect("RBRACE")
1090 return klass(
1091 name=name_tok.value, decls=decls, coord=self._tok_coord(name_tok)
1092 )
1094 return klass(
1095 name=name_tok.value, decls=None, coord=self._tok_coord(name_tok)
1096 )
1098 if self._peek_type() == "LBRACE":
1099 brace_tok = self._advance()
1100 if self._accept("RBRACE"):
1101 return klass(name=None, decls=[], coord=self._tok_coord(brace_tok))
1102 decls = self._parse_struct_declaration_list()
1103 self._expect("RBRACE")
1104 return klass(name=None, decls=decls, coord=self._tok_coord(brace_tok))
1106 self._parse_error("Invalid struct/union declaration", self._tok_coord(tok))
1108 # BNF: struct_declaration_list : struct_declaration+
1109 def _parse_struct_declaration_list(self) -> List[c_ast.Node]:
1110 decls = []
1111 while self._peek_type() not in {None, "RBRACE"}:
1112 items = self._parse_struct_declaration()
1113 if items is None:
1114 continue
1115 decls.extend(items)
1116 return decls
1118 # BNF: struct_declaration : specifier_qualifier_list struct_declarator_list? ';'
1119 # | static_assert
1120 # | pppragma_directive
1121 def _parse_struct_declaration(self) -> Optional[List[c_ast.Node]]:
1122 if self._peek_type() == "SEMI":
1123 self._advance()
1124 return None
1125 if self._peek_type() in {"PPPRAGMA", "_PRAGMA"}:
1126 return [self._parse_pppragma_directive()]
1128 spec = self._parse_specifier_qualifier_list()
1129 assert "typedef" not in spec.get("storage", [])
1131 decls = None
1132 if self._starts_declarator() or self._peek_type() == "COLON":
1133 decls = self._parse_struct_declarator_list()
1134 if decls is not None:
1135 self._expect("SEMI")
1136 return self._build_declarations(spec=spec, decls=decls)
1138 if len(spec["type"]) == 1:
1139 node = spec["type"][0]
1140 if isinstance(node, c_ast.Node):
1141 decl_type = node
1142 else:
1143 decl_type = c_ast.IdentifierType(node)
1144 self._expect("SEMI")
1145 return self._build_declarations(
1146 spec=spec, decls=[dict(decl=decl_type, init=None, bitsize=None)]
1147 )
1149 self._expect("SEMI")
1150 return self._build_declarations(
1151 spec=spec, decls=[dict(decl=None, init=None, bitsize=None)]
1152 )
1154 # BNF: struct_declarator_list : struct_declarator (',' struct_declarator)*
1155 def _parse_struct_declarator_list(self) -> List["_DeclInfo"]:
1156 decls = [self._parse_struct_declarator()]
1157 while self._accept("COMMA"):
1158 decls.append(self._parse_struct_declarator())
1159 return decls
1161 # BNF: struct_declarator : declarator? ':' constant_expression
1162 # | declarator (':' constant_expression)?
1163 def _parse_struct_declarator(self) -> "_DeclInfo":
1164 if self._accept("COLON"):
1165 bitsize = self._parse_constant_expression()
1166 return {
1167 "decl": c_ast.TypeDecl(None, None, None, None),
1168 "init": None,
1169 "bitsize": bitsize,
1170 }
1172 decl = self._parse_declarator()
1173 if self._accept("COLON"):
1174 bitsize = self._parse_constant_expression()
1175 return {"decl": decl, "init": None, "bitsize": bitsize}
1177 return {"decl": decl, "init": None, "bitsize": None}
1179 # BNF: enum_specifier : ENUM ID? '{' enumerator_list? '}'
1180 # | ENUM ID
1181 def _parse_enum_specifier(self) -> c_ast.Node:
1182 tok = self._expect("ENUM")
1183 if self._peek_type() in {"ID", "TYPEID"}:
1184 name_tok = self._advance()
1185 if self._peek_type() == "LBRACE":
1186 self._advance()
1187 enums = self._parse_enumerator_list()
1188 self._expect("RBRACE")
1189 return c_ast.Enum(name_tok.value, enums, self._tok_coord(tok))
1190 return c_ast.Enum(name_tok.value, None, self._tok_coord(tok))
1192 self._expect("LBRACE")
1193 enums = self._parse_enumerator_list()
1194 self._expect("RBRACE")
1195 return c_ast.Enum(None, enums, self._tok_coord(tok))
1197 # BNF: enumerator_list : enumerator (',' enumerator)* ','?
1198 def _parse_enumerator_list(self) -> c_ast.Node:
1199 enum = self._parse_enumerator()
1200 enum_list = c_ast.EnumeratorList([enum], enum.coord)
1201 while self._accept("COMMA"):
1202 if self._peek_type() == "RBRACE":
1203 break
1204 enum = self._parse_enumerator()
1205 enum_list.enumerators.append(enum)
1206 return enum_list
1208 # BNF: enumerator : ID ('=' constant_expression)?
1209 def _parse_enumerator(self) -> c_ast.Node:
1210 name_tok = self._expect("ID")
1211 if self._accept("EQUALS"):
1212 value = self._parse_constant_expression()
1213 else:
1214 value = None
1215 enum = c_ast.Enumerator(name_tok.value, value, self._tok_coord(name_tok))
1216 self._add_identifier(enum.name, enum.coord)
1217 return enum
1219 # ------------------------------------------------------------------
1220 # Declarators
1221 # ------------------------------------------------------------------
1222 # BNF: declarator : pointer? direct_declarator
1223 def _parse_declarator(self) -> c_ast.Node:
1224 decl, _ = self._parse_any_declarator(
1225 allow_abstract=False, typeid_paren_as_abstract=False
1226 )
1227 assert decl is not None
1228 return decl
1230 # BNF: id_declarator : declarator with ID name
1231 def _parse_id_declarator(self) -> c_ast.Node:
1232 return self._parse_declarator_kind(kind="id", allow_paren=True)
1234 # BNF: typeid_declarator : declarator with TYPEID name
1235 def _parse_typeid_declarator(self) -> c_ast.Node:
1236 return self._parse_declarator_kind(kind="typeid", allow_paren=True)
1238 # BNF: typeid_noparen_declarator : declarator without parenthesized name
1239 def _parse_typeid_noparen_declarator(self) -> c_ast.Node:
1240 return self._parse_declarator_kind(kind="typeid", allow_paren=False)
1242 # BNF: declarator_kind : pointer? direct_declarator(kind)
1243 def _parse_declarator_kind(self, kind: str, allow_paren: bool) -> c_ast.Node:
1244 ptr = None
1245 if self._peek_type() == "TIMES":
1246 ptr = self._parse_pointer()
1247 direct = self._parse_direct_declarator(kind, allow_paren=allow_paren)
1248 if ptr is not None:
1249 return self._type_modify_decl(direct, ptr)
1250 return direct
1252 # BNF: direct_declarator : ID | TYPEID | '(' declarator ')'
1253 # | direct_declarator '[' ... ']'
1254 # | direct_declarator '(' ... ')'
1255 def _parse_direct_declarator(
1256 self, kind: str, allow_paren: bool = True
1257 ) -> c_ast.Node:
1258 if allow_paren and self._accept("LPAREN"):
1259 decl = self._parse_declarator_kind(kind, allow_paren=True)
1260 self._expect("RPAREN")
1261 else:
1262 if kind == "id":
1263 name_tok = self._expect("ID")
1264 else:
1265 name_tok = self._expect("TYPEID")
1266 decl = c_ast.TypeDecl(
1267 declname=name_tok.value,
1268 type=None,
1269 quals=None,
1270 align=None,
1271 coord=self._tok_coord(name_tok),
1272 )
1274 return self._parse_decl_suffixes(decl)
1276 def _parse_decl_suffixes(self, decl: c_ast.Node) -> c_ast.Node:
1277 """Parse a chain of array/function suffixes and attach them to decl."""
1278 while True:
1279 if self._peek_type() == "LBRACKET":
1280 decl = self._type_modify_decl(decl, self._parse_array_decl(decl))
1281 continue
1282 if self._peek_type() == "LPAREN":
1283 func = self._parse_function_decl(decl)
1284 decl = self._type_modify_decl(decl, func)
1285 continue
1286 break
1287 return decl
1289 # BNF: array_decl : '[' array_specifiers? assignment_expression? ']'
1290 def _parse_array_decl(self, base_decl: c_ast.Node) -> c_ast.Node:
1291 return self._parse_array_decl_common(base_type=None, coord=base_decl.coord)
1293 def _parse_array_decl_common(
1294 self, base_type: Optional[c_ast.Node], coord: Optional[Coord] = None
1295 ) -> c_ast.Node:
1296 """Parse an array declarator suffix and return an ArrayDecl node.
1298 base_type:
1299 Base declarator node to attach (None for direct-declarator parsing,
1300 TypeDecl for abstract declarators).
1302 coord:
1303 Coordinate to use for the ArrayDecl. If None, uses the '[' token.
1304 """
1305 lbrack_tok = self._expect("LBRACKET")
1306 if coord is None:
1307 coord = self._tok_coord(lbrack_tok)
1309 def make_array_decl(dim, dim_quals):
1310 return c_ast.ArrayDecl(
1311 type=base_type, dim=dim, dim_quals=dim_quals, coord=coord
1312 )
1314 if self._accept("STATIC"):
1315 dim_quals = ["static"] + (self._parse_type_qualifier_list() or [])
1316 dim = self._parse_assignment_expression()
1317 self._expect("RBRACKET")
1318 return make_array_decl(dim, dim_quals)
1320 if self._peek_type() in _TYPE_QUALIFIER:
1321 dim_quals = self._parse_type_qualifier_list() or []
1322 if self._accept("STATIC"):
1323 dim_quals = dim_quals + ["static"]
1324 dim = self._parse_assignment_expression()
1325 self._expect("RBRACKET")
1326 return make_array_decl(dim, dim_quals)
1327 times_tok = self._accept("TIMES")
1328 if times_tok:
1329 self._expect("RBRACKET")
1330 dim = c_ast.ID(times_tok.value, self._tok_coord(times_tok))
1331 return make_array_decl(dim, dim_quals)
1332 dim = None
1333 if self._starts_expression():
1334 dim = self._parse_assignment_expression()
1335 self._expect("RBRACKET")
1336 return make_array_decl(dim, dim_quals)
1338 times_tok = self._accept("TIMES")
1339 if times_tok:
1340 self._expect("RBRACKET")
1341 dim = c_ast.ID(times_tok.value, self._tok_coord(times_tok))
1342 return make_array_decl(dim, [])
1344 dim = None
1345 if self._starts_expression():
1346 dim = self._parse_assignment_expression()
1347 self._expect("RBRACKET")
1348 return make_array_decl(dim, [])
1350 # BNF: function_decl : '(' parameter_type_list_opt | identifier_list_opt ')'
1351 def _parse_function_decl(self, base_decl: c_ast.Node) -> c_ast.Node:
1352 self._expect("LPAREN")
1353 if self._accept("RPAREN"):
1354 args = None
1355 else:
1356 args = (
1357 self._parse_parameter_type_list()
1358 if self._starts_declaration()
1359 else self._parse_identifier_list_opt()
1360 )
1361 self._expect("RPAREN")
1363 func = c_ast.FuncDecl(args=args, type=None, coord=base_decl.coord)
1365 if self._peek_type() == "LBRACE":
1366 if func.args is not None:
1367 for param in func.args.params:
1368 if isinstance(param, c_ast.EllipsisParam):
1369 break
1370 name = getattr(param, "name", None)
1371 if name:
1372 self._add_identifier(name, param.coord)
1374 return func
1376 # BNF: pointer : '*' type_qualifier_list? pointer?
1377 def _parse_pointer(self) -> Optional[c_ast.Node]:
1378 stars = []
1379 times_tok = self._accept("TIMES")
1380 while times_tok:
1381 quals = self._parse_type_qualifier_list() or []
1382 stars.append((quals, self._tok_coord(times_tok)))
1383 times_tok = self._accept("TIMES")
1385 if not stars:
1386 return None
1388 ptr = None
1389 for quals, coord in stars:
1390 ptr = c_ast.PtrDecl(quals=quals, type=ptr, coord=coord)
1391 return ptr
1393 # BNF: parameter_type_list : parameter_list (',' ELLIPSIS)?
1394 def _parse_parameter_type_list(self) -> c_ast.ParamList:
1395 params = self._parse_parameter_list()
1396 if self._peek_type() == "COMMA" and self._peek_type(2) == "ELLIPSIS":
1397 self._advance()
1398 ell_tok = self._advance()
1399 params.params.append(c_ast.EllipsisParam(self._tok_coord(ell_tok)))
1400 return params
1402 # BNF: parameter_list : parameter_declaration (',' parameter_declaration)*
1403 def _parse_parameter_list(self) -> c_ast.ParamList:
1404 first = self._parse_parameter_declaration()
1405 params = c_ast.ParamList([first], first.coord)
1406 while self._peek_type() == "COMMA" and self._peek_type(2) != "ELLIPSIS":
1407 self._advance()
1408 params.params.append(self._parse_parameter_declaration())
1409 return params
1411 # BNF: parameter_declaration : declaration_specifiers declarator?
1412 # | declaration_specifiers abstract_declarator_opt
1413 def _parse_parameter_declaration(self) -> c_ast.Node:
1414 spec, _, spec_coord = self._parse_declaration_specifiers(allow_no_type=True)
1416 if not spec["type"]:
1417 spec["type"] = [c_ast.IdentifierType(["int"], coord=spec_coord)]
1419 if self._starts_declarator():
1420 decl, is_named = self._parse_any_declarator(
1421 allow_abstract=True, typeid_paren_as_abstract=True
1422 )
1423 if is_named:
1424 return self._build_declarations(
1425 spec=spec, decls=[dict(decl=decl, init=None, bitsize=None)]
1426 )[0]
1427 return self._build_parameter_declaration(spec, decl, spec_coord)
1429 decl = self._parse_abstract_declarator_opt()
1430 return self._build_parameter_declaration(spec, decl, spec_coord)
1432 def _build_parameter_declaration(
1433 self, spec: "_DeclSpec", decl: Optional[c_ast.Node], spec_coord: Optional[Coord]
1434 ) -> c_ast.Node:
1435 if (
1436 len(spec["type"]) > 1
1437 and len(spec["type"][-1].names) == 1
1438 and self._is_type_in_scope(spec["type"][-1].names[0])
1439 ):
1440 return self._build_declarations(
1441 spec=spec, decls=[dict(decl=decl, init=None, bitsize=None)]
1442 )[0]
1444 decl = c_ast.Typename(
1445 name="",
1446 quals=spec["qual"],
1447 align=None,
1448 type=decl or c_ast.TypeDecl(None, None, None, None),
1449 coord=spec_coord,
1450 )
1451 return self._fix_decl_name_type(decl, spec["type"])
1453 # BNF: identifier_list_opt : identifier_list | empty
1454 def _parse_identifier_list_opt(self) -> Optional[c_ast.Node]:
1455 if self._peek_type() == "RPAREN":
1456 return None
1457 return self._parse_identifier_list()
1459 # BNF: identifier_list : identifier (',' identifier)*
1460 def _parse_identifier_list(self) -> c_ast.Node:
1461 first = self._parse_identifier()
1462 params = c_ast.ParamList([first], first.coord)
1463 while self._accept("COMMA"):
1464 params.params.append(self._parse_identifier())
1465 return params
1467 # ------------------------------------------------------------------
1468 # Abstract declarators
1469 # ------------------------------------------------------------------
1470 # BNF: type_name : specifier_qualifier_list abstract_declarator_opt
1471 def _parse_type_name(self) -> c_ast.Typename:
1472 spec = self._parse_specifier_qualifier_list()
1473 decl = self._parse_abstract_declarator_opt()
1475 coord = None
1476 if decl is not None:
1477 coord = decl.coord
1478 elif spec["type"]:
1479 coord = spec["type"][0].coord
1481 typename = c_ast.Typename(
1482 name="",
1483 quals=spec["qual"][:],
1484 align=None,
1485 type=decl or c_ast.TypeDecl(None, None, None, None),
1486 coord=coord,
1487 )
1488 return cast(c_ast.Typename, self._fix_decl_name_type(typename, spec["type"]))
1490 # BNF: abstract_declarator_opt : pointer? direct_abstract_declarator?
1491 def _parse_abstract_declarator_opt(self) -> Optional[c_ast.Node]:
1492 if self._peek_type() == "TIMES":
1493 ptr = self._parse_pointer()
1494 if self._starts_direct_abstract_declarator():
1495 decl = self._parse_direct_abstract_declarator()
1496 else:
1497 decl = c_ast.TypeDecl(None, None, None, None)
1498 assert ptr is not None
1499 return self._type_modify_decl(decl, ptr)
1501 if self._starts_direct_abstract_declarator():
1502 return self._parse_direct_abstract_declarator()
1504 return None
1506 # BNF: direct_abstract_declarator : '(' parameter_type_list_opt ')'
1507 # | '(' abstract_declarator ')'
1508 # | '[' ... ']'
1509 def _parse_direct_abstract_declarator(self) -> c_ast.Node:
1510 lparen_tok = self._accept("LPAREN")
1511 if lparen_tok:
1512 if self._starts_declaration() or self._peek_type() == "RPAREN":
1513 params = self._parse_parameter_type_list_opt()
1514 self._expect("RPAREN")
1515 decl = c_ast.FuncDecl(
1516 args=params,
1517 type=c_ast.TypeDecl(None, None, None, None),
1518 coord=self._tok_coord(lparen_tok),
1519 )
1520 else:
1521 decl = self._parse_abstract_declarator_opt()
1522 self._expect("RPAREN")
1523 assert decl is not None
1524 elif self._peek_type() == "LBRACKET":
1525 decl = self._parse_abstract_array_base()
1526 else:
1527 self._parse_error("Invalid abstract declarator", self.clex.filename)
1529 return self._parse_decl_suffixes(decl)
1531 # BNF: parameter_type_list_opt : parameter_type_list | empty
1532 def _parse_parameter_type_list_opt(self) -> Optional[c_ast.ParamList]:
1533 if self._peek_type() == "RPAREN":
1534 return None
1535 return self._parse_parameter_type_list()
1537 # BNF: abstract_array_base : '[' array_specifiers? assignment_expression? ']'
1538 def _parse_abstract_array_base(self) -> c_ast.Node:
1539 return self._parse_array_decl_common(
1540 base_type=c_ast.TypeDecl(None, None, None, None), coord=None
1541 )
1543 # ------------------------------------------------------------------
1544 # Statements
1545 # ------------------------------------------------------------------
1546 # BNF: statement : labeled_statement | compound_statement
1547 # | selection_statement | iteration_statement
1548 # | jump_statement | expression_statement
1549 # | static_assert | pppragma_directive
1550 def _parse_statement(self) -> c_ast.Node | List[c_ast.Node]:
1551 tok_type = self._peek_type()
1552 match tok_type:
1553 case "CASE" | "DEFAULT":
1554 return self._parse_labeled_statement()
1555 case "ID" if self._peek_type(2) == "COLON":
1556 return self._parse_labeled_statement()
1557 case "LBRACE":
1558 return self._parse_compound_statement()
1559 case "IF" | "SWITCH":
1560 return self._parse_selection_statement()
1561 case "WHILE" | "DO" | "FOR":
1562 return self._parse_iteration_statement()
1563 case "GOTO" | "BREAK" | "CONTINUE" | "RETURN":
1564 return self._parse_jump_statement()
1565 case "PPPRAGMA" | "_PRAGMA":
1566 return self._parse_pppragma_directive()
1567 case "_STATIC_ASSERT":
1568 return self._parse_static_assert()
1569 case _:
1570 return self._parse_expression_statement()
1572 # BNF: pragmacomp_or_statement : pppragma_directive* statement
1573 def _parse_pragmacomp_or_statement(self) -> c_ast.Node | List[c_ast.Node]:
1574 if self._peek_type() in {"PPPRAGMA", "_PRAGMA"}:
1575 pragmas = self._parse_pppragma_directive_list()
1576 stmt = self._parse_statement()
1577 return c_ast.Compound(block_items=pragmas + [stmt], coord=pragmas[0].coord)
1578 return self._parse_statement()
1580 # BNF: block_item : declaration | statement
1581 def _parse_block_item(self) -> c_ast.Node | List[c_ast.Node]:
1582 if self._starts_declaration():
1583 return self._parse_declaration()
1584 return self._parse_statement()
1586 # BNF: block_item_list : block_item+
1587 def _parse_block_item_list(self) -> List[c_ast.Node]:
1588 items = []
1589 while self._peek_type() not in {"RBRACE", None}:
1590 item = self._parse_block_item()
1591 if isinstance(item, list):
1592 if item == [None]:
1593 continue
1594 items.extend(item)
1595 else:
1596 items.append(item)
1597 return items
1599 # BNF: compound_statement : '{' block_item_list? '}'
1600 def _parse_compound_statement(self) -> c_ast.Node:
1601 lbrace_tok = self._expect("LBRACE")
1602 if self._accept("RBRACE"):
1603 return c_ast.Compound(block_items=None, coord=self._tok_coord(lbrace_tok))
1604 block_items = self._parse_block_item_list()
1605 self._expect("RBRACE")
1606 return c_ast.Compound(
1607 block_items=block_items, coord=self._tok_coord(lbrace_tok)
1608 )
1610 # BNF: labeled_statement : ID ':' statement
1611 # | CASE constant_expression ':' statement
1612 # | DEFAULT ':' statement
1613 def _parse_labeled_statement(self) -> c_ast.Node:
1614 tok_type = self._peek_type()
1615 match tok_type:
1616 case "ID":
1617 name_tok = self._advance()
1618 self._expect("COLON")
1619 if self._starts_statement():
1620 stmt = self._parse_pragmacomp_or_statement()
1621 else:
1622 stmt = c_ast.EmptyStatement(self._tok_coord(name_tok))
1623 return c_ast.Label(name_tok.value, stmt, self._tok_coord(name_tok))
1624 case "CASE":
1625 case_tok = self._advance()
1626 expr = self._parse_constant_expression()
1627 self._expect("COLON")
1628 if self._starts_statement():
1629 stmt = self._parse_pragmacomp_or_statement()
1630 else:
1631 stmt = c_ast.EmptyStatement(self._tok_coord(case_tok))
1632 return c_ast.Case(expr, [stmt], self._tok_coord(case_tok))
1633 case "DEFAULT":
1634 def_tok = self._advance()
1635 self._expect("COLON")
1636 if self._starts_statement():
1637 stmt = self._parse_pragmacomp_or_statement()
1638 else:
1639 stmt = c_ast.EmptyStatement(self._tok_coord(def_tok))
1640 return c_ast.Default([stmt], self._tok_coord(def_tok))
1641 case _:
1642 self._parse_error("Invalid labeled statement", self.clex.filename)
1644 # BNF: selection_statement : IF '(' expression ')' statement (ELSE statement)?
1645 # | SWITCH '(' expression ')' statement
1646 def _parse_selection_statement(self) -> c_ast.Node:
1647 tok = self._advance()
1648 match tok.type:
1649 case "IF":
1650 self._expect("LPAREN")
1651 cond = self._parse_expression()
1652 self._expect("RPAREN")
1653 then_stmt = self._parse_pragmacomp_or_statement()
1654 if self._accept("ELSE"):
1655 else_stmt = self._parse_pragmacomp_or_statement()
1656 return c_ast.If(cond, then_stmt, else_stmt, self._tok_coord(tok))
1657 return c_ast.If(cond, then_stmt, None, self._tok_coord(tok))
1658 case "SWITCH":
1659 self._expect("LPAREN")
1660 expr = self._parse_expression()
1661 self._expect("RPAREN")
1662 stmt = self._parse_pragmacomp_or_statement()
1663 return fix_switch_cases(c_ast.Switch(expr, stmt, self._tok_coord(tok)))
1664 case _:
1665 self._parse_error("Invalid selection statement", self._tok_coord(tok))
1667 # BNF: iteration_statement : WHILE '(' expression ')' statement
1668 # | DO statement WHILE '(' expression ')' ';'
1669 # | FOR '(' (declaration | expression_opt) ';'
1670 # expression_opt ';' expression_opt ')' statement
1671 def _parse_iteration_statement(self) -> c_ast.Node:
1672 tok = self._advance()
1673 match tok.type:
1674 case "WHILE":
1675 self._expect("LPAREN")
1676 cond = self._parse_expression()
1677 self._expect("RPAREN")
1678 stmt = self._parse_pragmacomp_or_statement()
1679 return c_ast.While(cond, stmt, self._tok_coord(tok))
1680 case "DO":
1681 stmt = self._parse_pragmacomp_or_statement()
1682 self._expect("WHILE")
1683 self._expect("LPAREN")
1684 cond = self._parse_expression()
1685 self._expect("RPAREN")
1686 self._expect("SEMI")
1687 return c_ast.DoWhile(cond, stmt, self._tok_coord(tok))
1688 case "FOR":
1689 self._expect("LPAREN")
1690 if self._starts_declaration():
1691 decls = self._parse_declaration()
1692 init = c_ast.DeclList(decls, self._tok_coord(tok))
1693 cond = self._parse_expression_opt()
1694 self._expect("SEMI")
1695 next_expr = self._parse_expression_opt()
1696 self._expect("RPAREN")
1697 stmt = self._parse_pragmacomp_or_statement()
1698 return c_ast.For(init, cond, next_expr, stmt, self._tok_coord(tok))
1700 init = self._parse_expression_opt()
1701 self._expect("SEMI")
1702 cond = self._parse_expression_opt()
1703 self._expect("SEMI")
1704 next_expr = self._parse_expression_opt()
1705 self._expect("RPAREN")
1706 stmt = self._parse_pragmacomp_or_statement()
1707 return c_ast.For(init, cond, next_expr, stmt, self._tok_coord(tok))
1708 case _:
1709 self._parse_error("Invalid iteration statement", self._tok_coord(tok))
1711 # BNF: jump_statement : GOTO ID ';' | BREAK ';' | CONTINUE ';'
1712 # | RETURN expression? ';'
1713 def _parse_jump_statement(self) -> c_ast.Node:
1714 tok = self._advance()
1715 match tok.type:
1716 case "GOTO":
1717 name_tok = self._expect("ID")
1718 self._expect("SEMI")
1719 return c_ast.Goto(name_tok.value, self._tok_coord(tok))
1720 case "BREAK":
1721 self._expect("SEMI")
1722 return c_ast.Break(self._tok_coord(tok))
1723 case "CONTINUE":
1724 self._expect("SEMI")
1725 return c_ast.Continue(self._tok_coord(tok))
1726 case "RETURN":
1727 if self._accept("SEMI"):
1728 return c_ast.Return(None, self._tok_coord(tok))
1729 expr = self._parse_expression()
1730 self._expect("SEMI")
1731 return c_ast.Return(expr, self._tok_coord(tok))
1732 case _:
1733 self._parse_error("Invalid jump statement", self._tok_coord(tok))
1735 # BNF: expression_statement : expression_opt ';'
1736 def _parse_expression_statement(self) -> c_ast.Node:
1737 expr = self._parse_expression_opt()
1738 semi_tok = self._expect("SEMI")
1739 if expr is None:
1740 return c_ast.EmptyStatement(self._tok_coord(semi_tok))
1741 return expr
1743 # ------------------------------------------------------------------
1744 # Expressions
1745 # ------------------------------------------------------------------
1746 # BNF: expression_opt : expression | empty
1747 def _parse_expression_opt(self) -> Optional[c_ast.Node]:
1748 if self._starts_expression():
1749 return self._parse_expression()
1750 return None
1752 # BNF: expression : assignment_expression (',' assignment_expression)*
1753 def _parse_expression(self) -> c_ast.Node:
1754 expr = self._parse_assignment_expression()
1755 if not self._accept("COMMA"):
1756 return expr
1757 exprs = [expr, self._parse_assignment_expression()]
1758 while self._accept("COMMA"):
1759 exprs.append(self._parse_assignment_expression())
1760 return c_ast.ExprList(exprs, expr.coord)
1762 # BNF: assignment_expression : conditional_expression
1763 # | unary_expression assignment_op assignment_expression
1764 def _parse_assignment_expression(self) -> c_ast.Node:
1765 if self._peek_type() == "LPAREN" and self._peek_type(2) == "LBRACE":
1766 self._advance()
1767 comp = self._parse_compound_statement()
1768 self._expect("RPAREN")
1769 return comp
1771 expr = self._parse_conditional_expression()
1772 if self._is_assignment_op():
1773 op = self._advance().value
1774 rhs = self._parse_assignment_expression()
1775 return c_ast.Assignment(op, expr, rhs, expr.coord)
1776 return expr
1778 # BNF: conditional_expression : binary_expression
1779 # | binary_expression '?' expression ':' conditional_expression
1780 def _parse_conditional_expression(self) -> c_ast.Node:
1781 expr = self._parse_binary_expression()
1782 if self._accept("CONDOP"):
1783 iftrue = self._parse_expression()
1784 self._expect("COLON")
1785 iffalse = self._parse_conditional_expression()
1786 return c_ast.TernaryOp(expr, iftrue, iffalse, expr.coord)
1787 return expr
1789 # BNF: binary_expression : cast_expression (binary_op cast_expression)*
1790 def _parse_binary_expression(
1791 self, min_prec: int = 0, lhs: Optional[c_ast.Node] = None
1792 ) -> c_ast.Node:
1793 if lhs is None:
1794 lhs = self._parse_cast_expression()
1796 while True:
1797 tok = self._peek()
1798 if tok is None or tok.type not in _BINARY_PRECEDENCE:
1799 break
1800 prec = _BINARY_PRECEDENCE[tok.type]
1801 if prec < min_prec:
1802 break
1804 op = tok.value
1805 self._advance()
1806 rhs = self._parse_cast_expression()
1808 while True:
1809 next_tok = self._peek()
1810 if next_tok is None or next_tok.type not in _BINARY_PRECEDENCE:
1811 break
1812 next_prec = _BINARY_PRECEDENCE[next_tok.type]
1813 if next_prec > prec:
1814 rhs = self._parse_binary_expression(next_prec, rhs)
1815 else:
1816 break
1818 lhs = c_ast.BinaryOp(op, lhs, rhs, lhs.coord)
1820 return lhs
1822 # BNF: cast_expression : '(' type_name ')' cast_expression
1823 # | unary_expression
1824 def _parse_cast_expression(self) -> c_ast.Node:
1825 result = self._try_parse_paren_type_name()
1826 if result is not None:
1827 typ, mark, lparen_tok = result
1828 if self._peek_type() == "LBRACE":
1829 # (type){...} is a compound literal, not a cast. Examples:
1830 # (int){1} -> compound literal, handled in postfix
1831 # (int) x -> cast, handled below
1832 self._reset(mark)
1833 else:
1834 expr = self._parse_cast_expression()
1835 return c_ast.Cast(typ, expr, self._tok_coord(lparen_tok))
1836 return self._parse_unary_expression()
1838 # BNF: unary_expression : postfix_expression
1839 # | '++' unary_expression
1840 # | '--' unary_expression
1841 # | unary_op cast_expression
1842 # | 'sizeof' unary_expression
1843 # | 'sizeof' '(' type_name ')'
1844 # | '_Alignof' '(' type_name ')'
1845 def _parse_unary_expression(self) -> c_ast.Node:
1846 tok_type = self._peek_type()
1847 if tok_type in {"PLUSPLUS", "MINUSMINUS"}:
1848 tok = self._advance()
1849 expr = self._parse_unary_expression()
1850 return c_ast.UnaryOp(tok.value, expr, expr.coord)
1852 if tok_type in {"AND", "TIMES", "PLUS", "MINUS", "NOT", "LNOT"}:
1853 tok = self._advance()
1854 expr = self._parse_cast_expression()
1855 return c_ast.UnaryOp(tok.value, expr, expr.coord)
1857 if tok_type == "SIZEOF":
1858 tok = self._advance()
1859 result = self._try_parse_paren_type_name()
1860 if result is not None:
1861 typ, _, _ = result
1862 return c_ast.UnaryOp(tok.value, typ, self._tok_coord(tok))
1863 expr = self._parse_unary_expression()
1864 return c_ast.UnaryOp(tok.value, expr, self._tok_coord(tok))
1866 if tok_type == "_ALIGNOF":
1867 tok = self._advance()
1868 self._expect("LPAREN")
1869 typ = self._parse_type_name()
1870 self._expect("RPAREN")
1871 return c_ast.UnaryOp(tok.value, typ, self._tok_coord(tok))
1873 return self._parse_postfix_expression()
1875 # BNF: postfix_expression : primary_expression postfix_suffix*
1876 # | '(' type_name ')' '{' initializer_list ','? '}'
1877 def _parse_postfix_expression(self) -> c_ast.Node:
1878 result = self._try_parse_paren_type_name()
1879 if result is not None:
1880 typ, mark, _ = result
1881 # Disambiguate between casts and compound literals:
1882 # (int) x -> cast
1883 # (int) {1} -> compound literal
1884 if self._accept("LBRACE"):
1885 init = self._parse_initializer_list()
1886 self._accept("COMMA")
1887 self._expect("RBRACE")
1888 return c_ast.CompoundLiteral(typ, init)
1889 else:
1890 self._reset(mark)
1892 expr = self._parse_primary_expression()
1893 while True:
1894 if self._accept("LBRACKET"):
1895 sub = self._parse_expression()
1896 self._expect("RBRACKET")
1897 expr = c_ast.ArrayRef(expr, sub, expr.coord)
1898 continue
1899 if self._accept("LPAREN"):
1900 if self._peek_type() == "RPAREN":
1901 self._advance()
1902 args = None
1903 else:
1904 args = self._parse_argument_expression_list()
1905 self._expect("RPAREN")
1906 expr = c_ast.FuncCall(expr, args, expr.coord)
1907 continue
1908 if self._peek_type() in {"PERIOD", "ARROW"}:
1909 op_tok = self._advance()
1910 name_tok = self._advance()
1911 if name_tok.type not in {"ID", "TYPEID"}:
1912 self._parse_error(
1913 "Invalid struct reference", self._tok_coord(name_tok)
1914 )
1915 field = c_ast.ID(name_tok.value, self._tok_coord(name_tok))
1916 expr = c_ast.StructRef(expr, op_tok.value, field, expr.coord)
1917 continue
1918 if self._peek_type() in {"PLUSPLUS", "MINUSMINUS"}:
1919 tok = self._advance()
1920 expr = c_ast.UnaryOp("p" + tok.value, expr, expr.coord)
1921 continue
1922 break
1923 return expr
1925 # BNF: primary_expression : ID | constant | string_literal
1926 # | '(' expression ')' | offsetof
1927 def _parse_primary_expression(self) -> c_ast.Node:
1928 tok_type = self._peek_type()
1929 if tok_type == "ID":
1930 return self._parse_identifier()
1931 if (
1932 tok_type in _INT_CONST
1933 or tok_type in _FLOAT_CONST
1934 or tok_type in _CHAR_CONST
1935 ):
1936 return self._parse_constant()
1937 if tok_type in _STRING_LITERAL:
1938 return self._parse_unified_string_literal()
1939 if tok_type in _WSTR_LITERAL:
1940 return self._parse_unified_wstring_literal()
1941 if tok_type == "LPAREN":
1942 self._advance()
1943 expr = self._parse_expression()
1944 self._expect("RPAREN")
1945 return expr
1946 if tok_type == "OFFSETOF":
1947 off_tok = self._advance()
1948 self._expect("LPAREN")
1949 typ = self._parse_type_name()
1950 self._expect("COMMA")
1951 designator = self._parse_offsetof_member_designator()
1952 self._expect("RPAREN")
1953 coord = self._tok_coord(off_tok)
1954 return c_ast.FuncCall(
1955 c_ast.ID(off_tok.value, coord),
1956 c_ast.ExprList([typ, designator], coord),
1957 coord,
1958 )
1960 self._parse_error("Invalid expression", self.clex.filename)
1962 # BNF: offsetof_member_designator : identifier_or_typeid
1963 # ('.' identifier_or_typeid | '[' expression ']')*
1964 def _parse_offsetof_member_designator(self) -> c_ast.Node:
1965 node = self._parse_identifier_or_typeid()
1966 while True:
1967 if self._accept("PERIOD"):
1968 field = self._parse_identifier_or_typeid()
1969 node = c_ast.StructRef(node, ".", field, node.coord)
1970 continue
1971 if self._accept("LBRACKET"):
1972 expr = self._parse_expression()
1973 self._expect("RBRACKET")
1974 node = c_ast.ArrayRef(node, expr, node.coord)
1975 continue
1976 break
1977 return node
1979 # BNF: argument_expression_list : assignment_expression (',' assignment_expression)*
1980 def _parse_argument_expression_list(self) -> c_ast.Node:
1981 expr = self._parse_assignment_expression()
1982 exprs = [expr]
1983 while self._accept("COMMA"):
1984 exprs.append(self._parse_assignment_expression())
1985 return c_ast.ExprList(exprs, expr.coord)
1987 # BNF: constant_expression : conditional_expression
1988 def _parse_constant_expression(self) -> c_ast.Node:
1989 return self._parse_conditional_expression()
1991 # ------------------------------------------------------------------
1992 # Terminals
1993 # ------------------------------------------------------------------
1994 # BNF: identifier : ID
1995 def _parse_identifier(self) -> c_ast.Node:
1996 tok = self._expect("ID")
1997 return c_ast.ID(tok.value, self._tok_coord(tok))
1999 # BNF: identifier_or_typeid : ID | TYPEID
2000 def _parse_identifier_or_typeid(self) -> c_ast.Node:
2001 tok = self._advance()
2002 if tok.type not in {"ID", "TYPEID"}:
2003 self._parse_error("Expected identifier", self._tok_coord(tok))
2004 return c_ast.ID(tok.value, self._tok_coord(tok))
2006 # BNF: constant : INT_CONST | FLOAT_CONST | CHAR_CONST
2007 def _parse_constant(self) -> c_ast.Node:
2008 tok = self._advance()
2009 if tok.type in _INT_CONST:
2010 u_count = 0
2011 l_count = 0
2012 for ch in tok.value[-3:]:
2013 if ch in ("l", "L"):
2014 l_count += 1
2015 elif ch in ("u", "U"):
2016 u_count += 1
2017 if u_count > 1:
2018 raise ValueError("Constant cannot have more than one u/U suffix.")
2019 if l_count > 2:
2020 raise ValueError("Constant cannot have more than two l/L suffix.")
2021 prefix = "unsigned " * u_count + "long " * l_count
2022 return c_ast.Constant(prefix + "int", tok.value, self._tok_coord(tok))
2024 if tok.type in _FLOAT_CONST:
2025 if tok.value[-1] in ("f", "F"):
2026 t = "float"
2027 elif tok.value[-1] in ("l", "L"):
2028 t = "long double"
2029 else:
2030 t = "double"
2031 return c_ast.Constant(t, tok.value, self._tok_coord(tok))
2033 if tok.type in _CHAR_CONST:
2034 return c_ast.Constant("char", tok.value, self._tok_coord(tok))
2036 self._parse_error("Invalid constant", self._tok_coord(tok))
2038 # BNF: unified_string_literal : STRING_LITERAL+
2039 def _parse_unified_string_literal(self) -> c_ast.Node:
2040 tok = self._expect("STRING_LITERAL")
2041 node = c_ast.Constant("string", tok.value, self._tok_coord(tok))
2042 while self._peek_type() == "STRING_LITERAL":
2043 tok2 = self._advance()
2044 node.value = node.value[:-1] + tok2.value[1:]
2045 return node
2047 # BNF: unified_wstring_literal : WSTRING_LITERAL+
2048 def _parse_unified_wstring_literal(self) -> c_ast.Node:
2049 tok = self._advance()
2050 if tok.type not in _WSTR_LITERAL:
2051 self._parse_error("Invalid string literal", self._tok_coord(tok))
2052 node = c_ast.Constant("string", tok.value, self._tok_coord(tok))
2053 while self._peek_type() in _WSTR_LITERAL:
2054 tok2 = self._advance()
2055 node.value = node.value.rstrip()[:-1] + tok2.value[2:]
2056 return node
2058 # ------------------------------------------------------------------
2059 # Initializers
2060 # ------------------------------------------------------------------
2061 # BNF: initializer : assignment_expression
2062 # | '{' initializer_list ','? '}'
2063 # | '{' '}'
2064 def _parse_initializer(self) -> c_ast.Node:
2065 lbrace_tok = self._accept("LBRACE")
2066 if lbrace_tok:
2067 if self._accept("RBRACE"):
2068 return c_ast.InitList([], self._tok_coord(lbrace_tok))
2069 init_list = self._parse_initializer_list()
2070 self._accept("COMMA")
2071 self._expect("RBRACE")
2072 return init_list
2074 return self._parse_assignment_expression()
2076 # BNF: initializer_list : initializer_item (',' initializer_item)* ','?
2077 def _parse_initializer_list(self) -> c_ast.Node:
2078 items = [self._parse_initializer_item()]
2079 while self._accept("COMMA"):
2080 if self._peek_type() == "RBRACE":
2081 break
2082 items.append(self._parse_initializer_item())
2083 return c_ast.InitList(items, items[0].coord)
2085 # BNF: initializer_item : designation? initializer
2086 def _parse_initializer_item(self) -> c_ast.Node:
2087 designation = None
2088 if self._peek_type() in {"LBRACKET", "PERIOD"}:
2089 designation = self._parse_designation()
2090 init = self._parse_initializer()
2091 if designation is not None:
2092 return c_ast.NamedInitializer(designation, init)
2093 return init
2095 # BNF: designation : designator_list '='
2096 def _parse_designation(self) -> List[c_ast.Node]:
2097 designators = self._parse_designator_list()
2098 self._expect("EQUALS")
2099 return designators
2101 # BNF: designator_list : designator+
2102 def _parse_designator_list(self) -> List[c_ast.Node]:
2103 designators = []
2104 while self._peek_type() in {"LBRACKET", "PERIOD"}:
2105 designators.append(self._parse_designator())
2106 return designators
2108 # BNF: designator : '[' constant_expression ']'
2109 # | '.' identifier_or_typeid
2110 def _parse_designator(self) -> c_ast.Node:
2111 if self._accept("LBRACKET"):
2112 expr = self._parse_constant_expression()
2113 self._expect("RBRACKET")
2114 return expr
2115 if self._accept("PERIOD"):
2116 return self._parse_identifier_or_typeid()
2117 self._parse_error("Invalid designator", self.clex.filename)
2119 # ------------------------------------------------------------------
2120 # Preprocessor-like directives
2121 # ------------------------------------------------------------------
2122 # BNF: pp_directive : '#' ... (unsupported)
2123 def _parse_pp_directive(self) -> NoReturn:
2124 tok = self._expect("PPHASH")
2125 self._parse_error("Directives not supported yet", self._tok_coord(tok))
2127 # BNF: pppragma_directive : PPPRAGMA PPPRAGMASTR?
2128 # | _PRAGMA '(' string_literal ')'
2129 def _parse_pppragma_directive(self) -> c_ast.Node:
2130 if self._peek_type() == "PPPRAGMA":
2131 tok = self._advance()
2132 if self._peek_type() == "PPPRAGMASTR":
2133 str_tok = self._advance()
2134 return c_ast.Pragma(str_tok.value, self._tok_coord(str_tok))
2135 return c_ast.Pragma("", self._tok_coord(tok))
2137 if self._peek_type() == "_PRAGMA":
2138 tok = self._advance()
2139 lparen = self._expect("LPAREN")
2140 literal = self._parse_unified_string_literal()
2141 self._expect("RPAREN")
2142 return c_ast.Pragma(literal, self._tok_coord(lparen))
2144 self._parse_error("Invalid pragma", self.clex.filename)
2146 # BNF: pppragma_directive_list : pppragma_directive+
2147 def _parse_pppragma_directive_list(self) -> List[c_ast.Node]:
2148 pragmas = []
2149 while self._peek_type() in {"PPPRAGMA", "_PRAGMA"}:
2150 pragmas.append(self._parse_pppragma_directive())
2151 return pragmas
2153 # BNF: static_assert : _STATIC_ASSERT '(' constant_expression (',' string_literal)? ')'
2154 def _parse_static_assert(self) -> List[c_ast.Node]:
2155 tok = self._expect("_STATIC_ASSERT")
2156 self._expect("LPAREN")
2157 cond = self._parse_constant_expression()
2158 msg = None
2159 if self._accept("COMMA"):
2160 msg = self._parse_unified_string_literal()
2161 self._expect("RPAREN")
2162 return [c_ast.StaticAssert(cond, msg, self._tok_coord(tok))]
2165_ASSIGNMENT_OPS = {
2166 "EQUALS",
2167 "XOREQUAL",
2168 "TIMESEQUAL",
2169 "DIVEQUAL",
2170 "MODEQUAL",
2171 "PLUSEQUAL",
2172 "MINUSEQUAL",
2173 "LSHIFTEQUAL",
2174 "RSHIFTEQUAL",
2175 "ANDEQUAL",
2176 "OREQUAL",
2177}
2179# Precedence of operators (lower number = weather binding)
2180# If this changes, c_generator.CGenerator.precedence_map needs to change as
2181# well
2182_BINARY_PRECEDENCE = {
2183 "LOR": 0,
2184 "LAND": 1,
2185 "OR": 2,
2186 "XOR": 3,
2187 "AND": 4,
2188 "EQ": 5,
2189 "NE": 5,
2190 "GT": 6,
2191 "GE": 6,
2192 "LT": 6,
2193 "LE": 6,
2194 "RSHIFT": 7,
2195 "LSHIFT": 7,
2196 "PLUS": 8,
2197 "MINUS": 8,
2198 "TIMES": 9,
2199 "DIVIDE": 9,
2200 "MOD": 9,
2201}
2203_STORAGE_CLASS = {"AUTO", "REGISTER", "STATIC", "EXTERN", "TYPEDEF", "_THREAD_LOCAL"}
2205_FUNCTION_SPEC = {"INLINE", "_NORETURN"}
2207_TYPE_QUALIFIER = {"CONST", "RESTRICT", "VOLATILE", "_ATOMIC"}
2209_TYPE_SPEC_SIMPLE = {
2210 "VOID",
2211 "_BOOL",
2212 "CHAR",
2213 "SHORT",
2214 "INT",
2215 "LONG",
2216 "FLOAT",
2217 "DOUBLE",
2218 "_COMPLEX",
2219 "SIGNED",
2220 "UNSIGNED",
2221 "__INT128",
2222}
2224_DECL_START = (
2225 _STORAGE_CLASS
2226 | _FUNCTION_SPEC
2227 | _TYPE_QUALIFIER
2228 | _TYPE_SPEC_SIMPLE
2229 | {"TYPEID", "STRUCT", "UNION", "ENUM", "_ALIGNAS", "_ATOMIC"}
2230)
2232_EXPR_START = {
2233 "ID",
2234 "LPAREN",
2235 "PLUSPLUS",
2236 "MINUSMINUS",
2237 "PLUS",
2238 "MINUS",
2239 "TIMES",
2240 "AND",
2241 "NOT",
2242 "LNOT",
2243 "SIZEOF",
2244 "_ALIGNOF",
2245 "OFFSETOF",
2246}
2248_INT_CONST = {
2249 "INT_CONST_DEC",
2250 "INT_CONST_OCT",
2251 "INT_CONST_HEX",
2252 "INT_CONST_BIN",
2253 "INT_CONST_CHAR",
2254}
2256_FLOAT_CONST = {"FLOAT_CONST", "HEX_FLOAT_CONST"}
2258_CHAR_CONST = {
2259 "CHAR_CONST",
2260 "WCHAR_CONST",
2261 "U8CHAR_CONST",
2262 "U16CHAR_CONST",
2263 "U32CHAR_CONST",
2264}
2266_STRING_LITERAL = {"STRING_LITERAL"}
2268_WSTR_LITERAL = {
2269 "WSTRING_LITERAL",
2270 "U8STRING_LITERAL",
2271 "U16STRING_LITERAL",
2272 "U32STRING_LITERAL",
2273}
2275_STARTS_EXPRESSION = (
2276 _EXPR_START
2277 | _INT_CONST
2278 | _FLOAT_CONST
2279 | _CHAR_CONST
2280 | _STRING_LITERAL
2281 | _WSTR_LITERAL
2282)
2284_STARTS_STATEMENT = {
2285 "LBRACE",
2286 "IF",
2287 "SWITCH",
2288 "WHILE",
2289 "DO",
2290 "FOR",
2291 "GOTO",
2292 "BREAK",
2293 "CONTINUE",
2294 "RETURN",
2295 "CASE",
2296 "DEFAULT",
2297 "PPPRAGMA",
2298 "_PRAGMA",
2299 "_STATIC_ASSERT",
2300 "SEMI",
2301}
2304class _TokenStream:
2305 """Wraps a lexer to provide convenient, buffered access to the underlying
2306 token stream. The lexer is expected to be initialized with the input
2307 string already.
2308 """
2310 def __init__(self, lexer: CLexer) -> None:
2311 self._lexer = lexer
2312 self._buffer: List[Optional[Token]] = []
2313 self._index = 0
2315 def peek(self, k: int = 1) -> Optional[Token]:
2316 """Peek at the k-th next token in the stream, without consuming it.
2318 Examples:
2319 k=1 returns the immediate next token.
2320 k=2 returns the token after that.
2321 """
2322 if k <= 0:
2323 return None
2324 self._fill(k)
2325 return self._buffer[self._index + k - 1]
2327 def next(self) -> Optional[Token]:
2328 """Consume a single token and return it."""
2329 self._fill(1)
2330 tok = self._buffer[self._index]
2331 self._index += 1
2332 return tok
2334 # The 'mark' and 'reset' methods are useful for speculative parsing with
2335 # backtracking; when the parser needs to examine a sequence of tokens
2336 # and potentially decide to try a different path on the same sequence, it
2337 # can call 'mark' to obtain the current token position, and if the first
2338 # path fails restore the position with `reset(pos)`.
2339 def mark(self) -> int:
2340 return self._index
2342 def reset(self, mark: int) -> None:
2343 self._index = mark
2345 def _fill(self, n: int) -> None:
2346 while len(self._buffer) < self._index + n:
2347 tok = self._lexer.token()
2348 self._buffer.append(tok)
2349 if tok is None:
2350 break
2353# Declaration specifiers are represented by a dictionary with entries:
2354# - qual: a list of type qualifiers
2355# - storage: a list of storage class specifiers
2356# - type: a list of type specifiers
2357# - function: a list of function specifiers
2358# - alignment: a list of alignment specifiers
2359class _DeclSpec(TypedDict):
2360 qual: List[Any]
2361 storage: List[Any]
2362 type: List[Any]
2363 function: List[Any]
2364 alignment: List[Any]
2367_DeclSpecKind = Literal["qual", "storage", "type", "function", "alignment"]
2370class _DeclInfo(TypedDict):
2371 # Declarator payloads used by declaration/initializer parsing:
2372 # - decl: the declarator node (may be None for abstract/implicit cases)
2373 # - init: optional initializer expression
2374 # - bitsize: optional bit-field width expression (for struct declarators)
2375 decl: Optional[c_ast.Node]
2376 init: Optional[c_ast.Node]
2377 bitsize: Optional[c_ast.Node]