cdecl.py 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  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. All the types used in it must be defined with
  10. # typedef, or parsing will fail. The definition can be arbitrary - pycparser
  11. # doesn't really care what the type is defined to be, only that it's a type.
  12. #
  13. # For example:
  14. #
  15. # 'typedef int Node; const Node* (*ar)[10];'
  16. # =>
  17. # ar is a pointer to array[10] of pointer to const Node
  18. #
  19. # Copyright (C) 2008-2015, Eli Bendersky
  20. # License: BSD
  21. #-----------------------------------------------------------------
  22. import sys
  23. # This is not required if you've installed pycparser into
  24. # your site-packages/ with setup.py
  25. #
  26. sys.path.extend(['.', '..'])
  27. from pycparser import c_parser, c_ast
  28. def explain_c_declaration(c_decl):
  29. """ Parses the declaration in c_decl and returns a text
  30. explanation as a string.
  31. The last external node of the string is used, to allow
  32. earlier typedefs for used types.
  33. """
  34. parser = c_parser.CParser()
  35. try:
  36. node = parser.parse(c_decl, filename='<stdin>')
  37. except c_parser.ParseError:
  38. e = sys.exc_info()[1]
  39. return "Parse error:" + str(e)
  40. if (not isinstance(node, c_ast.FileAST) or
  41. not isinstance(node.ext[-1], c_ast.Decl)
  42. ):
  43. return "Not a valid declaration"
  44. return _explain_decl_node(node.ext[-1])
  45. def _explain_decl_node(decl_node):
  46. """ Receives a c_ast.Decl note and returns its explanation in
  47. English.
  48. """
  49. storage = ' '.join(decl_node.storage) + ' ' if decl_node.storage else ''
  50. return (decl_node.name +
  51. " is a " +
  52. storage +
  53. _explain_type(decl_node.type))
  54. def _explain_type(decl):
  55. """ Recursively explains a type decl node
  56. """
  57. typ = type(decl)
  58. if typ == c_ast.TypeDecl:
  59. quals = ' '.join(decl.quals) + ' ' if decl.quals else ''
  60. return quals + _explain_type(decl.type)
  61. elif typ == c_ast.Typename or typ == c_ast.Decl:
  62. return _explain_type(decl.type)
  63. elif typ == c_ast.IdentifierType:
  64. return ' '.join(decl.names)
  65. elif typ == c_ast.PtrDecl:
  66. quals = ' '.join(decl.quals) + ' ' if decl.quals else ''
  67. return quals + 'pointer to ' + _explain_type(decl.type)
  68. elif typ == c_ast.ArrayDecl:
  69. arr = 'array'
  70. if decl.dim: arr += '[%s]' % decl.dim.value
  71. return arr + " of " + _explain_type(decl.type)
  72. elif typ == c_ast.FuncDecl:
  73. if decl.args:
  74. params = [_explain_type(param) for param in decl.args.params]
  75. args = ', '.join(params)
  76. else:
  77. args = ''
  78. return ('function(%s) returning ' % (args) +
  79. _explain_type(decl.type))
  80. if __name__ == "__main__":
  81. if len(sys.argv) > 1:
  82. c_decl = sys.argv[1]
  83. else:
  84. c_decl = "char *(*(**foo[][8])())[];"
  85. print("Explaining the declaration: " + c_decl + "\n")
  86. print(explain_c_declaration(c_decl) + "\n")