我有一个小程序,它使用pycparser来解析C头文件。代码,unfornatuley,有点蔓延到处处理不同的案例(例如下面的例子)。
使这更像Pythonic的最佳方法是什么?我考虑过case-statements,但那些在Python中不存在。将功能拆分为更小的功能是最好的方法吗?
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 total size
return c_types.fieldDefinition(decl.name, nested)
else:
# fields w/o bitsized defined
id = nested
# using defined types, like uint32_t
if id in c_types.size_d:
size = c_types.size_d[id]
# using defined structures, like fast_ip
elif id in c_types.structs:
return c_types.structs[id]
else:
raise c_types.UnknownIdentifier(id)
# regular fields, i.e. int count;
return c_types.fieldDefinition(decl.name, int(size))
elif _type == Typename: # for function parameters
raise c_types.NotImplemented
elif _type == ArrayDecl:
#raise c_types.NotImplemented
dimval = decl.dim.value if decl.dim else ''
id = nested
# using defined types, like uint32_t
if id in c_types.size_d:
size = c_types.size_d[id]
# using defined structures, like fast_ip
elif id in c_types.structs:
return c_types.structs[id]
else:
raise c_types.UnknownIdentifier(id)
return int(dimval) * size
elif _type == PtrDecl:
raise c_types.NotImplemented
elif _type == Typedef:
id = nested
# TODO -- this is very common... refactor
if isinstance(id, c_types.structureDefinition):
# typedef struct ...
# TODO -- very similar to code above...
id.name = decl.name
return id
if isinstance(id, c_types.unionDefinition):
# typedef struct ...
# TODO -- very similar to code above...
id.name = decl.name
return id
# TODO -- change to c_types.fieldDefinition
# TODO -- this is very common... refactor
if id in c_types.size_d:
# typdef uint32 unsigned long;
c_types.size_d[decl.name] = c_types.size_d[id]
return c_types.size_d[decl.name]
elif id in c_types.structs:
return c_types.structs[id]
elif not id:
# unhandled cases, like enum
return
else:
raise c_types.UnknownIdentifier(id)
elif _type == FuncDecl:
raise c_types.NotImplementede
答案 0 :(得分:0)
使用字典构建递归下降解析器:
struct_actions = {
TypeDecl: parse_type_decl,
IdentifierType: parse_identifier_type,
Etc: parse_etc,
}
def build_struct(decl):
function = struct_actions.get(type(decl))
if function is None:
raise InvalidToken
return function(decl)
替代方案,使用更正式的递归下降解析器,使用OO构建具有异构对象的语法树:
http://www.llvmpy.org/llvmpy-doc/0.9/doc/kaleidoscope/PythonLangImpl2.html
答案 1 :(得分:0)
您正在使用类型调度。从Python 3.4开始,您可以使用dedicated decorator来执行此操作。此装饰器也以backport package的形式提供。
try:
from functools import singledispatch
except ImportError:
from singledispatch import singledispatch
@singledispatch
def build_struct(decl):
# Don't know how to do the generic version
return
@build_struct.register(TypeDecl)
def build_struct_typedecl(decl):
return build_struct(decl.type)
@build_struct.register(IdentifierType)
def build_struct_identifier(decl)
return " ".join(decl.names)
@build_struct.register(ID)
def build_struct_id(decl)
return ['ID', decl.name]
# etc.
您可以将调度更接近班级本身;导入build_struct
泛型函数并根据需要注册更多调度方法。