cdecl.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. #-----------------------------------------------------------------
  2. # pycparser: cdecl.py
  3. #
  4. # Example of the CDECL tool using pycparser. CDECL "explains" C type
  5. # declarations in plain English.
  6. #
  7. # The AST generated by pycparser from the given declaration is traversed
  8. # recursively to build the explanation. Note that the declaration must be a
  9. # valid external declaration in C. As shown below, typedef can be optionally
  10. # expanded.
  11. #
  12. # For example:
  13. #
  14. # c_decl = 'typedef int Node; const Node* (*ar)[10];'
  15. #
  16. # explain_c_declaration(c_decl)
  17. # => ar is a pointer to array[10] of pointer to const Node
  18. #
  19. # struct and typedef can be optionally expanded:
  20. #
  21. # explain_c_declaration(c_decl, expand_typedef=True)
  22. # => ar is a pointer to array[10] of pointer to const int
  23. #
  24. # c_decl = 'struct P {int x; int y;} p;'
  25. #
  26. # explain_c_declaration(c_decl)
  27. # => p is a struct P
  28. #
  29. # explain_c_declaration(c_decl, expand_struct=True)
  30. # => p is a struct P containing {x is a int, y is a int}
  31. #
  32. # Eli Bendersky [http://eli.thegreenplace.net]
  33. # License: BSD
  34. #-----------------------------------------------------------------
  35. import copy
  36. import sys
  37. # This is not required if you've installed pycparser into
  38. # your site-packages/ with setup.py
  39. #
  40. sys.path.extend(['.', '..'])
  41. from pycparser import c_parser, c_ast
  42. def explain_c_declaration(c_decl, expand_struct=False, expand_typedef=False):
  43. """ Parses the declaration in c_decl and returns a text
  44. explanation as a string.
  45. The last external node of the string is used, to allow earlier typedefs
  46. for used types.
  47. expand_struct=True will spell out struct definitions recursively.
  48. expand_typedef=True will expand typedef'd types.
  49. """
  50. parser = c_parser.CParser()
  51. try:
  52. node = parser.parse(c_decl, filename='<stdin>')
  53. except c_parser.ParseError:
  54. e = sys.exc_info()[1]
  55. return "Parse error:" + str(e)
  56. if (not isinstance(node, c_ast.FileAST) or
  57. not isinstance(node.ext[-1], c_ast.Decl)
  58. ):
  59. return "Not a valid declaration"
  60. try:
  61. expanded = expand_struct_typedef(node.ext[-1], node,
  62. expand_struct=expand_struct,
  63. expand_typedef=expand_typedef)
  64. except Exception as e:
  65. return "Not a valid declaration: " + str(e)
  66. return _explain_decl_node(expanded)
  67. def _explain_decl_node(decl_node):
  68. """ Receives a c_ast.Decl note and returns its explanation in
  69. English.
  70. """
  71. storage = ' '.join(decl_node.storage) + ' ' if decl_node.storage else ''
  72. return (decl_node.name +
  73. " is a " +
  74. storage +
  75. _explain_type(decl_node.type))
  76. def _explain_type(decl):
  77. """ Recursively explains a type decl node
  78. """
  79. typ = type(decl)
  80. if typ == c_ast.TypeDecl:
  81. quals = ' '.join(decl.quals) + ' ' if decl.quals else ''
  82. return quals + _explain_type(decl.type)
  83. elif typ == c_ast.Typename or typ == c_ast.Decl:
  84. return _explain_type(decl.type)
  85. elif typ == c_ast.IdentifierType:
  86. return ' '.join(decl.names)
  87. elif typ == c_ast.PtrDecl:
  88. quals = ' '.join(decl.quals) + ' ' if decl.quals else ''
  89. return quals + 'pointer to ' + _explain_type(decl.type)
  90. elif typ == c_ast.ArrayDecl:
  91. arr = 'array'
  92. if decl.dim: arr += '[%s]' % decl.dim.value
  93. return arr + " of " + _explain_type(decl.type)
  94. elif typ == c_ast.FuncDecl:
  95. if decl.args:
  96. params = [_explain_type(param) for param in decl.args.params]
  97. args = ', '.join(params)
  98. else:
  99. args = ''
  100. return ('function(%s) returning ' % (args) +
  101. _explain_type(decl.type))
  102. elif typ == c_ast.Struct:
  103. decls = [_explain_decl_node(mem_decl) for mem_decl in decl.decls]
  104. members = ', '.join(decls)
  105. return ('struct%s ' % (' ' + decl.name if decl.name else '') +
  106. ('containing {%s}' % members if members else ''))
  107. def expand_struct_typedef(cdecl, file_ast,
  108. expand_struct=False,
  109. expand_typedef=False):
  110. """Expand struct & typedef and return a new expanded node."""
  111. decl_copy = copy.deepcopy(cdecl)
  112. _expand_in_place(decl_copy, file_ast, expand_struct, expand_typedef)
  113. return decl_copy
  114. def _expand_in_place(decl, file_ast, expand_struct=False, expand_typedef=False):
  115. """Recursively expand struct & typedef in place, throw RuntimeError if
  116. undeclared struct or typedef are used
  117. """
  118. typ = type(decl)
  119. if typ in (c_ast.Decl, c_ast.TypeDecl, c_ast.PtrDecl, c_ast.ArrayDecl):
  120. decl.type = _expand_in_place(decl.type, file_ast, expand_struct,
  121. expand_typedef)
  122. elif typ == c_ast.Struct:
  123. if not decl.decls:
  124. struct = _find_struct(decl.name, file_ast)
  125. if not struct:
  126. raise RuntimeError('using undeclared struct %s' % decl.name)
  127. decl.decls = struct.decls
  128. for i, mem_decl in enumerate(decl.decls):
  129. decl.decls[i] = _expand_in_place(mem_decl, file_ast, expand_struct,
  130. expand_typedef)
  131. if not expand_struct:
  132. decl.decls = []
  133. elif (typ == c_ast.IdentifierType and
  134. decl.names[0] not in ('int', 'char')):
  135. typedef = _find_typedef(decl.names[0], file_ast)
  136. if not typedef:
  137. raise RuntimeError('using undeclared type %s' % decl.names[0])
  138. if expand_typedef:
  139. return typedef.type
  140. return decl
  141. def _find_struct(name, file_ast):
  142. """Receives a struct name and return declared struct object in file_ast
  143. """
  144. for node in file_ast.ext:
  145. if (type(node) == c_ast.Decl and
  146. type(node.type) == c_ast.Struct and
  147. node.type.name == name):
  148. return node.type
  149. def _find_typedef(name, file_ast):
  150. """Receives a type name and return typedef object in file_ast
  151. """
  152. for node in file_ast.ext:
  153. if type(node) == c_ast.Typedef and node.name == name:
  154. return node
  155. if __name__ == "__main__":
  156. if len(sys.argv) > 1:
  157. c_decl = sys.argv[1]
  158. else:
  159. c_decl = "char *(*(**foo[][8])())[];"
  160. print("Explaining the declaration: " + c_decl + "\n")
  161. print(explain_c_declaration(c_decl) + "\n")