blob: 0e0727203be2075a1b9919d4c0d6dc88d0a2007c [file] [log] [blame]
eli.benderskyfe5c2bb2010-12-04 17:38:11 +02001#-----------------------------------------------------------------
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.bendersky84a6a632011-04-29 09:00:43 +030020# Copyright (C) 2008-2011, Eli Bendersky
21# License: BSD
eli.benderskyfe5c2bb2010-12-04 17:38:11 +020022#-----------------------------------------------------------------
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
31
32
Eli Bendersky3921e8e2010-05-21 09:05:39 +030033def explain_c_declaration(c_decl):
eli.benderskyfe5c2bb2010-12-04 17:38:11 +020034 """ Parses the declaration in c_decl and returns a text
35 explanation as a string.
36
37 The last external node of the string is used, to allow
Eli Bendersky3921e8e2010-05-21 09:05:39 +030038 earlier typedefs for used types.
eli.benderskyfe5c2bb2010-12-04 17:38:11 +020039 """
40 parser = c_parser.CParser()
41
42 try:
43 node = parser.parse(c_decl, filename='<stdin>')
44 except c_parser.ParseError:
45 e = sys.exc_info()[1]
46 return "Parse error:" + str(e)
47
48 if ( not isinstance(node, c_ast.FileAST) or
49 not isinstance(node.ext[-1], c_ast.Decl)):
50 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 """
59 #~ print decl_node.show()
60 storage = ' '.join(decl_node.storage) + ' ' if decl_node.storage else ''
61
62 return (decl_node.name +
63 " is a " +
64 storage +
65 _explain_type(decl_node.type))
66
67
Eli Bendersky3921e8e2010-05-21 09:05:39 +030068def _explain_type(decl):
69 """ Recursively explains a type decl node
eli.benderskyfe5c2bb2010-12-04 17:38:11 +020070 """
71 typ = type(decl)
72
73 if typ == c_ast.TypeDecl:
74 quals = ' '.join(decl.quals) + ' ' if decl.quals else ''
75 return quals + _explain_type(decl.type)
76 elif typ == c_ast.Typename or typ == c_ast.Decl:
77 return _explain_type(decl.type)
78 elif typ == c_ast.IdentifierType:
79 return ' '.join(decl.names)
80 elif typ == c_ast.PtrDecl:
81 quals = ' '.join(decl.quals) + ' ' if decl.quals else ''
82 return quals + 'pointer to ' + _explain_type(decl.type)
83 elif typ == c_ast.ArrayDecl:
84 arr = 'array'
85 if decl.dim: arr += '[%s]' % decl.dim.value
86
87 return arr + " of " + _explain_type(decl.type)
88
89 elif typ == c_ast.FuncDecl:
90 if decl.args:
91 params = [_explain_type(param) for param in decl.args.params]
92 args = ', '.join(params)
93 else:
94 args = ''
95
96 return ('function(%s) returning ' % (args) +
97 _explain_type(decl.type))
98
99
100if __name__ == "__main__":
101 if len(sys.argv) > 1:
102 c_decl = sys.argv[1]
103 else:
104 c_decl = "char *(*(**foo[][8])())[];"
105
106 print("Explaining the declaration: " + c_decl + "\n")
107 print(explain_c_declaration(c_decl) + "\n")
108