blob: 7daf15b2c0f0739059e771a3a6c58fe99e5ec86b [file] [log] [blame]
Eli Bendersky3921e8e2010-05-21 09:05:39 +03001#-----------------------------------------------------------------
2# pycparser: explore_ast.py
3#
4# This example demonstrates how to "explore" the AST created by
5# pycparser to understand its structure. The AST is a n-nary tree
6# of nodes, each node having several children, each with a name.
7# Just read the code, and let the comments guide you. The lines
8# beginning with #~ can be uncommented to print out useful
9# information from the AST.
10# It helps to have the _c_ast.yaml file in front of you.
11#
12# Copyright (C) 2008, Eli Bendersky
13# License: LGPL
14#-----------------------------------------------------------------
15import sys
16
17# This is not required if you've installed pycparser into
18# your site-packages/ with setup.py
19#
20sys.path.insert(0, '..')
21
22from pycparser import c_parser, c_ast
23
24# This is some C source to parse. Note that pycparser must begin
25# at the top level of the C file, i.e. with either declarations
26# or function definitions (this is called "external declarations"
27# in C grammar lingo)
28#
29# Also, a C parser must have all the types declared in order to
30# build the correct AST. It doesn't matter what they're declared
31# to, so I've inserted the dummy typedef in the code to let the
32# parser know Hash and Node are types. You don't need to do it
33# when parsing real, correct C code.
34#
35text = r"""
36 typedef int Node, Hash;
37
38 void HashPrint(Hash* hash, void (*PrintFunc)(char*, char*))
39 {
40 unsigned int i;
41
42 if (hash == NULL || hash->heads == NULL)
43 return;
44
45 for (i = 0; i < hash->table_size; ++i)
46 {
47 Node* temp = hash->heads[i];
48
49 while (temp != NULL)
50 {
51 PrintFunc(temp->entry->key, temp->entry->value);
52 temp = temp->next;
53 }
54 }
55 }
56"""
57
58# Create the parser and ask to parse the text. parse() will throw
59# a ParseError if there's an error in the code
60#
61parser = c_parser.CParser()
62ast = parser.parse(text, filename='<none>')
63
64# Uncomment the following line to see the AST in a nice, human
65# readable way. show() is the most useful tool in exploring ASTs
66# created by pycparser. See the c_ast.py file for the options you
67# can pass it.
68#
69#~ ast.show()
70
71# OK, we've seen that the top node is FileAST. This is always the
72# top node of the AST. Its children are "external declarations",
73# and are stored in a list called ext[] (see _c_ast.yaml for the
74# names and types of Nodes and their children).
75# As you see from the printout, our AST has two Typedef children
76# and one FuncDef child.
77# Let's explore FuncDef more closely. As I've mentioned, the list
78# ext[] holds the children of FileAST. Since the function
79# definition is the third child, it's ext[2]. Uncomment the
80# following line to show it:
81#
82#~ ast.ext[2].show()
83
84# A FuncDef consists of a declaration, a list of parameter
85# declarations (for K&R style function definitions), and a body.
86# Let's focus on the body for this example. The body is of
87# type Compound, which is a placeholder for a block surrounded
88# by {} (You should be reading _c_ast.yaml parallel to this
89# explanation and seeing these things by your own eyes).
90#
91# Let's see the block's declarations:
92#
93function_body = ast.ext[2].body
94
95# The following displays the variable declarations in the function
96# body
97#
98#~ for decl in function_body.decls:
99 #~ decl.show()
100
101# We can see a single variable, i, declared to be a simple type
102# declaration of type 'unsigned int'.
103#
104# Let's look at the statemts now:
105#
106#~ for stmt in function_body.stmts:
107 #~ stmt.show()
108
109# stmts is a list, so the second element is the For statement:
110#
111for_stmt = function_body.stmts[1]
112#~ for_stmt.show()
113
114# As you can see in _c_ast.yaml, For's children are 'init, cond,
115# next' for the respective parts of the 'for' loop specifier,
116# and stmt, which is either a single stmt or a Compound if there's
117# a block.
118#
119# Let's dig deeper, to the while statement inside the for loop:
120#
121while_stmt = for_stmt.stmt.stmts[0]
122#~ while_stmt.show()
123
124# While is simpler, it only has a condition node and a stmt node.
125# The condition:
126#
127while_cond = while_stmt.cond
128#~ while_cond.show()
129
130# Note that it's a BinaryOp node - the basic constituent of
131# expressions in our AST. BinaryOp is the expression tree, with
132# left and right nodes as children. It also has the op attribute,
133# which is just the string representation of the operator.
134#
135#~ print while_cond.op
136#~ while_cond.left.show()
137#~ while_cond.right.show()
138
139#
140# That's if for the example. I hope you now see how easy it is to
141# explore the AST created by pycparser. Although on the surface it
142# is quite complex and has a lot of node types, this is the
143# inherent complexity of the C language every parser/compiler
144# designer has to cope with.
145# Using the tools provided by the c_ast package it's easy to
146# explore the structure of AST nodes and write code that processes
147# them.
148# Specifically, see the cdecl.py example for a non-trivial
149# demonstration of what you can do by recursively going through
150# the AST.
151#
152
153