Eli Bendersky | 3921e8e | 2010-05-21 09:05:39 +0300 | [diff] [blame] | 1 | #-----------------------------------------------------------------
|
| 2 | # pycparser: cdecl.py
|
| 3 | #
|
| 4 | # Example of the CDECL tool using pycparser. CDECL "explains"
|
| 5 | # C type declarations in plain English.
|
| 6 | #
|
| 7 | # The AST generated by pycparser from the given declaration is
|
| 8 | # traversed recursively to build the explanation.
|
| 9 | # Note that the declaration must be a valid external declaration
|
| 10 | # in C. All the types used in it must be defined with typedef,
|
| 11 | # or parsing will fail. The definition can be arbitrary, it isn't
|
| 12 | # really used - by pycparser must know which tokens are types.
|
| 13 | #
|
| 14 | # For example:
|
| 15 | #
|
| 16 | # 'typedef int Node; const Node* (*ar)[10];'
|
| 17 | # =>
|
| 18 | # ar is a pointer to array[10] of pointer to const Node
|
| 19 | #
|
eli.bendersky | ef29ff9 | 2010-10-29 16:25:43 +0200 | [diff] [blame^] | 20 | # Copyright (C) 2008-2010, Eli Bendersky
|
Eli Bendersky | 3921e8e | 2010-05-21 09:05:39 +0300 | [diff] [blame] | 21 | # License: LGPL
|
| 22 | #-----------------------------------------------------------------
|
| 23 | import sys
|
| 24 |
|
| 25 | # This is not required if you've installed pycparser into
|
| 26 | # your site-packages/ with setup.py
|
| 27 | #
|
| 28 | sys.path.insert(0, '..')
|
| 29 |
|
| 30 | from pycparser import c_parser, c_ast
|
| 31 | from pycparser.portability import printme
|
| 32 |
|
| 33 |
|
| 34 | def explain_c_declaration(c_decl): |
| 35 | """ Parses the declaration in c_decl and returns a text
|
| 36 | explanation as a string.
|
| 37 |
|
| 38 | The last external node of the string is used, to allow
|
| 39 | earlier typedefs for used types. |
| 40 | """
|
| 41 | parser = c_parser.CParser()
|
| 42 |
|
| 43 | try:
|
| 44 | node = parser.parse(c_decl, filename='<stdin>')
|
| 45 | except c_parser.ParseError:
|
| 46 | e = sys.exc_info()[1]
|
| 47 | return "Parse error:" + str(e)
|
| 48 |
|
| 49 | if ( not isinstance(node, c_ast.FileAST) or
|
| 50 | not isinstance(node.ext[-1], c_ast.Decl)):
|
| 51 | return "Not a valid declaration"
|
| 52 |
|
| 53 | return _explain_decl_node(node.ext[-1])
|
| 54 |
|
| 55 |
|
| 56 | def _explain_decl_node(decl_node): |
| 57 | """ Receives a c_ast.Decl note and returns its explanation in
|
| 58 | English. |
| 59 | """
|
| 60 | #~ print decl_node.show()
|
| 61 | storage = ' '.join(decl_node.storage) + ' ' if decl_node.storage else ''
|
| 62 |
|
| 63 | return (decl_node.name +
|
| 64 | " is a " +
|
| 65 | storage +
|
| 66 | _explain_type(decl_node.type))
|
| 67 |
|
| 68 |
|
| 69 | def _explain_type(decl): |
| 70 | """ Recursively explains a type decl node |
| 71 | """
|
| 72 | typ = type(decl)
|
| 73 |
|
| 74 | if typ == c_ast.TypeDecl:
|
| 75 | quals = ' '.join(decl.quals) + ' ' if decl.quals else ''
|
| 76 | return quals + _explain_type(decl.type)
|
| 77 | elif typ == c_ast.Typename or typ == c_ast.Decl:
|
| 78 | return _explain_type(decl.type)
|
| 79 | elif typ == c_ast.IdentifierType:
|
| 80 | return ' '.join(decl.names)
|
| 81 | elif typ == c_ast.PtrDecl:
|
| 82 | quals = ' '.join(decl.quals) + ' ' if decl.quals else ''
|
| 83 | return quals + 'pointer to ' + _explain_type(decl.type)
|
| 84 | elif typ == c_ast.ArrayDecl:
|
| 85 | arr = 'array'
|
| 86 | if decl.dim: arr += '[%s]' % decl.dim.value
|
| 87 |
|
| 88 | return arr + " of " + _explain_type(decl.type)
|
| 89 |
|
| 90 | elif typ == c_ast.FuncDecl:
|
| 91 | if decl.args:
|
| 92 | params = [_explain_type(param) for param in decl.args.params]
|
| 93 | args = ', '.join(params)
|
| 94 | else:
|
| 95 | args = ''
|
| 96 |
|
| 97 | return ('function(%s) returning ' % (args) +
|
| 98 | _explain_type(decl.type))
|
| 99 |
|
| 100 |
|
| 101 | if __name__ == "__main__":
|
| 102 | if len(sys.argv) > 1:
|
| 103 | c_decl = sys.argv[1]
|
| 104 | else:
|
| 105 | c_decl = "char *(*(**foo[][8])())[];"
|
| 106 |
|
| 107 | printme(["Explaining the declaration:", c_decl])
|
| 108 | printme(["\n", explain_c_declaration(c_decl)])
|