1#!/usr/bin/env python3 2 3"""This is a yacc grammar for C. 4 5Derived from ANSI C grammar: 6 * Lexicon: http://www.lysator.liu.se/c/ANSI-C-grammar-l.html 7 * Grammar: http://www.lysator.liu.se/c/ANSI-C-grammar-y.html 8 9Reference is C99: 10 * http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1124.pdf 11 12""" 13 14__docformat__ = "restructuredtext" 15 16if __name__ == "__main__": 17 # NOTE if this file is modified, run to generate a new parsetab.py 18 # E.g.: 19 # env PYTHONPATH=. python ctypesgen/parser/cgrammar.py 20 # new_parsetab.py is generated in the current directory and needs to be 21 # manually copied (after inspection) to ctypesgen/parser/parsetab.py 22 import sys, os 23 24 sys.path.insert(0, os.path.join(os.path.pardir, os.path.pardir)) 25 from ctypesgen.parser.cgrammar import main 26 27 main() 28 sys.exit() 29 30import operator 31import os.path 32import re 33import sys 34import time 35import warnings 36 37from . import yacc 38from .. import expressions 39from . import cdeclarations 40 41tokens = ( 42 "PP_DEFINE", 43 "PP_DEFINE_NAME", 44 "PP_DEFINE_MACRO_NAME", 45 "PP_UNDEFINE", 46 "PP_MACRO_PARAM", 47 "PP_STRINGIFY", 48 "PP_IDENTIFIER_PASTE", 49 "PP_END_DEFINE", 50 "PRAGMA", 51 "PRAGMA_PACK", 52 "PRAGMA_END", 53 "IDENTIFIER", 54 "CONSTANT", 55 "CHARACTER_CONSTANT", 56 "STRING_LITERAL", 57 "SIZEOF", 58 "PTR_OP", 59 "INC_OP", 60 "DEC_OP", 61 "LEFT_OP", 62 "RIGHT_OP", 63 "LE_OP", 64 "GE_OP", 65 "EQ_OP", 66 "NE_OP", 67 "AND_OP", 68 "OR_OP", 69 "MUL_ASSIGN", 70 "DIV_ASSIGN", 71 "MOD_ASSIGN", 72 "ADD_ASSIGN", 73 "SUB_ASSIGN", 74 "LEFT_ASSIGN", 75 "RIGHT_ASSIGN", 76 "AND_ASSIGN", 77 "XOR_ASSIGN", 78 "OR_ASSIGN", 79 "PERIOD", 80 "TYPE_NAME", 81 "TYPEDEF", 82 "EXTERN", 83 "STATIC", 84 "AUTO", 85 "REGISTER", 86 "_BOOL", 87 "CHAR", 88 "SHORT", 89 "INT", 90 "LONG", 91 "SIGNED", 92 "UNSIGNED", 93 "FLOAT", 94 "DOUBLE", 95 "CONST", 96 "VOLATILE", 97 "VOID", 98 "STRUCT", 99 "UNION", 100 "ENUM", 101 "ELLIPSIS", 102 "CASE", 103 "DEFAULT", 104 "IF", 105 "ELSE", 106 "SWITCH", 107 "WHILE", 108 "DO", 109 "FOR", 110 "GOTO", 111 "CONTINUE", 112 "BREAK", 113 "RETURN", 114 "__ASM__", 115 "__ATTRIBUTE__", 116 # with new code that accepts arbitrary attributes-->must not be keywords 117 # "PACKED", 118 # "ALIGNED", 119 # "TRANSPARENT_UNION", 120 # "STDCALL", 121 # "CDECL", 122) 123 124keywords = [ 125 "auto", 126 "_Bool", 127 "break", 128 "case", 129 "char", 130 "const", 131 "continue", 132 "default", 133 "do", 134 "double", 135 "else", 136 "enum", 137 "extern", 138 "float", 139 "for", 140 "goto", 141 "if", 142 "int", 143 "long", 144 "register", 145 "return", 146 "short", 147 "signed", 148 "sizeof", 149 "static", 150 "struct", 151 "switch", 152 "typedef", 153 "union", 154 "unsigned", 155 "void", 156 "volatile", 157 "while", 158 "__asm__", 159 "__attribute__", 160 # with new code that accepts arbitrary attributes-->must not be keywords 161 # "packed", 162 # "aligned", 163 # "transparent_union", 164 # "stdcall", 165 # "cdecl", 166] 167 168precedence = (("nonassoc", "IF"), ("nonassoc", "ELSE")) 169 170 171def p_translation_unit(p): 172 """translation_unit : 173 | translation_unit external_declaration 174 | translation_unit directive 175 """ 176 # Starting production. 177 # Allow empty production so that files with no declarations are still 178 # valid. 179 # Intentionally empty 180 181 182def p_identifier(p): 183 """identifier : IDENTIFIER 184 | IDENTIFIER PP_IDENTIFIER_PASTE identifier 185 | PP_MACRO_PARAM PP_IDENTIFIER_PASTE identifier 186 | IDENTIFIER PP_IDENTIFIER_PASTE PP_MACRO_PARAM 187 | PP_MACRO_PARAM PP_IDENTIFIER_PASTE PP_MACRO_PARAM 188 """ 189 if len(p) == 2: 190 p[0] = expressions.IdentifierExpressionNode(p[1]) 191 else: 192 # Should it be supported? It wouldn't be very hard to add support. 193 # Basically, it would involve a new ExpressionNode called 194 # an IdentifierPasteExpressionNode that took a list of strings and 195 # ParameterExpressionNodes. Then it would generate code like 196 # "locals()['%s' + '%s' + ...]" where %s was substituted with the 197 # elements of the list. I haven't supported it yet because I think 198 # it's unnecessary and a little too powerful. 199 p[0] = expressions.UnsupportedExpressionNode( 200 "Identifier pasting is " "not supported by ctypesgen." 201 ) 202 203 204def p_constant(p): 205 """constant : CONSTANT 206 | CHARACTER_CONSTANT 207 """ 208 constant = p[1] 209 210 if constant[0] == "'": 211 # Character constant 212 value = constant[1:-1] 213 if isinstance(value, str): 214 value = value.encode() 215 else: 216 # This is a value formatted the way that the preprocessor formats 217 # numeric constants. It puts a prefix "l", "i", or "f" to indicate 218 # if it should be converted into an integer, long or float. 219 prefix = constant[0] 220 constant = constant[1:] 221 if prefix == "i": 222 value = int(constant) 223 elif prefix == "l": 224 value = int(constant) 225 else: 226 value = float(constant) 227 228 p[0] = expressions.ConstantExpressionNode(value) 229 230 231def p_string_literal(p): 232 """string_literal : STRING_LITERAL""" 233 p[0] = expressions.ConstantExpressionNode(p[1]) 234 235 236def p_multi_string_literal(p): 237 """multi_string_literal : string_literal 238 | macro_param 239 | multi_string_literal string_literal 240 | multi_string_literal macro_param 241 """ 242 if len(p) == 2: 243 p[0] = p[1] 244 else: 245 p[0] = expressions.BinaryExpressionNode( 246 "string concatenation", (lambda x, y: x + y), "(%s + %s)", (False, False), p[1], p[2] 247 ) 248 249 250def p_macro_param(p): 251 """macro_param : PP_MACRO_PARAM 252 | PP_STRINGIFY PP_MACRO_PARAM 253 """ 254 if len(p) == 2: 255 p[0] = expressions.ParameterExpressionNode(p[1]) 256 else: 257 p[0] = expressions.ParameterExpressionNode(p[2]) 258 259 260def p_primary_expression(p): 261 """primary_expression : identifier 262 | constant 263 | multi_string_literal 264 | '(' expression ')' 265 """ 266 if p[1] == "(": 267 p[0] = p[2] 268 else: 269 p[0] = p[1] 270 271 272def p_postfix_expression(p): 273 """postfix_expression : primary_expression 274 | postfix_expression '[' expression ']' 275 | postfix_expression '(' ')' 276 | postfix_expression '(' argument_expression_list ')' 277 | postfix_expression PERIOD IDENTIFIER 278 | postfix_expression PTR_OP IDENTIFIER 279 | postfix_expression INC_OP 280 | postfix_expression DEC_OP 281 """ 282 283 if len(p) == 2: 284 p[0] = p[1] 285 286 elif p[2] == "[": 287 p[0] = expressions.BinaryExpressionNode( 288 "array access", (lambda a, b: a[b]), "(%s [%s])", (True, False), p[1], p[3] 289 ) 290 291 elif p[2] == "(": 292 if p[3] == ")": 293 p[0] = expressions.CallExpressionNode(p[1], []) 294 else: 295 p[0] = expressions.CallExpressionNode(p[1], p[3]) 296 297 elif p[2] == ".": 298 p[0] = expressions.AttributeExpressionNode( 299 (lambda x, a: getattr(x, a)), "(%s.%s)", p[1], p[3] 300 ) 301 302 elif p[2] == "->": 303 p[0] = expressions.AttributeExpressionNode( 304 (lambda x, a: getattr(x.contents, a)), "(%s.contents.%s)", p[1], p[3] 305 ) 306 307 elif p[2] == "++": 308 p[0] = expressions.UnaryExpressionNode( 309 "increment", (lambda x: x + 1), "(%s + 1)", False, p[1] 310 ) 311 312 elif p[2] == "--": 313 p[0] = expressions.UnaryExpressionNode( 314 "decrement", (lambda x: x - 1), "(%s - 1)", False, p[1] 315 ) 316 317 318def p_argument_expression_list(p): 319 """argument_expression_list : assignment_expression 320 | argument_expression_list ',' assignment_expression 321 | type_name 322 | argument_expression_list ',' type_name 323 """ 324 if len(p) == 4: 325 p[1].append(p[3]) 326 p[0] = p[1] 327 else: 328 p[0] = [p[1]] 329 330 331def p_asm_expression(p): 332 """asm_expression : __ASM__ volatile_opt '(' string_literal ')' 333 | __ASM__ volatile_opt '(' string_literal ':' str_opt_expr_pair_list ')' 334 | __ASM__ volatile_opt '(' string_literal ':' str_opt_expr_pair_list ':' str_opt_expr_pair_list ')' 335 | __ASM__ volatile_opt '(' string_literal ':' str_opt_expr_pair_list ':' str_opt_expr_pair_list ':' str_opt_expr_pair_list ')' 336 """ 337 338 # Definitely not ISO C, adapted from example ANTLR GCC parser at 339 # http://www.antlr.org/grammar/cgram//grammars/GnuCParser.g 340 # but more lenient (expressions permitted in optional final part, when 341 # they shouldn't be -- avoids shift/reduce conflict with 342 # str_opt_expr_pair_list). 343 344 p[0] = expressions.UnsupportedExpressionNode("This node is ASM assembler.") 345 346 347def p_str_opt_expr_pair_list(p): 348 """str_opt_expr_pair_list : 349 | str_opt_expr_pair 350 | str_opt_expr_pair_list ',' str_opt_expr_pair 351 """ 352 353 354def p_str_opt_expr_pair(p): 355 """str_opt_expr_pair : string_literal 356 | string_literal '(' expression ')' 357 """ 358 359 360def p_volatile_opt(p): 361 """volatile_opt : 362 | VOLATILE 363 """ 364 365 366prefix_ops_dict = { 367 "++": ("increment", (lambda x: x + 1), "(%s + 1)", False), 368 "--": ("decrement", (lambda x: x - 1), "(%s - 1)", False), 369 "&": ("reference ('&')", None, "pointer(%s)", True), 370 "*": ("dereference ('*')", None, "(%s[0])", True), 371 "+": ("unary '+'", (lambda x: x), "%s", True), 372 "-": ("negation", (lambda x: -x), "(-%s)", False), 373 "~": ("inversion", (lambda x: ~x), "(~%s)", False), 374 "!": ("logical not", (lambda x: not x), "(not %s)", True), 375} 376 377 378def p_unary_expression(p): 379 """unary_expression : postfix_expression 380 | INC_OP unary_expression 381 | DEC_OP unary_expression 382 | unary_operator cast_expression 383 | SIZEOF unary_expression 384 | SIZEOF '(' type_name ')' 385 | asm_expression 386 """ 387 if len(p) == 2: 388 p[0] = p[1] 389 390 elif p[1] == "sizeof": 391 if len(p) == 5: 392 p[0] = expressions.SizeOfExpressionNode(p[3]) 393 else: 394 p[0] = expressions.SizeOfExpressionNode(p[2]) 395 396 else: 397 name, op, format, can_be_ctype = prefix_ops_dict[p[1]] 398 p[0] = expressions.UnaryExpressionNode(name, op, format, can_be_ctype, p[2]) 399 400 401def p_unary_operator(p): 402 """unary_operator : '&' 403 | '*' 404 | '+' 405 | '-' 406 | '~' 407 | '!' 408 """ 409 p[0] = p[1] 410 411 412def p_cast_expression(p): 413 """cast_expression : unary_expression 414 | '(' type_name ')' cast_expression 415 """ 416 if len(p) == 2: 417 p[0] = p[1] 418 else: 419 p[0] = expressions.TypeCastExpressionNode(p[4], p[2]) 420 421 422mult_ops_dict = { 423 "*": ("multiplication", (lambda x, y: x * y), "(%s * %s)"), 424 "/": ("division", (lambda x, y: x / y), "(%s / %s)"), 425 "%": ("modulo", (lambda x, y: x % y), "(%s %% %s)"), 426} 427 428 429def p_multiplicative_expression(p): 430 """multiplicative_expression : cast_expression 431 | multiplicative_expression '*' cast_expression 432 | multiplicative_expression '/' cast_expression 433 | multiplicative_expression '%' cast_expression 434 """ 435 if len(p) == 2: 436 p[0] = p[1] 437 else: 438 name, op, format = mult_ops_dict[p[2]] 439 p[0] = expressions.BinaryExpressionNode(name, op, format, (False, False), p[1], p[3]) 440 441 442add_ops_dict = { 443 "+": ("addition", (lambda x, y: x + y), "(%s + %s)"), 444 "-": ("subtraction", (lambda x, y: x - y), "(%s - %s)"), 445} 446 447 448def p_additive_expression(p): 449 """additive_expression : multiplicative_expression 450 | additive_expression '+' multiplicative_expression 451 | additive_expression '-' multiplicative_expression 452 """ 453 if len(p) == 2: 454 p[0] = p[1] 455 else: 456 name, op, format = add_ops_dict[p[2]] 457 p[0] = expressions.BinaryExpressionNode(name, op, format, (False, False), p[1], p[3]) 458 459 460shift_ops_dict = { 461 ">>": ("right shift", (lambda x, y: x >> y), "(%s >> %s)"), 462 "<<": ("left shift", (lambda x, y: x << y), "(%s << %s)"), 463} 464 465 466def p_shift_expression(p): 467 """shift_expression : additive_expression 468 | shift_expression LEFT_OP additive_expression 469 | shift_expression RIGHT_OP additive_expression 470 """ 471 if len(p) == 2: 472 p[0] = p[1] 473 else: 474 name, op, format = shift_ops_dict[p[2]] 475 p[0] = expressions.BinaryExpressionNode(name, op, format, (False, False), p[1], p[3]) 476 477 478rel_ops_dict = { 479 ">": ("greater-than", (lambda x, y: x > y), "(%s > %s)"), 480 "<": ("less-than", (lambda x, y: x < y), "(%s < %s)"), 481 ">=": ("greater-than-equal", (lambda x, y: x >= y), "(%s >= %s)"), 482 "<=": ("less-than-equal", (lambda x, y: x <= y), "(%s <= %s)"), 483} 484 485 486def p_relational_expression(p): 487 """relational_expression : shift_expression 488 | relational_expression '<' shift_expression 489 | relational_expression '>' shift_expression 490 | relational_expression LE_OP shift_expression 491 | relational_expression GE_OP shift_expression 492 """ 493 if len(p) == 2: 494 p[0] = p[1] 495 else: 496 name, op, format = rel_ops_dict[p[2]] 497 p[0] = expressions.BinaryExpressionNode(name, op, format, (False, False), p[1], p[3]) 498 499 500equality_ops_dict = { 501 "==": ("equals", (lambda x, y: x == y), "(%s == %s)"), 502 "!=": ("not equals", (lambda x, y: x != y), "(%s != %s)"), 503} 504 505 506def p_equality_expression(p): 507 """equality_expression : relational_expression 508 | equality_expression EQ_OP relational_expression 509 | equality_expression NE_OP relational_expression 510 """ 511 if len(p) == 2: 512 p[0] = p[1] 513 else: 514 name, op, format = equality_ops_dict[p[2]] 515 p[0] = expressions.BinaryExpressionNode(name, op, format, (False, False), p[1], p[3]) 516 517 518def p_and_expression(p): 519 """and_expression : equality_expression 520 | and_expression '&' equality_expression 521 """ 522 if len(p) == 2: 523 p[0] = p[1] 524 else: 525 p[0] = expressions.BinaryExpressionNode( 526 "bitwise and", (lambda x, y: x & y), "(%s & %s)", (False, False), p[1], p[3] 527 ) 528 529 530def p_exclusive_or_expression(p): 531 """exclusive_or_expression : and_expression 532 | exclusive_or_expression '^' and_expression 533 """ 534 if len(p) == 2: 535 p[0] = p[1] 536 else: 537 p[0] = expressions.BinaryExpressionNode( 538 "bitwise xor", (lambda x, y: x ^ y), "(%s ^ %s)", (False, False), p[1], p[3] 539 ) 540 541 542def p_inclusive_or_expression(p): 543 """inclusive_or_expression : exclusive_or_expression 544 | inclusive_or_expression '|' exclusive_or_expression 545 """ 546 if len(p) == 2: 547 p[0] = p[1] 548 else: 549 p[0] = expressions.BinaryExpressionNode( 550 "bitwise or", (lambda x, y: x | y), "(%s | %s)", (False, False), p[1], p[3] 551 ) 552 553 554def p_logical_and_expression(p): 555 """logical_and_expression : inclusive_or_expression 556 | logical_and_expression AND_OP inclusive_or_expression 557 """ 558 if len(p) == 2: 559 p[0] = p[1] 560 else: 561 p[0] = expressions.BinaryExpressionNode( 562 "logical and", (lambda x, y: x and y), "(%s and %s)", (True, True), p[1], p[3] 563 ) 564 565 566def p_logical_or_expression(p): 567 """logical_or_expression : logical_and_expression 568 | logical_or_expression OR_OP logical_and_expression 569 """ 570 if len(p) == 2: 571 p[0] = p[1] 572 else: 573 p[0] = expressions.BinaryExpressionNode( 574 "logical and", (lambda x, y: x or y), "(%s or %s)", (True, True), p[1], p[3] 575 ) 576 577 578def p_conditional_expression(p): 579 """conditional_expression : logical_or_expression 580 | logical_or_expression '?' expression ':' conditional_expression 581 """ 582 if len(p) == 2: 583 p[0] = p[1] 584 else: 585 p[0] = expressions.ConditionalExpressionNode(p[1], p[3], p[5]) 586 587 588assign_ops_dict = { 589 "*=": ("multiply", (lambda x, y: x * y), "(%s * %s)"), 590 "/=": ("divide", (lambda x, y: x / y), "(%s / %s)"), 591 "%=": ("modulus", (lambda x, y: x % y), "(%s % %s)"), 592 "+=": ("addition", (lambda x, y: x + y), "(%s + %s)"), 593 "-=": ("subtraction", (lambda x, y: x - y), "(%s - %s)"), 594 "<<=": ("left shift", (lambda x, y: x << y), "(%s << %s)"), 595 ">>=": ("right shift", (lambda x, y: x >> y), "(%s >> %s)"), 596 "&=": ("bitwise and", (lambda x, y: x & y), "(%s & %s)"), 597 "^=": ("bitwise xor", (lambda x, y: x ^ y), "(%s ^ %s)"), 598 "|=": ("bitwise or", (lambda x, y: x | y), "(%s | %s)"), 599} 600 601 602def p_assignment_expression(p): 603 """assignment_expression : conditional_expression 604 | unary_expression assignment_operator assignment_expression 605 """ 606 if len(p) == 2: 607 p[0] = p[1] 608 else: 609 # In C, the value of (x*=3) is the same as (x*3). We support that here. 610 # However, we don't support the change in the value of x. 611 if p[2] == "=": 612 p[0] = p[3] 613 else: 614 name, op, format = assign_ops_dict[p[2]] 615 p[0] = expressions.BinaryExpressionNode(name, op, format, (True, True), p[1], p[3]) 616 617 618def p_assignment_operator(p): 619 """assignment_operator : '=' 620 | MUL_ASSIGN 621 | DIV_ASSIGN 622 | MOD_ASSIGN 623 | ADD_ASSIGN 624 | SUB_ASSIGN 625 | LEFT_ASSIGN 626 | RIGHT_ASSIGN 627 | AND_ASSIGN 628 | XOR_ASSIGN 629 | OR_ASSIGN 630 """ 631 p[0] = p[1] 632 633 634def p_expression(p): 635 """expression : assignment_expression 636 | expression ',' assignment_expression 637 """ 638 p[0] = p[1] 639 # We don't need to support sequence expressions... 640 641 642def p_constant_expression(p): 643 """constant_expression : conditional_expression 644 """ 645 p[0] = p[1] 646 647 648def p_declaration(p): 649 """declaration : declaration_impl ';' 650 """ 651 # The ';' must be here, not in 'declaration', as declaration needs to 652 # be executed before the ';' is shifted (otherwise the next lookahead will 653 # be read, which may be affected by this declaration if its a typedef. 654 655 656def p_declaration_impl(p): 657 """declaration_impl : declaration_specifier_list 658 | declaration_specifier_list init_declarator_list 659 """ 660 declaration = cdeclarations.Declaration() 661 cdeclarations.apply_specifiers(p[1], declaration) 662 663 if len(p) == 2: 664 filename = p.slice[1].filename 665 lineno = p.slice[1].lineno 666 p.parser.cparser.impl_handle_declaration(declaration, filename, lineno) 667 return 668 669 filename = p.slice[2].filename 670 lineno = p.slice[2].lineno 671 for declarator in p[2]: 672 declaration.declarator = declarator 673 p.parser.cparser.impl_handle_declaration(declaration, filename, lineno) 674 675 676# shift/reduce conflict with p_statement_error. 677# def p_declaration_error(p): 678# '''declaration : error ';' 679# ''' 680# # Error resynchronisation catch-all 681 682 683def p_declaration_specifier_list(p): 684 """declaration_specifier_list : gcc_attributes declaration_specifier gcc_attributes 685 | declaration_specifier_list declaration_specifier gcc_attributes 686 """ 687 if type(p[1]) == cdeclarations.Attrib: 688 p[0] = (p[1], p[2], p[3]) 689 p.slice[0].filename = p.slice[2].filename 690 p.slice[0].lineno = p.slice[2].lineno 691 else: 692 p[0] = p[1] + (p[2], p[3]) 693 p.slice[0].filename = p.slice[1].filename 694 p.slice[0].lineno = p.slice[1].lineno 695 696 697def p_declaration_specifier(p): 698 """declaration_specifier : storage_class_specifier 699 | type_specifier 700 | type_qualifier 701 """ 702 p[0] = p[1] 703 704 705def p_init_declarator_list(p): 706 """init_declarator_list : init_declarator 707 | init_declarator_list ',' init_declarator 708 """ 709 if len(p) > 2: 710 p[0] = p[1] + (p[3],) 711 else: 712 p[0] = (p[1],) 713 714 715def p_init_declarator(p): 716 """init_declarator : declarator gcc_attributes 717 | declarator gcc_attributes '=' initializer 718 """ 719 p[0] = p[1] 720 p[0].attrib.update(p[2]) 721 p.slice[0].filename = p.slice[1].filename 722 p.slice[0].lineno = p.slice[1].lineno 723 if len(p) > 3: 724 p[0].initializer = p[4] 725 726 727def p_storage_class_specifier(p): 728 """storage_class_specifier : TYPEDEF 729 | EXTERN 730 | STATIC 731 | AUTO 732 | REGISTER 733 """ 734 p[0] = cdeclarations.StorageClassSpecifier(p[1]) 735 736 737def p_type_specifier(p): 738 """type_specifier : VOID 739 | _BOOL 740 | CHAR 741 | SHORT 742 | INT 743 | LONG 744 | FLOAT 745 | DOUBLE 746 | SIGNED 747 | UNSIGNED 748 | struct_or_union_specifier 749 | enum_specifier 750 | TYPE_NAME 751 """ 752 if type(p[1]) in (cdeclarations.StructTypeSpecifier, cdeclarations.EnumSpecifier): 753 p[0] = p[1] 754 else: 755 p[0] = cdeclarations.TypeSpecifier(p[1]) 756 757 758def p_struct_or_union_specifier(p): 759 """struct_or_union_specifier : struct_or_union gcc_attributes IDENTIFIER '{' struct_declaration_list '}' 760 | struct_or_union gcc_attributes TYPE_NAME '{' struct_declaration_list '}' 761 | struct_or_union gcc_attributes '{' struct_declaration_list '}' 762 | struct_or_union gcc_attributes IDENTIFIER 763 | struct_or_union gcc_attributes TYPE_NAME 764 """ 765 # format of grammar for gcc_attributes taken from c-parser.c in GCC source. 766 # The TYPE_NAME ones are dodgy, needed for Apple headers 767 # CoreServices.framework/Frameworks/CarbonCore.framework/Headers/Files.h. 768 # CoreServices.framework/Frameworks/OSServices.framework/Headers/Power.h 769 tag = None 770 decl = None 771 772 if len(p) == 4: # struct [attributes] <id/typname> 773 tag = p[3] 774 elif p[3] == "{": 775 tag, decl = "", p[4] 776 else: 777 tag, decl = p[3], p[5] 778 779 p[0] = cdeclarations.StructTypeSpecifier(p[1], p[2], tag, decl) 780 781 p.slice[0].filename = p.slice[1].filename 782 p.slice[0].lineno = p.slice[1].lineno 783 p[0].filename = p.slice[1].filename 784 p[0].lineno = p.slice[1].lineno 785 786 787def p_struct_or_union(p): 788 """struct_or_union : STRUCT 789 | UNION 790 """ 791 p[0] = p[1] == "union" 792 793 794def p_gcc_attributes(p): 795 """gcc_attributes : 796 | gcc_attributes gcc_attribute 797 """ 798 # Allow empty production on attributes (take from c-parser.c in GCC source) 799 if len(p) == 1: 800 p[0] = cdeclarations.Attrib() 801 else: 802 p[0] = p[1] 803 p[0].update(p[2]) 804 805 806def p_gcc_attribute(p): 807 """gcc_attribute : __ATTRIBUTE__ '(' '(' gcc_attrib_list ')' ')' 808 """ 809 p[0] = cdeclarations.Attrib() 810 p[0].update(p[4]) 811 812 813def p_gcc_attrib_list(p): 814 """gcc_attrib_list : gcc_attrib 815 | gcc_attrib_list ',' gcc_attrib 816 """ 817 if len(p) == 2: 818 p[0] = (p[1],) 819 else: 820 p[0] = p[1] + (p[3],) 821 822 823def p_gcc_attrib(p): 824 """gcc_attrib : 825 | IDENTIFIER 826 | IDENTIFIER '(' argument_expression_list ')' 827 """ 828 if len(p) == 1: 829 p[0] = (None, None) 830 elif len(p) == 2: 831 p[0] = (p[1], True) 832 elif len(p) == 5: 833 p[0] = (p[1], p[3]) 834 else: 835 raise RuntimeError("Should never reach this part of the grammar") 836 837 838def p_struct_declaration_list(p): 839 """struct_declaration_list : struct_declaration 840 | struct_declaration_list struct_declaration 841 """ 842 if len(p) == 2: 843 p[0] = p[1] 844 else: 845 p[0] = p[1] + p[2] 846 847 848def p_struct_declaration(p): 849 """struct_declaration : specifier_qualifier_list struct_declarator_list ';' 850 | specifier_qualifier_list ';' 851 """ 852 # p[0] returned is a tuple, to handle multiple declarators in one 853 # declaration. 854 r = () 855 if len(p) >= 4: 856 for declarator in p[2]: 857 declaration = cdeclarations.Declaration() 858 cdeclarations.apply_specifiers(p[1], declaration) 859 declaration.declarator = declarator 860 r += (declaration,) 861 else: 862 # anonymous field (C11/GCC extension) 863 declaration = cdeclarations.Declaration() 864 cdeclarations.apply_specifiers(p[1], declaration) 865 r = (declaration,) 866 867 p[0] = r 868 869 870def p_specifier_qualifier_list(p): 871 """specifier_qualifier_list : gcc_attributes specifier_qualifier gcc_attributes 872 | specifier_qualifier_list specifier_qualifier gcc_attributes 873 """ 874 if type(p[1]) == cdeclarations.Attrib: 875 p[0] = (p[1], p[2], p[3]) 876 else: 877 p[0] = p[1] + (p[2], p[3]) 878 879 880def p_specifier_qualifier(p): 881 """specifier_qualifier : type_specifier 882 | type_qualifier 883 """ 884 p[0] = p[1] 885 886 887def p_struct_declarator_list(p): 888 """struct_declarator_list : struct_declarator 889 | struct_declarator_list ',' struct_declarator 890 """ 891 if len(p) == 2: 892 p[0] = (p[1],) 893 else: 894 p[0] = p[1] + (p[3],) 895 896 897def p_struct_declarator(p): 898 """struct_declarator : declarator gcc_attributes 899 | ':' constant_expression gcc_attributes 900 | declarator ':' constant_expression gcc_attributes 901 """ 902 if p[1] == ":": 903 p[0] = cdeclarations.Declarator() 904 p[0].bitfield = p[2] 905 else: 906 p[0] = p[1] 907 # Bitfield support 908 if p[2] == ":": 909 p[0].bitfield = p[3] 910 911 p[0].attrib.update(p[len(p) - 1]) 912 913 914def p_enum_specifier(p): 915 """enum_specifier : ENUM '{' enumerator_list '}' 916 | ENUM IDENTIFIER '{' enumerator_list '}' 917 | ENUM IDENTIFIER 918 """ 919 if len(p) == 5: 920 p[0] = cdeclarations.EnumSpecifier(None, p[3]) 921 elif len(p) == 6: 922 p[0] = cdeclarations.EnumSpecifier(p[2], p[4]) 923 else: 924 p[0] = cdeclarations.EnumSpecifier(p[2], ()) 925 926 p[0].filename = p.slice[0].filename 927 p[0].lineno = p.slice[0].lineno 928 929 930def p_enumerator_list(p): 931 """enumerator_list : enumerator_list_iso 932 | enumerator_list_iso ',' 933 """ 934 # Apple headers sometimes have trailing ',' after enumerants, which is 935 # not ISO C. 936 p[0] = p[1] 937 938 939def p_enumerator_list_iso(p): 940 """enumerator_list_iso : enumerator 941 | enumerator_list_iso ',' enumerator 942 """ 943 if len(p) == 2: 944 p[0] = (p[1],) 945 else: 946 p[0] = p[1] + (p[3],) 947 948 949def p_enumerator(p): 950 """enumerator : IDENTIFIER 951 | IDENTIFIER '=' constant_expression 952 """ 953 if len(p) == 2: 954 p[0] = cdeclarations.Enumerator(p[1], None) 955 else: 956 p[0] = cdeclarations.Enumerator(p[1], p[3]) 957 958 959def p_type_qualifier(p): 960 """type_qualifier : CONST 961 | VOLATILE 962 """ 963 p[0] = cdeclarations.TypeQualifier(p[1]) 964 965 966def p_declarator(p): 967 """declarator : pointer direct_declarator 968 | direct_declarator 969 """ 970 if len(p) > 2: 971 p[0] = p[1] 972 ptr = p[1] 973 while ptr.pointer: 974 ptr = ptr.pointer 975 ptr.pointer = p[2] 976 p[2].attrib.update(p[1].attrib) 977 else: 978 p[0] = p[1] 979 980 981def p_direct_declarator(p): 982 """direct_declarator : IDENTIFIER 983 | '(' gcc_attributes declarator ')' 984 | direct_declarator '[' constant_expression ']' 985 | direct_declarator '[' ']' 986 | direct_declarator '(' parameter_type_list ')' 987 | direct_declarator '(' identifier_list ')' 988 | direct_declarator '(' ')' 989 """ 990 if isinstance(p[1], cdeclarations.Declarator): 991 p[0] = p[1] 992 if p[2] == "[": 993 a = cdeclarations.Array() 994 a.array = p[0].array 995 p[0].array = a 996 if p[3] != "]": 997 a.size = p[3] 998 else: 999 if p[3] == ")": 1000 p[0].parameters = () 1001 else: 1002 p[0].parameters = p[3] 1003 elif p[1] == "(": 1004 p[0] = p[3] 1005 p[3].attrib.update(p[2]) 1006 else: 1007 p[0] = cdeclarations.Declarator() 1008 p[0].identifier = p[1] 1009 1010 # Check parameters for (void) and simplify to empty tuple. 1011 if p[0].parameters and len(p[0].parameters) == 1: 1012 param = p[0].parameters[0] 1013 if param.type.specifiers == ["void"] and not param.declarator: 1014 p[0].parameters = () 1015 1016 1017def p_pointer(p): 1018 """pointer : '*' 1019 | '*' type_qualifier_list 1020 | '*' pointer 1021 | '*' type_qualifier_list pointer 1022 """ 1023 if len(p) == 2: 1024 p[0] = cdeclarations.Pointer() 1025 elif len(p) == 3 and isinstance(p[2], cdeclarations.Pointer): 1026 p[0] = cdeclarations.Pointer() 1027 p[0].pointer = p[2] 1028 p[0].attrib.update(p[2].attrib) 1029 else: 1030 p[0] = cdeclarations.Pointer() 1031 for tq in p[2]: 1032 if isinstance(tq, cdeclarations.Attrib): 1033 p[0].attrib.update(tq) 1034 else: 1035 p[0].qualifiers += (tq,) 1036 1037 if len(p) == 4: 1038 p[0].pointer = p[3] 1039 p[0].attrib.update(p[3].attrib) 1040 1041 1042def p_type_qualifier_list(p): 1043 """type_qualifier_list : type_qualifier 1044 | gcc_attribute 1045 | type_qualifier_list type_qualifier 1046 | type_qualifier_list gcc_attribute 1047 """ 1048 if len(p) > 2: 1049 p[0] = p[1] + (p[2],) 1050 else: 1051 p[0] = (p[1],) 1052 1053 1054def p_parameter_type_list(p): 1055 """parameter_type_list : parameter_list 1056 | parameter_list ',' ELLIPSIS 1057 """ 1058 if len(p) > 2: 1059 p[0] = p[1] + (p[3],) 1060 else: 1061 p[0] = p[1] 1062 1063 1064def p_parameter_list(p): 1065 """parameter_list : parameter_declaration 1066 | parameter_list ',' parameter_declaration 1067 """ 1068 if len(p) > 2: 1069 p[0] = p[1] + (p[3],) 1070 else: 1071 p[0] = (p[1],) 1072 1073 1074def p_parameter_declaration(p): 1075 """parameter_declaration : declaration_specifier_list declarator gcc_attributes 1076 | declaration_specifier_list abstract_declarator 1077 | declaration_specifier_list 1078 """ 1079 p[0] = cdeclarations.Parameter() 1080 specs = p[1] 1081 1082 if len(p) == 4: 1083 # add the attributes as a final specifier 1084 specs += (p[3],) 1085 p[0].declarator = p[2] 1086 elif len(p) == 3: 1087 p[0].declarator = p[2] 1088 1089 cdeclarations.apply_specifiers(specs, p[0]) 1090 1091 1092def p_identifier_list(p): 1093 """identifier_list : IDENTIFIER 1094 | identifier_list ',' IDENTIFIER 1095 """ 1096 param = cdeclarations.Parameter() 1097 param.declarator = cdeclarations.Declarator() 1098 if len(p) > 2: 1099 param.declarator.identifier = p[3] 1100 p[0] = p[1] + (param,) 1101 else: 1102 param.declarator.identifier = p[1] 1103 p[0] = (param,) 1104 1105 1106def p_type_name(p): 1107 """type_name : specifier_qualifier_list 1108 | specifier_qualifier_list abstract_declarator 1109 """ 1110 typ = p[1] 1111 if len(p) == 3: 1112 declarator = p[2] 1113 else: 1114 declarator = None 1115 1116 declaration = cdeclarations.Declaration() 1117 declaration.declarator = declarator 1118 cdeclarations.apply_specifiers(typ, declaration) 1119 ctype = p.parser.cparser.get_ctypes_type(declaration.type, declaration.declarator) 1120 p[0] = ctype 1121 1122 1123def p_abstract_declarator(p): 1124 """abstract_declarator : pointer 1125 | direct_abstract_declarator gcc_attributes 1126 | pointer direct_abstract_declarator gcc_attributes 1127 """ 1128 if len(p) == 2: 1129 p[0] = p[1] 1130 ptr = p[0] 1131 while ptr.pointer: 1132 ptr = ptr.pointer 1133 # Only if doesn't already terminate in a declarator 1134 if type(ptr) == cdeclarations.Pointer: 1135 ptr.pointer = cdeclarations.Declarator() 1136 ptr.pointer.attrib.update(p[1].attrib) 1137 else: 1138 ptr.attrib.update(p[1].attrib) 1139 elif len(p) == 3: 1140 p[0] = p[1] 1141 p[1].attrib.update(p[2]) 1142 else: 1143 p[0] = p[1] 1144 ptr = p[0] 1145 while ptr.pointer: 1146 ptr = ptr.pointer 1147 ptr.pointer = p[2] 1148 p[2].attrib.update(p[1].attrib) 1149 p[2].attrib.update(p[3]) 1150 1151 1152def p_direct_abstract_declarator(p): 1153 """direct_abstract_declarator : '(' gcc_attributes abstract_declarator ')' 1154 | '[' ']' 1155 | '[' constant_expression ']' 1156 | direct_abstract_declarator '[' ']' 1157 | direct_abstract_declarator '[' constant_expression ']' 1158 | '(' ')' 1159 | '(' parameter_type_list ')' 1160 | direct_abstract_declarator '(' ')' 1161 | direct_abstract_declarator '(' parameter_type_list ')' 1162 """ 1163 if p[1] == "(" and isinstance(p[3], cdeclarations.Declarator): 1164 p[0] = p[3] 1165 p[3].attrib.update(p[2]) 1166 else: 1167 if isinstance(p[1], cdeclarations.Declarator): 1168 p[0] = p[1] 1169 if p[2] == "[": 1170 a = cdeclarations.Array() 1171 a.array = p[0].array 1172 p[0].array = a 1173 if p[3] != "]": 1174 p[0].array.size = p[3] 1175 elif p[2] == "(": 1176 if p[3] == ")": 1177 p[0].parameters = () 1178 else: 1179 p[0].parameters = p[3] 1180 else: 1181 p[0] = cdeclarations.Declarator() 1182 if p[1] == "[": 1183 p[0].array = cdeclarations.Array() 1184 if p[2] != "]": 1185 p[0].array.size = p[2] 1186 elif p[1] == "(": 1187 if p[2] == ")": 1188 p[0].parameters = () 1189 else: 1190 p[0].parameters = p[2] 1191 1192 # Check parameters for (void) and simplify to empty tuple. 1193 if p[0].parameters and len(p[0].parameters) == 1: 1194 param = p[0].parameters[0] 1195 if param.type.specifiers == ["void"] and not param.declarator: 1196 p[0].parameters = () 1197 1198 1199def p_initializer(p): 1200 """initializer : assignment_expression 1201 | '{' initializer_list '}' 1202 | '{' initializer_list ',' '}' 1203 """ 1204 1205 1206def p_initializer_list(p): 1207 """initializer_list : initializer 1208 | initializer_list ',' initializer 1209 """ 1210 1211 1212def p_statement(p): 1213 """statement : labeled_statement 1214 | compound_statement 1215 | expression_statement 1216 | selection_statement 1217 | iteration_statement 1218 | jump_statement 1219 """ 1220 1221 1222def p_labeled_statement(p): 1223 """labeled_statement : IDENTIFIER ':' statement 1224 | CASE constant_expression ':' statement 1225 | DEFAULT ':' statement 1226 """ 1227 1228 1229def p_compound_statement(p): 1230 """compound_statement : '{' '}' 1231 | '{' statement_list '}' 1232 | '{' declaration_list '}' 1233 | '{' declaration_list statement_list '}' 1234 """ 1235 1236 1237def p_compound_statement_error(p): 1238 """compound_statement : '{' error '}' 1239 """ 1240 # Error resynchronisation catch-all 1241 1242 1243def p_declaration_list(p): 1244 """declaration_list : declaration 1245 | declaration_list declaration 1246 """ 1247 1248 1249def p_statement_list(p): 1250 """statement_list : statement 1251 | statement_list statement 1252 """ 1253 1254 1255def p_expression_statement(p): 1256 """expression_statement : ';' 1257 | expression ';' 1258 """ 1259 1260 1261def p_expression_statement_error(p): 1262 """expression_statement : error ';' 1263 """ 1264 # Error resynchronisation catch-all 1265 1266 1267def p_selection_statement(p): 1268 """selection_statement : IF '(' expression ')' statement %prec IF 1269 | IF '(' expression ')' statement ELSE statement 1270 | SWITCH '(' expression ')' statement 1271 """ 1272 1273 1274def p_iteration_statement(p): 1275 """iteration_statement : WHILE '(' expression ')' statement 1276 | DO statement WHILE '(' expression ')' ';' 1277 | FOR '(' expression_statement expression_statement ')' statement 1278 | FOR '(' expression_statement expression_statement expression ')' statement 1279 """ 1280 1281 1282def p_jump_statement(p): 1283 """jump_statement : GOTO IDENTIFIER ';' 1284 | CONTINUE ';' 1285 | BREAK ';' 1286 | RETURN ';' 1287 | RETURN expression ';' 1288 """ 1289 1290 1291def p_external_declaration(p): 1292 """external_declaration : declaration 1293 | function_definition 1294 """ 1295 # Intentionally empty 1296 1297 1298def p_function_definition(p): 1299 """function_definition : declaration_specifier_list declarator declaration_list compound_statement 1300 | declaration_specifier_list declarator compound_statement 1301 | declarator declaration_list compound_statement 1302 | declarator compound_statement 1303 """ 1304 # No impl of function defs 1305 1306 1307def p_directive(p): 1308 """directive : define 1309 | undefine 1310 | pragma 1311 """ 1312 1313 1314def p_define(p): 1315 """define : PP_DEFINE PP_DEFINE_NAME PP_END_DEFINE 1316 | PP_DEFINE PP_DEFINE_NAME type_name PP_END_DEFINE 1317 | PP_DEFINE PP_DEFINE_NAME constant_expression PP_END_DEFINE 1318 | PP_DEFINE PP_DEFINE_MACRO_NAME '(' ')' PP_END_DEFINE 1319 | PP_DEFINE PP_DEFINE_MACRO_NAME '(' ')' constant_expression PP_END_DEFINE 1320 | PP_DEFINE PP_DEFINE_MACRO_NAME '(' macro_parameter_list ')' PP_END_DEFINE 1321 | PP_DEFINE PP_DEFINE_MACRO_NAME '(' macro_parameter_list ')' constant_expression PP_END_DEFINE 1322 """ 1323 1324 filename = p.slice[1].filename 1325 lineno = p.slice[1].lineno 1326 1327 if p[3] != "(": 1328 if len(p) == 4: 1329 p.parser.cparser.handle_define_constant(p[2], None, filename, lineno) 1330 else: 1331 p.parser.cparser.handle_define_constant(p[2], p[3], filename, lineno) 1332 else: 1333 if p[4] == ")": 1334 params = [] 1335 if len(p) == 6: 1336 expr = None 1337 elif len(p) == 7: 1338 expr = p[5] 1339 else: 1340 params = p[4] 1341 if len(p) == 7: 1342 expr = None 1343 elif len(p) == 8: 1344 expr = p[6] 1345 1346 filename = p.slice[1].filename 1347 lineno = p.slice[1].lineno 1348 1349 p.parser.cparser.handle_define_macro(p[2], params, expr, filename, lineno) 1350 1351 1352def p_define_error(p): 1353 """define : PP_DEFINE error PP_END_DEFINE""" 1354 lexer = p[2].lexer 1355 clexdata = lexer.tokens 1356 start = end = p[2].clexpos 1357 while clexdata[start].type != "PP_DEFINE": 1358 start -= 1 1359 while clexdata[end].type != "PP_END_DEFINE": 1360 end += 1 1361 1362 name = clexdata[start + 1].value 1363 if clexdata[start + 1].type == "PP_DEFINE_NAME": 1364 params = None 1365 contents = [t.value for t in clexdata[start + 2 : end]] 1366 else: 1367 end_of_param_list = start 1368 while clexdata[end_of_param_list].value != ")" and end_of_param_list < end: 1369 end_of_param_list += 1 1370 params = [t.value for t in clexdata[start + 3 : end_of_param_list] if t.value != ","] 1371 contents = [t.value for t in clexdata[end_of_param_list + 1 : end]] 1372 1373 filename = p.slice[1].filename 1374 lineno = p.slice[1].lineno 1375 1376 p[2].lexer.cparser.handle_define_unparseable(name, params, contents, filename, lineno) 1377 1378 1379def p_undefine(p): 1380 """undefine : PP_UNDEFINE PP_DEFINE_NAME PP_END_DEFINE""" 1381 1382 filename = p.slice[1].filename 1383 lineno = p.slice[1].lineno 1384 1385 macro = expressions.IdentifierExpressionNode(p[2]) 1386 p.parser.cparser.handle_undefine(macro, filename, lineno) 1387 1388 1389def p_macro_parameter_list(p): 1390 """macro_parameter_list : PP_MACRO_PARAM 1391 | macro_parameter_list ',' PP_MACRO_PARAM 1392 """ 1393 if len(p) == 2: 1394 p[0] = [p[1]] 1395 else: 1396 p[1].append(p[3]) 1397 p[0] = p[1] 1398 1399 1400def p_error(t): 1401 if t.lexer.in_define: 1402 # p_define_error will generate an error message. 1403 pass 1404 else: 1405 if t.type == "$end": 1406 t.parser.cparser.handle_error("Syntax error at end of file.", t.filename, 0) 1407 else: 1408 t.lexer.cparser.handle_error("Syntax error at %r" % t.value, t.filename, t.lineno) 1409 # Don't alter lexer: default behaviour is to pass error production 1410 # up until it hits the catch-all at declaration, at which point 1411 # parsing continues (synchronisation). 1412 1413 1414def p_pragma(p): 1415 """pragma : pragma_pack 1416 """ 1417 1418 1419def p_pragma_pack(p): 1420 """pragma_pack : PRAGMA PRAGMA_PACK '(' ')' PRAGMA_END 1421 | PRAGMA PRAGMA_PACK '(' constant ')' PRAGMA_END 1422 | PRAGMA PRAGMA_PACK '(' pragma_pack_stack_args ')' PRAGMA_END 1423 """ 1424 1425 err = None 1426 if len(p) == 6: 1427 cdeclarations.pragma_pack.set_default() 1428 elif isinstance(p[4], tuple): 1429 op, id, n = p[4] 1430 if op == "push": 1431 err = cdeclarations.pragma_pack.push(id, n) 1432 elif op == "pop": 1433 err = cdeclarations.pragma_pack.pop(id) 1434 else: 1435 err = "Syntax error for #pragma pack at {}:{}".format( 1436 p.slice[1].filename, p.slice[1].lineno 1437 ) 1438 else: 1439 cdeclarations.pragma_pack.current = p[4] 1440 1441 if err: 1442 p.lexer.cparser.handle_error(err, p.slice[1].filename, p.slice[1].lineno) 1443 1444 1445def p_pragma_pack_stack_args(p): 1446 """pragma_pack_stack_args : IDENTIFIER 1447 | IDENTIFIER ',' IDENTIFIER 1448 | IDENTIFIER ',' IDENTIFIER ',' constant 1449 | IDENTIFIER ',' constant ',' IDENTIFIER 1450 | IDENTIFIER ',' constant 1451 """ 1452 op, id, n = p[1], None, None 1453 1454 if len(p) > 2: 1455 if isinstance(p[3], expressions.ConstantExpressionNode): 1456 n = p[3].value 1457 1458 if len(p) > 4: 1459 id = p[5] 1460 else: 1461 id = p[3] 1462 1463 if len(p) > 4: 1464 n = p[5].value 1465 1466 p[0] = (op, id, n) 1467 1468 1469def main(): 1470 yacc.yacc(tabmodule="new_parsetab") 1471