blob: 351efc262c1be85d834955e1df146ddfc1ce278b [file] [log] [blame]
eli.benderskyfe5c2bb2010-12-04 17:38:11 +02001#-----------------------------------------------------------------
2# pycparser: cdecl.py
3#
Eli Bendersky27797e82013-09-25 06:30:17 -07004# Example of the CDECL tool using pycparser. CDECL "explains" C type
5# declarations in plain English.
eli.benderskyfe5c2bb2010-12-04 17:38:11 +02006#
Eli Bendersky27797e82013-09-25 06:30:17 -07007# The AST generated by pycparser from the given declaration is traversed
8# recursively to build the explanation. Note that the declaration must be a
Eli Bendersky69bca702017-02-26 06:03:54 -08009# valid external declaration in C. As shown below, typedef can be optionally
10# expanded.
eli.benderskyfe5c2bb2010-12-04 17:38:11 +020011#
12# For example:
13#
Hart Chub23e2672017-02-26 21:56:44 +080014# 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#
Eli Bendersky69bca702017-02-26 06:03:54 -080019# struct and typedef can be optionally expanded:
Hart Chub23e2672017-02-26 21:56:44 +080020#
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}
eli.benderskyfe5c2bb2010-12-04 17:38:11 +020031#
Jon Dufresne1d866992018-06-26 13:49:35 -070032# Eli Bendersky [https://eli.thegreenplace.net/]
eli.bendersky84a6a632011-04-29 09:00:43 +030033# License: BSD
eli.benderskyfe5c2bb2010-12-04 17:38:11 +020034#-----------------------------------------------------------------
Hart Chub23e2672017-02-26 21:56:44 +080035import copy
eli.benderskyfe5c2bb2010-12-04 17:38:11 +020036import sys
37
38# This is not required if you've installed pycparser into
39# your site-packages/ with setup.py
40#
Benf86dea12012-02-03 06:24:55 +020041sys.path.extend(['.', '..'])
eli.benderskyfe5c2bb2010-12-04 17:38:11 +020042
43from pycparser import c_parser, c_ast
44
45
Hart Chub23e2672017-02-26 21:56:44 +080046def explain_c_declaration(c_decl, expand_struct=False, expand_typedef=False):
Eli Bendersky27797e82013-09-25 06:30:17 -070047 """ Parses the declaration in c_decl and returns a text
eli.benderskyfe5c2bb2010-12-04 17:38:11 +020048 explanation as a string.
Eli Bendersky27797e82013-09-25 06:30:17 -070049
Eli Bendersky69bca702017-02-26 06:03:54 -080050 The last external node of the string is used, to allow earlier typedefs
51 for used types.
52
53 expand_struct=True will spell out struct definitions recursively.
54 expand_typedef=True will expand typedef'd types.
eli.benderskyfe5c2bb2010-12-04 17:38:11 +020055 """
56 parser = c_parser.CParser()
Eli Bendersky27797e82013-09-25 06:30:17 -070057
eli.benderskyfe5c2bb2010-12-04 17:38:11 +020058 try:
59 node = parser.parse(c_decl, filename='<stdin>')
60 except c_parser.ParseError:
61 e = sys.exc_info()[1]
62 return "Parse error:" + str(e)
63
Eli Bendersky27797e82013-09-25 06:30:17 -070064 if (not isinstance(node, c_ast.FileAST) or
65 not isinstance(node.ext[-1], c_ast.Decl)
66 ):
eli.benderskyfe5c2bb2010-12-04 17:38:11 +020067 return "Not a valid declaration"
68
Hart Chub23e2672017-02-26 21:56:44 +080069 try:
70 expanded = expand_struct_typedef(node.ext[-1], node,
71 expand_struct=expand_struct,
72 expand_typedef=expand_typedef)
73 except Exception as e:
74 return "Not a valid declaration: " + str(e)
75
76 return _explain_decl_node(expanded)
eli.benderskyfe5c2bb2010-12-04 17:38:11 +020077
78
Eli Bendersky3921e8e2010-05-21 09:05:39 +030079def _explain_decl_node(decl_node):
eli.benderskyfe5c2bb2010-12-04 17:38:11 +020080 """ Receives a c_ast.Decl note and returns its explanation in
Eli Bendersky3921e8e2010-05-21 09:05:39 +030081 English.
eli.benderskyfe5c2bb2010-12-04 17:38:11 +020082 """
eli.benderskyfe5c2bb2010-12-04 17:38:11 +020083 storage = ' '.join(decl_node.storage) + ' ' if decl_node.storage else ''
Eli Bendersky27797e82013-09-25 06:30:17 -070084
85 return (decl_node.name +
86 " is a " +
87 storage +
eli.benderskyfe5c2bb2010-12-04 17:38:11 +020088 _explain_type(decl_node.type))
89
90
Eli Bendersky3921e8e2010-05-21 09:05:39 +030091def _explain_type(decl):
92 """ Recursively explains a type decl node
eli.benderskyfe5c2bb2010-12-04 17:38:11 +020093 """
94 typ = type(decl)
Eli Bendersky27797e82013-09-25 06:30:17 -070095
eli.benderskyfe5c2bb2010-12-04 17:38:11 +020096 if typ == c_ast.TypeDecl:
97 quals = ' '.join(decl.quals) + ' ' if decl.quals else ''
98 return quals + _explain_type(decl.type)
99 elif typ == c_ast.Typename or typ == c_ast.Decl:
100 return _explain_type(decl.type)
101 elif typ == c_ast.IdentifierType:
102 return ' '.join(decl.names)
103 elif typ == c_ast.PtrDecl:
104 quals = ' '.join(decl.quals) + ' ' if decl.quals else ''
105 return quals + 'pointer to ' + _explain_type(decl.type)
106 elif typ == c_ast.ArrayDecl:
107 arr = 'array'
108 if decl.dim: arr += '[%s]' % decl.dim.value
Eli Bendersky27797e82013-09-25 06:30:17 -0700109
eli.benderskyfe5c2bb2010-12-04 17:38:11 +0200110 return arr + " of " + _explain_type(decl.type)
Eli Bendersky27797e82013-09-25 06:30:17 -0700111
eli.benderskyfe5c2bb2010-12-04 17:38:11 +0200112 elif typ == c_ast.FuncDecl:
113 if decl.args:
114 params = [_explain_type(param) for param in decl.args.params]
115 args = ', '.join(params)
116 else:
117 args = ''
Eli Bendersky27797e82013-09-25 06:30:17 -0700118
eli.benderskyfe5c2bb2010-12-04 17:38:11 +0200119 return ('function(%s) returning ' % (args) +
120 _explain_type(decl.type))
121
Hart Chub23e2672017-02-26 21:56:44 +0800122 elif typ == c_ast.Struct:
123 decls = [_explain_decl_node(mem_decl) for mem_decl in decl.decls]
124 members = ', '.join(decls)
125
126 return ('struct%s ' % (' ' + decl.name if decl.name else '') +
127 ('containing {%s}' % members if members else ''))
128
129
Eli Bendersky69bca702017-02-26 06:03:54 -0800130def expand_struct_typedef(cdecl, file_ast,
131 expand_struct=False,
132 expand_typedef=False):
133 """Expand struct & typedef and return a new expanded node."""
Hart Chub23e2672017-02-26 21:56:44 +0800134 decl_copy = copy.deepcopy(cdecl)
135 _expand_in_place(decl_copy, file_ast, expand_struct, expand_typedef)
136 return decl_copy
137
138
139def _expand_in_place(decl, file_ast, expand_struct=False, expand_typedef=False):
Eli Bendersky69bca702017-02-26 06:03:54 -0800140 """Recursively expand struct & typedef in place, throw RuntimeError if
Hart Chub23e2672017-02-26 21:56:44 +0800141 undeclared struct or typedef are used
142 """
143 typ = type(decl)
144
145 if typ in (c_ast.Decl, c_ast.TypeDecl, c_ast.PtrDecl, c_ast.ArrayDecl):
Eli Bendersky69bca702017-02-26 06:03:54 -0800146 decl.type = _expand_in_place(decl.type, file_ast, expand_struct,
147 expand_typedef)
Hart Chub23e2672017-02-26 21:56:44 +0800148
149 elif typ == c_ast.Struct:
150 if not decl.decls:
151 struct = _find_struct(decl.name, file_ast)
152 if not struct:
Eli Bendersky69bca702017-02-26 06:03:54 -0800153 raise RuntimeError('using undeclared struct %s' % decl.name)
Hart Chub23e2672017-02-26 21:56:44 +0800154 decl.decls = struct.decls
155
156 for i, mem_decl in enumerate(decl.decls):
Eli Bendersky69bca702017-02-26 06:03:54 -0800157 decl.decls[i] = _expand_in_place(mem_decl, file_ast, expand_struct,
158 expand_typedef)
Hart Chub23e2672017-02-26 21:56:44 +0800159 if not expand_struct:
160 decl.decls = []
161
162 elif (typ == c_ast.IdentifierType and
163 decl.names[0] not in ('int', 'char')):
164 typedef = _find_typedef(decl.names[0], file_ast)
165 if not typedef:
Eli Bendersky69bca702017-02-26 06:03:54 -0800166 raise RuntimeError('using undeclared type %s' % decl.names[0])
Hart Chub23e2672017-02-26 21:56:44 +0800167
168 if expand_typedef:
169 return typedef.type
170
171 return decl
172
173
174def _find_struct(name, file_ast):
175 """Receives a struct name and return declared struct object in file_ast
176 """
177 for node in file_ast.ext:
178 if (type(node) == c_ast.Decl and
179 type(node.type) == c_ast.Struct and
180 node.type.name == name):
181 return node.type
182
183
184def _find_typedef(name, file_ast):
185 """Receives a type name and return typedef object in file_ast
186 """
187 for node in file_ast.ext:
188 if type(node) == c_ast.Typedef and node.name == name:
189 return node
190
eli.benderskyfe5c2bb2010-12-04 17:38:11 +0200191
192if __name__ == "__main__":
193 if len(sys.argv) > 1:
194 c_decl = sys.argv[1]
195 else:
196 c_decl = "char *(*(**foo[][8])())[];"
197
198 print("Explaining the declaration: " + c_decl + "\n")
Eli Bendersky27797e82013-09-25 06:30:17 -0700199 print(explain_c_declaration(c_decl) + "\n")