Skip to content

Commit 776ed69

Browse files
Add support for __attribute__(()) in enum/struct/union
Add support for GNU __attribute__(()) in enum/struct/union definitions, both on the type itself and on enumerators. Fixes #42 Signed-off-by: Douglas Raillard <douglas.raillard@arm.com>
1 parent 6b9db4a commit 776ed69

3 files changed

Lines changed: 404 additions & 0 deletions

File tree

pycparserext/ext_c_generator.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import copy
2+
13
from pycparser.c_generator import CGenerator as CGeneratorBaseBuggy
24
from pycparserext.ext_c_parser import FuncDeclExt, TypeDeclExt
35
import pycparser.c_ast as c_ast
@@ -39,6 +41,37 @@ def visit_Asm(self, n):
3941
" : ".join(
4042
self.visit(c) for c in components))
4143

44+
def _generate_struct_union_enum_ext(self, n, visitor):
45+
if n.attributes:
46+
# Adding __attribute__ at the end does not always work, so instead
47+
# we change the name on a shallow copy so that the existing
48+
# infrastructure just prints the attributes right before the name
49+
# (as recommended by the GNU doc).
50+
n = copy.copy(n)
51+
n.name = (
52+
'__attribute__((' + self.visit(n.attributes) + ')) ' +
53+
(n.name or '')
54+
)
55+
return visitor(n)
56+
57+
def visit_StructExt(self, n, *args, **kwargs):
58+
return self._generate_struct_union_enum_ext(n, self.visit_Struct)
59+
60+
def visit_UnionExt(self, n, *args, **kwargs):
61+
return self._generate_struct_union_enum_ext(n, self.visit_Union)
62+
63+
def visit_EnumExt(self, n, *args, **kwargs):
64+
return self._generate_struct_union_enum_ext(n, self.visit_Enum)
65+
66+
def visit_EnumeratorExt(self, n, *args, **kwargs):
67+
if n.attributes:
68+
n = copy.copy(n)
69+
n.name = (
70+
(n.name or '') +
71+
' __attribute__((' + self.visit(n.attributes) + ')) '
72+
)
73+
return super().visit_Enumerator(n)
74+
4275
def _generate_type(self, n, modifiers=None, emit_declname=True):
4376
""" Recursive generation from a type node. n is the type node.
4477
modifiers collects the PtrDecl, ArrayDecl and FuncDecl modifiers

pycparserext/ext_c_parser.py

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,38 @@ def __iter__(self):
240240

241241
attr_names = ()
242242

243+
244+
class _StructUnionEnumMixin:
245+
def __init__(self, *args, attributes=None, **kwargs):
246+
super().__init__(*args, **kwargs)
247+
self.attributes = attributes
248+
249+
def children(self):
250+
children = list(super().children())
251+
if self.attributes:
252+
children.append(("attributes", self.attributes))
253+
return children
254+
255+
def __iter__(self):
256+
yield from super().__iter__()
257+
if self.attributes:
258+
yield self.attributes
259+
260+
261+
class EnumExt(_StructUnionEnumMixin, c_ast.Enum):
262+
pass
263+
264+
265+
class EnumeratorExt(_StructUnionEnumMixin, c_ast.Enumerator):
266+
pass
267+
268+
269+
class StructExt(_StructUnionEnumMixin, c_ast.Struct):
270+
pass
271+
272+
273+
class UnionExt(_StructUnionEnumMixin, c_ast.Union):
274+
pass
243275
# }}}
244276

245277

@@ -468,6 +500,181 @@ def p_direct_abstract_declarator_6(self, p):
468500

469501
p[0] = self._type_modify_decl(decl=p[1], modifier=func)
470502

503+
def _select_struct_union_class(self, token):
504+
klass = super()._select_struct_union_class(token)
505+
return {
506+
c_ast.Struct: StructExt,
507+
c_ast.Union: UnionExt,
508+
}[klass]
509+
510+
def p_struct_or_union_specifier_with_attr_1(self, p):
511+
""" struct_or_union_specifier : struct_or_union ID brace_open brace_close attributes_opt
512+
| struct_or_union TYPEID brace_open brace_close attributes_opt
513+
"""
514+
klass = self._select_struct_union_class(p[1])
515+
p[0] = klass(
516+
name=p[2],
517+
decls=[],
518+
attributes=p[5],
519+
coord=self._token_coord(p, 2))
520+
521+
def p_struct_or_union_specifier_with_attr_2(self, p):
522+
""" struct_or_union_specifier : struct_or_union attributes_opt ID brace_open brace_close
523+
| struct_or_union attributes_opt TYPEID brace_open brace_close
524+
"""
525+
klass = self._select_struct_union_class(p[1])
526+
p[0] = klass(
527+
name=p[3],
528+
decls=[],
529+
attributes=p[2],
530+
coord=self._token_coord(p, 3))
531+
532+
def p_struct_or_union_specifier_with_attr_3(self, p):
533+
""" struct_or_union_specifier : attributes_opt struct_or_union ID brace_open brace_close
534+
| attributes_opt struct_or_union TYPEID brace_open brace_close
535+
"""
536+
klass = self._select_struct_union_class(p[2])
537+
p[0] = klass(
538+
name=p[3],
539+
decls=[],
540+
attributes=p[1],
541+
coord=self._token_coord(p, 3))
542+
543+
def p_struct_or_union_specifier_with_attr_4(self, p):
544+
""" struct_or_union_specifier : struct_or_union ID brace_open struct_declaration_list brace_close attributes_opt
545+
| struct_or_union TYPEID brace_open struct_declaration_list brace_close attributes_opt
546+
"""
547+
klass = self._select_struct_union_class(p[1])
548+
p[0] = klass(
549+
name=p[2],
550+
decls=p[4],
551+
attributes=p[6],
552+
coord=self._token_coord(p, 2))
553+
554+
def p_struct_or_union_specifier_with_attr_5(self, p):
555+
""" struct_or_union_specifier : struct_or_union attributes_opt ID brace_open struct_declaration_list brace_close
556+
| struct_or_union attributes_opt TYPEID brace_open struct_declaration_list brace_close
557+
"""
558+
klass = self._select_struct_union_class(p[1])
559+
p[0] = klass(
560+
name=p[3],
561+
decls=p[5],
562+
attributes=p[2],
563+
coord=self._token_coord(p, 3))
564+
565+
def p_struct_or_union_specifier_with_attr_6(self, p):
566+
""" struct_or_union_specifier : attributes_opt struct_or_union ID brace_open struct_declaration_list brace_close
567+
| attributes_opt struct_or_union TYPEID brace_open struct_declaration_list brace_close
568+
"""
569+
klass = self._select_struct_union_class(p[2])
570+
p[0] = klass(
571+
name=p[3],
572+
decls=p[5],
573+
attributes=p[1],
574+
coord=self._token_coord(p, 3))
575+
576+
def p_struct_or_union_specifier_with_attr_7(self, p):
577+
""" struct_or_union_specifier : struct_or_union attributes_opt ID
578+
| struct_or_union attributes_opt TYPEID
579+
"""
580+
klass = self._select_struct_union_class(p[1])
581+
# None means no list of members
582+
p[0] = klass(
583+
name=p[3],
584+
decls=None,
585+
attributes=p[2],
586+
coord=self._token_coord(p, 3))
587+
588+
def p_struct_or_union_specifier_with_attr_8(self, p):
589+
""" struct_or_union_specifier : struct_or_union brace_open brace_close attributes_opt
590+
"""
591+
klass = self._select_struct_union_class(p[1])
592+
p[0] = klass(
593+
name=None,
594+
decls=[],
595+
attributes=p[4],
596+
coord=self._token_coord(p, 2))
597+
598+
def p_struct_or_union_specifier_with_attr_9(self, p):
599+
""" struct_or_union_specifier : struct_or_union attributes_opt brace_open brace_close
600+
"""
601+
klass = self._select_struct_union_class(p[1])
602+
p[0] = klass(
603+
name=None,
604+
decls=[],
605+
attributes=p[2],
606+
coord=self._token_coord(p, 3))
607+
608+
def p_struct_or_union_specifier_with_attr_10(self, p):
609+
""" struct_or_union_specifier : struct_or_union brace_open struct_declaration_list brace_close attributes_opt
610+
"""
611+
klass = self._select_struct_union_class(p[1])
612+
p[0] = klass(
613+
name=None,
614+
decls=p[3],
615+
attributes=p[5],
616+
coord=self._token_coord(p, 2))
617+
618+
def p_struct_or_union_specifier_with_attr_11(self, p):
619+
""" struct_or_union_specifier : struct_or_union attributes_opt brace_open struct_declaration_list brace_close
620+
"""
621+
klass = self._select_struct_union_class(p[1])
622+
p[0] = klass(
623+
name=None,
624+
decls=p[4],
625+
attributes=p[2],
626+
coord=self._token_coord(p, 3))
627+
628+
def p_enum_specifier_with_attr_1(self, p):
629+
""" enum_specifier : ENUM attributes_opt ID
630+
| ENUM attributes_opt TYPEID
631+
"""
632+
p[0] = EnumExt(p[3], None, self._token_coord(p, 1), attributes=p[2])
633+
634+
def p_enum_specifier_with_attr_2(self, p):
635+
""" enum_specifier : ENUM attributes_opt brace_open enumerator_list brace_close
636+
"""
637+
p[0] = EnumExt(None, p[4], self._token_coord(p, 1), attributes=p[2])
638+
639+
def p_enum_specifier_with_attr_3(self, p):
640+
""" enum_specifier : ENUM brace_open enumerator_list brace_close attributes_opt
641+
"""
642+
p[0] = EnumExt(None, p[3], self._token_coord(p, 1), attributes=p[5])
643+
644+
def p_enum_specifier_with_attr_4(self, p):
645+
""" enum_specifier : ENUM attributes_opt ID brace_open enumerator_list brace_close
646+
| ENUM attributes_opt TYPEID brace_open enumerator_list brace_close
647+
"""
648+
p[0] = EnumExt(p[3], p[5], self._token_coord(p, 1), attributes=p[2])
649+
650+
def p_enum_specifier_with_attr_5(self, p):
651+
""" enum_specifier : ENUM ID brace_open enumerator_list brace_close attributes_opt
652+
| ENUM TYPEID brace_open enumerator_list brace_close attributes_opt
653+
"""
654+
p[0] = EnumExt(p[2], p[4], self._token_coord(p, 1), attributes=p[6])
655+
656+
def p_enumerator(self, p):
657+
""" enumerator : ID
658+
| ID EQUALS constant_expression
659+
| ID attributes_opt
660+
| ID attributes_opt EQUALS constant_expression
661+
"""
662+
if len(p) in (2, 4):
663+
super().p_enumerator(p)
664+
else:
665+
if len(p) == 3:
666+
enumerator = EnumeratorExt(
667+
p[1], None,
668+
self._token_coord(p, 1),
669+
attributes=p[2])
670+
else:
671+
enumerator = EnumeratorExt(
672+
p[1], p[4],
673+
self._token_coord(p, 1),
674+
attributes=p[2])
675+
self._add_identifier(enumerator.name, enumerator.coord)
676+
p[0] = enumerator
677+
471678
# }}}
472679
# }}}
473680

0 commit comments

Comments
 (0)