releasing version 2.01 - removed yaml dependency, fix installation problems
diff --git a/.hgignore b/.hgignore
index d6574a8..a666b98 100644
--- a/.hgignore
+++ b/.hgignore
@@ -3,6 +3,7 @@
 *.pyc
 tests/parser.out
 tests/*tab.py
+build
 
 
 
diff --git a/MANIFEST.in b/MANIFEST.in
index 22fa7fb..91b4533 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,6 +1,6 @@
 recursive-include examples *.c *.h *.py

 recursive-include tests *.c *.h *.py

-recursive-include pycparser *.py *.yaml

+recursive-include pycparser *.py *.cfg

 include utils/*.exe

 include utils/fake_libc_include/*.h

 include README.*

diff --git a/README.html b/README.html
index 3c4b4ff..3480054 100644
--- a/README.html
+++ b/README.html
@@ -1,523 +1,526 @@
-<?xml version="1.0" encoding="utf-8" ?>

-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">

-<head>

-<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

-<meta name="generator" content="Docutils 0.6: http://docutils.sourceforge.net/" />

-<title>pycparser v2.00</title>

-<meta name="author" content="Eli Bendersky" />

-<style type="text/css">

-

-/*

-:Author: David Goodger (goodger@python.org)

-:Id: $Id: html4css1.css 5951 2009-05-18 18:03:10Z milde $

-:Copyright: This stylesheet has been placed in the public domain.

-

-Default cascading style sheet for the HTML output of Docutils.

-

-See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to

-customize this style sheet.

-*/

-

-/* used to remove borders from tables and images */

-.borderless, table.borderless td, table.borderless th {

-  border: 0 }

-

-table.borderless td, table.borderless th {

-  /* Override padding for "table.docutils td" with "! important".

-     The right padding separates the table cells. */

-  padding: 0 0.5em 0 0 ! important }

-

-.first {

-  /* Override more specific margin styles with "! important". */

-  margin-top: 0 ! important }

-

-.last, .with-subtitle {

-  margin-bottom: 0 ! important }

-

-.hidden {

-  display: none }

-

-a.toc-backref {

-  text-decoration: none ;

-  color: black }

-

-blockquote.epigraph {

-  margin: 2em 5em ; }

-

-dl.docutils dd {

-  margin-bottom: 0.5em }

-

-/* Uncomment (and remove this text!) to get bold-faced definition list terms

-dl.docutils dt {

-  font-weight: bold }

-*/

-

-div.abstract {

-  margin: 2em 5em }

-

-div.abstract p.topic-title {

-  font-weight: bold ;

-  text-align: center }

-

-div.admonition, div.attention, div.caution, div.danger, div.error,

-div.hint, div.important, div.note, div.tip, div.warning {

-  margin: 2em ;

-  border: medium outset ;

-  padding: 1em }

-

-div.admonition p.admonition-title, div.hint p.admonition-title,

-div.important p.admonition-title, div.note p.admonition-title,

-div.tip p.admonition-title {

-  font-weight: bold ;

-  font-family: sans-serif }

-

-div.attention p.admonition-title, div.caution p.admonition-title,

-div.danger p.admonition-title, div.error p.admonition-title,

-div.warning p.admonition-title {

-  color: red ;

-  font-weight: bold ;

-  font-family: sans-serif }

-

-/* Uncomment (and remove this text!) to get reduced vertical space in

-   compound paragraphs.

-div.compound .compound-first, div.compound .compound-middle {

-  margin-bottom: 0.5em }

-

-div.compound .compound-last, div.compound .compound-middle {

-  margin-top: 0.5em }

-*/

-

-div.dedication {

-  margin: 2em 5em ;

-  text-align: center ;

-  font-style: italic }

-

-div.dedication p.topic-title {

-  font-weight: bold ;

-  font-style: normal }

-

-div.figure {

-  margin-left: 2em ;

-  margin-right: 2em }

-

-div.footer, div.header {

-  clear: both;

-  font-size: smaller }

-

-div.line-block {

-  display: block ;

-  margin-top: 1em ;

-  margin-bottom: 1em }

-

-div.line-block div.line-block {

-  margin-top: 0 ;

-  margin-bottom: 0 ;

-  margin-left: 1.5em }

-

-div.sidebar {

-  margin: 0 0 0.5em 1em ;

-  border: medium outset ;

-  padding: 1em ;

-  background-color: #ffffee ;

-  width: 40% ;

-  float: right ;

-  clear: right }

-

-div.sidebar p.rubric {

-  font-family: sans-serif ;

-  font-size: medium }

-

-div.system-messages {

-  margin: 5em }

-

-div.system-messages h1 {

-  color: red }

-

-div.system-message {

-  border: medium outset ;

-  padding: 1em }

-

-div.system-message p.system-message-title {

-  color: red ;

-  font-weight: bold }

-

-div.topic {

-  margin: 2em }

-

-h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,

-h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {

-  margin-top: 0.4em }

-

-h1.title {

-  text-align: center }

-

-h2.subtitle {

-  text-align: center }

-

-hr.docutils {

-  width: 75% }

-

-img.align-left, .figure.align-left{

-  clear: left ;

-  float: left ;

-  margin-right: 1em }

-

-img.align-right, .figure.align-right {

-  clear: right ;

-  float: right ;

-  margin-left: 1em }

-

-.align-left {

-  text-align: left }

-

-.align-center {

-  clear: both ;

-  text-align: center }

-

-.align-right {

-  text-align: right }

-

-/* reset inner alignment in figures */

-div.align-right {

-  text-align: left }

-

-/* div.align-center * { */

-/*   text-align: left } */

-

-ol.simple, ul.simple {

-  margin-bottom: 1em }

-

-ol.arabic {

-  list-style: decimal }

-

-ol.loweralpha {

-  list-style: lower-alpha }

-

-ol.upperalpha {

-  list-style: upper-alpha }

-

-ol.lowerroman {

-  list-style: lower-roman }

-

-ol.upperroman {

-  list-style: upper-roman }

-

-p.attribution {

-  text-align: right ;

-  margin-left: 50% }

-

-p.caption {

-  font-style: italic }

-

-p.credits {

-  font-style: italic ;

-  font-size: smaller }

-

-p.label {

-  white-space: nowrap }

-

-p.rubric {

-  font-weight: bold ;

-  font-size: larger ;

-  color: maroon ;

-  text-align: center }

-

-p.sidebar-title {

-  font-family: sans-serif ;

-  font-weight: bold ;

-  font-size: larger }

-

-p.sidebar-subtitle {

-  font-family: sans-serif ;

-  font-weight: bold }

-

-p.topic-title {

-  font-weight: bold }

-

-pre.address {

-  margin-bottom: 0 ;

-  margin-top: 0 ;

-  font: inherit }

-

-pre.literal-block, pre.doctest-block {

-  margin-left: 2em ;

-  margin-right: 2em }

-

-span.classifier {

-  font-family: sans-serif ;

-  font-style: oblique }

-

-span.classifier-delimiter {

-  font-family: sans-serif ;

-  font-weight: bold }

-

-span.interpreted {

-  font-family: sans-serif }

-

-span.option {

-  white-space: nowrap }

-

-span.pre {

-  white-space: pre }

-

-span.problematic {

-  color: red }

-

-span.section-subtitle {

-  /* font-size relative to parent (h1..h6 element) */

-  font-size: 80% }

-

-table.citation {

-  border-left: solid 1px gray;

-  margin-left: 1px }

-

-table.docinfo {

-  margin: 2em 4em }

-

-table.docutils {

-  margin-top: 0.5em ;

-  margin-bottom: 0.5em }

-

-table.footnote {

-  border-left: solid 1px black;

-  margin-left: 1px }

-

-table.docutils td, table.docutils th,

-table.docinfo td, table.docinfo th {

-  padding-left: 0.5em ;

-  padding-right: 0.5em ;

-  vertical-align: top }

-

-table.docutils th.field-name, table.docinfo th.docinfo-name {

-  font-weight: bold ;

-  text-align: left ;

-  white-space: nowrap ;

-  padding-left: 0 }

-

-h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,

-h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {

-  font-size: 100% }

-

-ul.auto-toc {

-  list-style-type: none }

-

-</style>

-</head>

-<body>

-<div class="document" id="pycparser-v2-00">

-<h1 class="title">pycparser v2.00</h1>

-<table class="docinfo" frame="void" rules="none">

-<col class="docinfo-name" />

-<col class="docinfo-content" />

-<tbody valign="top">

-<tr><th class="docinfo-name">Author:</th>

-<td><a class="first reference external" href="http://eli.thegreenplace.net">Eli Bendersky</a></td></tr>

-</tbody>

-</table>

-<div class="contents topic" id="contents">

-<p class="topic-title first">Contents</p>

-<ul class="auto-toc simple">

-<li><a class="reference internal" href="#introduction" id="id2">1&nbsp;&nbsp;&nbsp;Introduction</a><ul class="auto-toc">

-<li><a class="reference internal" href="#what-is-pycparser" id="id3">1.1&nbsp;&nbsp;&nbsp;What is pycparser?</a></li>

-<li><a class="reference internal" href="#what-is-it-good-for" id="id4">1.2&nbsp;&nbsp;&nbsp;What is it good for?</a></li>

-<li><a class="reference internal" href="#which-version-of-c-does-pycparser-support" id="id5">1.3&nbsp;&nbsp;&nbsp;Which version of C does pycparser support?</a></li>

-<li><a class="reference internal" href="#what-grammar-does-pycparser-follow" id="id6">1.4&nbsp;&nbsp;&nbsp;What grammar does pycparser follow?</a></li>

-<li><a class="reference internal" href="#what-is-an-ast" id="id7">1.5&nbsp;&nbsp;&nbsp;What is an AST?</a></li>

-<li><a class="reference internal" href="#how-is-pycparser-licensed" id="id8">1.6&nbsp;&nbsp;&nbsp;How is pycparser licensed?</a></li>

-<li><a class="reference internal" href="#contact-details" id="id9">1.7&nbsp;&nbsp;&nbsp;Contact details</a></li>

-</ul>

-</li>

-<li><a class="reference internal" href="#installing" id="id10">2&nbsp;&nbsp;&nbsp;Installing</a><ul class="auto-toc">

-<li><a class="reference internal" href="#prerequisites" id="id11">2.1&nbsp;&nbsp;&nbsp;Prerequisites</a></li>

-<li><a class="reference internal" href="#installation-process" id="id12">2.2&nbsp;&nbsp;&nbsp;Installation process</a></li>

-</ul>

-</li>

-<li><a class="reference internal" href="#using" id="id13">3&nbsp;&nbsp;&nbsp;Using</a><ul class="auto-toc">

-<li><a class="reference internal" href="#interaction-with-the-c-preprocessor" id="id14">3.1&nbsp;&nbsp;&nbsp;Interaction with the C preprocessor</a></li>

-<li><a class="reference internal" href="#what-about-the-standard-c-library-headers" id="id15">3.2&nbsp;&nbsp;&nbsp;What about the standard C library headers?</a></li>

-<li><a class="reference internal" href="#basic-usage" id="id16">3.3&nbsp;&nbsp;&nbsp;Basic usage</a></li>

-<li><a class="reference internal" href="#advanced-usage" id="id17">3.4&nbsp;&nbsp;&nbsp;Advanced usage</a></li>

-</ul>

-</li>

-<li><a class="reference internal" href="#modifying" id="id18">4&nbsp;&nbsp;&nbsp;Modifying</a></li>

-<li><a class="reference internal" href="#package-contents" id="id19">5&nbsp;&nbsp;&nbsp;Package contents</a></li>

-<li><a class="reference internal" href="#contributors" id="id20">6&nbsp;&nbsp;&nbsp;Contributors</a></li>

-<li><a class="reference internal" href="#changelog" id="id21">7&nbsp;&nbsp;&nbsp;Changelog</a></li>

-</ul>

-</div>

-<div class="section" id="introduction">

-<h1>1&nbsp;&nbsp;&nbsp;Introduction</h1>

-<div class="section" id="what-is-pycparser">

-<h2>1.1&nbsp;&nbsp;&nbsp;What is pycparser?</h2>

-<p><tt class="docutils literal"><span class="pre">pycparser</span></tt> is a parser for the C language, written in pure Python. It is a module designed to be easily integrated into applications that need to parse C source code.</p>

-</div>

-<div class="section" id="what-is-it-good-for">

-<h2>1.2&nbsp;&nbsp;&nbsp;What is it good for?</h2>

-<p>Anything that needs C code to be parsed. The following are some uses for <tt class="docutils literal"><span class="pre">pycparser</span></tt>, taken from real user reports:</p>

-<ul class="simple">

-<li>C code obfuscator</li>

-<li>Front-end for various specialized C compilers</li>

-<li>Static code checker</li>

-<li>Automatic unit-test discovery</li>

-<li>Adding specialized extensions to the C language</li>

-</ul>

-<p><tt class="docutils literal"><span class="pre">pycparser</span></tt> is unique in the sense that it's written in pure Python - a very high level language that's easy to experiment with and tweak. To people familiar with Lex and Yacc, <tt class="docutils literal"><span class="pre">pycparser</span></tt>'s code will be simple to understand.</p>

-</div>

-<div class="section" id="which-version-of-c-does-pycparser-support">

-<h2>1.3&nbsp;&nbsp;&nbsp;Which version of C does pycparser support?</h2>

-<p><tt class="docutils literal"><span class="pre">pycparser</span></tt> aims to support the full C99 language (according to the standard ISO/IEC 9899). This is a new feature in the version 2.x series - earlier versions only supported C89. For more information on the change, read <a class="reference external" href="http://code.google.com/p/pycparser/wiki/C99support">this wiki page</a>.</p>

-<p><tt class="docutils literal"><span class="pre">pycparser</span></tt> doesn't support any GCC extensions.</p>

-</div>

-<div class="section" id="what-grammar-does-pycparser-follow">

-<h2>1.4&nbsp;&nbsp;&nbsp;What grammar does pycparser follow?</h2>

-<p><tt class="docutils literal"><span class="pre">pycparser</span></tt> very closely follows the C grammar provided in the end of the C99 standard document</p>

-</div>

-<div class="section" id="what-is-an-ast">

-<h2>1.5&nbsp;&nbsp;&nbsp;What is an AST?</h2>

-<p><a class="reference external" href="http://en.wikipedia.org/wiki/Abstract_syntax_tree">AST</a> - Abstract Syntax Tree. It is a tree representation of the syntax of source code - a convenient hierarchical data structure that's built from the code and is readily suitable for exploration and manipulation.</p>

-</div>

-<div class="section" id="how-is-pycparser-licensed">

-<h2>1.6&nbsp;&nbsp;&nbsp;How is pycparser licensed?</h2>

-<p><a class="reference external" href="http://www.gnu.org/licenses/lgpl.html">LGPL</a></p>

-</div>

-<div class="section" id="contact-details">

-<h2>1.7&nbsp;&nbsp;&nbsp;Contact details</h2>

-<p>Drop me an email to <a class="reference external" href="mailto:eliben&#64;gmail.com">eliben&#64;gmail.com</a> for any questions regarding <tt class="docutils literal"><span class="pre">pycparser</span></tt>. For reporting problems with <tt class="docutils literal"><span class="pre">pycparser</span></tt> or submitting feature requests, the best way is to open an issue on the <a class="reference external" href="http://code.google.com/p/pycparser/">pycparser page at Google Code</a>.</p>

-</div>

-</div>

-<div class="section" id="installing">

-<h1>2&nbsp;&nbsp;&nbsp;Installing</h1>

-<div class="section" id="prerequisites">

-<h2>2.1&nbsp;&nbsp;&nbsp;Prerequisites</h2>

-<ul class="simple">

-<li><tt class="docutils literal"><span class="pre">pycparser</span></tt> was tested on Python 2.5, 2.6 and 3.1, on both Linux and Windows</li>

-<li><tt class="docutils literal"><span class="pre">pycparser</span></tt> uses the PLY module for the actual lexer and parser construction. Install PLY version 3.3 (earlier versions work at least since 2.5) from <a class="reference external" href="http://www.dabeaz.com/ply/">its website</a>.</li>

-<li>If you want to modify <tt class="docutils literal"><span class="pre">pycparser</span></tt>'s code, you'll need to install <a class="reference external" href="http://pyyaml.org/">PyYAML</a>, since it's used by <tt class="docutils literal"><span class="pre">pycparser</span></tt> to store the AST configuration in a YAML file.</li>

-</ul>

-</div>

-<div class="section" id="installation-process">

-<h2>2.2&nbsp;&nbsp;&nbsp;Installation process</h2>

-<p>Installing <tt class="docutils literal"><span class="pre">pycparser</span></tt> is very simple. Once you download it from its <a class="reference external" href="http://code.google.com/p/pycparser/">website</a> and unzip the package, you just have to execute the standard <tt class="docutils literal"><span class="pre">python</span> <span class="pre">setup.py</span> <span class="pre">install</span></tt>. The setup script will then place the <tt class="docutils literal"><span class="pre">pycparser</span></tt> module into <tt class="docutils literal"><span class="pre">site-packages</span></tt> in your Python's installation library.</p>

-<p>It's recommended to run <tt class="docutils literal"><span class="pre">_build_tables.py</span></tt> in the <tt class="docutils literal"><span class="pre">pycparser</span></tt> code directory to make sure the parsing tables of PLY are pre-generated. This can make your code run faster.</p>

-</div>

-</div>

-<div class="section" id="using">

-<h1>3&nbsp;&nbsp;&nbsp;Using</h1>

-<div class="section" id="interaction-with-the-c-preprocessor">

-<h2>3.1&nbsp;&nbsp;&nbsp;Interaction with the C preprocessor</h2>

-<p>In order to be compilable, C code must be preprocessed by the C preprocessor - <tt class="docutils literal"><span class="pre">cpp</span></tt>. <tt class="docutils literal"><span class="pre">cpp</span></tt> handles preprocessing directives like <tt class="docutils literal"><span class="pre">#include</span></tt> and <tt class="docutils literal"><span class="pre">#define</span></tt>, removes comments, and does other minor tasks that prepare the C code for compilation.</p>

-<p>For all but the most trivial snippets of C code, <tt class="docutils literal"><span class="pre">pycparser</span></tt>, like a C compiler, must receive preprocessed C code in order to function correctly. If you import the top-level <tt class="docutils literal"><span class="pre">parse_file</span></tt> function from the <tt class="docutils literal"><span class="pre">pycparser</span></tt> package, it will interact with <tt class="docutils literal"><span class="pre">cpp</span></tt> for you, as long as it's in your PATH, or you provide a path to it.</p>

-<p>On the vast majority of Linux systems, <tt class="docutils literal"><span class="pre">cpp</span></tt> is installed and is in the PATH. If you're on Windows and don't have <tt class="docutils literal"><span class="pre">cpp</span></tt> somewhere, you can use the one provided in the <tt class="docutils literal"><span class="pre">utils</span></tt> directory in <tt class="docutils literal"><span class="pre">pycparser</span></tt>'s distribution. This <tt class="docutils literal"><span class="pre">cpp</span></tt> executable was compiled from the <a class="reference external" href="http://www.cs.princeton.edu/software/lcc/">LCC distribution</a>, and is provided under LCC's license terms.</p>

-</div>

-<div class="section" id="what-about-the-standard-c-library-headers">

-<h2>3.2&nbsp;&nbsp;&nbsp;What about the standard C library headers?</h2>

-<p>C code almost always includes various header files from the standard C library, like <tt class="docutils literal"><span class="pre">stdio.h</span></tt>. While, with some effort, <tt class="docutils literal"><span class="pre">pycparser</span></tt> can be made to parse the standard headers from any C compiler, it's much simpler to use the provided &quot;fake&quot; standard in includes in <tt class="docutils literal"><span class="pre">utils/fake_libc_include</span></tt>. These are standard C header files that contain only the bare necessities to allow valid parsing of the files that use them. As a bonus, since they're minimal, it can significantly improve the performance of parsing C files.</p>

-<p>See the <tt class="docutils literal"><span class="pre">using_cpp_libc.py</span></tt> example for more details.</p>

-</div>

-<div class="section" id="basic-usage">

-<h2>3.3&nbsp;&nbsp;&nbsp;Basic usage</h2>

-<p>Take a look at the <tt class="docutils literal"><span class="pre">examples</span></tt> directory of the distribution for a few examples of using <tt class="docutils literal"><span class="pre">pycparser</span></tt>. These should be enough to get you started.</p>

-</div>

-<div class="section" id="advanced-usage">

-<h2>3.4&nbsp;&nbsp;&nbsp;Advanced usage</h2>

-<p>The public interface of <tt class="docutils literal"><span class="pre">pycparser</span></tt> is well documented with comments in <tt class="docutils literal"><span class="pre">pycparser/c_parser.py</span></tt>. For a detailed overview of the various AST nodes created by the parser, see <tt class="docutils literal"><span class="pre">pycparser/_c_ast.yaml</span></tt>.</p>

-<p>In any case, you can always drop me an <a class="reference external" href="mailto:eliben&#64;gmail.com">email</a> for help.</p>

-</div>

-</div>

-<div class="section" id="modifying">

-<h1>4&nbsp;&nbsp;&nbsp;Modifying</h1>

-<p>There are a few points to keep in mind when modifying <tt class="docutils literal"><span class="pre">pycparser</span></tt>:</p>

-<ul class="simple">

-<li>The code for <tt class="docutils literal"><span class="pre">pycparser</span></tt>'s AST nodes is automatically generated from a YAML configuration file - <tt class="docutils literal"><span class="pre">_c_ast.yaml</span></tt>, by <tt class="docutils literal"><span class="pre">_ast_gen.py</span></tt>. If you modify the AST configuration, make sure to re-generate the code.</li>

-<li>Make sure you understand the optimized mode of <tt class="docutils literal"><span class="pre">pycparser</span></tt> - for that you must read the docstring in the constructor of the <tt class="docutils literal"><span class="pre">CParser</span></tt> class. For development you should create the parser without optimizations, so that it will regenerate the Yacc and Lex tables when you change the grammar.</li>

-<li>The script <tt class="docutils literal"><span class="pre">_build_tables.py</span></tt> can be helpful - it regenerates all the tables needed by <tt class="docutils literal"><span class="pre">pycparser</span></tt>, and the AST code from YAML.</li>

-</ul>

-</div>

-<div class="section" id="package-contents">

-<h1>5&nbsp;&nbsp;&nbsp;Package contents</h1>

-<p>Once you unzip the <tt class="docutils literal"><span class="pre">pycparser</span></tt> package, you'll see the following files and directories:</p>

-<dl class="docutils">

-<dt>README.txt/html:</dt>

-<dd>This README file.</dd>

-<dt>setup.py:</dt>

-<dd>Installation script</dd>

-<dt>examples/:</dt>

-<dd>A directory with some examples of using <tt class="docutils literal"><span class="pre">pycparser</span></tt></dd>

-<dt>pycparser/:</dt>

-<dd>The <tt class="docutils literal"><span class="pre">pycparser</span></tt> module source code.</dd>

-<dt>tests/:</dt>

-<dd>Unit tests.</dd>

-<dt>utils/cpp.exe:</dt>

-<dd>A Windows executable of the C pre-processor suitable for working with pycparser</dd>

-<dt>utils/fake_libc_include:</dt>

-<dd>Minimal standard C library include files that should allow to parse any C code.</dd>

-<dt>utils/internal/:</dt>

-<dd>Internal utilities for my own use. You probably don't need them.</dd>

-</dl>

-</div>

-<div class="section" id="contributors">

-<h1>6&nbsp;&nbsp;&nbsp;Contributors</h1>

-<p>Some people have contributed to <tt class="docutils literal"><span class="pre">pycparser</span></tt> by opening issues on bugs they've found and/or submitting patches. The list of contributors is at <a class="reference external" href="http://code.google.com/p/pycparser/wiki/Contributors">this pycparser Wiki page</a>.</p>

-</div>

-<div class="section" id="changelog">

-<h1>7&nbsp;&nbsp;&nbsp;Changelog</h1>

-<ul class="simple">

-<li>Version 2.00 (31.10.2010)<ul>

-<li>Support for C99 (read <a class="reference external" href="http://code.google.com/p/pycparser/wiki/C99support">this wiki page</a> for more information).</li>

-</ul>

-</li>

-<li>Version 1.08 (09.10.2010)<ul>

-<li>Bug fixes:<ul>

-<li>Correct handling of <tt class="docutils literal"><span class="pre">do{}</span> <span class="pre">...</span> <span class="pre">while</span></tt> statements in some cases</li>

-<li>Issues 6 &amp; 7: Concatenation of string literals</li>

-<li>Issue 9: Support for unnamed bitfields in structs</li>

-</ul>

-</li>

-</ul>

-</li>

-<li>Version 1.07 (18.05.2010)<ul>

-<li>Python 3.1 compatibility: <tt class="docutils literal"><span class="pre">pycparser</span></tt> was modified to run on Python 3.1 as well as 2.6</li>

-</ul>

-</li>

-<li>Version 1.06 (10.04.2010)<ul>

-<li>Bug fixes:<ul>

-<li>coord not propagated to FuncCall nodes</li>

-<li>lexing of the ^= token (XOREQUALS)</li>

-<li>parsing failed on some abstract declarator rules</li>

-</ul>

-</li>

-<li>Linux compatibility: fixed end-of-line and <tt class="docutils literal"><span class="pre">cpp</span></tt> path issues to allow all tests and examples run on Linux</li>

-</ul>

-</li>

-<li>Version 1.05 (16.10.2009)<ul>

-<li>Fixed the <tt class="docutils literal"><span class="pre">parse_file</span></tt> auxiliary function to handle multiple arguments to <tt class="docutils literal"><span class="pre">cpp</span></tt> correctly</li>

-</ul>

-</li>

-<li>Version 1.04 (22.05.2009)<ul>

-<li>Added the <tt class="docutils literal"><span class="pre">fake_libc_include</span></tt> directory to allow parsing of C code that uses standard C library include files without dependency on a real C library.</li>

-<li>Tested with Python 2.6 and PLY 3.2</li>

-</ul>

-</li>

-<li>Version 1.03 (31.01.2009)<ul>

-<li>Accept enumeration lists with a comma after the last item (C99 feature).</li>

-</ul>

-</li>

-<li>Version 1.02 (16.01.2009)<ul>

-<li>Fixed problem of parsing struct/enum/union names that were named similarly to previously defined <tt class="docutils literal"><span class="pre">typedef</span></tt> types.</li>

-</ul>

-</li>

-<li>Version 1.01 (09.01.2009)<ul>

-<li>Fixed subprocess invocation in the helper function parse_file - now it's more portable</li>

-</ul>

-</li>

-<li>Version 1.0 (15.11.2008)<ul>

-<li>Initial release</li>

-<li>Support for ANSI C89</li>

-</ul>

-</li>

-</ul>

-</div>

-</div>

-</body>

-</html>

+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="generator" content="Docutils 0.6: http://docutils.sourceforge.net/" />
+<title>pycparser v2.01</title>
+<meta name="author" content="Eli Bendersky" />
+<style type="text/css">
+
+/*
+:Author: David Goodger (goodger@python.org)
+:Id: $Id: html4css1.css 5951 2009-05-18 18:03:10Z milde $
+:Copyright: This stylesheet has been placed in the public domain.
+
+Default cascading style sheet for the HTML output of Docutils.
+
+See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
+customize this style sheet.
+*/
+
+/* used to remove borders from tables and images */
+.borderless, table.borderless td, table.borderless th {
+  border: 0 }
+
+table.borderless td, table.borderless th {
+  /* Override padding for "table.docutils td" with "! important".
+     The right padding separates the table cells. */
+  padding: 0 0.5em 0 0 ! important }
+
+.first {
+  /* Override more specific margin styles with "! important". */
+  margin-top: 0 ! important }
+
+.last, .with-subtitle {
+  margin-bottom: 0 ! important }
+
+.hidden {
+  display: none }
+
+a.toc-backref {
+  text-decoration: none ;
+  color: black }
+
+blockquote.epigraph {
+  margin: 2em 5em ; }
+
+dl.docutils dd {
+  margin-bottom: 0.5em }
+
+/* Uncomment (and remove this text!) to get bold-faced definition list terms
+dl.docutils dt {
+  font-weight: bold }
+*/
+
+div.abstract {
+  margin: 2em 5em }
+
+div.abstract p.topic-title {
+  font-weight: bold ;
+  text-align: center }
+
+div.admonition, div.attention, div.caution, div.danger, div.error,
+div.hint, div.important, div.note, div.tip, div.warning {
+  margin: 2em ;
+  border: medium outset ;
+  padding: 1em }
+
+div.admonition p.admonition-title, div.hint p.admonition-title,
+div.important p.admonition-title, div.note p.admonition-title,
+div.tip p.admonition-title {
+  font-weight: bold ;
+  font-family: sans-serif }
+
+div.attention p.admonition-title, div.caution p.admonition-title,
+div.danger p.admonition-title, div.error p.admonition-title,
+div.warning p.admonition-title {
+  color: red ;
+  font-weight: bold ;
+  font-family: sans-serif }
+
+/* Uncomment (and remove this text!) to get reduced vertical space in
+   compound paragraphs.
+div.compound .compound-first, div.compound .compound-middle {
+  margin-bottom: 0.5em }
+
+div.compound .compound-last, div.compound .compound-middle {
+  margin-top: 0.5em }
+*/
+
+div.dedication {
+  margin: 2em 5em ;
+  text-align: center ;
+  font-style: italic }
+
+div.dedication p.topic-title {
+  font-weight: bold ;
+  font-style: normal }
+
+div.figure {
+  margin-left: 2em ;
+  margin-right: 2em }
+
+div.footer, div.header {
+  clear: both;
+  font-size: smaller }
+
+div.line-block {
+  display: block ;
+  margin-top: 1em ;
+  margin-bottom: 1em }
+
+div.line-block div.line-block {
+  margin-top: 0 ;
+  margin-bottom: 0 ;
+  margin-left: 1.5em }
+
+div.sidebar {
+  margin: 0 0 0.5em 1em ;
+  border: medium outset ;
+  padding: 1em ;
+  background-color: #ffffee ;
+  width: 40% ;
+  float: right ;
+  clear: right }
+
+div.sidebar p.rubric {
+  font-family: sans-serif ;
+  font-size: medium }
+
+div.system-messages {
+  margin: 5em }
+
+div.system-messages h1 {
+  color: red }
+
+div.system-message {
+  border: medium outset ;
+  padding: 1em }
+
+div.system-message p.system-message-title {
+  color: red ;
+  font-weight: bold }
+
+div.topic {
+  margin: 2em }
+
+h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
+h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
+  margin-top: 0.4em }
+
+h1.title {
+  text-align: center }
+
+h2.subtitle {
+  text-align: center }
+
+hr.docutils {
+  width: 75% }
+
+img.align-left, .figure.align-left{
+  clear: left ;
+  float: left ;
+  margin-right: 1em }
+
+img.align-right, .figure.align-right {
+  clear: right ;
+  float: right ;
+  margin-left: 1em }
+
+.align-left {
+  text-align: left }
+
+.align-center {
+  clear: both ;
+  text-align: center }
+
+.align-right {
+  text-align: right }
+
+/* reset inner alignment in figures */
+div.align-right {
+  text-align: left }
+
+/* div.align-center * { */
+/*   text-align: left } */
+
+ol.simple, ul.simple {
+  margin-bottom: 1em }
+
+ol.arabic {
+  list-style: decimal }
+
+ol.loweralpha {
+  list-style: lower-alpha }
+
+ol.upperalpha {
+  list-style: upper-alpha }
+
+ol.lowerroman {
+  list-style: lower-roman }
+
+ol.upperroman {
+  list-style: upper-roman }
+
+p.attribution {
+  text-align: right ;
+  margin-left: 50% }
+
+p.caption {
+  font-style: italic }
+
+p.credits {
+  font-style: italic ;
+  font-size: smaller }
+
+p.label {
+  white-space: nowrap }
+
+p.rubric {
+  font-weight: bold ;
+  font-size: larger ;
+  color: maroon ;
+  text-align: center }
+
+p.sidebar-title {
+  font-family: sans-serif ;
+  font-weight: bold ;
+  font-size: larger }
+
+p.sidebar-subtitle {
+  font-family: sans-serif ;
+  font-weight: bold }
+
+p.topic-title {
+  font-weight: bold }
+
+pre.address {
+  margin-bottom: 0 ;
+  margin-top: 0 ;
+  font: inherit }
+
+pre.literal-block, pre.doctest-block {
+  margin-left: 2em ;
+  margin-right: 2em }
+
+span.classifier {
+  font-family: sans-serif ;
+  font-style: oblique }
+
+span.classifier-delimiter {
+  font-family: sans-serif ;
+  font-weight: bold }
+
+span.interpreted {
+  font-family: sans-serif }
+
+span.option {
+  white-space: nowrap }
+
+span.pre {
+  white-space: pre }
+
+span.problematic {
+  color: red }
+
+span.section-subtitle {
+  /* font-size relative to parent (h1..h6 element) */
+  font-size: 80% }
+
+table.citation {
+  border-left: solid 1px gray;
+  margin-left: 1px }
+
+table.docinfo {
+  margin: 2em 4em }
+
+table.docutils {
+  margin-top: 0.5em ;
+  margin-bottom: 0.5em }
+
+table.footnote {
+  border-left: solid 1px black;
+  margin-left: 1px }
+
+table.docutils td, table.docutils th,
+table.docinfo td, table.docinfo th {
+  padding-left: 0.5em ;
+  padding-right: 0.5em ;
+  vertical-align: top }
+
+table.docutils th.field-name, table.docinfo th.docinfo-name {
+  font-weight: bold ;
+  text-align: left ;
+  white-space: nowrap ;
+  padding-left: 0 }
+
+h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
+h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
+  font-size: 100% }
+
+ul.auto-toc {
+  list-style-type: none }
+
+</style>
+</head>
+<body>
+<div class="document" id="pycparser-v2-01">
+<h1 class="title">pycparser v2.01</h1>
+<table class="docinfo" frame="void" rules="none">
+<col class="docinfo-name" />
+<col class="docinfo-content" />
+<tbody valign="top">
+<tr><th class="docinfo-name">Author:</th>
+<td><a class="first reference external" href="http://eli.thegreenplace.net">Eli Bendersky</a></td></tr>
+</tbody>
+</table>
+<div class="contents topic" id="contents">
+<p class="topic-title first">Contents</p>
+<ul class="auto-toc simple">
+<li><a class="reference internal" href="#introduction" id="id2">1&nbsp;&nbsp;&nbsp;Introduction</a><ul class="auto-toc">
+<li><a class="reference internal" href="#what-is-pycparser" id="id3">1.1&nbsp;&nbsp;&nbsp;What is pycparser?</a></li>
+<li><a class="reference internal" href="#what-is-it-good-for" id="id4">1.2&nbsp;&nbsp;&nbsp;What is it good for?</a></li>
+<li><a class="reference internal" href="#which-version-of-c-does-pycparser-support" id="id5">1.3&nbsp;&nbsp;&nbsp;Which version of C does pycparser support?</a></li>
+<li><a class="reference internal" href="#what-grammar-does-pycparser-follow" id="id6">1.4&nbsp;&nbsp;&nbsp;What grammar does pycparser follow?</a></li>
+<li><a class="reference internal" href="#what-is-an-ast" id="id7">1.5&nbsp;&nbsp;&nbsp;What is an AST?</a></li>
+<li><a class="reference internal" href="#how-is-pycparser-licensed" id="id8">1.6&nbsp;&nbsp;&nbsp;How is pycparser licensed?</a></li>
+<li><a class="reference internal" href="#contact-details" id="id9">1.7&nbsp;&nbsp;&nbsp;Contact details</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#installing" id="id10">2&nbsp;&nbsp;&nbsp;Installing</a><ul class="auto-toc">
+<li><a class="reference internal" href="#prerequisites" id="id11">2.1&nbsp;&nbsp;&nbsp;Prerequisites</a></li>
+<li><a class="reference internal" href="#installation-process" id="id12">2.2&nbsp;&nbsp;&nbsp;Installation process</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#using" id="id13">3&nbsp;&nbsp;&nbsp;Using</a><ul class="auto-toc">
+<li><a class="reference internal" href="#interaction-with-the-c-preprocessor" id="id14">3.1&nbsp;&nbsp;&nbsp;Interaction with the C preprocessor</a></li>
+<li><a class="reference internal" href="#what-about-the-standard-c-library-headers" id="id15">3.2&nbsp;&nbsp;&nbsp;What about the standard C library headers?</a></li>
+<li><a class="reference internal" href="#basic-usage" id="id16">3.3&nbsp;&nbsp;&nbsp;Basic usage</a></li>
+<li><a class="reference internal" href="#advanced-usage" id="id17">3.4&nbsp;&nbsp;&nbsp;Advanced usage</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#modifying" id="id18">4&nbsp;&nbsp;&nbsp;Modifying</a></li>
+<li><a class="reference internal" href="#package-contents" id="id19">5&nbsp;&nbsp;&nbsp;Package contents</a></li>
+<li><a class="reference internal" href="#contributors" id="id20">6&nbsp;&nbsp;&nbsp;Contributors</a></li>
+<li><a class="reference internal" href="#changelog" id="id21">7&nbsp;&nbsp;&nbsp;Changelog</a></li>
+</ul>
+</div>
+<div class="section" id="introduction">
+<h1>1&nbsp;&nbsp;&nbsp;Introduction</h1>
+<div class="section" id="what-is-pycparser">
+<h2>1.1&nbsp;&nbsp;&nbsp;What is pycparser?</h2>
+<p><tt class="docutils literal">pycparser</tt> is a parser for the C language, written in pure Python. It is a module designed to be easily integrated into applications that need to parse C source code.</p>
+</div>
+<div class="section" id="what-is-it-good-for">
+<h2>1.2&nbsp;&nbsp;&nbsp;What is it good for?</h2>
+<p>Anything that needs C code to be parsed. The following are some uses for <tt class="docutils literal">pycparser</tt>, taken from real user reports:</p>
+<ul class="simple">
+<li>C code obfuscator</li>
+<li>Front-end for various specialized C compilers</li>
+<li>Static code checker</li>
+<li>Automatic unit-test discovery</li>
+<li>Adding specialized extensions to the C language</li>
+</ul>
+<p><tt class="docutils literal">pycparser</tt> is unique in the sense that it's written in pure Python - a very high level language that's easy to experiment with and tweak. To people familiar with Lex and Yacc, <tt class="docutils literal">pycparser</tt>'s code will be simple to understand.</p>
+</div>
+<div class="section" id="which-version-of-c-does-pycparser-support">
+<h2>1.3&nbsp;&nbsp;&nbsp;Which version of C does pycparser support?</h2>
+<p><tt class="docutils literal">pycparser</tt> aims to support the full C99 language (according to the standard ISO/IEC 9899). This is a new feature in the version 2.x series - earlier versions only supported C89. For more information on the change, read <a class="reference external" href="http://code.google.com/p/pycparser/wiki/C99support">this wiki page</a>.</p>
+<p><tt class="docutils literal">pycparser</tt> doesn't support any GCC extensions.</p>
+</div>
+<div class="section" id="what-grammar-does-pycparser-follow">
+<h2>1.4&nbsp;&nbsp;&nbsp;What grammar does pycparser follow?</h2>
+<p><tt class="docutils literal">pycparser</tt> very closely follows the C grammar provided in the end of the C99 standard document</p>
+</div>
+<div class="section" id="what-is-an-ast">
+<h2>1.5&nbsp;&nbsp;&nbsp;What is an AST?</h2>
+<p><a class="reference external" href="http://en.wikipedia.org/wiki/Abstract_syntax_tree">AST</a> - Abstract Syntax Tree. It is a tree representation of the syntax of source code - a convenient hierarchical data structure that's built from the code and is readily suitable for exploration and manipulation.</p>
+</div>
+<div class="section" id="how-is-pycparser-licensed">
+<h2>1.6&nbsp;&nbsp;&nbsp;How is pycparser licensed?</h2>
+<p><a class="reference external" href="http://www.gnu.org/licenses/lgpl.html">LGPL</a></p>
+</div>
+<div class="section" id="contact-details">
+<h2>1.7&nbsp;&nbsp;&nbsp;Contact details</h2>
+<p>Drop me an email to <a class="reference external" href="mailto:eliben&#64;gmail.com">eliben&#64;gmail.com</a> for any questions regarding <tt class="docutils literal">pycparser</tt>. For reporting problems with <tt class="docutils literal">pycparser</tt> or submitting feature requests, the best way is to open an issue on the <a class="reference external" href="http://code.google.com/p/pycparser/">pycparser page at Google Code</a>.</p>
+</div>
+</div>
+<div class="section" id="installing">
+<h1>2&nbsp;&nbsp;&nbsp;Installing</h1>
+<div class="section" id="prerequisites">
+<h2>2.1&nbsp;&nbsp;&nbsp;Prerequisites</h2>
+<ul class="simple">
+<li><tt class="docutils literal">pycparser</tt> was tested on Python 2.5, 2.6 and 3.1, on both Linux and Windows</li>
+<li><tt class="docutils literal">pycparser</tt> uses the PLY module for the actual lexer and parser construction. Install PLY version 3.3 (earlier versions work at least since 2.5) from <a class="reference external" href="http://www.dabeaz.com/ply/">its website</a>.</li>
+</ul>
+</div>
+<div class="section" id="installation-process">
+<h2>2.2&nbsp;&nbsp;&nbsp;Installation process</h2>
+<p>Installing <tt class="docutils literal">pycparser</tt> is very simple. Once you download it from its <a class="reference external" href="http://code.google.com/p/pycparser/">website</a> and unzip the package, you just have to execute the standard <tt class="docutils literal">python setup.py install</tt>. The setup script will then place the <tt class="docutils literal">pycparser</tt> module into <tt class="docutils literal"><span class="pre">site-packages</span></tt> in your Python's installation library.</p>
+<p>It's recommended to run <tt class="docutils literal">_build_tables.py</tt> in the <tt class="docutils literal">pycparser</tt> code directory after installation to make sure the parsing tables of PLY are pre-generated. This can make your code run faster.</p>
+</div>
+</div>
+<div class="section" id="using">
+<h1>3&nbsp;&nbsp;&nbsp;Using</h1>
+<div class="section" id="interaction-with-the-c-preprocessor">
+<h2>3.1&nbsp;&nbsp;&nbsp;Interaction with the C preprocessor</h2>
+<p>In order to be compilable, C code must be preprocessed by the C preprocessor - <tt class="docutils literal">cpp</tt>. <tt class="docutils literal">cpp</tt> handles preprocessing directives like <tt class="docutils literal">#include</tt> and <tt class="docutils literal">#define</tt>, removes comments, and does other minor tasks that prepare the C code for compilation.</p>
+<p>For all but the most trivial snippets of C code, <tt class="docutils literal">pycparser</tt>, like a C compiler, must receive preprocessed C code in order to function correctly. If you import the top-level <tt class="docutils literal">parse_file</tt> function from the <tt class="docutils literal">pycparser</tt> package, it will interact with <tt class="docutils literal">cpp</tt> for you, as long as it's in your PATH, or you provide a path to it.</p>
+<p>On the vast majority of Linux systems, <tt class="docutils literal">cpp</tt> is installed and is in the PATH. If you're on Windows and don't have <tt class="docutils literal">cpp</tt> somewhere, you can use the one provided in the <tt class="docutils literal">utils</tt> directory in <tt class="docutils literal">pycparser</tt>'s distribution. This <tt class="docutils literal">cpp</tt> executable was compiled from the <a class="reference external" href="http://www.cs.princeton.edu/software/lcc/">LCC distribution</a>, and is provided under LCC's license terms.</p>
+</div>
+<div class="section" id="what-about-the-standard-c-library-headers">
+<h2>3.2&nbsp;&nbsp;&nbsp;What about the standard C library headers?</h2>
+<p>C code almost always includes various header files from the standard C library, like <tt class="docutils literal">stdio.h</tt>. While, with some effort, <tt class="docutils literal">pycparser</tt> can be made to parse the standard headers from any C compiler, it's much simpler to use the provided &quot;fake&quot; standard in includes in <tt class="docutils literal">utils/fake_libc_include</tt>. These are standard C header files that contain only the bare necessities to allow valid parsing of the files that use them. As a bonus, since they're minimal, it can significantly improve the performance of parsing C files.</p>
+<p>See the <tt class="docutils literal">using_cpp_libc.py</tt> example for more details.</p>
+</div>
+<div class="section" id="basic-usage">
+<h2>3.3&nbsp;&nbsp;&nbsp;Basic usage</h2>
+<p>Take a look at the <tt class="docutils literal">examples</tt> directory of the distribution for a few examples of using <tt class="docutils literal">pycparser</tt>. These should be enough to get you started.</p>
+</div>
+<div class="section" id="advanced-usage">
+<h2>3.4&nbsp;&nbsp;&nbsp;Advanced usage</h2>
+<p>The public interface of <tt class="docutils literal">pycparser</tt> is well documented with comments in <tt class="docutils literal">pycparser/c_parser.py</tt>. For a detailed overview of the various AST nodes created by the parser, see <tt class="docutils literal">pycparser/_c_ast.cfg</tt>.</p>
+<p>In any case, you can always drop me an <a class="reference external" href="mailto:eliben&#64;gmail.com">email</a> for help.</p>
+</div>
+</div>
+<div class="section" id="modifying">
+<h1>4&nbsp;&nbsp;&nbsp;Modifying</h1>
+<p>There are a few points to keep in mind when modifying <tt class="docutils literal">pycparser</tt>:</p>
+<ul class="simple">
+<li>The code for <tt class="docutils literal">pycparser</tt>'s AST nodes is automatically generated from a configuration file - <tt class="docutils literal">_c_ast.cfg</tt>, by <tt class="docutils literal">_ast_gen.py</tt>. If you modify the AST configuration, make sure to re-generate the code.</li>
+<li>Make sure you understand the optimized mode of <tt class="docutils literal">pycparser</tt> - for that you must read the docstring in the constructor of the <tt class="docutils literal">CParser</tt> class. For development you should create the parser without optimizations, so that it will regenerate the Yacc and Lex tables when you change the grammar.</li>
+</ul>
+</div>
+<div class="section" id="package-contents">
+<h1>5&nbsp;&nbsp;&nbsp;Package contents</h1>
+<p>Once you unzip the <tt class="docutils literal">pycparser</tt> package, you'll see the following files and directories:</p>
+<dl class="docutils">
+<dt>README.txt/html:</dt>
+<dd>This README file.</dd>
+<dt>setup.py:</dt>
+<dd>Installation script</dd>
+<dt>examples/:</dt>
+<dd>A directory with some examples of using <tt class="docutils literal">pycparser</tt></dd>
+<dt>pycparser/:</dt>
+<dd>The <tt class="docutils literal">pycparser</tt> module source code.</dd>
+<dt>tests/:</dt>
+<dd>Unit tests.</dd>
+<dt>utils/cpp.exe:</dt>
+<dd>A Windows executable of the C pre-processor suitable for working with pycparser</dd>
+<dt>utils/fake_libc_include:</dt>
+<dd>Minimal standard C library include files that should allow to parse any C code.</dd>
+<dt>utils/internal/:</dt>
+<dd>Internal utilities for my own use. You probably don't need them.</dd>
+</dl>
+</div>
+<div class="section" id="contributors">
+<h1>6&nbsp;&nbsp;&nbsp;Contributors</h1>
+<p>Some people have contributed to <tt class="docutils literal">pycparser</tt> by opening issues on bugs they've found and/or submitting patches. The list of contributors is at <a class="reference external" href="http://code.google.com/p/pycparser/wiki/Contributors">this pycparser Wiki page</a>.</p>
+</div>
+<div class="section" id="changelog">
+<h1>7&nbsp;&nbsp;&nbsp;Changelog</h1>
+<ul class="simple">
+<li>Version 2.01 (04.12.2010)<ul>
+<li>Removed dependency on YAML. Parsing of the AST node configuration file is done with a simple parser.</li>
+<li>Fixed issue 12: installation problems</li>
+</ul>
+</li>
+<li>Version 2.00 (31.10.2010)<ul>
+<li>Support for C99 (read <a class="reference external" href="http://code.google.com/p/pycparser/wiki/C99support">this wiki page</a> for more information).</li>
+</ul>
+</li>
+<li>Version 1.08 (09.10.2010)<ul>
+<li>Bug fixes:<ul>
+<li>Correct handling of <tt class="docutils literal">do{} ... while</tt> statements in some cases</li>
+<li>Issues 6 &amp; 7: Concatenation of string literals</li>
+<li>Issue 9: Support for unnamed bitfields in structs</li>
+</ul>
+</li>
+</ul>
+</li>
+<li>Version 1.07 (18.05.2010)<ul>
+<li>Python 3.1 compatibility: <tt class="docutils literal">pycparser</tt> was modified to run on Python 3.1 as well as 2.6</li>
+</ul>
+</li>
+<li>Version 1.06 (10.04.2010)<ul>
+<li>Bug fixes:<ul>
+<li>coord not propagated to FuncCall nodes</li>
+<li>lexing of the ^= token (XOREQUALS)</li>
+<li>parsing failed on some abstract declarator rules</li>
+</ul>
+</li>
+<li>Linux compatibility: fixed end-of-line and <tt class="docutils literal">cpp</tt> path issues to allow all tests and examples run on Linux</li>
+</ul>
+</li>
+<li>Version 1.05 (16.10.2009)<ul>
+<li>Fixed the <tt class="docutils literal">parse_file</tt> auxiliary function to handle multiple arguments to <tt class="docutils literal">cpp</tt> correctly</li>
+</ul>
+</li>
+<li>Version 1.04 (22.05.2009)<ul>
+<li>Added the <tt class="docutils literal">fake_libc_include</tt> directory to allow parsing of C code that uses standard C library include files without dependency on a real C library.</li>
+<li>Tested with Python 2.6 and PLY 3.2</li>
+</ul>
+</li>
+<li>Version 1.03 (31.01.2009)<ul>
+<li>Accept enumeration lists with a comma after the last item (C99 feature).</li>
+</ul>
+</li>
+<li>Version 1.02 (16.01.2009)<ul>
+<li>Fixed problem of parsing struct/enum/union names that were named similarly to previously defined <tt class="docutils literal">typedef</tt> types.</li>
+</ul>
+</li>
+<li>Version 1.01 (09.01.2009)<ul>
+<li>Fixed subprocess invocation in the helper function parse_file - now it's more portable</li>
+</ul>
+</li>
+<li>Version 1.0 (15.11.2008)<ul>
+<li>Initial release</li>
+<li>Support for ANSI C89</li>
+</ul>
+</li>
+</ul>
+</div>
+</div>
+</body>
+</html>
diff --git a/README.txt b/README.txt
index 6b795c9..69eff24 100644
--- a/README.txt
+++ b/README.txt
@@ -1,5 +1,5 @@
 ===============

-pycparser v2.00

+pycparser v2.01

 ===============

 

 :Author: `Eli Bendersky <http://eli.thegreenplace.net>`_

@@ -70,14 +70,13 @@
 

 * ``pycparser`` was tested on Python 2.5, 2.6 and 3.1, on both Linux and Windows

 * ``pycparser`` uses the PLY module for the actual lexer and parser construction. Install PLY version 3.3 (earlier versions work at least since 2.5) from `its website <http://www.dabeaz.com/ply/>`_.

-* If you want to modify ``pycparser``'s code, you'll need to install `PyYAML <http://pyyaml.org/>`_, since it's used by ``pycparser`` to store the AST configuration in a YAML file.

 

 Installation process

 --------------------

 

 Installing ``pycparser`` is very simple. Once you download it from its `website <http://code.google.com/p/pycparser/>`_ and unzip the package, you just have to execute the standard ``python setup.py install``. The setup script will then place the ``pycparser`` module into ``site-packages`` in your Python's installation library.

 

-It's recommended to run ``_build_tables.py`` in the ``pycparser`` code directory to make sure the parsing tables of PLY are pre-generated. This can make your code run faster.

+It's recommended to run ``_build_tables.py`` in the ``pycparser`` code directory after installation to make sure the parsing tables of PLY are pre-generated. This can make your code run faster.

 

 

 Using

@@ -107,7 +106,7 @@
 Advanced usage

 --------------

 

-The public interface of ``pycparser`` is well documented with comments in ``pycparser/c_parser.py``. For a detailed overview of the various AST nodes created by the parser, see ``pycparser/_c_ast.yaml``.

+The public interface of ``pycparser`` is well documented with comments in ``pycparser/c_parser.py``. For a detailed overview of the various AST nodes created by the parser, see ``pycparser/_c_ast.cfg``.

 

 In any case, you can always drop me an `email <eliben@gmail.com>`_ for help.

 

@@ -116,9 +115,8 @@
 

 There are a few points to keep in mind when modifying ``pycparser``:

 

-* The code for ``pycparser``'s AST nodes is automatically generated from a YAML configuration file - ``_c_ast.yaml``, by ``_ast_gen.py``. If you modify the AST configuration, make sure to re-generate the code.

+* The code for ``pycparser``'s AST nodes is automatically generated from a configuration file - ``_c_ast.cfg``, by ``_ast_gen.py``. If you modify the AST configuration, make sure to re-generate the code.

 * Make sure you understand the optimized mode of ``pycparser`` - for that you must read the docstring in the constructor of the ``CParser`` class. For development you should create the parser without optimizations, so that it will regenerate the Yacc and Lex tables when you change the grammar.

-* The script ``_build_tables.py`` can be helpful - it regenerates all the tables needed by ``pycparser``, and the AST code from YAML.

 

 

 Package contents

@@ -158,6 +156,11 @@
 Changelog

 =========

 

++ Version 2.01 (04.12.2010)

+

+  * Removed dependency on YAML. Parsing of the AST node configuration file is done with a simple parser.

+  * Fixed issue 12: installation problems

+

 + Version 2.00 (31.10.2010)

 

   * Support for C99 (read `this wiki page <http://code.google.com/p/pycparser/wiki/C99support>`_ for more information).

diff --git a/examples/cdecl.py b/examples/cdecl.py
index 3df6efc..23148f8 100644
--- a/examples/cdecl.py
+++ b/examples/cdecl.py
@@ -1,108 +1,108 @@
-#-----------------------------------------------------------------

-# pycparser: cdecl.py

-#

-# Example of the CDECL tool using pycparser. CDECL "explains"

-# C type declarations in plain English.

-#

-# The AST generated by pycparser from the given declaration is

-# traversed recursively to build the explanation.

-# Note that the declaration must be a valid external declaration

-# in C. All the types used in it must be defined with typedef,

-# or parsing will fail. The definition can be arbitrary, it isn't

-# really used - by pycparser must know which tokens are types.

-#

-# For example:

-#

-# 'typedef int Node; const Node* (*ar)[10];'

-# =>

-# ar is a pointer to array[10] of pointer to const Node

-#

-# Copyright (C) 2008-2010, Eli Bendersky

-# License: LGPL

-#-----------------------------------------------------------------

-import sys

-

-# This is not required if you've installed pycparser into

-# your site-packages/ with setup.py

-#

-sys.path.insert(0, '..')

-

-from pycparser import c_parser, c_ast

-from pycparser.portability import printme

-

-

+#-----------------------------------------------------------------
+# pycparser: cdecl.py
+#
+# Example of the CDECL tool using pycparser. CDECL "explains"
+# C type declarations in plain English.
+#
+# The AST generated by pycparser from the given declaration is
+# traversed recursively to build the explanation.
+# Note that the declaration must be a valid external declaration
+# in C. All the types used in it must be defined with typedef,
+# or parsing will fail. The definition can be arbitrary, it isn't
+# really used - by pycparser must know which tokens are types.
+#
+# For example:
+#
+# 'typedef int Node; const Node* (*ar)[10];'
+# =>
+# ar is a pointer to array[10] of pointer to const Node
+#
+# Copyright (C) 2008-2010, Eli Bendersky
+# License: LGPL
+#-----------------------------------------------------------------
+import sys
+
+# This is not required if you've installed pycparser into
+# your site-packages/ with setup.py
+#
+sys.path.insert(0, '..')
+
+from pycparser import c_parser, c_ast
+
+
 def explain_c_declaration(c_decl):
-    """ Parses the declaration in c_decl and returns a text 

-        explanation as a string.

-        

-        The last external node of the string is used, to allow

+    """ Parses the declaration in c_decl and returns a text 
+        explanation as a string.
+        
+        The last external node of the string is used, to allow
         earlier typedefs for used types.
-    """

-    parser = c_parser.CParser()

-    

-    try:

-        node = parser.parse(c_decl, filename='<stdin>')

-    except c_parser.ParseError:

-        e = sys.exc_info()[1]

-        return "Parse error:" + str(e)

-

-    if (    not isinstance(node, c_ast.FileAST) or 

-            not isinstance(node.ext[-1], c_ast.Decl)):

-        return "Not a valid declaration"

-

-    return _explain_decl_node(node.ext[-1])

-

-

+    """
+    parser = c_parser.CParser()
+    
+    try:
+        node = parser.parse(c_decl, filename='<stdin>')
+    except c_parser.ParseError:
+        e = sys.exc_info()[1]
+        return "Parse error:" + str(e)
+
+    if (    not isinstance(node, c_ast.FileAST) or 
+            not isinstance(node.ext[-1], c_ast.Decl)):
+        return "Not a valid declaration"
+
+    return _explain_decl_node(node.ext[-1])
+
+
 def _explain_decl_node(decl_node):
-    """ Receives a c_ast.Decl note and returns its explanation in

+    """ Receives a c_ast.Decl note and returns its explanation in
         English.
-    """

-    #~ print decl_node.show()

-    storage = ' '.join(decl_node.storage) + ' ' if decl_node.storage else ''

-        

-    return (decl_node.name + 

-            " is a " + 

-            storage + 

-            _explain_type(decl_node.type))

-

-

+    """
+    #~ print decl_node.show()
+    storage = ' '.join(decl_node.storage) + ' ' if decl_node.storage else ''
+        
+    return (decl_node.name + 
+            " is a " + 
+            storage + 
+            _explain_type(decl_node.type))
+
+
 def _explain_type(decl):
     """ Recursively explains a type decl node
-    """

-    typ = type(decl)

-    

-    if typ == c_ast.TypeDecl:

-        quals = ' '.join(decl.quals) + ' ' if decl.quals else ''

-        return quals + _explain_type(decl.type)

-    elif typ == c_ast.Typename or typ == c_ast.Decl:

-        return _explain_type(decl.type)

-    elif typ == c_ast.IdentifierType:

-        return ' '.join(decl.names)

-    elif typ == c_ast.PtrDecl:

-        quals = ' '.join(decl.quals) + ' ' if decl.quals else ''

-        return quals + 'pointer to ' + _explain_type(decl.type)

-    elif typ == c_ast.ArrayDecl:

-        arr = 'array'

-        if decl.dim: arr += '[%s]' % decl.dim.value

-        

-        return arr + " of " + _explain_type(decl.type)

-        

-    elif typ == c_ast.FuncDecl:

-        if decl.args:

-            params = [_explain_type(param) for param in decl.args.params]

-            args = ', '.join(params)

-        else:

-            args = ''

-        

-        return ('function(%s) returning ' % (args) +

-                _explain_type(decl.type))

-

-

-if __name__ == "__main__":

-    if len(sys.argv) > 1:

-        c_decl  = sys.argv[1]

-    else:

-        c_decl = "char *(*(**foo[][8])())[];"

-

-    printme(["Explaining the declaration:", c_decl])

-    printme(["\n", explain_c_declaration(c_decl)])

+    """
+    typ = type(decl)
+    
+    if typ == c_ast.TypeDecl:
+        quals = ' '.join(decl.quals) + ' ' if decl.quals else ''
+        return quals + _explain_type(decl.type)
+    elif typ == c_ast.Typename or typ == c_ast.Decl:
+        return _explain_type(decl.type)
+    elif typ == c_ast.IdentifierType:
+        return ' '.join(decl.names)
+    elif typ == c_ast.PtrDecl:
+        quals = ' '.join(decl.quals) + ' ' if decl.quals else ''
+        return quals + 'pointer to ' + _explain_type(decl.type)
+    elif typ == c_ast.ArrayDecl:
+        arr = 'array'
+        if decl.dim: arr += '[%s]' % decl.dim.value
+        
+        return arr + " of " + _explain_type(decl.type)
+        
+    elif typ == c_ast.FuncDecl:
+        if decl.args:
+            params = [_explain_type(param) for param in decl.args.params]
+            args = ', '.join(params)
+        else:
+            args = ''
+        
+        return ('function(%s) returning ' % (args) +
+                _explain_type(decl.type))
+
+
+if __name__ == "__main__":
+    if len(sys.argv) > 1:
+        c_decl  = sys.argv[1]
+    else:
+        c_decl = "char *(*(**foo[][8])())[];"
+
+    print("Explaining the declaration: " + c_decl + "\n")
+    print(explain_c_declaration(c_decl) + "\n") 
+
diff --git a/pycparser/__init__.py b/pycparser/__init__.py
index 7d91134..a51239b 100644
--- a/pycparser/__init__.py
+++ b/pycparser/__init__.py
@@ -9,7 +9,7 @@
 #-----------------------------------------------------------------

 

 __all__ = ['c_lexer', 'c_parser', 'c_ast']

-__version__ = '2.00'

+__version__ = '2.01'

 

 from subprocess import Popen, PIPE

 

diff --git a/pycparser/_ast_gen.py b/pycparser/_ast_gen.py
index 68904d1..2bef0fb 100644
--- a/pycparser/_ast_gen.py
+++ b/pycparser/_ast_gen.py
@@ -1,249 +1,264 @@
-#-----------------------------------------------------------------

-# _ast_gen.py

-#

-# Generates the AST Node classes from a specification given in 

-# a .yaml file

-#

-# The design of this module was inspired by astgen.py from the

-# Python 2.5 code-base.

-#

-# Copyright (C) 2008-2010, Eli Bendersky

-# License: LGPL

-#-----------------------------------------------------------------

-

-import pprint

-from string import Template

-

-import yaml

-

-

+#-----------------------------------------------------------------
+# _ast_gen.py
+#
+# Generates the AST Node classes from a specification given in 
+# a .yaml file
+#
+# The design of this module was inspired by astgen.py from the
+# Python 2.5 code-base.
+#
+# Copyright (C) 2008-2010, Eli Bendersky
+# License: LGPL
+#-----------------------------------------------------------------
+import pprint
+from string import Template
+
+
 class ASTCodeGenerator(object):
-    def __init__(self, cfg_filename='_c_ast.yaml'):

-        """ Initialize the code generator from a configuration

+    def __init__(self, cfg_filename='_c_ast.cfg'):
+        """ Initialize the code generator from a configuration
             file.
-        """

-        self.cfg_filename = cfg_filename

-        cfg = yaml.load(open(cfg_filename).read())

-        self.node_cfg = [NodeCfg(name, cfg[name]) for name in cfg]

-

-        #~ pprint.pprint(self.node_cfg)

-        #~ print ''

-

-    def generate(self, file=None):

-        """ Generates the code into file, an open file buffer.

-        """

-        src = Template(_PROLOGUE_COMMENT).substitute(

-            cfg_filename=self.cfg_filename)

-        

-        src += _PROLOGUE_CODE

-        for node_cfg in self.node_cfg:

-            src += node_cfg.generate_source() + '\n\n'

-        

+        """
+        self.cfg_filename = cfg_filename
+        self.node_cfg = [NodeCfg(name, contents) for (name, contents) in self.parse_cfgfile(cfg_filename)]
+
+    def generate(self, file=None):
+        """ Generates the code into file, an open file buffer.
+        """
+        src = Template(_PROLOGUE_COMMENT).substitute(
+            cfg_filename=self.cfg_filename)
+        
+        src += _PROLOGUE_CODE
+        for node_cfg in self.node_cfg:
+            src += node_cfg.generate_source() + '\n\n'
+        
         file.write(src)
-

-

+
+    def parse_cfgfile(self, filename):
+        """ Parse the configuration file and yield pairs of
+            (name, contents) for each node.
+        """
+        with open(filename, "r") as f:
+            for line in f:
+                line = line.strip()
+                if not line or line.startswith('#'):
+                    continue
+                colon_i = line.find(':')
+                lbracket_i = line.find('[')
+                rbracket_i = line.find(']')
+                if colon_i < 1 or lbracket_i <= colon_i or rbracket_i <= lbracket_i:
+                    raise RuntimeError("Invalid line in %s:\n%s\n" % (filename, line))
+
+                name = line[:colon_i]
+                val = line[lbracket_i + 1:rbracket_i]
+                vallist = [v.strip() for v in val.split(',')] if val else []
+                yield name, vallist
+
+
 class NodeCfg(object):
-    def __init__(self, name, contents):

-        self.name = name

-        self.all_entries = []

-        self.attr = []

-        self.child = []

-        self.seq_child = []

-        

-        for entry in contents:

-            clean_entry = entry.rstrip('*')

-            self.all_entries.append(clean_entry)

-            

-            if entry.endswith('**'):

-                self.seq_child.append(clean_entry)

-            elif entry.endswith('*'):

-                self.child.append(clean_entry)

-            else:

+    """ Node configuration. 
+
+        name: node name
+        contents: a list of contents - attributes and child nodes 
+        See comment at the top of the configuration file for details.
+    """
+    def __init__(self, name, contents):
+        self.name = name
+        self.all_entries = []
+        self.attr = []
+        self.child = []
+        self.seq_child = []
+
+        for entry in contents:
+            clean_entry = entry.rstrip('*')
+            self.all_entries.append(clean_entry)
+            
+            if entry.endswith('**'):
+                self.seq_child.append(clean_entry)
+            elif entry.endswith('*'):
+                self.child.append(clean_entry)
+            else:
                 self.attr.append(entry)
-

+
     def generate_source(self):
-        src = self._gen_init()

-        src += '\n' + self._gen_children()

-        src += '\n' + self._gen_show()

-        return src

-    

-    def _gen_init(self):
-        src = "class %s(Node):\n" % self.name

-

-        if self.all_entries:

-            args = ', '.join(self.all_entries)

-            arglist = '(self, %s, coord=None)' % args

-        else:

-            arglist = '(self, coord=None)'

-        

-        src += "    def __init__%s:\n" % arglist

-        

-        for name in self.all_entries + ['coord']:

-            src += "        self.%s = %s\n" % (name, name)

-        

-        return src

-    

-    def _gen_children(self):
-        src = '    def children(self):\n'

-        

-        if self.all_entries:

-            src += '        nodelist = []\n'

-            

-            template = ('' +

-                '        if self.%s is not None:' +

-                ' nodelist.%s(self.%s)\n')

-            

-            for child in self.child:

-                src += template % (

-                    child, 'append', child)

-            

-            for seq_child in self.seq_child:

-                src += template % (

-                    seq_child, 'extend', seq_child)

-                    

-            src += '        return tuple(nodelist)\n'

-        else:

-            src += '        return ()\n'

-            

-        return src

-

-    def _gen_show(self):
-        src = '    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):\n'

-        src += "        lead = ' ' * offset\n"

-        

-        src += "        buf.write(lead + '%s: ')\n\n" % self.name

-        

-        if self.attr:

-            src += "        if attrnames:\n"

-            src += "            attrstr = ', '.join('%s=%s' % nv for nv in ["

-            src += ', '.join('("%s", repr(%s))' % (nv, 'self.%s' % nv) for nv in self.attr)

-            src += '])\n'

-            src += "        else:\n"

-            src += "            attrstr = ', '.join('%s' % v for v in ["

-            src += ', '.join('self.%s' % v for v in self.attr)

-            src += '])\n'

-            src += "        buf.write(attrstr)\n\n"

-        

-        src += "        if showcoord:\n"

-        src += "            buf.write(' (at %s)' % self.coord)\n"

-        src += "        buf.write('\\n')\n\n"

-        

-        src += "        for c in self.children():\n"

-        src += "            c.show(buf, offset + 2, attrnames, showcoord)\n"

-        

-        return src

-

-

-_PROLOGUE_COMMENT = \

-r'''#-----------------------------------------------------------------

-# ** ATTENTION **

-# This code was automatically generated from the file:

-# $cfg_filename 

-#

-# Do not modify it directly. Modify the configuration file and

-# run the generator again.

-# ** ** *** ** **

-#

-# pycparser: c_ast.py

-#

-# AST Node classes.

-#

-# Copyright (C) 2008, Eli Bendersky

-# License: LGPL

-#-----------------------------------------------------------------

-

-'''

-

-_PROLOGUE_CODE = r'''

-import sys

-

-

-class Node(object):

-    """ Abstract base class for AST nodes.

-    """

-    def children(self):

-        """ A sequence of all children that are Nodes

-        """

-        pass

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        """ Pretty print the Node and all its attributes and

-            children (recursively) to a buffer.

-            

-            file:   

-                Open IO buffer into which the Node is printed.

-            

-            offset: 

-                Initial offset (amount of leading spaces) 

-            

-            attrnames:

-                True if you want to see the attribute names in

-                name=value pairs. False to only see the values.

-            

-            showcoord:

-                Do you want the coordinates of each Node to be

-                displayed.

-        """

-        pass

-

-

-class NodeVisitor(object):

-    """ A base NodeVisitor class for visiting c_ast nodes. 

-        Subclass it and define your own visit_XXX methods, where

-        XXX is the class name you want to visit with these 

-        methods.

-        

-        For example:

-        

-        class ConstantVisitor(NodeVisitor):

-            def __init__(self):

-                self.values = []

-            

-            def visit_Constant(self, node):

-                self.values.append(node.value)

-

-        Creates a list of values of all the constant nodes 

-        encountered below the given node. To use it:

-        

-        cv = ConstantVisitor()

-        cv.visit(node)

-        

-        Notes:

-        

-        *   generic_visit() will be called for AST nodes for which 

-            no visit_XXX method was defined. 

-        *   The children of nodes for which a visit_XXX was 

-            defined will not be visited - if you need this, call

-            generic_visit() on the node. 

-            You can use:

-                NodeVisitor.generic_visit(self, node)

-        *   Modeled after Python's own AST visiting facilities

-            (the ast module of Python 3.0)

-    """

-    def visit(self, node):

-        """ Visit a node. 

-        """

-        method = 'visit_' + node.__class__.__name__

-        visitor = getattr(self, method, self.generic_visit)

-        return visitor(node)

-        

-    def generic_visit(self, node):

-        """ Called if no explicit visitor function exists for a 

-            node. Implements preorder visiting of the node.

-        """

-        for c in node.children():

-            self.visit(c)

-

-

-'''

-

-

-

-if __name__ == "__main__":

-    import sys

+        src = self._gen_init()
+        src += '\n' + self._gen_children()
+        src += '\n' + self._gen_show()
+        return src
     
-    ast_gen = ASTCodeGenerator('_c_ast.yaml')

-    ast_gen.generate(open('c_ast.py', 'w'))

-    

-    

-    

+    def _gen_init(self):
+        src = "class %s(Node):\n" % self.name
+
+        if self.all_entries:
+            args = ', '.join(self.all_entries)
+            arglist = '(self, %s, coord=None)' % args
+        else:
+            arglist = '(self, coord=None)'
+        
+        src += "    def __init__%s:\n" % arglist
+        
+        for name in self.all_entries + ['coord']:
+            src += "        self.%s = %s\n" % (name, name)
+        
+        return src
+    
+    def _gen_children(self):
+        src = '    def children(self):\n'
+        
+        if self.all_entries:
+            src += '        nodelist = []\n'
+            
+            template = ('' +
+                '        if self.%s is not None:' +
+                ' nodelist.%s(self.%s)\n')
+            
+            for child in self.child:
+                src += template % (
+                    child, 'append', child)
+            
+            for seq_child in self.seq_child:
+                src += template % (
+                    seq_child, 'extend', seq_child)
+                    
+            src += '        return tuple(nodelist)\n'
+        else:
+            src += '        return ()\n'
+            
+        return src
+
+    def _gen_show(self):
+        src = '    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):\n'
+        src += "        lead = ' ' * offset\n"
+        
+        src += "        buf.write(lead + '%s: ')\n\n" % self.name
+        
+        if self.attr:
+            src += "        if attrnames:\n"
+            src += "            attrstr = ', '.join('%s=%s' % nv for nv in ["
+            src += ', '.join('("%s", repr(%s))' % (nv, 'self.%s' % nv) for nv in self.attr)
+            src += '])\n'
+            src += "        else:\n"
+            src += "            attrstr = ', '.join('%s' % v for v in ["
+            src += ', '.join('self.%s' % v for v in self.attr)
+            src += '])\n'
+            src += "        buf.write(attrstr)\n\n"
+        
+        src += "        if showcoord:\n"
+        src += "            buf.write(' (at %s)' % self.coord)\n"
+        src += "        buf.write('\\n')\n\n"
+        
+        src += "        for c in self.children():\n"
+        src += "            c.show(buf, offset + 2, attrnames, showcoord)\n"
+        
+        return src
+
+
+_PROLOGUE_COMMENT = \
+r'''#-----------------------------------------------------------------
+# ** ATTENTION **
+# This code was automatically generated from the file:
+# $cfg_filename 
+#
+# Do not modify it directly. Modify the configuration file and
+# run the generator again.
+# ** ** *** ** **
+#
+# pycparser: c_ast.py
+#
+# AST Node classes.
+#
+# Copyright (C) 2008-2010, Eli Bendersky
+# License: LGPL
+#-----------------------------------------------------------------
+
+'''
+
+_PROLOGUE_CODE = r'''
+import sys
+
+
+class Node(object):
+    """ Abstract base class for AST nodes.
+    """
+    def children(self):
+        """ A sequence of all children that are Nodes
+        """
+        pass
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        """ Pretty print the Node and all its attributes and
+            children (recursively) to a buffer.
+            
+            file:   
+                Open IO buffer into which the Node is printed.
+            
+            offset: 
+                Initial offset (amount of leading spaces) 
+            
+            attrnames:
+                True if you want to see the attribute names in
+                name=value pairs. False to only see the values.
+            
+            showcoord:
+                Do you want the coordinates of each Node to be
+                displayed.
+        """
+        pass
+
+
+class NodeVisitor(object):
+    """ A base NodeVisitor class for visiting c_ast nodes. 
+        Subclass it and define your own visit_XXX methods, where
+        XXX is the class name you want to visit with these 
+        methods.
+        
+        For example:
+        
+        class ConstantVisitor(NodeVisitor):
+            def __init__(self):
+                self.values = []
+            
+            def visit_Constant(self, node):
+                self.values.append(node.value)
+
+        Creates a list of values of all the constant nodes 
+        encountered below the given node. To use it:
+        
+        cv = ConstantVisitor()
+        cv.visit(node)
+        
+        Notes:
+        
+        *   generic_visit() will be called for AST nodes for which 
+            no visit_XXX method was defined. 
+        *   The children of nodes for which a visit_XXX was 
+            defined will not be visited - if you need this, call
+            generic_visit() on the node. 
+            You can use:
+                NodeVisitor.generic_visit(self, node)
+        *   Modeled after Python's own AST visiting facilities
+            (the ast module of Python 3.0)
+    """
+    def visit(self, node):
+        """ Visit a node. 
+        """
+        method = 'visit_' + node.__class__.__name__
+        visitor = getattr(self, method, self.generic_visit)
+        return visitor(node)
+        
+    def generic_visit(self, node):
+        """ Called if no explicit visitor function exists for a 
+            node. Implements preorder visiting of the node.
+        """
+        for c in node.children():
+            self.visit(c)
+
+
+'''
+
+
+if __name__ == "__main__":
+    import sys
+    ast_gen = ASTCodeGenerator('_c_ast.cfg')
+    ast_gen.generate(open('c_ast.py', 'w'))
+
diff --git a/pycparser/_build_tables.py b/pycparser/_build_tables.py
index 902773e..04524e0 100644
--- a/pycparser/_build_tables.py
+++ b/pycparser/_build_tables.py
@@ -3,7 +3,8 @@
 #
 # A dummy for generating the lexing/parsing tables and and 
 # compiling them into .pyc for faster execution in optimized mode.
-# Also generates AST code from the _c_ast.yaml configuration file.
+# Also generates AST code from the configuration file.
+# Should be called from the installation directory.
 #
 # Copyright (C) 2008-2010, Eli Bendersky
 # License: LGPL
@@ -12,7 +13,7 @@
 # Generate c_ast.py
 #
 from _ast_gen import ASTCodeGenerator
-ast_gen = ASTCodeGenerator('_c_ast.yaml')
+ast_gen = ASTCodeGenerator('_c_ast.cfg')
 ast_gen.generate(open('c_ast.py', 'w'))
 
 from pycparser import c_parser
diff --git a/pycparser/c_ast.py b/pycparser/c_ast.py
index 12d690c..532fa8e 100644
--- a/pycparser/c_ast.py
+++ b/pycparser/c_ast.py
@@ -1,1237 +1,1237 @@
-#-----------------------------------------------------------------

-# ** ATTENTION **

-# This code was automatically generated from the file:

-# _c_ast.yaml 

-#

-# Do not modify it directly. Modify the configuration file and

-# run the generator again.

-# ** ** *** ** **

-#

-# pycparser: c_ast.py

-#

-# AST Node classes.

-#

-# Copyright (C) 2008, Eli Bendersky

-# License: LGPL

-#-----------------------------------------------------------------

-

-

-import sys

-

-

-class Node(object):

-    """ Abstract base class for AST nodes.

-    """

-    def children(self):

-        """ A sequence of all children that are Nodes

-        """

-        pass

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        """ Pretty print the Node and all its attributes and

-            children (recursively) to a buffer.

-            

-            file:   

-                Open IO buffer into which the Node is printed.

-            

-            offset: 

-                Initial offset (amount of leading spaces) 

-            

-            attrnames:

-                True if you want to see the attribute names in

-                name=value pairs. False to only see the values.

-            

-            showcoord:

-                Do you want the coordinates of each Node to be

-                displayed.

-        """

-        pass

-

-

-class NodeVisitor(object):

-    """ A base NodeVisitor class for visiting c_ast nodes. 

-        Subclass it and define your own visit_XXX methods, where

-        XXX is the class name you want to visit with these 

-        methods.

-        

-        For example:

-        

-        class ConstantVisitor(NodeVisitor):

-            def __init__(self):

-                self.values = []

-            

-            def visit_Constant(self, node):

-                self.values.append(node.value)

-

-        Creates a list of values of all the constant nodes 

-        encountered below the given node. To use it:

-        

-        cv = ConstantVisitor()

-        cv.visit(node)

-        

-        Notes:

-        

-        *   generic_visit() will be called for AST nodes for which 

-            no visit_XXX method was defined. 

-        *   The children of nodes for which a visit_XXX was 

-            defined will not be visited - if you need this, call

-            generic_visit() on the node. 

-            You can use:

-                NodeVisitor.generic_visit(self, node)

-        *   Modeled after Python's own AST visiting facilities

-            (the ast module of Python 3.0)

-    """

-    def visit(self, node):

-        """ Visit a node. 

-        """

-        method = 'visit_' + node.__class__.__name__

-        visitor = getattr(self, method, self.generic_visit)

-        return visitor(node)

-        

-    def generic_visit(self, node):

-        """ Called if no explicit visitor function exists for a 

-            node. Implements preorder visiting of the node.

-        """

-        for c in node.children():

-            self.visit(c)

-

-

-class Typedef(Node):

-    def __init__(self, name, quals, storage, type, coord=None):

-        self.name = name

-        self.quals = quals

-        self.storage = storage

-        self.type = type

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        if self.type is not None: nodelist.append(self.type)

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'Typedef: ')

-

-        if attrnames:

-            attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name)), ("quals", repr(self.quals)), ("storage", repr(self.storage))])

-        else:

-            attrstr = ', '.join('%s' % v for v in [self.name, self.quals, self.storage])

-        buf.write(attrstr)

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class Struct(Node):

-    def __init__(self, name, decls, coord=None):

-        self.name = name

-        self.decls = decls

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        if self.decls is not None: nodelist.extend(self.decls)

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'Struct: ')

-

-        if attrnames:

-            attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))])

-        else:

-            attrstr = ', '.join('%s' % v for v in [self.name])

-        buf.write(attrstr)

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class For(Node):

-    def __init__(self, init, cond, next, stmt, coord=None):

-        self.init = init

-        self.cond = cond

-        self.next = next

-        self.stmt = stmt

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        if self.init is not None: nodelist.append(self.init)

-        if self.cond is not None: nodelist.append(self.cond)

-        if self.next is not None: nodelist.append(self.next)

-        if self.stmt is not None: nodelist.append(self.stmt)

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'For: ')

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class UnaryOp(Node):

-    def __init__(self, op, expr, coord=None):

-        self.op = op

-        self.expr = expr

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        if self.expr is not None: nodelist.append(self.expr)

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'UnaryOp: ')

-

-        if attrnames:

-            attrstr = ', '.join('%s=%s' % nv for nv in [("op", repr(self.op))])

-        else:

-            attrstr = ', '.join('%s' % v for v in [self.op])

-        buf.write(attrstr)

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class Union(Node):

-    def __init__(self, name, decls, coord=None):

-        self.name = name

-        self.decls = decls

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        if self.decls is not None: nodelist.extend(self.decls)

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'Union: ')

-

-        if attrnames:

-            attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))])

-        else:

-            attrstr = ', '.join('%s' % v for v in [self.name])

-        buf.write(attrstr)

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class CompoundLiteral(Node):

-    def __init__(self, type, init, coord=None):

-        self.type = type

-        self.init = init

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        if self.type is not None: nodelist.append(self.type)

-        if self.init is not None: nodelist.append(self.init)

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'CompoundLiteral: ')

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class TernaryOp(Node):

-    def __init__(self, cond, iftrue, iffalse, coord=None):

-        self.cond = cond

-        self.iftrue = iftrue

-        self.iffalse = iffalse

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        if self.cond is not None: nodelist.append(self.cond)

-        if self.iftrue is not None: nodelist.append(self.iftrue)

-        if self.iffalse is not None: nodelist.append(self.iffalse)

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'TernaryOp: ')

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class Label(Node):

-    def __init__(self, name, stmt, coord=None):

-        self.name = name

-        self.stmt = stmt

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        if self.stmt is not None: nodelist.append(self.stmt)

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'Label: ')

-

-        if attrnames:

-            attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))])

-        else:

-            attrstr = ', '.join('%s' % v for v in [self.name])

-        buf.write(attrstr)

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class IdentifierType(Node):

-    def __init__(self, names, coord=None):

-        self.names = names

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'IdentifierType: ')

-

-        if attrnames:

-            attrstr = ', '.join('%s=%s' % nv for nv in [("names", repr(self.names))])

-        else:

-            attrstr = ', '.join('%s' % v for v in [self.names])

-        buf.write(attrstr)

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class FuncDef(Node):

-    def __init__(self, decl, param_decls, body, coord=None):

-        self.decl = decl

-        self.param_decls = param_decls

-        self.body = body

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        if self.decl is not None: nodelist.append(self.decl)

-        if self.body is not None: nodelist.append(self.body)

-        if self.param_decls is not None: nodelist.extend(self.param_decls)

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'FuncDef: ')

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class DeclList(Node):

-    def __init__(self, decls, coord=None):

-        self.decls = decls

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        if self.decls is not None: nodelist.extend(self.decls)

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'DeclList: ')

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class Enumerator(Node):

-    def __init__(self, name, value, coord=None):

-        self.name = name

-        self.value = value

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        if self.value is not None: nodelist.append(self.value)

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'Enumerator: ')

-

-        if attrnames:

-            attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))])

-        else:

-            attrstr = ', '.join('%s' % v for v in [self.name])

-        buf.write(attrstr)

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class FuncCall(Node):

-    def __init__(self, name, args, coord=None):

-        self.name = name

-        self.args = args

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        if self.name is not None: nodelist.append(self.name)

-        if self.args is not None: nodelist.append(self.args)

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'FuncCall: ')

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class Assignment(Node):

-    def __init__(self, op, lvalue, rvalue, coord=None):

-        self.op = op

-        self.lvalue = lvalue

-        self.rvalue = rvalue

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        if self.lvalue is not None: nodelist.append(self.lvalue)

-        if self.rvalue is not None: nodelist.append(self.rvalue)

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'Assignment: ')

-

-        if attrnames:

-            attrstr = ', '.join('%s=%s' % nv for nv in [("op", repr(self.op))])

-        else:

-            attrstr = ', '.join('%s' % v for v in [self.op])

-        buf.write(attrstr)

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class FuncDecl(Node):

-    def __init__(self, args, type, coord=None):

-        self.args = args

-        self.type = type

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        if self.args is not None: nodelist.append(self.args)

-        if self.type is not None: nodelist.append(self.type)

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'FuncDecl: ')

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class Enum(Node):

-    def __init__(self, name, values, coord=None):

-        self.name = name

-        self.values = values

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        if self.values is not None: nodelist.append(self.values)

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'Enum: ')

-

-        if attrnames:

-            attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))])

-        else:

-            attrstr = ', '.join('%s' % v for v in [self.name])

-        buf.write(attrstr)

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class ExprList(Node):

-    def __init__(self, exprs, coord=None):

-        self.exprs = exprs

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        if self.exprs is not None: nodelist.extend(self.exprs)

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'ExprList: ')

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class Break(Node):

-    def __init__(self, coord=None):

-        self.coord = coord

-

-    def children(self):

-        return ()

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'Break: ')

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class DoWhile(Node):

-    def __init__(self, cond, stmt, coord=None):

-        self.cond = cond

-        self.stmt = stmt

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        if self.cond is not None: nodelist.append(self.cond)

-        if self.stmt is not None: nodelist.append(self.stmt)

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'DoWhile: ')

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class StructRef(Node):

-    def __init__(self, name, type, field, coord=None):

-        self.name = name

-        self.type = type

-        self.field = field

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        if self.name is not None: nodelist.append(self.name)

-        if self.field is not None: nodelist.append(self.field)

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'StructRef: ')

-

-        if attrnames:

-            attrstr = ', '.join('%s=%s' % nv for nv in [("type", repr(self.type))])

-        else:

-            attrstr = ', '.join('%s' % v for v in [self.type])

-        buf.write(attrstr)

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class BinaryOp(Node):

-    def __init__(self, op, left, right, coord=None):

-        self.op = op

-        self.left = left

-        self.right = right

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        if self.left is not None: nodelist.append(self.left)

-        if self.right is not None: nodelist.append(self.right)

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'BinaryOp: ')

-

-        if attrnames:

-            attrstr = ', '.join('%s=%s' % nv for nv in [("op", repr(self.op))])

-        else:

-            attrstr = ', '.join('%s' % v for v in [self.op])

-        buf.write(attrstr)

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class Compound(Node):

-    def __init__(self, block_items, coord=None):

-        self.block_items = block_items

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        if self.block_items is not None: nodelist.extend(self.block_items)

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'Compound: ')

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class ArrayDecl(Node):

-    def __init__(self, type, dim, coord=None):

-        self.type = type

-        self.dim = dim

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        if self.type is not None: nodelist.append(self.type)

-        if self.dim is not None: nodelist.append(self.dim)

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'ArrayDecl: ')

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class Case(Node):

-    def __init__(self, expr, stmt, coord=None):

-        self.expr = expr

-        self.stmt = stmt

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        if self.expr is not None: nodelist.append(self.expr)

-        if self.stmt is not None: nodelist.append(self.stmt)

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'Case: ')

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class Cast(Node):

-    def __init__(self, to_type, expr, coord=None):

-        self.to_type = to_type

-        self.expr = expr

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        if self.to_type is not None: nodelist.append(self.to_type)

-        if self.expr is not None: nodelist.append(self.expr)

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'Cast: ')

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class TypeDecl(Node):

-    def __init__(self, declname, quals, type, coord=None):

-        self.declname = declname

-        self.quals = quals

-        self.type = type

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        if self.type is not None: nodelist.append(self.type)

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'TypeDecl: ')

-

-        if attrnames:

-            attrstr = ', '.join('%s=%s' % nv for nv in [("declname", repr(self.declname)), ("quals", repr(self.quals))])

-        else:

-            attrstr = ', '.join('%s' % v for v in [self.declname, self.quals])

-        buf.write(attrstr)

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class Default(Node):

-    def __init__(self, stmt, coord=None):

-        self.stmt = stmt

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        if self.stmt is not None: nodelist.append(self.stmt)

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'Default: ')

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class PtrDecl(Node):

-    def __init__(self, quals, type, coord=None):

-        self.quals = quals

-        self.type = type

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        if self.type is not None: nodelist.append(self.type)

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'PtrDecl: ')

-

-        if attrnames:

-            attrstr = ', '.join('%s=%s' % nv for nv in [("quals", repr(self.quals))])

-        else:

-            attrstr = ', '.join('%s' % v for v in [self.quals])

-        buf.write(attrstr)

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class Switch(Node):

-    def __init__(self, cond, stmt, coord=None):

-        self.cond = cond

-        self.stmt = stmt

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        if self.cond is not None: nodelist.append(self.cond)

-        if self.stmt is not None: nodelist.append(self.stmt)

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'Switch: ')

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class Continue(Node):

-    def __init__(self, coord=None):

-        self.coord = coord

-

-    def children(self):

-        return ()

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'Continue: ')

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class ParamList(Node):

-    def __init__(self, params, coord=None):

-        self.params = params

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        if self.params is not None: nodelist.extend(self.params)

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'ParamList: ')

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class Return(Node):

-    def __init__(self, expr, coord=None):

-        self.expr = expr

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        if self.expr is not None: nodelist.append(self.expr)

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'Return: ')

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class Typename(Node):

-    def __init__(self, quals, type, coord=None):

-        self.quals = quals

-        self.type = type

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        if self.type is not None: nodelist.append(self.type)

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'Typename: ')

-

-        if attrnames:

-            attrstr = ', '.join('%s=%s' % nv for nv in [("quals", repr(self.quals))])

-        else:

-            attrstr = ', '.join('%s' % v for v in [self.quals])

-        buf.write(attrstr)

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class ID(Node):

-    def __init__(self, name, coord=None):

-        self.name = name

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'ID: ')

-

-        if attrnames:

-            attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))])

-        else:

-            attrstr = ', '.join('%s' % v for v in [self.name])

-        buf.write(attrstr)

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class Goto(Node):

-    def __init__(self, name, coord=None):

-        self.name = name

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'Goto: ')

-

-        if attrnames:

-            attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))])

-        else:

-            attrstr = ', '.join('%s' % v for v in [self.name])

-        buf.write(attrstr)

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class Decl(Node):

-    def __init__(self, name, quals, storage, funcspec, type, init, bitsize, coord=None):

-        self.name = name

-        self.quals = quals

-        self.storage = storage

-        self.funcspec = funcspec

-        self.type = type

-        self.init = init

-        self.bitsize = bitsize

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        if self.type is not None: nodelist.append(self.type)

-        if self.init is not None: nodelist.append(self.init)

-        if self.bitsize is not None: nodelist.append(self.bitsize)

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'Decl: ')

-

-        if attrnames:

-            attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name)), ("quals", repr(self.quals)), ("storage", repr(self.storage)), ("funcspec", repr(self.funcspec))])

-        else:

-            attrstr = ', '.join('%s' % v for v in [self.name, self.quals, self.storage, self.funcspec])

-        buf.write(attrstr)

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class Constant(Node):

-    def __init__(self, type, value, coord=None):

-        self.type = type

-        self.value = value

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'Constant: ')

-

-        if attrnames:

-            attrstr = ', '.join('%s=%s' % nv for nv in [("type", repr(self.type)), ("value", repr(self.value))])

-        else:

-            attrstr = ', '.join('%s' % v for v in [self.type, self.value])

-        buf.write(attrstr)

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class FileAST(Node):

-    def __init__(self, ext, coord=None):

-        self.ext = ext

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        if self.ext is not None: nodelist.extend(self.ext)

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'FileAST: ')

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class ArrayRef(Node):

-    def __init__(self, name, subscript, coord=None):

-        self.name = name

-        self.subscript = subscript

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        if self.name is not None: nodelist.append(self.name)

-        if self.subscript is not None: nodelist.append(self.subscript)

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'ArrayRef: ')

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class While(Node):

-    def __init__(self, cond, stmt, coord=None):

-        self.cond = cond

-        self.stmt = stmt

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        if self.cond is not None: nodelist.append(self.cond)

-        if self.stmt is not None: nodelist.append(self.stmt)

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'While: ')

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class NamedInitializer(Node):

-    def __init__(self, name, expr, coord=None):

-        self.name = name

-        self.expr = expr

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        if self.expr is not None: nodelist.append(self.expr)

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'NamedInitializer: ')

-

-        if attrnames:

-            attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))])

-        else:

-            attrstr = ', '.join('%s' % v for v in [self.name])

-        buf.write(attrstr)

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class EnumeratorList(Node):

-    def __init__(self, enumerators, coord=None):

-        self.enumerators = enumerators

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        if self.enumerators is not None: nodelist.extend(self.enumerators)

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'EnumeratorList: ')

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class EllipsisParam(Node):

-    def __init__(self, coord=None):

-        self.coord = coord

-

-    def children(self):

-        return ()

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'EllipsisParam: ')

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

-class If(Node):

-    def __init__(self, cond, iftrue, iffalse, coord=None):

-        self.cond = cond

-        self.iftrue = iftrue

-        self.iffalse = iffalse

-        self.coord = coord

-

-    def children(self):

-        nodelist = []

-        if self.cond is not None: nodelist.append(self.cond)

-        if self.iftrue is not None: nodelist.append(self.iftrue)

-        if self.iffalse is not None: nodelist.append(self.iffalse)

-        return tuple(nodelist)

-

-    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):

-        lead = ' ' * offset

-        buf.write(lead + 'If: ')

-

-        if showcoord:

-            buf.write(' (at %s)' % self.coord)

-        buf.write('\n')

-

-        for c in self.children():

-            c.show(buf, offset + 2, attrnames, showcoord)

-

-

+#-----------------------------------------------------------------
+# ** ATTENTION **
+# This code was automatically generated from the file:
+# _c_ast.cfg 
+#
+# Do not modify it directly. Modify the configuration file and
+# run the generator again.
+# ** ** *** ** **
+#
+# pycparser: c_ast.py
+#
+# AST Node classes.
+#
+# Copyright (C) 2008-2010, Eli Bendersky
+# License: LGPL
+#-----------------------------------------------------------------
+
+
+import sys
+
+
+class Node(object):
+    """ Abstract base class for AST nodes.
+    """
+    def children(self):
+        """ A sequence of all children that are Nodes
+        """
+        pass
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        """ Pretty print the Node and all its attributes and
+            children (recursively) to a buffer.
+            
+            file:   
+                Open IO buffer into which the Node is printed.
+            
+            offset: 
+                Initial offset (amount of leading spaces) 
+            
+            attrnames:
+                True if you want to see the attribute names in
+                name=value pairs. False to only see the values.
+            
+            showcoord:
+                Do you want the coordinates of each Node to be
+                displayed.
+        """
+        pass
+
+
+class NodeVisitor(object):
+    """ A base NodeVisitor class for visiting c_ast nodes. 
+        Subclass it and define your own visit_XXX methods, where
+        XXX is the class name you want to visit with these 
+        methods.
+        
+        For example:
+        
+        class ConstantVisitor(NodeVisitor):
+            def __init__(self):
+                self.values = []
+            
+            def visit_Constant(self, node):
+                self.values.append(node.value)
+
+        Creates a list of values of all the constant nodes 
+        encountered below the given node. To use it:
+        
+        cv = ConstantVisitor()
+        cv.visit(node)
+        
+        Notes:
+        
+        *   generic_visit() will be called for AST nodes for which 
+            no visit_XXX method was defined. 
+        *   The children of nodes for which a visit_XXX was 
+            defined will not be visited - if you need this, call
+            generic_visit() on the node. 
+            You can use:
+                NodeVisitor.generic_visit(self, node)
+        *   Modeled after Python's own AST visiting facilities
+            (the ast module of Python 3.0)
+    """
+    def visit(self, node):
+        """ Visit a node. 
+        """
+        method = 'visit_' + node.__class__.__name__
+        visitor = getattr(self, method, self.generic_visit)
+        return visitor(node)
+        
+    def generic_visit(self, node):
+        """ Called if no explicit visitor function exists for a 
+            node. Implements preorder visiting of the node.
+        """
+        for c in node.children():
+            self.visit(c)
+
+
+class ArrayDecl(Node):
+    def __init__(self, type, dim, coord=None):
+        self.type = type
+        self.dim = dim
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.type is not None: nodelist.append(self.type)
+        if self.dim is not None: nodelist.append(self.dim)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'ArrayDecl: ')
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class ArrayRef(Node):
+    def __init__(self, name, subscript, coord=None):
+        self.name = name
+        self.subscript = subscript
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.name is not None: nodelist.append(self.name)
+        if self.subscript is not None: nodelist.append(self.subscript)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'ArrayRef: ')
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class Assignment(Node):
+    def __init__(self, op, lvalue, rvalue, coord=None):
+        self.op = op
+        self.lvalue = lvalue
+        self.rvalue = rvalue
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.lvalue is not None: nodelist.append(self.lvalue)
+        if self.rvalue is not None: nodelist.append(self.rvalue)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'Assignment: ')
+
+        if attrnames:
+            attrstr = ', '.join('%s=%s' % nv for nv in [("op", repr(self.op))])
+        else:
+            attrstr = ', '.join('%s' % v for v in [self.op])
+        buf.write(attrstr)
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class BinaryOp(Node):
+    def __init__(self, op, left, right, coord=None):
+        self.op = op
+        self.left = left
+        self.right = right
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.left is not None: nodelist.append(self.left)
+        if self.right is not None: nodelist.append(self.right)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'BinaryOp: ')
+
+        if attrnames:
+            attrstr = ', '.join('%s=%s' % nv for nv in [("op", repr(self.op))])
+        else:
+            attrstr = ', '.join('%s' % v for v in [self.op])
+        buf.write(attrstr)
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class Break(Node):
+    def __init__(self, coord=None):
+        self.coord = coord
+
+    def children(self):
+        return ()
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'Break: ')
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class Case(Node):
+    def __init__(self, expr, stmt, coord=None):
+        self.expr = expr
+        self.stmt = stmt
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.expr is not None: nodelist.append(self.expr)
+        if self.stmt is not None: nodelist.append(self.stmt)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'Case: ')
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class Cast(Node):
+    def __init__(self, to_type, expr, coord=None):
+        self.to_type = to_type
+        self.expr = expr
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.to_type is not None: nodelist.append(self.to_type)
+        if self.expr is not None: nodelist.append(self.expr)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'Cast: ')
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class Compound(Node):
+    def __init__(self, block_items, coord=None):
+        self.block_items = block_items
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.block_items is not None: nodelist.extend(self.block_items)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'Compound: ')
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class CompoundLiteral(Node):
+    def __init__(self, type, init, coord=None):
+        self.type = type
+        self.init = init
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.type is not None: nodelist.append(self.type)
+        if self.init is not None: nodelist.append(self.init)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'CompoundLiteral: ')
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class Constant(Node):
+    def __init__(self, type, value, coord=None):
+        self.type = type
+        self.value = value
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'Constant: ')
+
+        if attrnames:
+            attrstr = ', '.join('%s=%s' % nv for nv in [("type", repr(self.type)), ("value", repr(self.value))])
+        else:
+            attrstr = ', '.join('%s' % v for v in [self.type, self.value])
+        buf.write(attrstr)
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class Continue(Node):
+    def __init__(self, coord=None):
+        self.coord = coord
+
+    def children(self):
+        return ()
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'Continue: ')
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class Decl(Node):
+    def __init__(self, name, quals, storage, funcspec, type, init, bitsize, coord=None):
+        self.name = name
+        self.quals = quals
+        self.storage = storage
+        self.funcspec = funcspec
+        self.type = type
+        self.init = init
+        self.bitsize = bitsize
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.type is not None: nodelist.append(self.type)
+        if self.init is not None: nodelist.append(self.init)
+        if self.bitsize is not None: nodelist.append(self.bitsize)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'Decl: ')
+
+        if attrnames:
+            attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name)), ("quals", repr(self.quals)), ("storage", repr(self.storage)), ("funcspec", repr(self.funcspec))])
+        else:
+            attrstr = ', '.join('%s' % v for v in [self.name, self.quals, self.storage, self.funcspec])
+        buf.write(attrstr)
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class DeclList(Node):
+    def __init__(self, decls, coord=None):
+        self.decls = decls
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.decls is not None: nodelist.extend(self.decls)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'DeclList: ')
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class Default(Node):
+    def __init__(self, stmt, coord=None):
+        self.stmt = stmt
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.stmt is not None: nodelist.append(self.stmt)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'Default: ')
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class DoWhile(Node):
+    def __init__(self, cond, stmt, coord=None):
+        self.cond = cond
+        self.stmt = stmt
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.cond is not None: nodelist.append(self.cond)
+        if self.stmt is not None: nodelist.append(self.stmt)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'DoWhile: ')
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class EllipsisParam(Node):
+    def __init__(self, coord=None):
+        self.coord = coord
+
+    def children(self):
+        return ()
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'EllipsisParam: ')
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class Enum(Node):
+    def __init__(self, name, values, coord=None):
+        self.name = name
+        self.values = values
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.values is not None: nodelist.append(self.values)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'Enum: ')
+
+        if attrnames:
+            attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))])
+        else:
+            attrstr = ', '.join('%s' % v for v in [self.name])
+        buf.write(attrstr)
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class Enumerator(Node):
+    def __init__(self, name, value, coord=None):
+        self.name = name
+        self.value = value
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.value is not None: nodelist.append(self.value)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'Enumerator: ')
+
+        if attrnames:
+            attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))])
+        else:
+            attrstr = ', '.join('%s' % v for v in [self.name])
+        buf.write(attrstr)
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class EnumeratorList(Node):
+    def __init__(self, enumerators, coord=None):
+        self.enumerators = enumerators
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.enumerators is not None: nodelist.extend(self.enumerators)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'EnumeratorList: ')
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class ExprList(Node):
+    def __init__(self, exprs, coord=None):
+        self.exprs = exprs
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.exprs is not None: nodelist.extend(self.exprs)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'ExprList: ')
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class FileAST(Node):
+    def __init__(self, ext, coord=None):
+        self.ext = ext
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.ext is not None: nodelist.extend(self.ext)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'FileAST: ')
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class For(Node):
+    def __init__(self, init, cond, next, stmt, coord=None):
+        self.init = init
+        self.cond = cond
+        self.next = next
+        self.stmt = stmt
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.init is not None: nodelist.append(self.init)
+        if self.cond is not None: nodelist.append(self.cond)
+        if self.next is not None: nodelist.append(self.next)
+        if self.stmt is not None: nodelist.append(self.stmt)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'For: ')
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class FuncCall(Node):
+    def __init__(self, name, args, coord=None):
+        self.name = name
+        self.args = args
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.name is not None: nodelist.append(self.name)
+        if self.args is not None: nodelist.append(self.args)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'FuncCall: ')
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class FuncDecl(Node):
+    def __init__(self, args, type, coord=None):
+        self.args = args
+        self.type = type
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.args is not None: nodelist.append(self.args)
+        if self.type is not None: nodelist.append(self.type)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'FuncDecl: ')
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class FuncDef(Node):
+    def __init__(self, decl, param_decls, body, coord=None):
+        self.decl = decl
+        self.param_decls = param_decls
+        self.body = body
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.decl is not None: nodelist.append(self.decl)
+        if self.body is not None: nodelist.append(self.body)
+        if self.param_decls is not None: nodelist.extend(self.param_decls)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'FuncDef: ')
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class Goto(Node):
+    def __init__(self, name, coord=None):
+        self.name = name
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'Goto: ')
+
+        if attrnames:
+            attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))])
+        else:
+            attrstr = ', '.join('%s' % v for v in [self.name])
+        buf.write(attrstr)
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class ID(Node):
+    def __init__(self, name, coord=None):
+        self.name = name
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'ID: ')
+
+        if attrnames:
+            attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))])
+        else:
+            attrstr = ', '.join('%s' % v for v in [self.name])
+        buf.write(attrstr)
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class IdentifierType(Node):
+    def __init__(self, names, coord=None):
+        self.names = names
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'IdentifierType: ')
+
+        if attrnames:
+            attrstr = ', '.join('%s=%s' % nv for nv in [("names", repr(self.names))])
+        else:
+            attrstr = ', '.join('%s' % v for v in [self.names])
+        buf.write(attrstr)
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class If(Node):
+    def __init__(self, cond, iftrue, iffalse, coord=None):
+        self.cond = cond
+        self.iftrue = iftrue
+        self.iffalse = iffalse
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.cond is not None: nodelist.append(self.cond)
+        if self.iftrue is not None: nodelist.append(self.iftrue)
+        if self.iffalse is not None: nodelist.append(self.iffalse)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'If: ')
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class Label(Node):
+    def __init__(self, name, stmt, coord=None):
+        self.name = name
+        self.stmt = stmt
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.stmt is not None: nodelist.append(self.stmt)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'Label: ')
+
+        if attrnames:
+            attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))])
+        else:
+            attrstr = ', '.join('%s' % v for v in [self.name])
+        buf.write(attrstr)
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class NamedInitializer(Node):
+    def __init__(self, name, expr, coord=None):
+        self.name = name
+        self.expr = expr
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.expr is not None: nodelist.append(self.expr)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'NamedInitializer: ')
+
+        if attrnames:
+            attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))])
+        else:
+            attrstr = ', '.join('%s' % v for v in [self.name])
+        buf.write(attrstr)
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class ParamList(Node):
+    def __init__(self, params, coord=None):
+        self.params = params
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.params is not None: nodelist.extend(self.params)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'ParamList: ')
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class PtrDecl(Node):
+    def __init__(self, quals, type, coord=None):
+        self.quals = quals
+        self.type = type
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.type is not None: nodelist.append(self.type)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'PtrDecl: ')
+
+        if attrnames:
+            attrstr = ', '.join('%s=%s' % nv for nv in [("quals", repr(self.quals))])
+        else:
+            attrstr = ', '.join('%s' % v for v in [self.quals])
+        buf.write(attrstr)
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class Return(Node):
+    def __init__(self, expr, coord=None):
+        self.expr = expr
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.expr is not None: nodelist.append(self.expr)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'Return: ')
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class Struct(Node):
+    def __init__(self, name, decls, coord=None):
+        self.name = name
+        self.decls = decls
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.decls is not None: nodelist.extend(self.decls)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'Struct: ')
+
+        if attrnames:
+            attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))])
+        else:
+            attrstr = ', '.join('%s' % v for v in [self.name])
+        buf.write(attrstr)
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class StructRef(Node):
+    def __init__(self, name, type, field, coord=None):
+        self.name = name
+        self.type = type
+        self.field = field
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.name is not None: nodelist.append(self.name)
+        if self.field is not None: nodelist.append(self.field)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'StructRef: ')
+
+        if attrnames:
+            attrstr = ', '.join('%s=%s' % nv for nv in [("type", repr(self.type))])
+        else:
+            attrstr = ', '.join('%s' % v for v in [self.type])
+        buf.write(attrstr)
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class Switch(Node):
+    def __init__(self, cond, stmt, coord=None):
+        self.cond = cond
+        self.stmt = stmt
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.cond is not None: nodelist.append(self.cond)
+        if self.stmt is not None: nodelist.append(self.stmt)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'Switch: ')
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class TernaryOp(Node):
+    def __init__(self, cond, iftrue, iffalse, coord=None):
+        self.cond = cond
+        self.iftrue = iftrue
+        self.iffalse = iffalse
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.cond is not None: nodelist.append(self.cond)
+        if self.iftrue is not None: nodelist.append(self.iftrue)
+        if self.iffalse is not None: nodelist.append(self.iffalse)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'TernaryOp: ')
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class TypeDecl(Node):
+    def __init__(self, declname, quals, type, coord=None):
+        self.declname = declname
+        self.quals = quals
+        self.type = type
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.type is not None: nodelist.append(self.type)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'TypeDecl: ')
+
+        if attrnames:
+            attrstr = ', '.join('%s=%s' % nv for nv in [("declname", repr(self.declname)), ("quals", repr(self.quals))])
+        else:
+            attrstr = ', '.join('%s' % v for v in [self.declname, self.quals])
+        buf.write(attrstr)
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class Typedef(Node):
+    def __init__(self, name, quals, storage, type, coord=None):
+        self.name = name
+        self.quals = quals
+        self.storage = storage
+        self.type = type
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.type is not None: nodelist.append(self.type)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'Typedef: ')
+
+        if attrnames:
+            attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name)), ("quals", repr(self.quals)), ("storage", repr(self.storage))])
+        else:
+            attrstr = ', '.join('%s' % v for v in [self.name, self.quals, self.storage])
+        buf.write(attrstr)
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class Typename(Node):
+    def __init__(self, quals, type, coord=None):
+        self.quals = quals
+        self.type = type
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.type is not None: nodelist.append(self.type)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'Typename: ')
+
+        if attrnames:
+            attrstr = ', '.join('%s=%s' % nv for nv in [("quals", repr(self.quals))])
+        else:
+            attrstr = ', '.join('%s' % v for v in [self.quals])
+        buf.write(attrstr)
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class UnaryOp(Node):
+    def __init__(self, op, expr, coord=None):
+        self.op = op
+        self.expr = expr
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.expr is not None: nodelist.append(self.expr)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'UnaryOp: ')
+
+        if attrnames:
+            attrstr = ', '.join('%s=%s' % nv for nv in [("op", repr(self.op))])
+        else:
+            attrstr = ', '.join('%s' % v for v in [self.op])
+        buf.write(attrstr)
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class Union(Node):
+    def __init__(self, name, decls, coord=None):
+        self.name = name
+        self.decls = decls
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.decls is not None: nodelist.extend(self.decls)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'Union: ')
+
+        if attrnames:
+            attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))])
+        else:
+            attrstr = ', '.join('%s' % v for v in [self.name])
+        buf.write(attrstr)
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
+class While(Node):
+    def __init__(self, cond, stmt, coord=None):
+        self.cond = cond
+        self.stmt = stmt
+        self.coord = coord
+
+    def children(self):
+        nodelist = []
+        if self.cond is not None: nodelist.append(self.cond)
+        if self.stmt is not None: nodelist.append(self.stmt)
+        return tuple(nodelist)
+
+    def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
+        lead = ' ' * offset
+        buf.write(lead + 'While: ')
+
+        if showcoord:
+            buf.write(' (at %s)' % self.coord)
+        buf.write('\n')
+
+        for c in self.children():
+            c.show(buf, offset + 2, attrnames, showcoord)
+
+
diff --git a/pycparser/c_parser.py b/pycparser/c_parser.py
index e9d0403..38c80b3 100644
--- a/pycparser/c_parser.py
+++ b/pycparser/c_parser.py
@@ -1,1354 +1,1353 @@
-#-----------------------------------------------------------------

-# pycparser: c_parser.py

-#

-# CParser class: Parser and AST builder for the C language

-#

-# Copyright (C) 2008-2010, Eli Bendersky

-# License: LGPL

-#-----------------------------------------------------------------

-

-import re

-

-import ply.yacc

-

-from . import c_ast

-from .c_lexer import CLexer

-from .plyparser import PLYParser, Coord, ParseError

-

-

-class CParser(PLYParser):    

-    def __init__(

-            self, 

-            lex_optimize=True,

-            lextab='pycparser.lextab',

-            yacc_optimize=True,

-            yacctab='pycparser.yacctab',

-            yacc_debug=False):

-        """ Create a new CParser.

-        

-            Some arguments for controlling the debug/optimization

-            level of the parser are provided. The defaults are 

-            tuned for release/performance mode. 

-            The simple rules for using them are:

-            *) When tweaking CParser/CLexer, set these to False

-            *) When releasing a stable parser, set to True

-            

-            lex_optimize:

-                Set to False when you're modifying the lexer.

-                Otherwise, changes in the lexer won't be used, if

-                some lextab.py file exists.

-                When releasing with a stable lexer, set to True

-                to save the re-generation of the lexer table on 

-                each run.

-            

-            lextab:

-                Points to the lex table that's used for optimized

-                mode. Only if you're modifying the lexer and want

-                some tests to avoid re-generating the table, make 

-                this point to a local lex table file (that's been

-                earlier generated with lex_optimize=True)

-            

-            yacc_optimize:

-                Set to False when you're modifying the parser.

-                Otherwise, changes in the parser won't be used, if

-                some parsetab.py file exists.

-                When releasing with a stable parser, set to True

-                to save the re-generation of the parser table on 

-                each run.

-            

-            yacctab:

-                Points to the yacc table that's used for optimized

-                mode. Only if you're modifying the parser, make 

-                this point to a local yacc table file

-                        

-            yacc_debug:

-                Generate a parser.out file that explains how yacc

-                built the parsing table from the grammar.

-        """

-        self.clex = CLexer(

-            error_func=self._lex_error_func,

-            type_lookup_func=self._lex_type_lookup_func)

-            

-        self.clex.build(

-            optimize=lex_optimize,

-            lextab=lextab)

-        self.tokens = self.clex.tokens

-        

-        rules_with_opt = [

-            'abstract_declarator',

-            'assignment_expression',

-            'declaration_list',

-            'declaration_specifiers',

-            'designation',

-            'expression',

-            'identifier_list',

-            'init_declarator_list',

-            'parameter_type_list',

-            'specifier_qualifier_list',

-            'block_item_list',

-            'type_qualifier_list',

-        ]

-        

-        for rule in rules_with_opt:

-            self._create_opt_rule(rule)

-        

-        self.cparser = ply.yacc.yacc(

-            module=self, 

-            start='translation_unit',

-            debug=yacc_debug,

-            optimize=yacc_optimize,

-            tabmodule=yacctab)

-        

-        # A table of identifiers defined as typedef types during

-        # parsing.

-        #

-        self.typedef_table = set([])

-    

-    def parse(self, text, filename='', debuglevel=0):

-        """ Parses C code and returns an AST.

-        

-            text:

-                A string containing the C source code

-            

-            filename:

-                Name of the file being parsed (for meaningful

-                error messages)

-            

-            debuglevel:

-                Debug level to yacc

-        """

-        self.clex.filename = filename

-        self.clex.reset_lineno()

-        self.typedef_table = set([])

-        return self.cparser.parse(text, lexer=self.clex, debug=debuglevel)

-    

-    ######################--   PRIVATE   --######################

-    

-    def _lex_error_func(self, msg, line, column):

-        self._parse_error(msg, self._coord(line, column))

-    

-    def _lex_type_lookup_func(self, name):

-        """ Looks up types that were previously defined with

-            typedef. 

-            Passed to the lexer for recognizing identifiers that

-            are types.

-        """

-        return name in self.typedef_table

-    

-    def _add_typedef_type(self, name):

-        """ Adds names that were defined as new types with 

-            typedef.

-        """

-        self.typedef_table.add(name)

-    

-    # To understand what's going on here, read sections A.8.5 and 

-    # A.8.6 of K&R2 very carefully.

-    # 

-    # A C type consists of a basic type declaration, with a list

-    # of modifiers. For example:

-    #

-    # int *c[5];

-    #

-    # The basic declaration here is 'int x', and the pointer and

-    # the array are the modifiers.

-    #

-    # Basic declarations are represented by TypeDecl (from module

-    # c_ast) and the modifiers are FuncDecl, PtrDecl and 

-    # ArrayDecl.

-    #

-    # The standard states that whenever a new modifier is parsed,

-    # it should be added to the end of the list of modifiers. For

-    # example:

-    #

-    # K&R2 A.8.6.2: Array Declarators

-    #

-    # In a declaration T D where D has the form  

-    #   D1 [constant-expression-opt]  

-    # and the type of the identifier in the declaration T D1 is 

-    # "type-modifier T", the type of the 

-    # identifier of D is "type-modifier array of T"

-    #

-    # This is what this method does. The declarator it receives

-    # can be a list of declarators ending with TypeDecl. It 

-    # tacks the modifier to the end of this list, just before 

-    # the TypeDecl.

-    #

-    # Additionally, the modifier may be a list itself. This is 

-    # useful for pointers, that can come as a chain from the rule

-    # p_pointer. In this case, the whole modifier list is spliced 

-    # into the new location.

-    #

-    def _type_modify_decl(self, decl, modifier):

-        """ Tacks a type modifier on a declarator, and returns

-            the modified declarator.

-            

-            Note: the declarator and modifier may be modified

-        """

-        #~ print '****'

-        #~ decl.show(offset=3)

-        #~ modifier.show(offset=3)

-        #~ print '****'

-        

-        modifier_head = modifier

-        modifier_tail = modifier

-        

-        # The modifier may be a nested list. Reach its tail.

-        #

-        while modifier_tail.type: 

-            modifier_tail = modifier_tail.type

-        

-        # If the decl is a basic type, just tack the modifier onto

-        # it

-        #

-        if isinstance(decl, c_ast.TypeDecl):

-            modifier_tail.type = decl

-            return modifier

-        else:

-            # Otherwise, the decl is a list of modifiers. Reach

-            # its tail and splice the modifier onto the tail,

-            # pointing to the underlying basic type.

-            #

-            decl_tail = decl

-            

-            while not isinstance(decl_tail.type, c_ast.TypeDecl):

-                decl_tail = decl_tail.type

-            

-            modifier_tail.type = decl_tail.type

-            decl_tail.type = modifier_head

-            return decl

-

-    # Due to the order in which declarators are constructed,

-    # they have to be fixed in order to look like a normal AST.

-    # 

-    # When a declaration arrives from syntax construction, it has

-    # these problems:

-    # * The innermost TypeDecl has no type (because the basic

-    #   type is only known at the uppermost declaration level)

-    # * The declaration has no variable name, since that is saved

-    #   in the innermost TypeDecl

-    # * The typename of the declaration is a list of type 

-    #   specifiers, and not a node. Here, basic identifier types

-    #   should be separated from more complex types like enums

-    #   and structs.

-    #

-    # This method fixes these problem.

-    #

-    def _fix_decl_name_type(self, decl, typename):

-        """ Fixes a declaration. Modifies decl.

-        """

-        # Reach the underlying basic type

-        #

-        type = decl

-        while not isinstance(type, c_ast.TypeDecl):

-            type = type.type

-        

-        decl.name = type.declname

-        type.quals = decl.quals

-        

-        # The typename is a list of types. If any type in this 

-        # list isn't a simple string type, it must be the only

-        # type in the list (it's illegal to declare "int enum .."

-        # If all the types are basic, they're collected in the

-        # IdentifierType holder.

-        #

-        for tn in typename:

-            if not isinstance(tn, str):

-                if len(typename) > 1:

-                    self._parse_error(

-                        "Invalid multiple types specified", tn.coord)

-                else:

-                    type.type = tn

-                    return decl

-        

-        type.type = c_ast.IdentifierType(typename)

-        return decl

-    

-    def _add_declaration_specifier(self, declspec, newspec, kind):

-        """ Declaration specifiers are represented by a dictionary

-            with the entries:

-            * qual: a list of type qualifiers

-            * storage: a list of storage type qualifiers

-            * type: a list of type specifiers

-            * function: a list of function specifiers

-            

-            This method is given a declaration specifier, and a 

-            new specifier of a given kind.

-            Returns the declaration specifier, with the new 

-            specifier incorporated.

-        """

-        spec = declspec or dict(qual=[], storage=[], type=[], function=[])

-        spec[kind].append(newspec)

-        return spec

-    

-    def _build_function_definition(self, decl, spec, param_decls, body):

-        """ Builds a function definition.

-        """

-        declaration = c_ast.Decl(

-            name=None,

-            quals=spec['qual'],

-            storage=spec['storage'],

-            funcspec=spec['function'],

-            type=decl, 

-            init=None, 

-            bitsize=None, 

-            coord=decl.coord)

-        

-        typename = spec['type']

-        declaration = self._fix_decl_name_type(declaration, typename)

-        return c_ast.FuncDef(

-            decl=declaration,

-            param_decls=param_decls,

-            body=body,

-            coord=decl.coord)

-

-    def _select_struct_union_class(self, token):

-        """ Given a token (either STRUCT or UNION), selects the

-            appropriate AST class.

-        """

-        if token == 'struct':

-            return c_ast.Struct

-        else:

-            return c_ast.Union

-

-    ##

-    ## Precedence and associativity of operators

-    ##

-    precedence = (

-        ('left', 'LOR'),

-        ('left', 'LAND'),

-        ('left', 'OR'),

-        ('left', 'XOR'),

-        ('left', 'AND'),

-        ('left', 'EQ', 'NE'),

-        ('left', 'GT', 'GE', 'LT', 'LE'),

-        ('left', 'RSHIFT', 'LSHIFT'),

-        ('left', 'PLUS', 'MINUS'),

-        ('left', 'TIMES', 'DIVIDE', 'MOD')

-    )

-    

-    ##

-    ## Grammar productions

-    ## Implementation of the BNF defined in K&R2 A.13

-    ##

-    def p_translation_unit_1(self, p):

-        """ translation_unit    : external_declaration 

-        """

-        # Note: external_declaration is already a list

-        #

-        p[0] = c_ast.FileAST(p[1])

-    

-    def p_translation_unit_2(self, p):

-        """ translation_unit    : translation_unit external_declaration

-        """

-        p[1].ext.extend(p[2])

-        p[0] = p[1]

-    

-    # Declarations always come as lists (because they can be

-    # several in one line), so we wrap the function definition 

-    # into a list as well, to make the return value of 

-    # external_declaration homogenous.

-    #

-    def p_external_declaration_1(self, p):

-        """ external_declaration    : function_definition

-        """

-        p[0] = [p[1]]

-    

-    def p_external_declaration_2(self, p):

-        """ external_declaration    : declaration

-        """

-        p[0] = p[1]

-

-    def p_external_declaration_3(self, p):

-        """ external_declaration    : pp_directive

-        """

-        p[0] = p[1]

-

-    def p_pp_directive(self, p):

-        """ pp_directive  : PPHASH 

-        """

-        self._parse_error('Directives not supported yet', 

-            self._coord(p.lineno(1)))

-

-    # In function definitions, the declarator can be followed by

-    # a declaration list, for old "K&R style" function definitios.

-    #

-    def p_function_definition_1(self, p):

-        """ function_definition : declarator declaration_list_opt compound_statement

-        """

-        # no declaration specifiers

-        spec = dict(qual=[], storage=[], type=[])

-

-        p[0] = self._build_function_definition(

-            decl=p[1],

-            spec=spec, 

-            param_decls=p[2],

-            body=p[3])

-                    

-    def p_function_definition_2(self, p):

-        """ function_definition : declaration_specifiers declarator declaration_list_opt compound_statement

-        """

-        spec = p[1]

-

-        p[0] = self._build_function_definition(

-            decl=p[2],

-            spec=spec, 

-            param_decls=p[3],

-            body=p[4])

-        

-    def p_statement(self, p):

-        """ statement   : labeled_statement

-                        | expression_statement

-                        | compound_statement

-                        | selection_statement

-                        | iteration_statement    

-                        | jump_statement

-        """

-        p[0] = p[1]

-

-    # In C, declarations can come several in a line:

-    #   int x, *px, romulo = 5;

-    #

-    # However, for the AST, we will split them to separate Decl

-    # nodes.

-    #

-    # This rule splits its declarations and always returns a list

-    # of Decl nodes, even if it's one element long.

-    #

-    def p_decl_body(self, p):

-        """ decl_body : declaration_specifiers init_declarator_list_opt

-        """

-        spec = p[1]

-        is_typedef = 'typedef' in spec['storage']

-        decls = []

-

-        # p[2] (init_declarator_list_opt) is either a list or None

-        #

-        if p[2] is None:

-            # Then it's a declaration of a struct / enum tag,

-            # without an actual declarator.

-            #

-            type = spec['type']

-            if len(type) > 1:

-                coord = '?'

-                for t in type:

-                    if hasattr(t, 'coord'):

-                        coord = t.coord

-                        break

-                        

-                self._parse_error('Multiple type specifiers with a type tag', coord)

-            

-            decl = c_ast.Decl(

-                name=None,

-                quals=spec['qual'],

-                storage=spec['storage'],

-                funcspec=spec['function'],

-                type=type[0],

-                init=None,

-                bitsize=None,

-                coord=type[0].coord)

-            decls = [decl]

-        else:

-            for decl, init in p[2] or []:

-                if is_typedef:

-                    decl = c_ast.Typedef(

-                        name=None,

-                        quals=spec['qual'],

-                        storage=spec['storage'],

-                        type=decl,

-                        coord=decl.coord)

-                else:

-                    decl = c_ast.Decl(

-                        name=None,

-                        quals=spec['qual'],

-                        storage=spec['storage'],

-                        funcspec=spec['function'],

-                        type=decl, 

-                        init=init, 

-                        bitsize=None, 

-                        coord=decl.coord)

-                

-                typename = spec['type']

-                fixed_decl = self._fix_decl_name_type(decl, typename)

-

-                # Add the type name defined by typedef to a

-                # symbol table (for usage in the lexer)

-                # 

-                if is_typedef:

-                    self._add_typedef_type(fixed_decl.name)

-

-                decls.append(fixed_decl)

-

-        p[0] = decls

-

-    # The declaration has been split to a decl_body sub-rule and

-    # SEMI, because having them in a single rule created a problem

-    # for defining typedefs.

-    #

-    # If a typedef line was directly followed by a line using the

-    # type defined with the typedef, the type would not be 

-    # recognized. This is because to reduce the declaration rule,

-    # the parser's lookahead asked for the token after SEMI, which

-    # was the type from the next line, and the lexer had no chance

-    # to see the updated type symbol table.

-    #

-    # Splitting solves this problem, because after seeing SEMI,

-    # the parser reduces decl_body, which actually adds the new

-    # type into the table to be seen by the lexer before the next

-    # line is reached.

-    #

-    def p_declaration(self, p):

-        """ declaration : decl_body SEMI 

-        """

-        p[0] = p[1]

-

-    # Since each declaration is a list of declarations, this

-    # rule will combine all the declarations and return a single

-    # list

-    # 

-    def p_declaration_list(self, p):

-        """ declaration_list    : declaration

-                                | declaration_list declaration

-        """

-        p[0] = p[1] if len(p) == 2 else p[1] + p[2]

-    

-    def p_declaration_specifiers_1(self, p):

-        """ declaration_specifiers  : type_qualifier declaration_specifiers_opt 

-        """

-        p[0] = self._add_declaration_specifier(p[2], p[1], 'qual')

-        

-    def p_declaration_specifiers_2(self, p):

-        """ declaration_specifiers  : type_specifier declaration_specifiers_opt

-        """

-        p[0] = self._add_declaration_specifier(p[2], p[1], 'type')

-        

-    def p_declaration_specifiers_3(self, p):

-        """ declaration_specifiers  : storage_class_specifier declaration_specifiers_opt

-        """

-        p[0] = self._add_declaration_specifier(p[2], p[1], 'storage')

-        

-    def p_declaration_specifiers_4(self, p):

-        """ declaration_specifiers  : function_specifier declaration_specifiers_opt

-        """

-        p[0] = self._add_declaration_specifier(p[2], p[1], 'function')

-    

-    def p_storage_class_specifier(self, p):

-        """ storage_class_specifier : AUTO

-                                    | REGISTER

-                                    | STATIC

-                                    | EXTERN

-                                    | TYPEDEF

-        """

-        p[0] = p[1]

-    

+#-----------------------------------------------------------------
+# pycparser: c_parser.py
+#
+# CParser class: Parser and AST builder for the C language
+#
+# Copyright (C) 2008-2010, Eli Bendersky
+# License: LGPL
+#-----------------------------------------------------------------
+import re
+
+import ply.yacc
+
+from . import c_ast
+from .c_lexer import CLexer
+from .plyparser import PLYParser, Coord, ParseError
+
+
+class CParser(PLYParser):    
+    def __init__(
+            self, 
+            lex_optimize=True,
+            lextab='pycparser.lextab',
+            yacc_optimize=True,
+            yacctab='pycparser.yacctab',
+            yacc_debug=False):
+        """ Create a new CParser.
+        
+            Some arguments for controlling the debug/optimization
+            level of the parser are provided. The defaults are 
+            tuned for release/performance mode. 
+            The simple rules for using them are:
+            *) When tweaking CParser/CLexer, set these to False
+            *) When releasing a stable parser, set to True
+            
+            lex_optimize:
+                Set to False when you're modifying the lexer.
+                Otherwise, changes in the lexer won't be used, if
+                some lextab.py file exists.
+                When releasing with a stable lexer, set to True
+                to save the re-generation of the lexer table on 
+                each run.
+            
+            lextab:
+                Points to the lex table that's used for optimized
+                mode. Only if you're modifying the lexer and want
+                some tests to avoid re-generating the table, make 
+                this point to a local lex table file (that's been
+                earlier generated with lex_optimize=True)
+            
+            yacc_optimize:
+                Set to False when you're modifying the parser.
+                Otherwise, changes in the parser won't be used, if
+                some parsetab.py file exists.
+                When releasing with a stable parser, set to True
+                to save the re-generation of the parser table on 
+                each run.
+            
+            yacctab:
+                Points to the yacc table that's used for optimized
+                mode. Only if you're modifying the parser, make 
+                this point to a local yacc table file
+                        
+            yacc_debug:
+                Generate a parser.out file that explains how yacc
+                built the parsing table from the grammar.
+        """
+        self.clex = CLexer(
+            error_func=self._lex_error_func,
+            type_lookup_func=self._lex_type_lookup_func)
+            
+        self.clex.build(
+            optimize=lex_optimize,
+            lextab=lextab)
+        self.tokens = self.clex.tokens
+        
+        rules_with_opt = [
+            'abstract_declarator',
+            'assignment_expression',
+            'declaration_list',
+            'declaration_specifiers',
+            'designation',
+            'expression',
+            'identifier_list',
+            'init_declarator_list',
+            'parameter_type_list',
+            'specifier_qualifier_list',
+            'block_item_list',
+            'type_qualifier_list',
+        ]
+        
+        for rule in rules_with_opt:
+            self._create_opt_rule(rule)
+        
+        self.cparser = ply.yacc.yacc(
+            module=self, 
+            start='translation_unit',
+            debug=yacc_debug,
+            optimize=yacc_optimize,
+            tabmodule=yacctab)
+        
+        # A table of identifiers defined as typedef types during
+        # parsing.
+        #
+        self.typedef_table = set([])
+    
+    def parse(self, text, filename='', debuglevel=0):
+        """ Parses C code and returns an AST.
+        
+            text:
+                A string containing the C source code
+            
+            filename:
+                Name of the file being parsed (for meaningful
+                error messages)
+            
+            debuglevel:
+                Debug level to yacc
+        """
+        self.clex.filename = filename
+        self.clex.reset_lineno()
+        self.typedef_table = set([])
+        return self.cparser.parse(text, lexer=self.clex, debug=debuglevel)
+    
+    ######################--   PRIVATE   --######################
+    
+    def _lex_error_func(self, msg, line, column):
+        self._parse_error(msg, self._coord(line, column))
+    
+    def _lex_type_lookup_func(self, name):
+        """ Looks up types that were previously defined with
+            typedef. 
+            Passed to the lexer for recognizing identifiers that
+            are types.
+        """
+        return name in self.typedef_table
+    
+    def _add_typedef_type(self, name):
+        """ Adds names that were defined as new types with 
+            typedef.
+        """
+        self.typedef_table.add(name)
+    
+    # To understand what's going on here, read sections A.8.5 and 
+    # A.8.6 of K&R2 very carefully.
+    # 
+    # A C type consists of a basic type declaration, with a list
+    # of modifiers. For example:
+    #
+    # int *c[5];
+    #
+    # The basic declaration here is 'int x', and the pointer and
+    # the array are the modifiers.
+    #
+    # Basic declarations are represented by TypeDecl (from module
+    # c_ast) and the modifiers are FuncDecl, PtrDecl and 
+    # ArrayDecl.
+    #
+    # The standard states that whenever a new modifier is parsed,
+    # it should be added to the end of the list of modifiers. For
+    # example:
+    #
+    # K&R2 A.8.6.2: Array Declarators
+    #
+    # In a declaration T D where D has the form  
+    #   D1 [constant-expression-opt]  
+    # and the type of the identifier in the declaration T D1 is 
+    # "type-modifier T", the type of the 
+    # identifier of D is "type-modifier array of T"
+    #
+    # This is what this method does. The declarator it receives
+    # can be a list of declarators ending with TypeDecl. It 
+    # tacks the modifier to the end of this list, just before 
+    # the TypeDecl.
+    #
+    # Additionally, the modifier may be a list itself. This is 
+    # useful for pointers, that can come as a chain from the rule
+    # p_pointer. In this case, the whole modifier list is spliced 
+    # into the new location.
+    #
+    def _type_modify_decl(self, decl, modifier):
+        """ Tacks a type modifier on a declarator, and returns
+            the modified declarator.
+            
+            Note: the declarator and modifier may be modified
+        """
+        #~ print '****'
+        #~ decl.show(offset=3)
+        #~ modifier.show(offset=3)
+        #~ print '****'
+        
+        modifier_head = modifier
+        modifier_tail = modifier
+        
+        # The modifier may be a nested list. Reach its tail.
+        #
+        while modifier_tail.type: 
+            modifier_tail = modifier_tail.type
+        
+        # If the decl is a basic type, just tack the modifier onto
+        # it
+        #
+        if isinstance(decl, c_ast.TypeDecl):
+            modifier_tail.type = decl
+            return modifier
+        else:
+            # Otherwise, the decl is a list of modifiers. Reach
+            # its tail and splice the modifier onto the tail,
+            # pointing to the underlying basic type.
+            #
+            decl_tail = decl
+            
+            while not isinstance(decl_tail.type, c_ast.TypeDecl):
+                decl_tail = decl_tail.type
+            
+            modifier_tail.type = decl_tail.type
+            decl_tail.type = modifier_head
+            return decl
+
+    # Due to the order in which declarators are constructed,
+    # they have to be fixed in order to look like a normal AST.
+    # 
+    # When a declaration arrives from syntax construction, it has
+    # these problems:
+    # * The innermost TypeDecl has no type (because the basic
+    #   type is only known at the uppermost declaration level)
+    # * The declaration has no variable name, since that is saved
+    #   in the innermost TypeDecl
+    # * The typename of the declaration is a list of type 
+    #   specifiers, and not a node. Here, basic identifier types
+    #   should be separated from more complex types like enums
+    #   and structs.
+    #
+    # This method fixes these problem.
+    #
+    def _fix_decl_name_type(self, decl, typename):
+        """ Fixes a declaration. Modifies decl.
+        """
+        # Reach the underlying basic type
+        #
+        type = decl
+        while not isinstance(type, c_ast.TypeDecl):
+            type = type.type
+        
+        decl.name = type.declname
+        type.quals = decl.quals
+        
+        # The typename is a list of types. If any type in this 
+        # list isn't a simple string type, it must be the only
+        # type in the list (it's illegal to declare "int enum .."
+        # If all the types are basic, they're collected in the
+        # IdentifierType holder.
+        #
+        for tn in typename:
+            if not isinstance(tn, str):
+                if len(typename) > 1:
+                    self._parse_error(
+                        "Invalid multiple types specified", tn.coord)
+                else:
+                    type.type = tn
+                    return decl
+        
+        type.type = c_ast.IdentifierType(typename)
+        return decl
+    
+    def _add_declaration_specifier(self, declspec, newspec, kind):
+        """ Declaration specifiers are represented by a dictionary
+            with the entries:
+            * qual: a list of type qualifiers
+            * storage: a list of storage type qualifiers
+            * type: a list of type specifiers
+            * function: a list of function specifiers
+            
+            This method is given a declaration specifier, and a 
+            new specifier of a given kind.
+            Returns the declaration specifier, with the new 
+            specifier incorporated.
+        """
+        spec = declspec or dict(qual=[], storage=[], type=[], function=[])
+        spec[kind].append(newspec)
+        return spec
+    
+    def _build_function_definition(self, decl, spec, param_decls, body):
+        """ Builds a function definition.
+        """
+        declaration = c_ast.Decl(
+            name=None,
+            quals=spec['qual'],
+            storage=spec['storage'],
+            funcspec=spec['function'],
+            type=decl, 
+            init=None, 
+            bitsize=None, 
+            coord=decl.coord)
+        
+        typename = spec['type']
+        declaration = self._fix_decl_name_type(declaration, typename)
+        return c_ast.FuncDef(
+            decl=declaration,
+            param_decls=param_decls,
+            body=body,
+            coord=decl.coord)
+
+    def _select_struct_union_class(self, token):
+        """ Given a token (either STRUCT or UNION), selects the
+            appropriate AST class.
+        """
+        if token == 'struct':
+            return c_ast.Struct
+        else:
+            return c_ast.Union
+
+    ##
+    ## Precedence and associativity of operators
+    ##
+    precedence = (
+        ('left', 'LOR'),
+        ('left', 'LAND'),
+        ('left', 'OR'),
+        ('left', 'XOR'),
+        ('left', 'AND'),
+        ('left', 'EQ', 'NE'),
+        ('left', 'GT', 'GE', 'LT', 'LE'),
+        ('left', 'RSHIFT', 'LSHIFT'),
+        ('left', 'PLUS', 'MINUS'),
+        ('left', 'TIMES', 'DIVIDE', 'MOD')
+    )
+    
+    ##
+    ## Grammar productions
+    ## Implementation of the BNF defined in K&R2 A.13
+    ##
+    def p_translation_unit_1(self, p):
+        """ translation_unit    : external_declaration 
+        """
+        # Note: external_declaration is already a list
+        #
+        p[0] = c_ast.FileAST(p[1])
+    
+    def p_translation_unit_2(self, p):
+        """ translation_unit    : translation_unit external_declaration
+        """
+        p[1].ext.extend(p[2])
+        p[0] = p[1]
+    
+    # Declarations always come as lists (because they can be
+    # several in one line), so we wrap the function definition 
+    # into a list as well, to make the return value of 
+    # external_declaration homogenous.
+    #
+    def p_external_declaration_1(self, p):
+        """ external_declaration    : function_definition
+        """
+        p[0] = [p[1]]
+    
+    def p_external_declaration_2(self, p):
+        """ external_declaration    : declaration
+        """
+        p[0] = p[1]
+
+    def p_external_declaration_3(self, p):
+        """ external_declaration    : pp_directive
+        """
+        p[0] = p[1]
+
+    def p_pp_directive(self, p):
+        """ pp_directive  : PPHASH 
+        """
+        self._parse_error('Directives not supported yet', 
+            self._coord(p.lineno(1)))
+
+    # In function definitions, the declarator can be followed by
+    # a declaration list, for old "K&R style" function definitios.
+    #
+    def p_function_definition_1(self, p):
+        """ function_definition : declarator declaration_list_opt compound_statement
+        """
+        # no declaration specifiers
+        spec = dict(qual=[], storage=[], type=[])
+
+        p[0] = self._build_function_definition(
+            decl=p[1],
+            spec=spec, 
+            param_decls=p[2],
+            body=p[3])
+                    
+    def p_function_definition_2(self, p):
+        """ function_definition : declaration_specifiers declarator declaration_list_opt compound_statement
+        """
+        spec = p[1]
+
+        p[0] = self._build_function_definition(
+            decl=p[2],
+            spec=spec, 
+            param_decls=p[3],
+            body=p[4])
+        
+    def p_statement(self, p):
+        """ statement   : labeled_statement
+                        | expression_statement
+                        | compound_statement
+                        | selection_statement
+                        | iteration_statement    
+                        | jump_statement
+        """
+        p[0] = p[1]
+
+    # In C, declarations can come several in a line:
+    #   int x, *px, romulo = 5;
+    #
+    # However, for the AST, we will split them to separate Decl
+    # nodes.
+    #
+    # This rule splits its declarations and always returns a list
+    # of Decl nodes, even if it's one element long.
+    #
+    def p_decl_body(self, p):
+        """ decl_body : declaration_specifiers init_declarator_list_opt
+        """
+        spec = p[1]
+        is_typedef = 'typedef' in spec['storage']
+        decls = []
+
+        # p[2] (init_declarator_list_opt) is either a list or None
+        #
+        if p[2] is None:
+            # Then it's a declaration of a struct / enum tag,
+            # without an actual declarator.
+            #
+            type = spec['type']
+            if len(type) > 1:
+                coord = '?'
+                for t in type:
+                    if hasattr(t, 'coord'):
+                        coord = t.coord
+                        break
+                        
+                self._parse_error('Multiple type specifiers with a type tag', coord)
+            
+            decl = c_ast.Decl(
+                name=None,
+                quals=spec['qual'],
+                storage=spec['storage'],
+                funcspec=spec['function'],
+                type=type[0],
+                init=None,
+                bitsize=None,
+                coord=type[0].coord)
+            decls = [decl]
+        else:
+            for decl, init in p[2] or []:
+                if is_typedef:
+                    decl = c_ast.Typedef(
+                        name=None,
+                        quals=spec['qual'],
+                        storage=spec['storage'],
+                        type=decl,
+                        coord=decl.coord)
+                else:
+                    decl = c_ast.Decl(
+                        name=None,
+                        quals=spec['qual'],
+                        storage=spec['storage'],
+                        funcspec=spec['function'],
+                        type=decl, 
+                        init=init, 
+                        bitsize=None, 
+                        coord=decl.coord)
+                
+                typename = spec['type']
+                fixed_decl = self._fix_decl_name_type(decl, typename)
+
+                # Add the type name defined by typedef to a
+                # symbol table (for usage in the lexer)
+                # 
+                if is_typedef:
+                    self._add_typedef_type(fixed_decl.name)
+
+                decls.append(fixed_decl)
+
+        p[0] = decls
+
+    # The declaration has been split to a decl_body sub-rule and
+    # SEMI, because having them in a single rule created a problem
+    # for defining typedefs.
+    #
+    # If a typedef line was directly followed by a line using the
+    # type defined with the typedef, the type would not be 
+    # recognized. This is because to reduce the declaration rule,
+    # the parser's lookahead asked for the token after SEMI, which
+    # was the type from the next line, and the lexer had no chance
+    # to see the updated type symbol table.
+    #
+    # Splitting solves this problem, because after seeing SEMI,
+    # the parser reduces decl_body, which actually adds the new
+    # type into the table to be seen by the lexer before the next
+    # line is reached.
+    #
+    def p_declaration(self, p):
+        """ declaration : decl_body SEMI 
+        """
+        p[0] = p[1]
+
+    # Since each declaration is a list of declarations, this
+    # rule will combine all the declarations and return a single
+    # list
+    # 
+    def p_declaration_list(self, p):
+        """ declaration_list    : declaration
+                                | declaration_list declaration
+        """
+        p[0] = p[1] if len(p) == 2 else p[1] + p[2]
+    
+    def p_declaration_specifiers_1(self, p):
+        """ declaration_specifiers  : type_qualifier declaration_specifiers_opt 
+        """
+        p[0] = self._add_declaration_specifier(p[2], p[1], 'qual')
+        
+    def p_declaration_specifiers_2(self, p):
+        """ declaration_specifiers  : type_specifier declaration_specifiers_opt
+        """
+        p[0] = self._add_declaration_specifier(p[2], p[1], 'type')
+        
+    def p_declaration_specifiers_3(self, p):
+        """ declaration_specifiers  : storage_class_specifier declaration_specifiers_opt
+        """
+        p[0] = self._add_declaration_specifier(p[2], p[1], 'storage')
+        
+    def p_declaration_specifiers_4(self, p):
+        """ declaration_specifiers  : function_specifier declaration_specifiers_opt
+        """
+        p[0] = self._add_declaration_specifier(p[2], p[1], 'function')
+    
+    def p_storage_class_specifier(self, p):
+        """ storage_class_specifier : AUTO
+                                    | REGISTER
+                                    | STATIC
+                                    | EXTERN
+                                    | TYPEDEF
+        """
+        p[0] = p[1]
+    
     def p_function_specifier(self, p):
         """ function_specifier  : INLINE
-        """

-        p[0] = p[1]

-    

-    def p_type_specifier_1(self, p):

-        """ type_specifier  : VOID

-                            | CHAR

-                            | SHORT

-                            | INT

-                            | LONG

-                            | FLOAT

-                            | DOUBLE

-                            | SIGNED

-                            | UNSIGNED

-                            | typedef_name

-                            | enum_specifier

-                            | struct_or_union_specifier

-        """

-        p[0] = p[1]

-    

-    def p_type_qualifier(self, p):

-        """ type_qualifier  : CONST

-                            | RESTRICT

-                            | VOLATILE

-        """

-        p[0] = p[1]

-    

-    def p_init_declarator_list(self, p):

-        """ init_declarator_list    : init_declarator

-                                    | init_declarator_list COMMA init_declarator

-        """

-        p[0] = p[1] + [p[3]] if len(p) == 4 else [p[1]]

-

-    # Returns a (declarator, initializer) pair

-    # If there's no initializer, returns (declarator, None)

-    #

-    def p_init_declarator(self, p):

-        """ init_declarator : declarator

-                            | declarator EQUALS initializer

-        """

-        p[0] = (p[1], p[3] if len(p) > 2 else None)        

-    

-    def p_specifier_qualifier_list_1(self, p):

-        """ specifier_qualifier_list    : type_qualifier specifier_qualifier_list_opt

-        """

-        p[0] = self._add_declaration_specifier(p[2], p[1], 'qual')

-        

-    def p_specifier_qualifier_list_2(self, p):

-        """ specifier_qualifier_list    : type_specifier specifier_qualifier_list_opt

-        """

-        p[0] = self._add_declaration_specifier(p[2], p[1], 'type')

-

-    # TYPEID is allowed here (and in other struct/enum related tag names), because

-    # struct/enum tags reside in their own namespace and can be named the same as types

-    #

-    def p_struct_or_union_specifier_1(self, p):

-        """ struct_or_union_specifier   : struct_or_union ID

-                                        | struct_or_union TYPEID

-        """

-        klass = self._select_struct_union_class(p[1])

-        p[0] = klass(

-            name=p[2], 

-            decls=None, 

-            coord=self._coord(p.lineno(2)))

-

-    def p_struct_or_union_specifier_2(self, p):

-        """ struct_or_union_specifier : struct_or_union LBRACE struct_declaration_list RBRACE

-        """

-        klass = self._select_struct_union_class(p[1])

-        p[0] = klass(

-            name=None,

-            decls=p[3],

-            coord=self._coord(p.lineno(2)))

-

-    def p_struct_or_union_specifier_3(self, p):

-        """ struct_or_union_specifier   : struct_or_union ID LBRACE struct_declaration_list RBRACE

-                                        | struct_or_union TYPEID LBRACE struct_declaration_list RBRACE

-        """

-        klass = self._select_struct_union_class(p[1])

-        p[0] = klass(

-            name=p[2],

-            decls=p[4],

-            coord=self._coord(p.lineno(2)))

-

-    def p_struct_or_union(self, p):

-        """ struct_or_union : STRUCT 

-                            | UNION

-        """

-        p[0] = p[1]

-

-    # Combine all declarations into a single list

-    #

-    def p_struct_declaration_list(self, p):

-        """ struct_declaration_list     : struct_declaration

-                                        | struct_declaration_list struct_declaration

-        """

-        p[0] = p[1] if len(p) == 2 else p[1] + p[2]

-

-    def p_struct_declaration_1(self, p):

-        """ struct_declaration : specifier_qualifier_list struct_declarator_list SEMI

-        """

-        spec = p[1]

-        decls = []

-        

-        for struct_decl in p[2]:

-            if struct_decl['decl'] is not None:

-                decl_coord = struct_decl['decl'].coord

-            else:

-                decl_coord = struct_decl['bitsize'].coord

-            

-            decl = c_ast.Decl(

-                name=None,

-                quals=spec['qual'],

-                funcspec=spec['function'],

-                storage=spec['storage'],

-                type=struct_decl['decl'],

-                init=None,

-                bitsize=struct_decl['bitsize'],

-                coord=decl_coord)

-            

-            typename = spec['type']

-            decls.append(self._fix_decl_name_type(decl, typename))

-        

-        p[0] = decls

-    

-    def p_struct_declarator_list(self, p):

-        """ struct_declarator_list  : struct_declarator

-                                    | struct_declarator_list COMMA struct_declarator

-        """

-        p[0] = p[1] + [p[3]] if len(p) == 4 else [p[1]]

-    

-    # struct_declarator passes up a dict with the keys: decl (for

-    # the underlying declarator) and bitsize (for the bitsize)

-    #

-    def p_struct_declarator_1(self, p):

-        """ struct_declarator : declarator

-        """

-        p[0] = {'decl': p[1], 'bitsize': None}

-    

-    def p_struct_declarator_2(self, p):

-        """ struct_declarator   : declarator COLON constant_expression

-                                | COLON constant_expression

-        """

-        if len(p) > 3:

-            p[0] = {'decl': p[1], 'bitsize': p[3]}

-        else:

-            p[0] = {'decl': c_ast.TypeDecl(None, None, None), 'bitsize': p[2]}

-    

-    def p_enum_specifier_1(self, p):

-        """ enum_specifier  : ENUM ID

-                            | ENUM TYPEID

-        """

-        p[0] = c_ast.Enum(p[2], None, self._coord(p.lineno(1)))

-    

-    def p_enum_specifier_2(self, p):

-        """ enum_specifier  : ENUM LBRACE enumerator_list RBRACE

-        """

-        p[0] = c_ast.Enum(None, p[3], self._coord(p.lineno(1)))

-    

-    def p_enum_specifier_3(self, p):

-        """ enum_specifier  : ENUM ID LBRACE enumerator_list RBRACE

-                            | ENUM TYPEID LBRACE enumerator_list RBRACE

-        """

-        p[0] = c_ast.Enum(p[2], p[4], self._coord(p.lineno(1)))

-        

-    def p_enumerator_list(self, p):

-        """ enumerator_list : enumerator

-                            | enumerator_list COMMA

-                            | enumerator_list COMMA enumerator

-        """

-        if len(p) == 2:

-            p[0] = c_ast.EnumeratorList([p[1]], p[1].coord)

-        elif len(p) == 3:

-            p[0] = p[1]

-        else:

-            p[1].enumerators.append(p[3])

-            p[0] = p[1]

-

-    def p_enumerator(self, p):

-        """ enumerator  : ID

-                        | ID EQUALS constant_expression

-        """

-        if len(p) == 2:

-            p[0] = c_ast.Enumerator(

-                        p[1], None, 

-                        self._coord(p.lineno(1)))

-        else:

-            p[0] = c_ast.Enumerator(

-                        p[1], p[3], 

-                        self._coord(p.lineno(1)))

-    

-    def p_declarator_1(self, p):

-        """ declarator  : direct_declarator 

-        """

-        p[0] = p[1]

-    

-    def p_declarator_2(self, p):

-        """ declarator  : pointer direct_declarator 

-        """

-        p[0] = self._type_modify_decl(p[2], p[1])

-    

-    def p_direct_declarator_1(self, p):

-        """ direct_declarator   : ID 

-        """

-        p[0] = c_ast.TypeDecl(

-            declname=p[1], 

-            type=None, 

-            quals=None,

-            coord=self._coord(p.lineno(1)))

-        

-    def p_direct_declarator_2(self, p):

-        """ direct_declarator   : LPAREN declarator RPAREN 

-        """

-        p[0] = p[2]

-        

-    def p_direct_declarator_3(self, p):

-        """ direct_declarator   : direct_declarator LBRACKET assignment_expression_opt RBRACKET 

-        """

-        arr = c_ast.ArrayDecl(

-            type=None,

-            dim=p[3],

-            coord=p[1].coord)

-        

-        p[0] = self._type_modify_decl(decl=p[1], modifier=arr)

-

-    # Special for VLAs

-    #

-    def p_direct_declarator_4(self, p):

-        """ direct_declarator   : direct_declarator LBRACKET TIMES RBRACKET 

-        """

-        arr = c_ast.ArrayDecl(

-            type=None,

-            dim=c_ast.ID(p[3], self._coord(p.lineno(3))),

-            coord=p[1].coord)

-        

-        p[0] = self._type_modify_decl(decl=p[1], modifier=arr)

-

-    def p_direct_declarator_5(self, p):

-        """ direct_declarator   : direct_declarator LPAREN parameter_type_list RPAREN 

-                                | direct_declarator LPAREN identifier_list_opt RPAREN

-        """

-        func = c_ast.FuncDecl(

-            args=p[3],

-            type=None,

-            coord=p[1].coord)

-        

-        p[0] = self._type_modify_decl(decl=p[1], modifier=func)

-    

-    def p_pointer(self, p):

-        """ pointer : TIMES type_qualifier_list_opt

-                    | TIMES type_qualifier_list_opt pointer

-        """

-        coord = self._coord(p.lineno(1))

-        

-        p[0] = c_ast.PtrDecl(

-            quals=p[2] or [],

-            type=p[3] if len(p) > 3 else None,

-            coord=coord)

-    

-    def p_type_qualifier_list(self, p):

-        """ type_qualifier_list : type_qualifier

-                                | type_qualifier_list type_qualifier

-        """

-        p[0] = [p[1]] if len(p) == 2 else p[1] + [p[2]]

-    

-    def p_parameter_type_list(self, p):

-        """ parameter_type_list : parameter_list

-                                | parameter_list COMMA ELLIPSIS

-        """

-        if len(p) > 2: 

-            p[1].params.append(c_ast.EllipsisParam())

-        

-        p[0] = p[1]

-

-    def p_parameter_list(self, p):

-        """ parameter_list  : parameter_declaration

-                            | parameter_list COMMA parameter_declaration

-        """

-        if len(p) == 2: # single parameter

-            p[0] = c_ast.ParamList([p[1]], p[1].coord)

-        else:

-            p[1].params.append(p[3])

-            p[0] = p[1]

-

-    def p_parameter_declaration_1(self, p):

-        """ parameter_declaration   : declaration_specifiers declarator

-        """

-        spec = p[1]

-        decl = p[2]

-        

-        decl = c_ast.Decl(

-            name=None,

-            quals=spec['qual'],

-            storage=spec['storage'],

-            funcspec=spec['function'],

-            type=decl, 

-            init=None, 

-            bitsize=None, 

-            coord=decl.coord)

-        

-        typename = spec['type'] or ['int']

-        p[0] = self._fix_decl_name_type(decl, typename)

-        

-    def p_parameter_declaration_2(self, p):

-        """ parameter_declaration   : declaration_specifiers abstract_declarator_opt

-        """

-        spec = p[1]

-        decl = c_ast.Typename(

-            quals=spec['qual'], 

-            type=p[2] or c_ast.TypeDecl(None, None, None))

-            

-        typename = spec['type'] or ['int']

-        p[0] = self._fix_decl_name_type(decl, typename)        

-    

-    def p_identifier_list(self, p):

-        """ identifier_list : identifier

-                            | identifier_list COMMA identifier

-        """

-        if len(p) == 2: # single parameter

-            p[0] = c_ast.ParamList([p[1]], p[1].coord)

-        else:

-            p[1].params.append(p[3])

-            p[0] = p[1]

-

-    def p_initializer_1(self, p):

-        """ initializer : assignment_expression

-        """

-        p[0] = p[1]

-    

-    def p_initializer_2(self, p):

-        """ initializer : LBRACE initializer_list RBRACE

-                        | LBRACE initializer_list COMMA RBRACE

-        """

-        p[0] = p[2]

-

-    def p_initializer_list(self, p):

-        """ initializer_list    : designation_opt initializer

-                                | initializer_list COMMA designation_opt initializer

-        """

-        if len(p) == 3: # single initializer

-            init = p[2] if p[1] is None else c_ast.NamedInitializer(p[1], p[2])

-            p[0] = c_ast.ExprList([init], p[2].coord)

-        else:

-            init = p[4] if p[3] is None else c_ast.NamedInitializer(p[3], p[4])

-            p[1].exprs.append(init)

-            p[0] = p[1]

-    

+        """
+        p[0] = p[1]
+    
+    def p_type_specifier_1(self, p):
+        """ type_specifier  : VOID
+                            | CHAR
+                            | SHORT
+                            | INT
+                            | LONG
+                            | FLOAT
+                            | DOUBLE
+                            | SIGNED
+                            | UNSIGNED
+                            | typedef_name
+                            | enum_specifier
+                            | struct_or_union_specifier
+        """
+        p[0] = p[1]
+    
+    def p_type_qualifier(self, p):
+        """ type_qualifier  : CONST
+                            | RESTRICT
+                            | VOLATILE
+        """
+        p[0] = p[1]
+    
+    def p_init_declarator_list(self, p):
+        """ init_declarator_list    : init_declarator
+                                    | init_declarator_list COMMA init_declarator
+        """
+        p[0] = p[1] + [p[3]] if len(p) == 4 else [p[1]]
+
+    # Returns a (declarator, initializer) pair
+    # If there's no initializer, returns (declarator, None)
+    #
+    def p_init_declarator(self, p):
+        """ init_declarator : declarator
+                            | declarator EQUALS initializer
+        """
+        p[0] = (p[1], p[3] if len(p) > 2 else None)        
+    
+    def p_specifier_qualifier_list_1(self, p):
+        """ specifier_qualifier_list    : type_qualifier specifier_qualifier_list_opt
+        """
+        p[0] = self._add_declaration_specifier(p[2], p[1], 'qual')
+        
+    def p_specifier_qualifier_list_2(self, p):
+        """ specifier_qualifier_list    : type_specifier specifier_qualifier_list_opt
+        """
+        p[0] = self._add_declaration_specifier(p[2], p[1], 'type')
+
+    # TYPEID is allowed here (and in other struct/enum related tag names), because
+    # struct/enum tags reside in their own namespace and can be named the same as types
+    #
+    def p_struct_or_union_specifier_1(self, p):
+        """ struct_or_union_specifier   : struct_or_union ID
+                                        | struct_or_union TYPEID
+        """
+        klass = self._select_struct_union_class(p[1])
+        p[0] = klass(
+            name=p[2], 
+            decls=None, 
+            coord=self._coord(p.lineno(2)))
+
+    def p_struct_or_union_specifier_2(self, p):
+        """ struct_or_union_specifier : struct_or_union LBRACE struct_declaration_list RBRACE
+        """
+        klass = self._select_struct_union_class(p[1])
+        p[0] = klass(
+            name=None,
+            decls=p[3],
+            coord=self._coord(p.lineno(2)))
+
+    def p_struct_or_union_specifier_3(self, p):
+        """ struct_or_union_specifier   : struct_or_union ID LBRACE struct_declaration_list RBRACE
+                                        | struct_or_union TYPEID LBRACE struct_declaration_list RBRACE
+        """
+        klass = self._select_struct_union_class(p[1])
+        p[0] = klass(
+            name=p[2],
+            decls=p[4],
+            coord=self._coord(p.lineno(2)))
+
+    def p_struct_or_union(self, p):
+        """ struct_or_union : STRUCT 
+                            | UNION
+        """
+        p[0] = p[1]
+
+    # Combine all declarations into a single list
+    #
+    def p_struct_declaration_list(self, p):
+        """ struct_declaration_list     : struct_declaration
+                                        | struct_declaration_list struct_declaration
+        """
+        p[0] = p[1] if len(p) == 2 else p[1] + p[2]
+
+    def p_struct_declaration_1(self, p):
+        """ struct_declaration : specifier_qualifier_list struct_declarator_list SEMI
+        """
+        spec = p[1]
+        decls = []
+        
+        for struct_decl in p[2]:
+            if struct_decl['decl'] is not None:
+                decl_coord = struct_decl['decl'].coord
+            else:
+                decl_coord = struct_decl['bitsize'].coord
+            
+            decl = c_ast.Decl(
+                name=None,
+                quals=spec['qual'],
+                funcspec=spec['function'],
+                storage=spec['storage'],
+                type=struct_decl['decl'],
+                init=None,
+                bitsize=struct_decl['bitsize'],
+                coord=decl_coord)
+            
+            typename = spec['type']
+            decls.append(self._fix_decl_name_type(decl, typename))
+        
+        p[0] = decls
+    
+    def p_struct_declarator_list(self, p):
+        """ struct_declarator_list  : struct_declarator
+                                    | struct_declarator_list COMMA struct_declarator
+        """
+        p[0] = p[1] + [p[3]] if len(p) == 4 else [p[1]]
+    
+    # struct_declarator passes up a dict with the keys: decl (for
+    # the underlying declarator) and bitsize (for the bitsize)
+    #
+    def p_struct_declarator_1(self, p):
+        """ struct_declarator : declarator
+        """
+        p[0] = {'decl': p[1], 'bitsize': None}
+    
+    def p_struct_declarator_2(self, p):
+        """ struct_declarator   : declarator COLON constant_expression
+                                | COLON constant_expression
+        """
+        if len(p) > 3:
+            p[0] = {'decl': p[1], 'bitsize': p[3]}
+        else:
+            p[0] = {'decl': c_ast.TypeDecl(None, None, None), 'bitsize': p[2]}
+    
+    def p_enum_specifier_1(self, p):
+        """ enum_specifier  : ENUM ID
+                            | ENUM TYPEID
+        """
+        p[0] = c_ast.Enum(p[2], None, self._coord(p.lineno(1)))
+    
+    def p_enum_specifier_2(self, p):
+        """ enum_specifier  : ENUM LBRACE enumerator_list RBRACE
+        """
+        p[0] = c_ast.Enum(None, p[3], self._coord(p.lineno(1)))
+    
+    def p_enum_specifier_3(self, p):
+        """ enum_specifier  : ENUM ID LBRACE enumerator_list RBRACE
+                            | ENUM TYPEID LBRACE enumerator_list RBRACE
+        """
+        p[0] = c_ast.Enum(p[2], p[4], self._coord(p.lineno(1)))
+        
+    def p_enumerator_list(self, p):
+        """ enumerator_list : enumerator
+                            | enumerator_list COMMA
+                            | enumerator_list COMMA enumerator
+        """
+        if len(p) == 2:
+            p[0] = c_ast.EnumeratorList([p[1]], p[1].coord)
+        elif len(p) == 3:
+            p[0] = p[1]
+        else:
+            p[1].enumerators.append(p[3])
+            p[0] = p[1]
+
+    def p_enumerator(self, p):
+        """ enumerator  : ID
+                        | ID EQUALS constant_expression
+        """
+        if len(p) == 2:
+            p[0] = c_ast.Enumerator(
+                        p[1], None, 
+                        self._coord(p.lineno(1)))
+        else:
+            p[0] = c_ast.Enumerator(
+                        p[1], p[3], 
+                        self._coord(p.lineno(1)))
+    
+    def p_declarator_1(self, p):
+        """ declarator  : direct_declarator 
+        """
+        p[0] = p[1]
+    
+    def p_declarator_2(self, p):
+        """ declarator  : pointer direct_declarator 
+        """
+        p[0] = self._type_modify_decl(p[2], p[1])
+    
+    def p_direct_declarator_1(self, p):
+        """ direct_declarator   : ID 
+        """
+        p[0] = c_ast.TypeDecl(
+            declname=p[1], 
+            type=None, 
+            quals=None,
+            coord=self._coord(p.lineno(1)))
+        
+    def p_direct_declarator_2(self, p):
+        """ direct_declarator   : LPAREN declarator RPAREN 
+        """
+        p[0] = p[2]
+        
+    def p_direct_declarator_3(self, p):
+        """ direct_declarator   : direct_declarator LBRACKET assignment_expression_opt RBRACKET 
+        """
+        arr = c_ast.ArrayDecl(
+            type=None,
+            dim=p[3],
+            coord=p[1].coord)
+        
+        p[0] = self._type_modify_decl(decl=p[1], modifier=arr)
+
+    # Special for VLAs
+    #
+    def p_direct_declarator_4(self, p):
+        """ direct_declarator   : direct_declarator LBRACKET TIMES RBRACKET 
+        """
+        arr = c_ast.ArrayDecl(
+            type=None,
+            dim=c_ast.ID(p[3], self._coord(p.lineno(3))),
+            coord=p[1].coord)
+        
+        p[0] = self._type_modify_decl(decl=p[1], modifier=arr)
+
+    def p_direct_declarator_5(self, p):
+        """ direct_declarator   : direct_declarator LPAREN parameter_type_list RPAREN 
+                                | direct_declarator LPAREN identifier_list_opt RPAREN
+        """
+        func = c_ast.FuncDecl(
+            args=p[3],
+            type=None,
+            coord=p[1].coord)
+        
+        p[0] = self._type_modify_decl(decl=p[1], modifier=func)
+    
+    def p_pointer(self, p):
+        """ pointer : TIMES type_qualifier_list_opt
+                    | TIMES type_qualifier_list_opt pointer
+        """
+        coord = self._coord(p.lineno(1))
+        
+        p[0] = c_ast.PtrDecl(
+            quals=p[2] or [],
+            type=p[3] if len(p) > 3 else None,
+            coord=coord)
+    
+    def p_type_qualifier_list(self, p):
+        """ type_qualifier_list : type_qualifier
+                                | type_qualifier_list type_qualifier
+        """
+        p[0] = [p[1]] if len(p) == 2 else p[1] + [p[2]]
+    
+    def p_parameter_type_list(self, p):
+        """ parameter_type_list : parameter_list
+                                | parameter_list COMMA ELLIPSIS
+        """
+        if len(p) > 2: 
+            p[1].params.append(c_ast.EllipsisParam())
+        
+        p[0] = p[1]
+
+    def p_parameter_list(self, p):
+        """ parameter_list  : parameter_declaration
+                            | parameter_list COMMA parameter_declaration
+        """
+        if len(p) == 2: # single parameter
+            p[0] = c_ast.ParamList([p[1]], p[1].coord)
+        else:
+            p[1].params.append(p[3])
+            p[0] = p[1]
+
+    def p_parameter_declaration_1(self, p):
+        """ parameter_declaration   : declaration_specifiers declarator
+        """
+        spec = p[1]
+        decl = p[2]
+        
+        decl = c_ast.Decl(
+            name=None,
+            quals=spec['qual'],
+            storage=spec['storage'],
+            funcspec=spec['function'],
+            type=decl, 
+            init=None, 
+            bitsize=None, 
+            coord=decl.coord)
+        
+        typename = spec['type'] or ['int']
+        p[0] = self._fix_decl_name_type(decl, typename)
+        
+    def p_parameter_declaration_2(self, p):
+        """ parameter_declaration   : declaration_specifiers abstract_declarator_opt
+        """
+        spec = p[1]
+        decl = c_ast.Typename(
+            quals=spec['qual'], 
+            type=p[2] or c_ast.TypeDecl(None, None, None))
+            
+        typename = spec['type'] or ['int']
+        p[0] = self._fix_decl_name_type(decl, typename)        
+    
+    def p_identifier_list(self, p):
+        """ identifier_list : identifier
+                            | identifier_list COMMA identifier
+        """
+        if len(p) == 2: # single parameter
+            p[0] = c_ast.ParamList([p[1]], p[1].coord)
+        else:
+            p[1].params.append(p[3])
+            p[0] = p[1]
+
+    def p_initializer_1(self, p):
+        """ initializer : assignment_expression
+        """
+        p[0] = p[1]
+    
+    def p_initializer_2(self, p):
+        """ initializer : LBRACE initializer_list RBRACE
+                        | LBRACE initializer_list COMMA RBRACE
+        """
+        p[0] = p[2]
+
+    def p_initializer_list(self, p):
+        """ initializer_list    : designation_opt initializer
+                                | initializer_list COMMA designation_opt initializer
+        """
+        if len(p) == 3: # single initializer
+            init = p[2] if p[1] is None else c_ast.NamedInitializer(p[1], p[2])
+            p[0] = c_ast.ExprList([init], p[2].coord)
+        else:
+            init = p[4] if p[3] is None else c_ast.NamedInitializer(p[3], p[4])
+            p[1].exprs.append(init)
+            p[0] = p[1]
+    
     def p_designation(self, p):
         """ designation : designator_list EQUALS
-        """

-        p[0] = p[1]

-    

-    # Designators are represented as a list of nodes, in the order in which

-    # they're written in the code.

-    #

+        """
+        p[0] = p[1]
+    
+    # Designators are represented as a list of nodes, in the order in which
+    # they're written in the code.
+    #
     def p_designator_list(self, p):
-        """ designator_list : designator

+        """ designator_list : designator
                             | designator_list designator
-        """

-        p[0] = [p[1]] if len(p) == 2 else p[1] + [p[2]]

-    

+        """
+        p[0] = [p[1]] if len(p) == 2 else p[1] + [p[2]]
+    
     def p_designator(self, p):
-        """ designator  : LBRACKET constant_expression RBRACKET

+        """ designator  : LBRACKET constant_expression RBRACKET
                         | PERIOD identifier
-        """

-        p[0] = p[2]

-    

-    def p_type_name(self, p):

-        """ type_name   : specifier_qualifier_list abstract_declarator_opt 

-        """

-        #~ print '=========='

-        #~ print p[1]

-        #~ print p[2]

-        #~ print p[2].children()

-        #~ print '=========='

-        

-        typename = c_ast.Typename(

-            quals=p[1]['qual'], 

-            type=p[2] or c_ast.TypeDecl(None, None, None))

-        

-        p[0] = self._fix_decl_name_type(typename, p[1]['type'])

-

-    def p_abstract_declarator_1(self, p):

-        """ abstract_declarator     : pointer

-        """

-        dummytype = c_ast.TypeDecl(None, None, None)

-        p[0] = self._type_modify_decl(

-            decl=dummytype, 

-            modifier=p[1])

-        

-    def p_abstract_declarator_2(self, p):

-        """ abstract_declarator     : pointer direct_abstract_declarator

-        """

-        p[0] = self._type_modify_decl(p[2], p[1])

-        

-    def p_abstract_declarator_3(self, p):

-        """ abstract_declarator     : direct_abstract_declarator

-        """

-        p[0] = p[1]

-    

-    # Creating and using direct_abstract_declarator_opt here 

-    # instead of listing both direct_abstract_declarator and the

-    # lack of it in the beginning of _1 and _2 caused two 

-    # shift/reduce errors.

-    #

-    def p_direct_abstract_declarator_1(self, p):

-        """ direct_abstract_declarator  : LPAREN abstract_declarator RPAREN """

-        p[0] = p[2]

-    

-    def p_direct_abstract_declarator_2(self, p):

-        """ direct_abstract_declarator  : direct_abstract_declarator LBRACKET assignment_expression_opt RBRACKET 

-        """

-        arr = c_ast.ArrayDecl(

-            type=None,

-            dim=p[3],

-            coord=p[1].coord)

-        

-        p[0] = self._type_modify_decl(decl=p[1], modifier=arr)

-        

-    def p_direct_abstract_declarator_3(self, p):

-        """ direct_abstract_declarator  : LBRACKET assignment_expression_opt RBRACKET 

-        """

-        p[0] = c_ast.ArrayDecl(

-            type=c_ast.TypeDecl(None, None, None),

-            dim=p[2],

-            coord=self._coord(p.lineno(1)))

-

-    def p_direct_abstract_declarator_4(self, p):

-        """ direct_abstract_declarator  : direct_abstract_declarator LBRACKET TIMES RBRACKET 

-        """

-        arr = c_ast.ArrayDecl(

-            type=None,

-            dim=c_ast.ID(p[3], self._coord(p.lineno(3))),

-            coord=p[1].coord)

-        

-        p[0] = self._type_modify_decl(decl=p[1], modifier=arr)

-

-    def p_direct_abstract_declarator_5(self, p):

-        """ direct_abstract_declarator  : LBRACKET TIMES RBRACKET 

-        """

-        p[0] = c_ast.ArrayDecl(

-            type=c_ast.TypeDecl(None, None, None),

-            dim=c_ast.ID(p[3], self._coord(p.lineno(3))),

-            coord=self._coord(p.lineno(1)))

-

-    def p_direct_abstract_declarator_6(self, p):

-        """ direct_abstract_declarator  : direct_abstract_declarator LPAREN parameter_type_list_opt RPAREN 

-        """

-        func = c_ast.FuncDecl(

-            args=p[3],

-            type=None,

-            coord=p[1].coord)

-        

-        p[0] = self._type_modify_decl(decl=p[1], modifier=func)

-        

-    def p_direct_abstract_declarator_7(self, p):

-        """ direct_abstract_declarator  : LPAREN parameter_type_list_opt RPAREN 

-        """

-        p[0] = c_ast.FuncDecl(

-            args=p[2],

-            type=c_ast.TypeDecl(None, None, None),

-            coord=self._coord(p.lineno(1)))

-    

-    # declaration is a list, statement isn't. To make it consistent, block_item

-    # will always be a list

-    #

+        """
+        p[0] = p[2]
+    
+    def p_type_name(self, p):
+        """ type_name   : specifier_qualifier_list abstract_declarator_opt 
+        """
+        #~ print '=========='
+        #~ print p[1]
+        #~ print p[2]
+        #~ print p[2].children()
+        #~ print '=========='
+        
+        typename = c_ast.Typename(
+            quals=p[1]['qual'], 
+            type=p[2] or c_ast.TypeDecl(None, None, None))
+        
+        p[0] = self._fix_decl_name_type(typename, p[1]['type'])
+
+    def p_abstract_declarator_1(self, p):
+        """ abstract_declarator     : pointer
+        """
+        dummytype = c_ast.TypeDecl(None, None, None)
+        p[0] = self._type_modify_decl(
+            decl=dummytype, 
+            modifier=p[1])
+        
+    def p_abstract_declarator_2(self, p):
+        """ abstract_declarator     : pointer direct_abstract_declarator
+        """
+        p[0] = self._type_modify_decl(p[2], p[1])
+        
+    def p_abstract_declarator_3(self, p):
+        """ abstract_declarator     : direct_abstract_declarator
+        """
+        p[0] = p[1]
+    
+    # Creating and using direct_abstract_declarator_opt here 
+    # instead of listing both direct_abstract_declarator and the
+    # lack of it in the beginning of _1 and _2 caused two 
+    # shift/reduce errors.
+    #
+    def p_direct_abstract_declarator_1(self, p):
+        """ direct_abstract_declarator  : LPAREN abstract_declarator RPAREN """
+        p[0] = p[2]
+    
+    def p_direct_abstract_declarator_2(self, p):
+        """ direct_abstract_declarator  : direct_abstract_declarator LBRACKET assignment_expression_opt RBRACKET 
+        """
+        arr = c_ast.ArrayDecl(
+            type=None,
+            dim=p[3],
+            coord=p[1].coord)
+        
+        p[0] = self._type_modify_decl(decl=p[1], modifier=arr)
+        
+    def p_direct_abstract_declarator_3(self, p):
+        """ direct_abstract_declarator  : LBRACKET assignment_expression_opt RBRACKET 
+        """
+        p[0] = c_ast.ArrayDecl(
+            type=c_ast.TypeDecl(None, None, None),
+            dim=p[2],
+            coord=self._coord(p.lineno(1)))
+
+    def p_direct_abstract_declarator_4(self, p):
+        """ direct_abstract_declarator  : direct_abstract_declarator LBRACKET TIMES RBRACKET 
+        """
+        arr = c_ast.ArrayDecl(
+            type=None,
+            dim=c_ast.ID(p[3], self._coord(p.lineno(3))),
+            coord=p[1].coord)
+        
+        p[0] = self._type_modify_decl(decl=p[1], modifier=arr)
+
+    def p_direct_abstract_declarator_5(self, p):
+        """ direct_abstract_declarator  : LBRACKET TIMES RBRACKET 
+        """
+        p[0] = c_ast.ArrayDecl(
+            type=c_ast.TypeDecl(None, None, None),
+            dim=c_ast.ID(p[3], self._coord(p.lineno(3))),
+            coord=self._coord(p.lineno(1)))
+
+    def p_direct_abstract_declarator_6(self, p):
+        """ direct_abstract_declarator  : direct_abstract_declarator LPAREN parameter_type_list_opt RPAREN 
+        """
+        func = c_ast.FuncDecl(
+            args=p[3],
+            type=None,
+            coord=p[1].coord)
+        
+        p[0] = self._type_modify_decl(decl=p[1], modifier=func)
+        
+    def p_direct_abstract_declarator_7(self, p):
+        """ direct_abstract_declarator  : LPAREN parameter_type_list_opt RPAREN 
+        """
+        p[0] = c_ast.FuncDecl(
+            args=p[2],
+            type=c_ast.TypeDecl(None, None, None),
+            coord=self._coord(p.lineno(1)))
+    
+    # declaration is a list, statement isn't. To make it consistent, block_item
+    # will always be a list
+    #
     def p_block_item(self, p):
-        """ block_item  : declaration

+        """ block_item  : declaration
                         | statement
-        """

-        p[0] = p[1] if isinstance(p[1], list) else [p[1]]

-    

-    # Since we made block_item a list, this just combines lists

-    # 

-    def p_block_item_list(self, p):

-        """ block_item_list : block_item 

-                            | block_item_list block_item

-        """

-        p[0] = p[1] if len(p) == 2 else p[1] + p[2]

-    

-    def p_compound_statement_1(self, p):

-        """ compound_statement : LBRACE block_item_list_opt RBRACE """

-        p[0] = c_ast.Compound(

-            block_items=p[2], 

-            coord=self._coord(p.lineno(1)))

-    

-    def p_labeled_statement_1(self, p):

-        """ labeled_statement : ID COLON statement """

-        p[0] = c_ast.Label(p[1], p[3], self._coord(p.lineno(1)))

-    

-    def p_labeled_statement_2(self, p):

-        """ labeled_statement : CASE constant_expression COLON statement """

-        p[0] = c_ast.Case(p[2], p[4], self._coord(p.lineno(1)))

-        

-    def p_labeled_statement_3(self, p):

-        """ labeled_statement : DEFAULT COLON statement """

-        p[0] = c_ast.Default(p[3], self._coord(p.lineno(1)))

-        

-    def p_selection_statement_1(self, p):

-        """ selection_statement : IF LPAREN expression RPAREN statement """

-        p[0] = c_ast.If(p[3], p[5], None, self._coord(p.lineno(1)))

-    

-    def p_selection_statement_2(self, p):

-        """ selection_statement : IF LPAREN expression RPAREN statement ELSE statement """

-        p[0] = c_ast.If(p[3], p[5], p[7], self._coord(p.lineno(1)))

-    

-    def p_selection_statement_3(self, p):

-        """ selection_statement : SWITCH LPAREN expression RPAREN statement """

-        p[0] = c_ast.Switch(p[3], p[5], self._coord(p.lineno(1)))

-    

-    def p_iteration_statement_1(self, p):

-        """ iteration_statement : WHILE LPAREN expression RPAREN statement """

-        p[0] = c_ast.While(p[3], p[5], self._coord(p.lineno(1)))

-    

-    def p_iteration_statement_2(self, p):

-        """ iteration_statement : DO statement WHILE LPAREN expression RPAREN SEMI """

-        p[0] = c_ast.DoWhile(p[5], p[2], self._coord(p.lineno(1)))

-    

-    def p_iteration_statement_3(self, p):

-        """ iteration_statement : FOR LPAREN expression_opt SEMI expression_opt SEMI expression_opt RPAREN statement """

-        p[0] = c_ast.For(p[3], p[5], p[7], p[9], self._coord(p.lineno(1)))

-    

-    def p_iteration_statement_4(self, p):

-        """ iteration_statement : FOR LPAREN declaration expression_opt SEMI expression_opt RPAREN statement """

-        p[0] = c_ast.For(c_ast.DeclList(p[3]), p[4], p[6], p[8], self._coord(p.lineno(1)))

-

-    def p_jump_statement_1(self, p):

-        """ jump_statement  : GOTO ID SEMI """

-        p[0] = c_ast.Goto(p[2], self._coord(p.lineno(1)))

-    

-    def p_jump_statement_2(self, p):

-        """ jump_statement  : BREAK SEMI """

-        p[0] = c_ast.Break(self._coord(p.lineno(1)))

-    

-    def p_jump_statement_3(self, p):

-        """ jump_statement  : CONTINUE SEMI """

-        p[0] = c_ast.Continue(self._coord(p.lineno(1)))

-        

-    def p_jump_statement_4(self, p):

-        """ jump_statement  : RETURN expression SEMI  

-                            | RETURN SEMI 

-        """

-        p[0] = c_ast.Return(p[2] if len(p) == 4 else None, self._coord(p.lineno(1)))

-    

-    def p_expression_statement(self, p):

-        """ expression_statement : expression_opt SEMI """

-        p[0] = p[1]

-    

-    def p_expression(self, p):

-        """ expression  : assignment_expression 

-                        | expression COMMA assignment_expression

-        """

-        if len(p) == 2:

-            p[0] = p[1]

-        else:

-            if not isinstance(p[1], c_ast.ExprList):

-                p[1] = c_ast.ExprList([p[1]], p[1].coord)

-            

-            p[1].exprs.append(p[3])

-            p[0] = p[1] 

-

-    def p_typedef_name(self, p):

-        """ typedef_name : TYPEID """

-        p[0] = p[1]

-

-    def p_assignment_expression(self, p):

-        """ assignment_expression   : conditional_expression

-                                    | unary_expression assignment_operator assignment_expression

-        """

-        if len(p) == 2:

-            p[0] = p[1]

-        else:

-            p[0] = c_ast.Assignment(p[2], p[1], p[3], p[1].coord)

-

-    # K&R2 defines these as many separate rules, to encode 

-    # precedence and associativity. Why work hard ? I'll just use

-    # the built in precedence/associativity specification feature

-    # of PLY. (see precedence declaration above)

-    #

-    def p_assignment_operator(self, p):

-        """ assignment_operator : EQUALS

-                                | XOREQUAL   

-                                | TIMESEQUAL  

-                                | DIVEQUAL    

-                                | MODEQUAL    

-                                | PLUSEQUAL   

-                                | MINUSEQUAL  

-                                | LSHIFTEQUAL 

-                                | RSHIFTEQUAL 

-                                | ANDEQUAL    

-                                | OREQUAL     

-        """

-        p[0] = p[1]

-        

-    def p_constant_expression(self, p):

-        """ constant_expression : conditional_expression """

-        p[0] = p[1]

-    

-    def p_conditional_expression(self, p):

-        """ conditional_expression  : binary_expression

-                                    | binary_expression CONDOP expression COLON conditional_expression

-        """

-        if len(p) == 2:

-            p[0] = p[1]

-        else:

-            p[0] = c_ast.TernaryOp(p[1], p[3], p[5], p[1].coord)

-    

-    def p_binary_expression(self, p):

-        """ binary_expression   : cast_expression

-                                | binary_expression TIMES binary_expression

-                                | binary_expression DIVIDE binary_expression

-                                | binary_expression MOD binary_expression

-                                | binary_expression PLUS binary_expression

-                                | binary_expression MINUS binary_expression

-                                | binary_expression RSHIFT binary_expression

-                                | binary_expression LSHIFT binary_expression

-                                | binary_expression LT binary_expression

-                                | binary_expression LE binary_expression

-                                | binary_expression GE binary_expression

-                                | binary_expression GT binary_expression

-                                | binary_expression EQ binary_expression

-                                | binary_expression NE binary_expression

-                                | binary_expression AND binary_expression

-                                | binary_expression OR binary_expression

-                                | binary_expression XOR binary_expression

-                                | binary_expression LAND binary_expression

-                                | binary_expression LOR binary_expression

-        """

-        if len(p) == 2:

-            p[0] = p[1]

-        else:

-            p[0] = c_ast.BinaryOp(p[2], p[1], p[3], p[1].coord)

-    

-    def p_cast_expression_1(self, p):

-        """ cast_expression : unary_expression """

-        p[0] = p[1]

-        

-    def p_cast_expression_2(self, p):

-        """ cast_expression : LPAREN type_name RPAREN cast_expression """

-        p[0] = c_ast.Cast(p[2], p[4], p[2].coord)

-    

-    def p_unary_expression_1(self, p):

-        """ unary_expression    : postfix_expression """

-        p[0] = p[1]

-    

-    def p_unary_expression_2(self, p):

-        """ unary_expression    : PLUSPLUS unary_expression 

-                                | MINUSMINUS unary_expression

-                                | unary_operator cast_expression

-        """

-        p[0] = c_ast.UnaryOp(p[1], p[2], p[2].coord)

-    

-    def p_unary_expression_3(self, p):

-        """ unary_expression    : SIZEOF unary_expression 

-                                | SIZEOF LPAREN type_name RPAREN

-        """

-        p[0] = c_ast.UnaryOp(

-            p[1], 

-            p[2] if len(p) == 3 else p[3], 

-            self._coord(p.lineno(1)))

-    

-    def p_unary_operator(self, p):

-        """ unary_operator  : AND

-                            | TIMES

-                            | PLUS

-                            | MINUS

-                            | NOT

-                            | LNOT

-        """

-        p[0] = p[1]

-                                

-    def p_postfix_exptession_1(self, p):

-        """ postfix_expression  : primary_expression """

-        p[0] = p[1]

-    

-    def p_postfix_exptession_2(self, p):

-        """ postfix_expression  : postfix_expression LBRACKET expression RBRACKET """

-        p[0] = c_ast.ArrayRef(p[1], p[3], p[1].coord)

-    

-    def p_postfix_exptession_3(self, p):

-        """ postfix_expression  : postfix_expression LPAREN argument_expression_list RPAREN

-                                | postfix_expression LPAREN RPAREN

-        """

-        p[0] = c_ast.FuncCall(p[1], p[3] if len(p) == 5 else None, p[1].coord)

-    

-    def p_postfix_expression_4(self, p):

-        """ postfix_expression  : postfix_expression PERIOD identifier

-                                | postfix_expression ARROW identifier

-        """

-        p[0] = c_ast.StructRef(p[1], p[2], p[3], p[1].coord)

-

-    def p_postfix_expression_5(self, p):

-        """ postfix_expression  : postfix_expression PLUSPLUS 

-                                | postfix_expression MINUSMINUS

-        """

-        p[0] = c_ast.UnaryOp('p' + p[2], p[1], p[1].coord)

-

+        """
+        p[0] = p[1] if isinstance(p[1], list) else [p[1]]
+    
+    # Since we made block_item a list, this just combines lists
+    # 
+    def p_block_item_list(self, p):
+        """ block_item_list : block_item 
+                            | block_item_list block_item
+        """
+        p[0] = p[1] if len(p) == 2 else p[1] + p[2]
+    
+    def p_compound_statement_1(self, p):
+        """ compound_statement : LBRACE block_item_list_opt RBRACE """
+        p[0] = c_ast.Compound(
+            block_items=p[2], 
+            coord=self._coord(p.lineno(1)))
+    
+    def p_labeled_statement_1(self, p):
+        """ labeled_statement : ID COLON statement """
+        p[0] = c_ast.Label(p[1], p[3], self._coord(p.lineno(1)))
+    
+    def p_labeled_statement_2(self, p):
+        """ labeled_statement : CASE constant_expression COLON statement """
+        p[0] = c_ast.Case(p[2], p[4], self._coord(p.lineno(1)))
+        
+    def p_labeled_statement_3(self, p):
+        """ labeled_statement : DEFAULT COLON statement """
+        p[0] = c_ast.Default(p[3], self._coord(p.lineno(1)))
+        
+    def p_selection_statement_1(self, p):
+        """ selection_statement : IF LPAREN expression RPAREN statement """
+        p[0] = c_ast.If(p[3], p[5], None, self._coord(p.lineno(1)))
+    
+    def p_selection_statement_2(self, p):
+        """ selection_statement : IF LPAREN expression RPAREN statement ELSE statement """
+        p[0] = c_ast.If(p[3], p[5], p[7], self._coord(p.lineno(1)))
+    
+    def p_selection_statement_3(self, p):
+        """ selection_statement : SWITCH LPAREN expression RPAREN statement """
+        p[0] = c_ast.Switch(p[3], p[5], self._coord(p.lineno(1)))
+    
+    def p_iteration_statement_1(self, p):
+        """ iteration_statement : WHILE LPAREN expression RPAREN statement """
+        p[0] = c_ast.While(p[3], p[5], self._coord(p.lineno(1)))
+    
+    def p_iteration_statement_2(self, p):
+        """ iteration_statement : DO statement WHILE LPAREN expression RPAREN SEMI """
+        p[0] = c_ast.DoWhile(p[5], p[2], self._coord(p.lineno(1)))
+    
+    def p_iteration_statement_3(self, p):
+        """ iteration_statement : FOR LPAREN expression_opt SEMI expression_opt SEMI expression_opt RPAREN statement """
+        p[0] = c_ast.For(p[3], p[5], p[7], p[9], self._coord(p.lineno(1)))
+    
+    def p_iteration_statement_4(self, p):
+        """ iteration_statement : FOR LPAREN declaration expression_opt SEMI expression_opt RPAREN statement """
+        p[0] = c_ast.For(c_ast.DeclList(p[3]), p[4], p[6], p[8], self._coord(p.lineno(1)))
+
+    def p_jump_statement_1(self, p):
+        """ jump_statement  : GOTO ID SEMI """
+        p[0] = c_ast.Goto(p[2], self._coord(p.lineno(1)))
+    
+    def p_jump_statement_2(self, p):
+        """ jump_statement  : BREAK SEMI """
+        p[0] = c_ast.Break(self._coord(p.lineno(1)))
+    
+    def p_jump_statement_3(self, p):
+        """ jump_statement  : CONTINUE SEMI """
+        p[0] = c_ast.Continue(self._coord(p.lineno(1)))
+        
+    def p_jump_statement_4(self, p):
+        """ jump_statement  : RETURN expression SEMI  
+                            | RETURN SEMI 
+        """
+        p[0] = c_ast.Return(p[2] if len(p) == 4 else None, self._coord(p.lineno(1)))
+    
+    def p_expression_statement(self, p):
+        """ expression_statement : expression_opt SEMI """
+        p[0] = p[1]
+    
+    def p_expression(self, p):
+        """ expression  : assignment_expression 
+                        | expression COMMA assignment_expression
+        """
+        if len(p) == 2:
+            p[0] = p[1]
+        else:
+            if not isinstance(p[1], c_ast.ExprList):
+                p[1] = c_ast.ExprList([p[1]], p[1].coord)
+            
+            p[1].exprs.append(p[3])
+            p[0] = p[1] 
+
+    def p_typedef_name(self, p):
+        """ typedef_name : TYPEID """
+        p[0] = p[1]
+
+    def p_assignment_expression(self, p):
+        """ assignment_expression   : conditional_expression
+                                    | unary_expression assignment_operator assignment_expression
+        """
+        if len(p) == 2:
+            p[0] = p[1]
+        else:
+            p[0] = c_ast.Assignment(p[2], p[1], p[3], p[1].coord)
+
+    # K&R2 defines these as many separate rules, to encode 
+    # precedence and associativity. Why work hard ? I'll just use
+    # the built in precedence/associativity specification feature
+    # of PLY. (see precedence declaration above)
+    #
+    def p_assignment_operator(self, p):
+        """ assignment_operator : EQUALS
+                                | XOREQUAL   
+                                | TIMESEQUAL  
+                                | DIVEQUAL    
+                                | MODEQUAL    
+                                | PLUSEQUAL   
+                                | MINUSEQUAL  
+                                | LSHIFTEQUAL 
+                                | RSHIFTEQUAL 
+                                | ANDEQUAL    
+                                | OREQUAL     
+        """
+        p[0] = p[1]
+        
+    def p_constant_expression(self, p):
+        """ constant_expression : conditional_expression """
+        p[0] = p[1]
+    
+    def p_conditional_expression(self, p):
+        """ conditional_expression  : binary_expression
+                                    | binary_expression CONDOP expression COLON conditional_expression
+        """
+        if len(p) == 2:
+            p[0] = p[1]
+        else:
+            p[0] = c_ast.TernaryOp(p[1], p[3], p[5], p[1].coord)
+    
+    def p_binary_expression(self, p):
+        """ binary_expression   : cast_expression
+                                | binary_expression TIMES binary_expression
+                                | binary_expression DIVIDE binary_expression
+                                | binary_expression MOD binary_expression
+                                | binary_expression PLUS binary_expression
+                                | binary_expression MINUS binary_expression
+                                | binary_expression RSHIFT binary_expression
+                                | binary_expression LSHIFT binary_expression
+                                | binary_expression LT binary_expression
+                                | binary_expression LE binary_expression
+                                | binary_expression GE binary_expression
+                                | binary_expression GT binary_expression
+                                | binary_expression EQ binary_expression
+                                | binary_expression NE binary_expression
+                                | binary_expression AND binary_expression
+                                | binary_expression OR binary_expression
+                                | binary_expression XOR binary_expression
+                                | binary_expression LAND binary_expression
+                                | binary_expression LOR binary_expression
+        """
+        if len(p) == 2:
+            p[0] = p[1]
+        else:
+            p[0] = c_ast.BinaryOp(p[2], p[1], p[3], p[1].coord)
+    
+    def p_cast_expression_1(self, p):
+        """ cast_expression : unary_expression """
+        p[0] = p[1]
+        
+    def p_cast_expression_2(self, p):
+        """ cast_expression : LPAREN type_name RPAREN cast_expression """
+        p[0] = c_ast.Cast(p[2], p[4], p[2].coord)
+    
+    def p_unary_expression_1(self, p):
+        """ unary_expression    : postfix_expression """
+        p[0] = p[1]
+    
+    def p_unary_expression_2(self, p):
+        """ unary_expression    : PLUSPLUS unary_expression 
+                                | MINUSMINUS unary_expression
+                                | unary_operator cast_expression
+        """
+        p[0] = c_ast.UnaryOp(p[1], p[2], p[2].coord)
+    
+    def p_unary_expression_3(self, p):
+        """ unary_expression    : SIZEOF unary_expression 
+                                | SIZEOF LPAREN type_name RPAREN
+        """
+        p[0] = c_ast.UnaryOp(
+            p[1], 
+            p[2] if len(p) == 3 else p[3], 
+            self._coord(p.lineno(1)))
+    
+    def p_unary_operator(self, p):
+        """ unary_operator  : AND
+                            | TIMES
+                            | PLUS
+                            | MINUS
+                            | NOT
+                            | LNOT
+        """
+        p[0] = p[1]
+                                
+    def p_postfix_exptession_1(self, p):
+        """ postfix_expression  : primary_expression """
+        p[0] = p[1]
+    
+    def p_postfix_exptession_2(self, p):
+        """ postfix_expression  : postfix_expression LBRACKET expression RBRACKET """
+        p[0] = c_ast.ArrayRef(p[1], p[3], p[1].coord)
+    
+    def p_postfix_exptession_3(self, p):
+        """ postfix_expression  : postfix_expression LPAREN argument_expression_list RPAREN
+                                | postfix_expression LPAREN RPAREN
+        """
+        p[0] = c_ast.FuncCall(p[1], p[3] if len(p) == 5 else None, p[1].coord)
+    
+    def p_postfix_expression_4(self, p):
+        """ postfix_expression  : postfix_expression PERIOD identifier
+                                | postfix_expression ARROW identifier
+        """
+        p[0] = c_ast.StructRef(p[1], p[2], p[3], p[1].coord)
+
+    def p_postfix_expression_5(self, p):
+        """ postfix_expression  : postfix_expression PLUSPLUS 
+                                | postfix_expression MINUSMINUS
+        """
+        p[0] = c_ast.UnaryOp('p' + p[2], p[1], p[1].coord)
+
     def p_postfix_expression_6(self, p):
-        """ postfix_expression  : LPAREN type_name RPAREN LBRACE initializer_list RBRACE

-                                | LPAREN type_name RPAREN LBRACE initializer_list COMMA RBRACE

-        """

-        p[0] = c_ast.CompoundLiteral(p[2], p[5])

-

-    def p_primary_expression_1(self, p):

-        """ primary_expression  : identifier """

-        p[0] = p[1]

-        

-    def p_primary_expression_2(self, p):

-        """ primary_expression  : constant """

-        p[0] = p[1]

-        

-    def p_primary_expression_3(self, p):

-        """ primary_expression  : unified_string_literal 

-                                | unified_wstring_literal

-        """

-        p[0] = p[1]

-            

-    def p_primary_expression_4(self, p):

-        """ primary_expression  : LPAREN expression RPAREN """

-        p[0] = p[2]

-        

-    def p_argument_expression_list(self, p):

-        """ argument_expression_list    : assignment_expression 

-                                        | argument_expression_list COMMA assignment_expression

-        """

-        if len(p) == 2: # single expr

-            p[0] = c_ast.ExprList([p[1]], p[1].coord)

-        else:

-            p[1].exprs.append(p[3])

-            p[0] = p[1]

-        

-    def p_identifier(self, p):

-        """ identifier  : ID """

-        p[0] = c_ast.ID(p[1], self._coord(p.lineno(1)))

-        

-    def p_constant_1(self, p):

-        """ constant    : INT_CONST_DEC

-                        | INT_CONST_OCT

-                        | INT_CONST_HEX

-        """

-        p[0] = c_ast.Constant(

-            'int', p[1], self._coord(p.lineno(1)))

-            

-    def p_constant_2(self, p):

-        """ constant    : FLOAT_CONST """

-        p[0] = c_ast.Constant(

-            'float', p[1], self._coord(p.lineno(1)))

-    

-    def p_constant_3(self, p):

-        """ constant    : CHAR_CONST

-                        | WCHAR_CONST

-        """

-        p[0] = c_ast.Constant(

-            'char', p[1], self._coord(p.lineno(1)))

-    

-    # The "unified" string and wstring literal rules are for supporting 

-    # concatenation of adjacent string literals.

-    # I.e. "hello " "world" is seen by the C compiler as a single string literal

-    # with the value "hello world"

-    #

+        """ postfix_expression  : LPAREN type_name RPAREN LBRACE initializer_list RBRACE
+                                | LPAREN type_name RPAREN LBRACE initializer_list COMMA RBRACE
+        """
+        p[0] = c_ast.CompoundLiteral(p[2], p[5])
+
+    def p_primary_expression_1(self, p):
+        """ primary_expression  : identifier """
+        p[0] = p[1]
+        
+    def p_primary_expression_2(self, p):
+        """ primary_expression  : constant """
+        p[0] = p[1]
+        
+    def p_primary_expression_3(self, p):
+        """ primary_expression  : unified_string_literal 
+                                | unified_wstring_literal
+        """
+        p[0] = p[1]
+            
+    def p_primary_expression_4(self, p):
+        """ primary_expression  : LPAREN expression RPAREN """
+        p[0] = p[2]
+        
+    def p_argument_expression_list(self, p):
+        """ argument_expression_list    : assignment_expression 
+                                        | argument_expression_list COMMA assignment_expression
+        """
+        if len(p) == 2: # single expr
+            p[0] = c_ast.ExprList([p[1]], p[1].coord)
+        else:
+            p[1].exprs.append(p[3])
+            p[0] = p[1]
+        
+    def p_identifier(self, p):
+        """ identifier  : ID """
+        p[0] = c_ast.ID(p[1], self._coord(p.lineno(1)))
+        
+    def p_constant_1(self, p):
+        """ constant    : INT_CONST_DEC
+                        | INT_CONST_OCT
+                        | INT_CONST_HEX
+        """
+        p[0] = c_ast.Constant(
+            'int', p[1], self._coord(p.lineno(1)))
+            
+    def p_constant_2(self, p):
+        """ constant    : FLOAT_CONST """
+        p[0] = c_ast.Constant(
+            'float', p[1], self._coord(p.lineno(1)))
+    
+    def p_constant_3(self, p):
+        """ constant    : CHAR_CONST
+                        | WCHAR_CONST
+        """
+        p[0] = c_ast.Constant(
+            'char', p[1], self._coord(p.lineno(1)))
+    
+    # The "unified" string and wstring literal rules are for supporting 
+    # concatenation of adjacent string literals.
+    # I.e. "hello " "world" is seen by the C compiler as a single string literal
+    # with the value "hello world"
+    #
     def p_unified_string_literal(self, p):
-        """ unified_string_literal  : STRING_LITERAL

+        """ unified_string_literal  : STRING_LITERAL
                                     | unified_string_literal STRING_LITERAL  
-        """

-        if len(p) == 2: # single literal

-            p[0] = c_ast.Constant(

-                'string', p[1], self._coord(p.lineno(1)))

-        else:

-            p[1].value = p[1].value[:-1] + p[2][1:]

-            p[0] = p[1]

-            

-    def p_unified_wstring_literal(self, p):

-        """ unified_wstring_literal : WSTRING_LITERAL

-                                    | unified_wstring_literal WSTRING_LITERAL  

-        """

-        if len(p) == 2: # single literal

-            p[0] = c_ast.Constant(

-                'string', p[1], self._coord(p.lineno(1)))

-        else:

-            p[1].value = p[1].value.rstrip[:-1] + p[2][1:]

-            p[0] = p[1]

-            

-    def p_empty(self, p):

-        'empty : '

-        p[0] = None

-        

-    def p_error(self, p):

-        if p:

-            self._parse_error(

-                'before: %s' % p.value, 

-                self._coord(p.lineno))

-        else:

-            self._parse_error('At end of input', '')

-

-

-if __name__ == "__main__":

-    import pprint

-    import time

-    from portability import printme

-    

-    t1 = time.time()

-    parser = CParser(lex_optimize=True, yacc_debug=True, yacc_optimize=False)

-    printme(time.time() - t1)

-    

-    buf = ''' 

-        int (*k)(int);

-    '''

-    

-    # set debuglevel to 2 for debugging

-    t = parser.parse(buf, 'x.c', debuglevel=0)

-    t.show(showcoord=True)

+        """
+        if len(p) == 2: # single literal
+            p[0] = c_ast.Constant(
+                'string', p[1], self._coord(p.lineno(1)))
+        else:
+            p[1].value = p[1].value[:-1] + p[2][1:]
+            p[0] = p[1]
+            
+    def p_unified_wstring_literal(self, p):
+        """ unified_wstring_literal : WSTRING_LITERAL
+                                    | unified_wstring_literal WSTRING_LITERAL  
+        """
+        if len(p) == 2: # single literal
+            p[0] = c_ast.Constant(
+                'string', p[1], self._coord(p.lineno(1)))
+        else:
+            p[1].value = p[1].value.rstrip[:-1] + p[2][1:]
+            p[0] = p[1]
+            
+    def p_empty(self, p):
+        'empty : '
+        p[0] = None
+        
+    def p_error(self, p):
+        if p:
+            self._parse_error(
+                'before: %s' % p.value, 
+                self._coord(p.lineno))
+        else:
+            self._parse_error('At end of input', '')
+
+
+if __name__ == "__main__":
+    import pprint
+    import time
+    from portability import printme
+    
+    t1 = time.time()
+    parser = CParser(lex_optimize=True, yacc_debug=True, yacc_optimize=False)
+    printme(time.time() - t1)
+    
+    buf = ''' 
+        int (*k)(int);
+    '''
+    
+    # set debuglevel to 2 for debugging
+    t = parser.parse(buf, 'x.c', debuglevel=0)
+    t.show(showcoord=True)
diff --git a/setup.py b/setup.py
index 3d7b72e..e4a348d 100644
--- a/setup.py
+++ b/setup.py
@@ -13,7 +13,7 @@
         C compilers or analysis tools.

     """,

     license='LGPL',

-    version='2.00',

+    version='2.01',

     author='Eli Bendersky',

     maintainer='Eli Bendersky',

     author_email='eliben@gmail.com',

@@ -21,7 +21,7 @@
     platforms='Cross Platform',

     

     packages=['pycparser'],

-    package_data={'pycparser': ['*.yaml']},

+    package_data={'pycparser': ['*.cfg']},

 )