snippetpythonMinor
Using pycparser to parse C header files
Viewed 0 times
headerparsefilespycparserusing
Problem
I have a small program which makes uses of pycparser to parse C header files. The code, unfortunately, kinda sprawls out everywhere to handle the different cases (example below).
What's the best way to make this more Pythonic? I thought about case-statements, but those don't exist in Python. Is splitting the function into smaller functions the best approach?
```
def build_struct(decl):
""" Recursively builds a structure from external definition.
"""
_type = type(decl)
if _type == TypeDecl:
return build_struct(decl.type)
elif _type == IdentifierType:
return " ".join(decl.names)
elif _type == ID:
return ['ID', decl.name]
elif _type == Struct:
struct = c_types.structureDefinition()
for d in decl.decls:
field = build_struct(d)
struct.add_field(field)
return struct
elif _type == Union:
union = c_types.unionDefinition()
for d in decl.decls:
field = build_struct(d)
union.add_field(field)
return union
elif _type == Enum:
# not implemented yet... but don't raise an exception
# unsure if there is any value in supporting enums
return
else:
nested = build_struct(decl.type)
if _type == Decl:
if decl.bitsize:
# fields with bitsize defined (i.e. valid:1)
return c_types.fieldDefinition(decl.name,
int(decl.bitsize.value))
elif isinstance(nested, c_types.structureDefinition):
# if it's a structure, assign it's name
nested.name = decl.name
return nested
elif isinstance(nested, c_types.unionDefinition):
# if it's a union, assign it's name
nested.name = decl.name
return nested
elif isinstance(nested, int):
# if it's an array, we will just return the tot
What's the best way to make this more Pythonic? I thought about case-statements, but those don't exist in Python. Is splitting the function into smaller functions the best approach?
```
def build_struct(decl):
""" Recursively builds a structure from external definition.
"""
_type = type(decl)
if _type == TypeDecl:
return build_struct(decl.type)
elif _type == IdentifierType:
return " ".join(decl.names)
elif _type == ID:
return ['ID', decl.name]
elif _type == Struct:
struct = c_types.structureDefinition()
for d in decl.decls:
field = build_struct(d)
struct.add_field(field)
return struct
elif _type == Union:
union = c_types.unionDefinition()
for d in decl.decls:
field = build_struct(d)
union.add_field(field)
return union
elif _type == Enum:
# not implemented yet... but don't raise an exception
# unsure if there is any value in supporting enums
return
else:
nested = build_struct(decl.type)
if _type == Decl:
if decl.bitsize:
# fields with bitsize defined (i.e. valid:1)
return c_types.fieldDefinition(decl.name,
int(decl.bitsize.value))
elif isinstance(nested, c_types.structureDefinition):
# if it's a structure, assign it's name
nested.name = decl.name
return nested
elif isinstance(nested, c_types.unionDefinition):
# if it's a union, assign it's name
nested.name = decl.name
return nested
elif isinstance(nested, int):
# if it's an array, we will just return the tot
Solution
I don't think you're going to fundamentally be able to solve the sprawl, as you have a problem composed of lots of small details. These won't go away no matter how well you organize them, but there are options that help you organize them in ways with lesser algorithmic performance hits.
If you can use a version of python with PEP-443 there are some further alternatives, but assuming you don't have single dispatch support in your python (I believe only alphas/betas have been released yet), or you want to do things manually, it's quite feasible to implement this using a dict mapping types to functions as alternative to the if/elif tree or missing switch statement. The outer one could look something like this:
I'm not fully satisfied with the lambdas, even though I chose them for shorter code length. Most of why this code looks shorter is due to not implementing the nested half of your original code. But I do think I prefer the readability for the most part.
If you can use a version of python with PEP-443 there are some further alternatives, but assuming you don't have single dispatch support in your python (I believe only alphas/betas have been released yet), or you want to do things manually, it's quite feasible to implement this using a dict mapping types to functions as alternative to the if/elif tree or missing switch statement. The outer one could look something like this:
def build_struct(decl):
builder = build_struct.type_builder.get(type(decl))
if builder:
return builder(decl)
nested = build_struct(decl.type)
builder = build_struct.nested_type_builder.get(type(decl))
if builder:
return builder(decl, nested)
build_struct.type_builder = {
TypeDecl: lambda d: build_struct(d.type),
IdentifierType: lambda d: " ".join(d.names),
ID: lambda d: ["ID", decl.name],
Struct: lambda d: build_definition(d, c_types.structureDefinition()),
Union: lambda d: build_definition(d, c_types.unionDefinition()),
Enum: lambda d: None, # XXX: let Enums be ignored silently
}
def build_definition(decl, definition):
for d in decl.decls:
definition.add_field(build_struct(d))
return definition
build_struct.nested_type_builder = {
...
}I'm not fully satisfied with the lambdas, even though I chose them for shorter code length. Most of why this code looks shorter is due to not implementing the nested half of your original code. But I do think I prefer the readability for the most part.
Code Snippets
def build_struct(decl):
builder = build_struct.type_builder.get(type(decl))
if builder:
return builder(decl)
nested = build_struct(decl.type)
builder = build_struct.nested_type_builder.get(type(decl))
if builder:
return builder(decl, nested)
build_struct.type_builder = {
TypeDecl: lambda d: build_struct(d.type),
IdentifierType: lambda d: " ".join(d.names),
ID: lambda d: ["ID", decl.name],
Struct: lambda d: build_definition(d, c_types.structureDefinition()),
Union: lambda d: build_definition(d, c_types.unionDefinition()),
Enum: lambda d: None, # XXX: let Enums be ignored silently
}
def build_definition(decl, definition):
for d in decl.decls:
definition.add_field(build_struct(d))
return definition
build_struct.nested_type_builder = {
...
}Context
StackExchange Code Review Q#37348, answer score: 3
Revisions (0)
No revisions yet.