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