blob: 3df6efc2e2786375476583d4c5bd553ebe61ff2e [file] [log] [blame]
Eli Bendersky3921e8e2010-05-21 09:05:39 +03001#-----------------------------------------------------------------
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.benderskyef29ff92010-10-29 16:25:43 +020020# Copyright (C) 2008-2010, Eli Bendersky
Eli Bendersky3921e8e2010-05-21 09:05:39 +030021# License: LGPL
22#-----------------------------------------------------------------
23import sys
24
25# This is not required if you've installed pycparser into
26# your site-packages/ with setup.py
27#
28sys.path.insert(0, '..')
29
30from pycparser import c_parser, c_ast
31from pycparser.portability import printme
32
33
34def 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
56def _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
69def _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
101if __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)])