blob: 83f096b64be37e509c6e0994d3d78cb89eab270d [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#
eli.bendersky84a6a632011-04-29 09:00:43 +030012# Copyright (C) 2008-2011, Eli Bendersky
13# License: BSD
Eli Bendersky3921e8e2010-05-21 09:05:39 +030014#-----------------------------------------------------------------
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
eli.benderskyef29ff92010-10-29 16:25:43 +020095# The following displays the declarations and statements in the function
Eli Bendersky3921e8e2010-05-21 09:05:39 +030096# body
97#
eli.benderskyef29ff92010-10-29 16:25:43 +020098#~ for decl in function_body.block_items:
Eli Bendersky3921e8e2010-05-21 09:05:39 +030099 #~ decl.show()
100
eli.benderskyef29ff92010-10-29 16:25:43 +0200101# We can see a single variable declaration, i, declared to be a simple type
102# declaration of type 'unsigned int', followed by statements.
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300103#
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300104
eli.benderskyef29ff92010-10-29 16:25:43 +0200105# block_items is a list, so the third element is the For statement:
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300106#
eli.benderskyef29ff92010-10-29 16:25:43 +0200107for_stmt = function_body.block_items[2]
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300108#~ for_stmt.show()
109
110# As you can see in _c_ast.yaml, For's children are 'init, cond,
111# next' for the respective parts of the 'for' loop specifier,
112# and stmt, which is either a single stmt or a Compound if there's
113# a block.
114#
115# Let's dig deeper, to the while statement inside the for loop:
116#
eli.benderskyef29ff92010-10-29 16:25:43 +0200117while_stmt = for_stmt.stmt.block_items[1]
Eli Bendersky3921e8e2010-05-21 09:05:39 +0300118#~ while_stmt.show()
119
120# While is simpler, it only has a condition node and a stmt node.
121# The condition:
122#
123while_cond = while_stmt.cond
124#~ while_cond.show()
125
126# Note that it's a BinaryOp node - the basic constituent of
127# expressions in our AST. BinaryOp is the expression tree, with
128# left and right nodes as children. It also has the op attribute,
129# which is just the string representation of the operator.
130#
131#~ print while_cond.op
132#~ while_cond.left.show()
133#~ while_cond.right.show()
134
135#
136# That's if for the example. I hope you now see how easy it is to
137# explore the AST created by pycparser. Although on the surface it
138# is quite complex and has a lot of node types, this is the
139# inherent complexity of the C language every parser/compiler
140# designer has to cope with.
141# Using the tools provided by the c_ast package it's easy to
142# explore the structure of AST nodes and write code that processes
143# them.
144# Specifically, see the cdecl.py example for a non-trivial
145# demonstration of what you can do by recursively going through
146# the AST.
147#
148
149