blob: 58721d180027edd4a951343cfb4429fe3dd4df02 [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
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.
eli.benderskyfe5c2bb2010-12-04 17:38:11 +020012#
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#
Eli Bendersky3c0c6012015-04-20 07:19:40 -070019# Copyright (C) 2008-2015, Eli Bendersky
eli.bendersky84a6a632011-04-29 09:00:43 +030020# License: BSD
eli.benderskyfe5c2bb2010-12-04 17:38:11 +020021#-----------------------------------------------------------------
22import sys
23
24# This is not required if you've installed pycparser into
25# your site-packages/ with setup.py
26#
Benf86dea12012-02-03 06:24:55 +020027sys.path.extend(['.', '..'])
eli.benderskyfe5c2bb2010-12-04 17:38:11 +020028
29from pycparser import c_parser, c_ast
30
31
Eli Bendersky3921e8e2010-05-21 09:05:39 +030032def explain_c_declaration(c_decl):
Eli Bendersky27797e82013-09-25 06:30:17 -070033 """ Parses the declaration in c_decl and returns a text
eli.benderskyfe5c2bb2010-12-04 17:38:11 +020034 explanation as a string.
Eli Bendersky27797e82013-09-25 06:30:17 -070035
eli.benderskyfe5c2bb2010-12-04 17:38:11 +020036 The last external node of the string is used, to allow
Eli Bendersky3921e8e2010-05-21 09:05:39 +030037 earlier typedefs for used types.
eli.benderskyfe5c2bb2010-12-04 17:38:11 +020038 """
39 parser = c_parser.CParser()
Eli Bendersky27797e82013-09-25 06:30:17 -070040
eli.benderskyfe5c2bb2010-12-04 17:38:11 +020041 try:
42 node = parser.parse(c_decl, filename='<stdin>')
43 except c_parser.ParseError:
44 e = sys.exc_info()[1]
45 return "Parse error:" + str(e)
46
Eli Bendersky27797e82013-09-25 06:30:17 -070047 if (not isinstance(node, c_ast.FileAST) or
48 not isinstance(node.ext[-1], c_ast.Decl)
49 ):
eli.benderskyfe5c2bb2010-12-04 17:38:11 +020050 return "Not a valid declaration"
51
52 return _explain_decl_node(node.ext[-1])
53
54
Eli Bendersky3921e8e2010-05-21 09:05:39 +030055def _explain_decl_node(decl_node):
eli.benderskyfe5c2bb2010-12-04 17:38:11 +020056 """ Receives a c_ast.Decl note and returns its explanation in
Eli Bendersky3921e8e2010-05-21 09:05:39 +030057 English.
eli.benderskyfe5c2bb2010-12-04 17:38:11 +020058 """
eli.benderskyfe5c2bb2010-12-04 17:38:11 +020059 storage = ' '.join(decl_node.storage) + ' ' if decl_node.storage else ''
Eli Bendersky27797e82013-09-25 06:30:17 -070060
61 return (decl_node.name +
62 " is a " +
63 storage +
eli.benderskyfe5c2bb2010-12-04 17:38:11 +020064 _explain_type(decl_node.type))
65
66
Eli Bendersky3921e8e2010-05-21 09:05:39 +030067def _explain_type(decl):
68 """ Recursively explains a type decl node
eli.benderskyfe5c2bb2010-12-04 17:38:11 +020069 """
70 typ = type(decl)
Eli Bendersky27797e82013-09-25 06:30:17 -070071
eli.benderskyfe5c2bb2010-12-04 17:38:11 +020072 if typ == c_ast.TypeDecl:
73 quals = ' '.join(decl.quals) + ' ' if decl.quals else ''
74 return quals + _explain_type(decl.type)
75 elif typ == c_ast.Typename or typ == c_ast.Decl:
76 return _explain_type(decl.type)
77 elif typ == c_ast.IdentifierType:
78 return ' '.join(decl.names)
79 elif typ == c_ast.PtrDecl:
80 quals = ' '.join(decl.quals) + ' ' if decl.quals else ''
81 return quals + 'pointer to ' + _explain_type(decl.type)
82 elif typ == c_ast.ArrayDecl:
83 arr = 'array'
84 if decl.dim: arr += '[%s]' % decl.dim.value
Eli Bendersky27797e82013-09-25 06:30:17 -070085
eli.benderskyfe5c2bb2010-12-04 17:38:11 +020086 return arr + " of " + _explain_type(decl.type)
Eli Bendersky27797e82013-09-25 06:30:17 -070087
eli.benderskyfe5c2bb2010-12-04 17:38:11 +020088 elif typ == c_ast.FuncDecl:
89 if decl.args:
90 params = [_explain_type(param) for param in decl.args.params]
91 args = ', '.join(params)
92 else:
93 args = ''
Eli Bendersky27797e82013-09-25 06:30:17 -070094
eli.benderskyfe5c2bb2010-12-04 17:38:11 +020095 return ('function(%s) returning ' % (args) +
96 _explain_type(decl.type))
97
98
99if __name__ == "__main__":
100 if len(sys.argv) > 1:
101 c_decl = sys.argv[1]
102 else:
103 c_decl = "char *(*(**foo[][8])())[];"
104
105 print("Explaining the declaration: " + c_decl + "\n")
Eli Bendersky27797e82013-09-25 06:30:17 -0700106 print(explain_c_declaration(c_decl) + "\n")