summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorHart Chu <cthesky@yeah.net>2017-02-26 21:56:44 +0800
committerEli Bendersky <eliben@users.noreply.github.com>2017-02-26 05:56:44 -0800
commitb23e2673242b943b79112e008f5fb395371ff3aa (patch)
tree58a7570d132a84087c851dce1cdb085847448923 /examples
parent8bd02c3bc1600c07bf31985dcd69cab29d7b5b27 (diff)
downloadpycparser-b23e2673242b943b79112e008f5fb395371ff3aa.tar.gz
Add support for expanding struct and typedef -- Issue 93 (#174)
* Add support for expanding struct and typedef * Make expansion return a new node instead of in-place modification
Diffstat (limited to 'examples')
-rw-r--r--examples/cdecl.py98
1 files changed, 93 insertions, 5 deletions
diff --git a/examples/cdecl.py b/examples/cdecl.py
index 39ac5e8..92ac715 100644
--- a/examples/cdecl.py
+++ b/examples/cdecl.py
@@ -12,13 +12,28 @@
#
# For example:
#
-# 'typedef int Node; const Node* (*ar)[10];'
-# =>
-# ar is a pointer to array[10] of pointer to const Node
+# c_decl = 'typedef int Node; const Node* (*ar)[10];'
+#
+# explain_c_declaration(c_decl)
+# => ar is a pointer to array[10] of pointer to const Node
+#
+# struct and typedef are expanded when according arguments are set:
+#
+# explain_c_declaration(c_decl, expand_typedef=True)
+# => ar is a pointer to array[10] of pointer to const int
+#
+# c_decl = 'struct P {int x; int y;} p;'
+#
+# explain_c_declaration(c_decl)
+# => p is a struct P
+#
+# explain_c_declaration(c_decl, expand_struct=True)
+# => p is a struct P containing {x is a int, y is a int}
#
# Eli Bendersky [http://eli.thegreenplace.net]
# License: BSD
#-----------------------------------------------------------------
+import copy
import sys
# This is not required if you've installed pycparser into
@@ -29,7 +44,7 @@ sys.path.extend(['.', '..'])
from pycparser import c_parser, c_ast
-def explain_c_declaration(c_decl):
+def explain_c_declaration(c_decl, expand_struct=False, expand_typedef=False):
""" Parses the declaration in c_decl and returns a text
explanation as a string.
@@ -49,7 +64,14 @@ def explain_c_declaration(c_decl):
):
return "Not a valid declaration"
- return _explain_decl_node(node.ext[-1])
+ try:
+ expanded = expand_struct_typedef(node.ext[-1], node,
+ expand_struct=expand_struct,
+ expand_typedef=expand_typedef)
+ except Exception as e:
+ return "Not a valid declaration: " + str(e)
+
+ return _explain_decl_node(expanded)
def _explain_decl_node(decl_node):
@@ -95,6 +117,72 @@ def _explain_type(decl):
return ('function(%s) returning ' % (args) +
_explain_type(decl.type))
+ elif typ == c_ast.Struct:
+ decls = [_explain_decl_node(mem_decl) for mem_decl in decl.decls]
+ members = ', '.join(decls)
+
+ return ('struct%s ' % (' ' + decl.name if decl.name else '') +
+ ('containing {%s}' % members if members else ''))
+
+
+def expand_struct_typedef(cdecl, file_ast, expand_struct=False, expand_typedef=False):
+ """Expand struct & typedef in context of file_ast and return a new expanded node"""
+ decl_copy = copy.deepcopy(cdecl)
+ _expand_in_place(decl_copy, file_ast, expand_struct, expand_typedef)
+ return decl_copy
+
+
+def _expand_in_place(decl, file_ast, expand_struct=False, expand_typedef=False):
+ """Recursively expand struct & typedef in place, throw Exception if
+ undeclared struct or typedef are used
+ """
+ typ = type(decl)
+
+ if typ in (c_ast.Decl, c_ast.TypeDecl, c_ast.PtrDecl, c_ast.ArrayDecl):
+ decl.type = _expand_in_place(decl.type, file_ast, expand_struct, expand_typedef)
+
+ elif typ == c_ast.Struct:
+ if not decl.decls:
+ struct = _find_struct(decl.name, file_ast)
+ if not struct:
+ raise Exception('using undeclared struct %s' % decl.name)
+ decl.decls = struct.decls
+
+ for i, mem_decl in enumerate(decl.decls):
+ decl.decls[i] = _expand_in_place(mem_decl, file_ast, expand_struct, expand_typedef)
+
+ if not expand_struct:
+ decl.decls = []
+
+ elif (typ == c_ast.IdentifierType and
+ decl.names[0] not in ('int', 'char')):
+ typedef = _find_typedef(decl.names[0], file_ast)
+ if not typedef:
+ raise Exception('using undeclared type %s' % decl.names[0])
+
+ if expand_typedef:
+ return typedef.type
+
+ return decl
+
+
+def _find_struct(name, file_ast):
+ """Receives a struct name and return declared struct object in file_ast
+ """
+ for node in file_ast.ext:
+ if (type(node) == c_ast.Decl and
+ type(node.type) == c_ast.Struct and
+ node.type.name == name):
+ return node.type
+
+
+def _find_typedef(name, file_ast):
+ """Receives a type name and return typedef object in file_ast
+ """
+ for node in file_ast.ext:
+ if type(node) == c_ast.Typedef and node.name == name:
+ return node
+
if __name__ == "__main__":
if len(sys.argv) > 1: