107 lines
3.2 KiB
Python
107 lines
3.2 KiB
Python
#-----------------------------------------------------------------
|
|
# pycparser: cdecl.py
|
|
#
|
|
# Example of the CDECL tool using pycparser. CDECL "explains"
|
|
# C type declarations in plain English.
|
|
#
|
|
# The AST generated by pycparser from the given declaration is
|
|
# traversed recursively to build the explanation.
|
|
# Note that the declaration must be a valid external declaration
|
|
# in C. All the types used in it must be defined with typedef,
|
|
# or parsing will fail. The definition can be arbitrary, it isn't
|
|
# really used - by pycparser must know which tokens are types.
|
|
#
|
|
# For example:
|
|
#
|
|
# 'typedef int Node; const Node* (*ar)[10];'
|
|
# =>
|
|
# ar is a pointer to array[10] of pointer to const Node
|
|
#
|
|
# Copyright (C) 2008, Eli Bendersky
|
|
# License: LGPL
|
|
#-----------------------------------------------------------------
|
|
import sys
|
|
|
|
# This is not required if you've installed pycparser into
|
|
# your site-packages/ with setup.py
|
|
#
|
|
sys.path.insert(0, '..')
|
|
|
|
from pycparser import c_parser, c_ast
|
|
|
|
|
|
def explain_c_declaration(c_decl):
|
|
""" Parses the declaration in c_decl and returns a text
|
|
explanation as a string.
|
|
|
|
The last external node of the string is used, to allow
|
|
earlier typedefs for used types.
|
|
"""
|
|
parser = c_parser.CParser()
|
|
|
|
try:
|
|
node = parser.parse(c_decl, filename='<stdin>')
|
|
except c_parser.ParseError, e:
|
|
return None
|
|
|
|
if ( not isinstance(node, c_ast.FileAST) or
|
|
not isinstance(node.ext[-1], c_ast.Decl)):
|
|
return None
|
|
|
|
return _explain_decl_node(node.ext[-1])
|
|
|
|
|
|
def _explain_decl_node(decl_node):
|
|
""" Receives a c_ast.Decl note and returns its explanation in
|
|
English.
|
|
"""
|
|
#~ print decl_node.show()
|
|
storage = ' '.join(decl_node.storage) + ' ' if decl_node.storage else ''
|
|
|
|
return (decl_node.name +
|
|
" is a " +
|
|
storage +
|
|
_explain_type(decl_node.type))
|
|
|
|
|
|
def _explain_type(decl):
|
|
""" Recursively explains a type decl node
|
|
"""
|
|
typ = type(decl)
|
|
|
|
if typ == c_ast.TypeDecl:
|
|
quals = ' '.join(decl.quals) + ' ' if decl.quals else ''
|
|
return quals + _explain_type(decl.type)
|
|
elif typ == c_ast.Typename or typ == c_ast.Decl:
|
|
return _explain_type(decl.type)
|
|
elif typ == c_ast.IdentifierType:
|
|
return ' '.join(decl.names)
|
|
elif typ == c_ast.PtrDecl:
|
|
quals = ' '.join(decl.quals) + ' ' if decl.quals else ''
|
|
return quals + 'pointer to ' + _explain_type(decl.type)
|
|
elif typ == c_ast.ArrayDecl:
|
|
arr = 'array'
|
|
if decl.dim: arr += '[%s]' % decl.dim.value
|
|
|
|
return arr + " of " + _explain_type(decl.type)
|
|
|
|
elif typ == c_ast.FuncDecl:
|
|
if decl.args:
|
|
params = [_explain_type(param) for param in decl.args.params]
|
|
args = ', '.join(params)
|
|
else:
|
|
args = ''
|
|
|
|
return ('function(%s) returning ' % (args) +
|
|
_explain_type(decl.type))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
if len(sys.argv) > 1:
|
|
c_decl = sys.argv[1]
|
|
else:
|
|
c_decl = "char *(*(**foo[][8])())[];"
|
|
|
|
print "Explaining the declaration:", c_decl
|
|
print "\n", explain_c_declaration(c_decl)
|