Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for __attribute__(()) in enum/struct/union #76

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions pycparserext/ext_c_generator.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import copy

from pycparser.c_generator import CGenerator as CGeneratorBaseBuggy
from pycparserext.ext_c_parser import FuncDeclExt, TypeDeclExt
import pycparser.c_ast as c_ast
Expand Down Expand Up @@ -39,6 +41,37 @@ def visit_Asm(self, n):
" : ".join(
self.visit(c) for c in components))

def _generate_struct_union_enum_ext(self, n, visitor):
if n.attributes:
# Adding __attribute__ at the end does not always work, so instead
# we change the name on a shallow copy so that the existing
# infrastructure just prints the attributes right before the name
# (as recommended by the GNU doc).
n = copy.copy(n)
n.name = (
'__attribute__((' + self.visit(n.attributes) + ')) ' +
(n.name or '')
)
return visitor(n)

def visit_StructExt(self, n, *args, **kwargs):
return self._generate_struct_union_enum_ext(n, self.visit_Struct)

def visit_UnionExt(self, n, *args, **kwargs):
return self._generate_struct_union_enum_ext(n, self.visit_Union)

def visit_EnumExt(self, n, *args, **kwargs):
return self._generate_struct_union_enum_ext(n, self.visit_Enum)

def visit_EnumeratorExt(self, n, *args, **kwargs):
if n.attributes:
n = copy.copy(n)
n.name = (
(n.name or '') +
' __attribute__((' + self.visit(n.attributes) + ')) '
)
return super().visit_Enumerator(n)

def _generate_type(self, n, modifiers=None, emit_declname=True):
""" Recursive generation from a type node. n is the type node.
modifiers collects the PtrDecl, ArrayDecl and FuncDecl modifiers
Expand Down
186 changes: 181 additions & 5 deletions pycparserext/ext_c_parser.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from __future__ import division

import itertools

import pycparser.c_parser
import pycparser.c_ast as c_ast
try:
Expand Down Expand Up @@ -252,27 +254,78 @@ def __iter__(self):

attr_names = ()


class _StructUnionEnumMixin:
def __init__(self, *args, attributes=None, **kwargs):
super().__init__(*args, **kwargs)
self.attributes = attributes

def children(self):
children = list(super().children())
if self.attributes:
children.append(("attributes", self.attributes))
return children

def __iter__(self):
yield from super().__iter__()
if self.attributes:
yield self.attributes


class EnumExt(_StructUnionEnumMixin, c_ast.Enum):
pass


class EnumeratorExt(_StructUnionEnumMixin, c_ast.Enumerator):
pass


class StructExt(_StructUnionEnumMixin, c_ast.Struct):
pass


class UnionExt(_StructUnionEnumMixin, c_ast.Union):
pass
# }}}


# {{{ attributes

class _AttributesMixin(object):

def _merge_attributes(self, p, attrs):
print(999,attrs)
attrs = [
attr
for attr in attrs
if attr is not None
]
if attrs:
fst, *others = attrs
fst.exprs.extend(itertools.chain.from_iterable(
attr.exprs
for attr in others
))
return fst
else:
return c_ast.ExprList([], self._coord(p.lineno(1)))

def p_attributes_opt_1(self, p):
""" attributes_opt : attribute_decl attributes_opt
"""
p[1].exprs.extend(p[2].exprs)
p[0] = p[1]
print(991)
p[0] = self._merge_attributes(p, (p[1], p[2]))

def p_attributes_opt_2(self, p):
""" attributes_opt : empty
"""
p[0] = c_ast.ExprList([], self._coord(p.lineno(1)))
p[0] = self._merge_attributes(p, [])

def p_attribute_decl(self, p):
""" attribute_decl : __ATTRIBUTE__ LPAREN LPAREN attribute_list RPAREN RPAREN
| __ATTRIBUTE LPAREN LPAREN attribute_list RPAREN RPAREN
"""
print(992)
p[0] = p[4]

def p_attribute_list_1(self, p):
Expand All @@ -283,8 +336,7 @@ def p_attribute_list_1(self, p):
def p_attribute_list_2(self, p):
""" attribute_list : attribute_list COMMA attribute
"""
p[1].exprs.append(p[3])
p[0] = p[1]
p[0] = self._merge_attributes(p, (p[1], p[3]))

def p_attribute_1(self, p):
""" attribute : CONST
Expand All @@ -299,6 +351,7 @@ def p_attribute_3(self, p):
def p_function_specifier_attr(self, p):
""" function_specifier : attribute_decl
"""
print(993)
p[0] = AttributeSpecifier(p[1])

# }}}
Expand Down Expand Up @@ -389,6 +442,7 @@ class _AsmAndAttributesMixin(_AsmMixin, _AttributesMixin):
def p_xxx_declarator_1(self, p):
""" xxx_declarator : direct_xxx_declarator asm_label_opt attributes_opt
"""
print(555, p[3])
if p[2] or p[3].exprs:
if isinstance(p[1], (c_ast.ArrayDecl, c_ast.FuncDecl)):
decl_ext = to_decl_ext(p[1].type)
Expand Down Expand Up @@ -418,6 +472,7 @@ def p_xxx_declarator_2(self, p):
| pointer attributes_opt direct_xxx_declarator \
asm_label_opt
"""
print(666)
if hasattr(p[4], "exprs"):
attr_decl = p[4]
asm_label = p[3]
Expand Down Expand Up @@ -458,6 +513,7 @@ def p_direct_xxx_declarator_6(self, p):
LPAREN identifier_list_opt RPAREN \
asm_label_opt attributes_opt
"""
print(777)
func = FuncDeclExt(
args=p[3],
type=None,
Expand All @@ -471,6 +527,7 @@ def p_direct_abstract_declarator_6(self, p):
""" direct_abstract_declarator : direct_abstract_declarator \
LPAREN parameter_type_list_opt RPAREN asm_label_opt attributes_opt
"""
print(888)
func = FuncDeclExt(
args=p[3],
type=None,
Expand All @@ -480,6 +537,125 @@ def p_direct_abstract_declarator_6(self, p):

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

def _select_struct_union_class(self, token):
klass = super()._select_struct_union_class(token)
return {
c_ast.Struct: StructExt,
c_ast.Union: UnionExt,
}[klass]

def p_struct_or_union_specifier_with_attr_1(self, p):
""" struct_or_union_specifier : struct_or_union attributes_opt ID brace_open brace_close attributes_opt
| struct_or_union attributes_opt TYPEID brace_open brace_close attributes_opt
"""
print(111)
klass = self._select_struct_union_class(p[1])
attrs = self._merge_attributes(p, (p[2], p[6]))

p[0] = klass(
name=p[3],
decls=[],
attributes=attrs,
coord=self._token_coord(p, 3))

def p_struct_or_union_specifier_with_attr_5(self, p):
""" struct_or_union_specifier : struct_or_union attributes_opt ID brace_open struct_declaration_list brace_close attributes_opt
| struct_or_union attributes_opt TYPEID brace_open struct_declaration_list brace_close attributes_opt
"""
print(222)
klass = self._select_struct_union_class(p[1])
attrs = self._merge_attributes(p, (p[2], p[7]))

p[0] = klass(
name=p[3],
decls=p[5],
attributes=attrs,
coord=self._token_coord(p, 3))

def p_struct_or_union_specifier_with_attr_7(self, p):
""" struct_or_union_specifier : struct_or_union attributes_opt ID attributes_opt
| struct_or_union attributes_opt TYPEID attributes_opt
"""
print(333)
klass = self._select_struct_union_class(p[1])
attrs = self._merge_attributes(p, (p[2], p[4]))

# None means no list of members
p[0] = klass(
name=p[3],
decls=None,
attributes=attrs,
coord=self._token_coord(p, 3))

def p_struct_or_union_specifier_with_attr_8(self, p):
""" struct_or_union_specifier : struct_or_union attributes_opt brace_open brace_close attributes_opt
"""
print(444)
klass = self._select_struct_union_class(p[1])
attrs = self._merge_attributes(p, (p[2], p[5]))

p[0] = klass(
name=None,
decls=[],
attributes=attrs,
coord=self._token_coord(p, 3))

def p_enum_specifier_with_attr_1(self, p):
""" enum_specifier : ENUM attributes_opt ID
| ENUM attributes_opt TYPEID
"""
print(991)
p[0] = EnumExt(p[3], None, self._token_coord(p, 1), attributes=p[2])

def p_enum_specifier_with_attr_2(self, p):
""" enum_specifier : ENUM attributes_opt brace_open enumerator_list brace_close
"""
print(992)
p[0] = EnumExt(None, p[4], self._token_coord(p, 1), attributes=p[2])

def p_enum_specifier_with_attr_3(self, p):
""" enum_specifier : ENUM brace_open enumerator_list brace_close attributes_opt
"""
print(993)
p[0] = EnumExt(None, p[3], self._token_coord(p, 1), attributes=p[5])

def p_enum_specifier_with_attr_4(self, p):
""" enum_specifier : ENUM attributes_opt ID brace_open enumerator_list brace_close
| ENUM attributes_opt TYPEID brace_open enumerator_list brace_close
"""
print(994)
p[0] = EnumExt(p[3], p[5], self._token_coord(p, 1), attributes=p[2])

def p_enum_specifier_with_attr_5(self, p):
""" enum_specifier : ENUM ID brace_open enumerator_list brace_close attributes_opt
| ENUM TYPEID brace_open enumerator_list brace_close attributes_opt
"""
print(995)
p[0] = EnumExt(p[2], p[4], self._token_coord(p, 1), attributes=p[6])

def p_enumerator(self, p):
""" enumerator : ID
| ID EQUALS constant_expression
| ID attributes_opt
| ID attributes_opt EQUALS constant_expression
"""
print(996)
if len(p) in (2, 4):
super().p_enumerator(p)
else:
if len(p) == 3:
enumerator = EnumeratorExt(
p[1], None,
self._token_coord(p, 1),
attributes=p[2])
else:
enumerator = EnumeratorExt(
p[1], p[4],
self._token_coord(p, 1),
attributes=p[2])
self._add_identifier(enumerator.name, enumerator.coord)
p[0] = enumerator

# }}}
# }}}

Expand Down
Loading