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

1311 statements  

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) 

21 

22from . import c_ast 

23from .c_lexer import CLexer, Token 

24from .ast_transforms import fix_switch_cases, fix_atomic_specifiers 

25 

26 

27@dataclass 

28class Coord: 

29 """Coordinates of a syntactic element. Consists of: 

30 - File name 

31 - Line number 

32 - Column number 

33 """ 

34 

35 file: str 

36 line: int 

37 column: Optional[int] = None 

38 

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 

44 

45 

46class ParseError(Exception): 

47 pass 

48 

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 with 

59 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] 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) 

89 

90 def parse( 

91 self, text: str, filename: str = "", debug: bool = False 

92 ) -> c_ast.FileAST: 

93 """Parses C code and returns an AST. 

94 

95 text: 

96 A string containing the C source code 

97 

98 filename: 

99 Name of the file being parsed (for meaningful error messages) 

100 

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) 

107 

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 

113 

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) 

119 

120 def _parse_error(self, msg: str, coord: Coord | str | None) -> NoReturn: 

121 raise ParseError(f"{coord}: {msg}") 

122 

123 def _push_scope(self) -> None: 

124 self._scope_stack.append(dict()) 

125 

126 def _pop_scope(self) -> None: 

127 if len(self._scope_stack) <= 1: 

128 raise ParseError("Unmatched '}'") 

129 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] = True 

139 

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 

150 

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 

159 

160 def _lex_error_func(self, msg: str, line: int, column: int) -> None: 

161 self._parse_error(msg, self._coord(line, column)) 

162 

163 def _lex_on_lbrace_func(self) -> None: 

164 self._push_scope() 

165 

166 def _lex_on_rbrace_func(self) -> None: 

167 self._pop_scope() 

168 

169 def _lex_type_lookup_func(self, name: str) -> bool: 

170 """Looks up types that were previously defined with typedef. 

171 

172 Passed to the lexer for recognizing identifiers that are types. 

173 """ 

174 return self._is_type_in_scope(name) 

175 

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. 

213 

214 Note: the declarator and modifier may be modified 

215 """ 

216 modifier_head = modifier 

217 modifier_tail = modifier 

218 

219 # The modifier may be a nested list. Reach its tail. 

220 while modifier_tail.type: 

221 modifier_tail = modifier_tail.type 

222 

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 

234 

235 modifier_tail.type = decl_tail.type 

236 decl_tail.type = modifier_head 

237 return decl 

238 

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 

264 

265 decl.name = typ.declname 

266 typ.quals = decl.quals[:] 

267 

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 

280 

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 

293 

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 

308 

309 if append: 

310 spec[kind].append(newspec) 

311 else: 

312 spec[kind].insert(0, newspec) 

313 

314 return spec 

315 

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 = [] 

329 

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) 

348 

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] 

372 

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 ) 

395 

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"]) 

403 

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) 

411 

412 fixed_decl = fix_atomic_specifiers( 

413 cast(c_ast.Decl | c_ast.Typedef, fixed_decl) 

414 ) 

415 declarations.append(fixed_decl) 

416 

417 return declarations 

418 

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) 

429 

430 declaration = self._build_declarations( 

431 spec=spec, 

432 decls=[dict(decl=decl, init=None, bitsize=None)], 

433 typedef_namespace=True, 

434 )[0] 

435 

436 return c_ast.FuncDef( 

437 decl=declaration, param_decls=param_decls, body=body, coord=decl.coord 

438 ) 

439 

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 

448 

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) 

455 

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 

460 

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 

467 

468 def _accept(self, token_type: str) -> Optional[Token]: 

469 """Conditionally consume next token, only if it's of token_type. 

470 

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 

478 

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 

484 

485 def _mark(self) -> int: 

486 return self._tokens.mark() 

487 

488 def _reset(self, mark: int) -> None: 

489 self._tokens.reset(mark) 

490 

491 def _tok_coord(self, tok: Token) -> Coord: 

492 return self._coord(tok.lineno, tok.column) 

493 

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 

499 

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 

505 

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() 

513 

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"} 

523 

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 

529 

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 

547 

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 

556 

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() 

562 

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 

591 

592 def _starts_direct_abstract_declarator(self) -> bool: 

593 return self._peek_type() in {"LPAREN", "LBRACKET"} 

594 

595 def _is_assignment_op(self) -> bool: 

596 tok = self._peek() 

597 return tok is not None and tok.type in _ASSIGNMENT_OPS 

598 

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. 

603 

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 

621 

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()) 

630 

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 

637 

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() 

657 

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] 

685 

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 ) 

690 

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 

696 

697 decl = self._parse_id_declarator() 

698 

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] 

714 

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 

722 

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 

734 

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) 

739 

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) 

754 

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 ) 

783 

784 return decls 

785 

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 

792 

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. 

802 

803 allow_no_type: 

804 If True, allow a missing type specifier without error. 

805 

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 

815 

816 while True: 

817 tok = self._peek() 

818 if tok is None: 

819 break 

820 

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 

828 

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 

837 

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 

845 

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 

853 

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 

861 

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 

874 

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 

889 

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 

898 

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 

907 

908 break 

909 

910 if spec is None: 

911 self._parse_error("Invalid declaration", self.clex.filename) 

912 

913 if not saw_type and not allow_no_type: 

914 self._parse_error("Missing type in declaration", first_coord) 

915 

916 return spec, saw_type, first_coord 

917 

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 

926 

927 while True: 

928 tok = self._peek() 

929 if tok is None: 

930 break 

931 

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 

940 

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 

949 

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 

957 

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 

970 

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 

985 

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 

994 

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 

1003 

1004 break 

1005 

1006 if spec is None: 

1007 self._parse_error("Invalid specifier list", self.clex.filename) 

1008 

1009 if not saw_type and not saw_alignment: 

1010 self._parse_error("Missing type in declaration", first_coord) 

1011 

1012 if spec.get("storage") is None: 

1013 spec["storage"] = [] 

1014 if spec.get("function") is None: 

1015 spec["function"] = [] 

1016 

1017 return spec 

1018 

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 

1025 

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") 

1030 

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)) 

1035 

1036 expr = self._parse_constant_expression() 

1037 self._expect("RPAREN") 

1038 return c_ast.Alignas(expr, self._tok_coord(tok)) 

1039 

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 

1048 

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 ) 

1058 

1059 while self._accept("COMMA"): 

1060 decls.append(self._parse_init_declarator(id_only=id_only)) 

1061 return decls 

1062 

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) 

1070 

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) 

1079 

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 ) 

1093 

1094 return klass( 

1095 name=name_tok.value, decls=None, coord=self._tok_coord(name_tok) 

1096 ) 

1097 

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)) 

1105 

1106 self._parse_error("Invalid struct/union declaration", self._tok_coord(tok)) 

1107 

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 

1117 

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()] 

1127 

1128 spec = self._parse_specifier_qualifier_list() 

1129 assert "typedef" not in spec.get("storage", []) 

1130 

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) 

1137 

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 ) 

1148 

1149 self._expect("SEMI") 

1150 return self._build_declarations( 

1151 spec=spec, decls=[dict(decl=None, init=None, bitsize=None)] 

1152 ) 

1153 

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 

1160 

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 } 

1171 

1172 decl = self._parse_declarator() 

1173 if self._accept("COLON"): 

1174 bitsize = self._parse_constant_expression() 

1175 return {"decl": decl, "init": None, "bitsize": bitsize} 

1176 

1177 return {"decl": decl, "init": None, "bitsize": None} 

1178 

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)) 

1191 

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)) 

1196 

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 

1207 

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 

1218 

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 

1229 

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) 

1233 

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) 

1237 

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) 

1241 

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 

1251 

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 ) 

1273 

1274 return self._parse_decl_suffixes(decl) 

1275 

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 

1288 

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) 

1292 

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. 

1297 

1298 base_type: 

1299 Base declarator node to attach (None for direct-declarator parsing, 

1300 TypeDecl for abstract declarators). 

1301 

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) 

1308 

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 ) 

1313 

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) 

1319 

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) 

1337 

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, []) 

1343 

1344 dim = None 

1345 if self._starts_expression(): 

1346 dim = self._parse_assignment_expression() 

1347 self._expect("RBRACKET") 

1348 return make_array_decl(dim, []) 

1349 

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") 

1362 

1363 func = c_ast.FuncDecl(args=args, type=None, coord=base_decl.coord) 

1364 

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) 

1373 

1374 return func 

1375 

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") 

1384 

1385 if not stars: 

1386 return None 

1387 

1388 ptr = None 

1389 for quals, coord in stars: 

1390 ptr = c_ast.PtrDecl(quals=quals, type=ptr, coord=coord) 

1391 return ptr 

1392 

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 

1401 

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 

1410 

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) 

1415 

1416 if not spec["type"]: 

1417 spec["type"] = [c_ast.IdentifierType(["int"], coord=spec_coord)] 

1418 

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) 

1428 

1429 decl = self._parse_abstract_declarator_opt() 

1430 return self._build_parameter_declaration(spec, decl, spec_coord) 

1431 

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] 

1443 

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"]) 

1452 

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() 

1458 

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 

1466 

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() 

1474 

1475 coord = None 

1476 if decl is not None: 

1477 coord = decl.coord 

1478 elif spec["type"]: 

1479 coord = spec["type"][0].coord 

1480 

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"])) 

1489 

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) 

1500 

1501 if self._starts_direct_abstract_declarator(): 

1502 return self._parse_direct_abstract_declarator() 

1503 

1504 return None 

1505 

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) 

1528 

1529 return self._parse_decl_suffixes(decl) 

1530 

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() 

1536 

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 ) 

1542 

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() 

1571 

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() 

1579 

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() 

1585 

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 

1598 

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 ) 

1609 

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) 

1643 

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)) 

1666 

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)) 

1699 

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)) 

1710 

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)) 

1734 

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 

1742 

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 

1751 

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) 

1761 

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 

1770 

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 

1777 

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 

1788 

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() 

1795 

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 

1803 

1804 op = tok.value 

1805 self._advance() 

1806 rhs = self._parse_cast_expression() 

1807 

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 

1817 

1818 lhs = c_ast.BinaryOp(op, lhs, rhs, lhs.coord) 

1819 

1820 return lhs 

1821 

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() 

1837 

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) 

1851 

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) 

1856 

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)) 

1865 

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)) 

1872 

1873 return self._parse_postfix_expression() 

1874 

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) 

1891 

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 

1924 

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 ) 

1959 

1960 self._parse_error("Invalid expression", self.clex.filename) 

1961 

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 

1978 

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) 

1986 

1987 # BNF: constant_expression : conditional_expression 

1988 def _parse_constant_expression(self) -> c_ast.Node: 

1989 return self._parse_conditional_expression() 

1990 

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)) 

1998 

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)) 

2005 

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)) 

2023 

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)) 

2032 

2033 if tok.type in _CHAR_CONST: 

2034 return c_ast.Constant("char", tok.value, self._tok_coord(tok)) 

2035 

2036 self._parse_error("Invalid constant", self._tok_coord(tok)) 

2037 

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 

2046 

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 

2057 

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 

2073 

2074 return self._parse_assignment_expression() 

2075 

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) 

2084 

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 

2094 

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 

2100 

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 

2107 

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) 

2118 

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)) 

2126 

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)) 

2136 

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)) 

2143 

2144 self._parse_error("Invalid pragma", self.clex.filename) 

2145 

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 

2152 

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))] 

2163 

2164 

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} 

2178 

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} 

2202 

2203_STORAGE_CLASS = {"AUTO", "REGISTER", "STATIC", "EXTERN", "TYPEDEF", "_THREAD_LOCAL"} 

2204 

2205_FUNCTION_SPEC = {"INLINE", "_NORETURN"} 

2206 

2207_TYPE_QUALIFIER = {"CONST", "RESTRICT", "VOLATILE", "_ATOMIC"} 

2208 

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} 

2223 

2224_DECL_START = ( 

2225 _STORAGE_CLASS 

2226 | _FUNCTION_SPEC 

2227 | _TYPE_QUALIFIER 

2228 | _TYPE_SPEC_SIMPLE 

2229 | {"TYPEID", "STRUCT", "UNION", "ENUM", "_ALIGNAS", "_ATOMIC"} 

2230) 

2231 

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} 

2247 

2248_INT_CONST = { 

2249 "INT_CONST_DEC", 

2250 "INT_CONST_OCT", 

2251 "INT_CONST_HEX", 

2252 "INT_CONST_BIN", 

2253 "INT_CONST_CHAR", 

2254} 

2255 

2256_FLOAT_CONST = {"FLOAT_CONST", "HEX_FLOAT_CONST"} 

2257 

2258_CHAR_CONST = { 

2259 "CHAR_CONST", 

2260 "WCHAR_CONST", 

2261 "U8CHAR_CONST", 

2262 "U16CHAR_CONST", 

2263 "U32CHAR_CONST", 

2264} 

2265 

2266_STRING_LITERAL = {"STRING_LITERAL"} 

2267 

2268_WSTR_LITERAL = { 

2269 "WSTRING_LITERAL", 

2270 "U8STRING_LITERAL", 

2271 "U16STRING_LITERAL", 

2272 "U32STRING_LITERAL", 

2273} 

2274 

2275_STARTS_EXPRESSION = ( 

2276 _EXPR_START 

2277 | _INT_CONST 

2278 | _FLOAT_CONST 

2279 | _CHAR_CONST 

2280 | _STRING_LITERAL 

2281 | _WSTR_LITERAL 

2282) 

2283 

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} 

2302 

2303 

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 """ 

2309 

2310 def __init__(self, lexer: CLexer) -> None: 

2311 self._lexer = lexer 

2312 self._buffer: List[Optional[Token]] = [] 

2313 self._index = 0 

2314 

2315 def peek(self, k: int = 1) -> Optional[Token]: 

2316 """Peek at the k-th next token in the stream, without consuming it. 

2317 

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] 

2326 

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 

2333 

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 

2341 

2342 def reset(self, mark: int) -> None: 

2343 self._index = mark 

2344 

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 

2351 

2352 

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] 

2365 

2366 

2367_DeclSpecKind = Literal["qual", "storage", "type", "function", "alignment"] 

2368 

2369 

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]