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