To get the exact type of identifiers in the AST you - just like Leo in the Inception movie - "need to go deeper". 8]
Here is an extension of your visit_FuncDef function to demonstrate how different items of the AST can be reached from a given point:
def visit_FuncDef(self, node):
#node.decl.type.args.params
print "Function name is", node.decl.name, "at", node.decl.coord
print " It's parameters name and type is (are)"
for params in (node.decl.type.args.params): ###FuncDef/Decl/FuncDecl/ParamList
# Assign parameter name
pname = params.name ###ParamList/Decl
# Parameter is a pointer type of some kind
if type(params.type) is c_ast.PtrDecl:
# Parameter is a pointer to a pointer type - double indirection
if type(params.type.type) is c_ast.PtrDecl:
ptype = params.type.type.type.type.names ###Decl/PtrDecl/PtrDecl/TypeDecl/IdentifierType
# There is no double indirection
else:
# Parameter is a pointer to a function type
if type(params.type.type) is c_ast.FuncDecl:
pname = str(params.type.type.type.type.names) + ' (*' ###Decl/PtrDecl/TypeDecl/IdentifierType
pname = pname + params.type.type.type.declname + ')' ###Decl/PtrDecl/FuncDecl/TypeDecl
ptype = ''
for subparams in params.type.type.args.params: ###Decl/PtrDecl/FuncDecl/ParamList
ptype = ptype + str(subparams.type.type.type.names) ###Typename/PtrDecl/TypeDecl/IdentifierType
# Parameter is a pointer type - single indirection
else:
ptype = params.type.type.type.names ###Decl/PtrDecl/TypeDecl/IdentifierType
# Parameter is a variable
elif type(params.type.type) is c_ast.IdentifierType:
ptype = params.type.type.names
print " ", pname, ptype
With the comments I tried to explain which type of parameter the code is looking for. With the triple hashmarks I marked the actual location in the AST tree.
As an example here is a part of the AST tree of the function HashPrint() which contains a pointer to a function as a parameter:
FuncDef:
Decl: HashPrint, [], [], []
FuncDecl:
ParamList:
Decl: hash, [], [], []
PtrDecl: []
TypeDecl: hash, []
IdentifierType: ['Hash']
Decl: PrintFunc, [], [], []
PtrDecl: []
FuncDecl:
ParamList:
Typename: None, []
PtrDecl: []
TypeDecl: None, []
IdentifierType: ['char']
Typename: None, []
PtrDecl: []
TypeDecl: None, []
IdentifierType: ['char']
TypeDecl: PrintFunc, []
IdentifierType: ['void']
TypeDecl: HashPrint, []
IdentifierType: ['void']
Compound:
And finally here is the output of the function:
Function name is hash_func at c_files/hash.c:32
It's parameters name and type is (are)
str ['char']
table_size ['unsigned', 'int']
Function name is HashCreate at c_files/hash.c:44
It's parameters name and type is (are)
hash ['Hash']
table_size ['unsigned', 'int']
Function name is HashInsert at c_files/hash.c:77
It's parameters name and type is (are)
hash ['Hash']
entry ['Entry']
Function name is HashFind at c_files/hash.c:100
It's parameters name and type is (are)
hash ['Hash']
key ['char']
Function name is HashRemove at c_files/hash.c:117
It's parameters name and type is (are)
hash ['Hash']
key ['char']
Function name is HashPrint at c_files/hash.c:149
It's parameters name and type is (are)
hash ['Hash']
['void'] (*PrintFunc) ['char']['char']
Function name is HashDestroy at c_files/hash.c:170
It's parameters name and type is (are)
hash ['Hash']
This works specifically for the example file hash.c. I just wanted you to get an insight on how to access specific parts of the AST from one point.
Best practice is to save the AST to a file:
file = open('ast.txt', 'w')
ast.show(buf=file)
file.close()
then to compare the AST with _c_ast.cfg to see what kind of properties each node have so that you can "go deeper" in the tree.