Skip to content

Commit 2d27fd3

Browse files
committed
Add support for multiple definition to cstruct.parse
1 parent e23fc1a commit 2d27fd3

3 files changed

Lines changed: 74 additions & 35 deletions

File tree

cstruct/__init__.py

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -134,28 +134,24 @@ def sizeof(type_: str) -> int:
134134

135135

136136
def parse(
137-
__struct__: str, __cls__: Optional[Type[AbstractCStruct]] = None, __name__: Optional[str] = None, **kargs: Dict[str, Any]
137+
__struct__: str, __cls__: Optional[Type[AbstractCStruct]] = None, **kargs: Dict[str, Any]
138138
) -> Union[Type[AbstractCStruct], Type[AbstractCEnum], None]:
139139
"""
140140
Return a new class mapping a C struct/union/enum definition.
141141
If the string does not contains any definition, return None.
142142
143+
143144
Args:
144145
__struct__ (str): definition of the struct (or union/enum) in C syntax
145146
__cls__ (type): super class - CStruct(default) or MemCStruct
146-
__name__ (str): name of the new class. If empty, a name based on the __struct__ hash is generated
147147
__byte_order__ (str): byte order, valid values are LITTLE_ENDIAN, BIG_ENDIAN, NATIVE_ORDER
148-
__is_union__ (bool): True for union, False for struct (default)
149148
150149
Returns:
151150
cls: __cls__ subclass
152151
"""
153152
if __cls__ is None:
154-
__cls__ = CStruct
155-
cls_def = parse_struct_def(__struct__, __cls__=__cls__, **kargs)
153+
__cls__ = MemCStruct
154+
cls_def = parse_struct_def(__struct__, __cls__=__cls__, process_muliple_definition=True, **kargs)
156155
if cls_def is None:
157156
return None
158-
elif cls_def['__is_enum__']:
159-
return AbstractCEnum.parse(cls_def, __name__, **kargs)
160-
else:
161-
return __cls__.parse(cls_def, __name__, **kargs)
157+
return cls_def['__cls__'].parse(cls_def, **kargs)

cstruct/abstract.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
from .field import calculate_padding, FieldType
3636
from .exceptions import CStructException
3737

38-
__all__ = ['CStructMeta', 'AbstractCStruct', "CEnumMeta", 'AbstractCEnum']
38+
__all__ = ['CStructMeta', 'AbstractCStruct', 'CEnumMeta', 'AbstractCEnum']
3939

4040

4141
class CStructMeta(ABCMeta):
@@ -138,6 +138,7 @@ def parse(
138138
del cls_kargs['__struct__']
139139
cls_kargs.update(__struct__)
140140
cls_kargs['__struct__'] = None
141+
__name__ = cls_kargs.get('__name__') or __name__
141142
if __name__ is None: # Anonymous struct
142143
__name__ = cls.__name__ + '_' + hashlib.sha1(str(__struct__).encode('utf-8')).hexdigest()
143144
cls_kargs['__anonymous__'] = True
@@ -363,6 +364,7 @@ def parse(
363364
elif isinstance(__enum__, dict):
364365
cls_kargs.update(__enum__)
365366

367+
__name__ = cls_kargs.get('__name__') or __name__
366368
if __name__ is None:
367369
__name__ = cls.__name__ + "_" + hashlib.sha1(str(__enum__).encode("utf-8")).hexdigest()
368370
cls_kargs["__anonymous__"] = True

cstruct/c_parser.py

Lines changed: 66 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -180,32 +180,55 @@ def parse_struct_def(
180180
__def__: Union[str, Tokens],
181181
__cls__: Type['AbstractCStruct'],
182182
__byte_order__: Optional[str] = None,
183+
process_muliple_definition: bool = False,
183184
**kargs: Any, # Type['AbstractCStruct'],
184185
) -> Optional[Dict[str, Any]]:
185186
# naive C struct parsing
186187
if isinstance(__def__, Tokens):
187188
tokens = __def__
188189
else:
189190
tokens = Tokens(__def__)
190-
if not tokens:
191-
return None
192-
kind = tokens.pop()
193-
if kind == 'typedef':
194-
parse_typedef(tokens, __cls__, __byte_order__)
195-
return parse_struct_def(tokens, __cls__, __byte_order__, **kargs)
196-
if kind == 'enum':
197-
return parse_enum_def(__def__, **kargs)
198-
if kind not in ['struct', 'union']:
199-
raise ParserError(f"struct, union, or enum expected - {kind}")
200-
__is_union__ = kind == 'union'
201-
vtype = tokens.pop()
202-
if tokens.get() == '{': # Named nested struct
203-
tokens.pop()
204-
return parse_struct(tokens, __cls__=__cls__, __is_union__=__is_union__, __byte_order__=__byte_order__)
205-
elif vtype == '{': # Unnamed nested struct
206-
return parse_struct(tokens, __cls__=__cls__, __is_union__=__is_union__, __byte_order__=__byte_order__)
207-
else:
208-
raise ParserError(f"{vtype} definition expected")
191+
result = None
192+
while tokens and (process_muliple_definition or not result):
193+
kind = tokens.pop()
194+
if kind == ';':
195+
pass
196+
197+
elif kind == 'typedef':
198+
if result:
199+
result['__cls__'].parse(result, **kargs)
200+
parse_typedef(tokens, __cls__, __byte_order__)
201+
202+
elif kind == 'enum':
203+
if result:
204+
result['__cls__'].parse(result, **kargs)
205+
name = tokens.pop()
206+
if tokens.get() == '{': # named enum
207+
tokens.pop() # pop "{"
208+
result = parse_enum(tokens, __name__=name)
209+
elif name == '{': # unnamed enum
210+
result = parse_enum(tokens)
211+
else:
212+
raise ParserError(f"{name} definition expected")
213+
214+
elif kind in ['struct', 'union']:
215+
if result:
216+
result['__cls__'].parse(result, **kargs)
217+
__is_union__ = kind == 'union'
218+
name = tokens.pop()
219+
if name == '{': # unnamed nested struct
220+
result = parse_struct(tokens, __cls__=__cls__, __is_union__=__is_union__, __byte_order__=__byte_order__)
221+
elif tokens.get() == '{': # Named nested struct
222+
tokens.pop() # pop "{"
223+
result = parse_struct(
224+
tokens, __cls__=__cls__, __is_union__=__is_union__, __byte_order__=__byte_order__, __name__=name
225+
)
226+
else:
227+
raise ParserError(f"{name} definition expected")
228+
229+
else:
230+
raise ParserError(f"struct, union, or enum expected - {kind}")
231+
return result
209232

210233

211234
def parse_enum_def(__def__: Union[str, Tokens], **kargs: Any) -> Optional[Dict[str, Any]]:
@@ -220,26 +243,33 @@ def parse_enum_def(__def__: Union[str, Tokens], **kargs: Any) -> Optional[Dict[s
220243
if kind not in ['enum']:
221244
raise ParserError(f"enum expected - {kind}")
222245

223-
vtype = tokens.pop()
246+
name = tokens.pop()
224247
if tokens.get() == '{': # named enum
225-
tokens.pop()
226-
return parse_enum(tokens)
227-
elif vtype == '{':
248+
tokens.pop() # pop "{"
249+
return parse_enum(tokens, __name__=name)
250+
elif name == '{': # unnamed enum
228251
return parse_enum(tokens)
229252
else:
230-
raise ParserError(f"{vtype} definition expected")
253+
raise ParserError(f"{name} definition expected")
231254

232255

233-
def parse_enum(__enum__: Union[str, Tokens], **kargs: Any) -> Optional[Dict[str, Any]]:
256+
def parse_enum(
257+
__enum__: Union[str, Tokens],
258+
__name__: Optional[str] = None,
259+
**kargs: Any,
260+
) -> Optional[Dict[str, Any]]:
234261
"""
235262
Parser for C-like enum syntax.
236263
237264
Args:
238265
__enum__: definition of the enum in C syntax
266+
__name__: enum name
239267
240268
Returns:
241269
dict: the parsed definition
242270
"""
271+
from .cenum import CEnum
272+
243273
constants: Dict[str, int] = OrderedDict()
244274

245275
if isinstance(__enum__, Tokens):
@@ -293,6 +323,8 @@ def parse_enum(__enum__: Union[str, Tokens], **kargs: Any) -> Optional[Dict[str,
293323
'__is_struct__': False,
294324
'__is_union__': False,
295325
'__is_enum__': True,
326+
'__name__': __name__,
327+
'__cls__': CEnum,
296328
}
297329
return result
298330

@@ -302,6 +334,7 @@ def parse_struct(
302334
__cls__: Type['AbstractCStruct'],
303335
__is_union__: bool = False,
304336
__byte_order__: Optional[str] = None,
337+
__name__: Optional[str] = None,
305338
**kargs: Any,
306339
) -> Dict[str, Any]:
307340
"""
@@ -312,11 +345,17 @@ def parse_struct(
312345
__cls__: base class (MemCStruct or CStruct)
313346
__is_union__: True for union, False for struct
314347
__byte_order__: byte order, valid values are LITTLE_ENDIAN, BIG_ENDIAN, NATIVE_ORDER
348+
__name__: struct/union name
315349
316350
Returns:
317351
dict: the parsed definition
318352
"""
319353
# naive C struct parsing
354+
from .abstract import AbstractCStruct
355+
from .mem_cstruct import MemCStruct
356+
357+
if __cls__ is None or __cls__ == AbstractCStruct:
358+
__cls__ = MemCStruct
320359
__is_union__ = bool(__is_union__)
321360
fields_types: Dict[str, FieldType] = OrderedDict()
322361
flexible_array: bool = False
@@ -378,5 +417,7 @@ def parse_struct(
378417
'__is_enum__': False,
379418
'__byte_order__': __byte_order__,
380419
'__alignment__': max_alignment,
420+
'__name__': __name__,
421+
'__cls__': __cls__,
381422
}
382423
return result

0 commit comments

Comments
 (0)