Eli Bendersky avatar Eli Bendersky committed d7ae3ce

initial import from SVN

Comments (0)

Files changed (94)

+recursive-include examples *.c *.h *.py
+recursive-include tests *.c *.h *.py
+recursive-include pycparser *.py *.yaml
+include utils/*.exe
+include utils/fake_libc_include/*.h
+include README.*
+include setup.*
+
+prune tests/yacctab.*
+<?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 v1.06</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-v1-06">
+<h1 class="title">pycparser v1.06</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="simple">
+<li><a class="reference internal" href="#introduction" id="id1">Introduction</a><ul>
+<li><a class="reference internal" href="#what-is-pycparser" id="id2">What is pycparser?</a></li>
+<li><a class="reference internal" href="#what-is-it-good-for" id="id3">What is it good for?</a></li>
+<li><a class="reference internal" href="#which-version-of-c-does-pycparser-support" id="id4">Which version of C does pycparser support?</a></li>
+<li><a class="reference internal" href="#what-grammar-does-pycparser-follow" id="id5">What grammar does pycparser follow?</a></li>
+<li><a class="reference internal" href="#what-is-an-ast" id="id6">What is an AST?</a></li>
+<li><a class="reference internal" href="#how-is-pycparser-licensed" id="id7">How is pycparser licensed?</a></li>
+<li><a class="reference internal" href="#contact-details" id="id8">Contact details</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#installing" id="id9">Installing</a><ul>
+<li><a class="reference internal" href="#prerequisites" id="id10">Prerequisites</a></li>
+<li><a class="reference internal" href="#installation-process" id="id11">Installation process</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#using" id="id12">Using</a><ul>
+<li><a class="reference internal" href="#interaction-with-the-c-preprocessor" id="id13">Interaction with the C preprocessor</a></li>
+<li><a class="reference internal" href="#what-about-the-standard-c-library-headers" id="id14">What about the standard C library headers?</a></li>
+<li><a class="reference internal" href="#basic-usage" id="id15">Basic usage</a></li>
+<li><a class="reference internal" href="#advanced-usage" id="id16">Advanced usage</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#modifying" id="id17">Modifying</a></li>
+<li><a class="reference internal" href="#package-contents" id="id18">Package contents</a></li>
+<li><a class="reference internal" href="#changelog" id="id19">Changelog</a><ul>
+<li><a class="reference internal" href="#version-1-07-18-05-2010" id="id20">Version 1.07 (18.05.2010)</a></li>
+<li><a class="reference internal" href="#version-1-06-10-04-2010" id="id21">Version 1.06 (10.04.2010)</a></li>
+<li><a class="reference internal" href="#version-1-05-16-10-2009" id="id22">Version 1.05 (16.10.2009)</a></li>
+<li><a class="reference internal" href="#version-1-04-22-05-2009" id="id23">Version 1.04 (22.05.2009)</a></li>
+<li><a class="reference internal" href="#version-1-03-31-01-2009" id="id24">Version 1.03 (31.01.2009)</a></li>
+<li><a class="reference internal" href="#version-1-02-16-01-2009" id="id25">Version 1.02 (16.01.2009)</a></li>
+<li><a class="reference internal" href="#version-1-01-09-01-2009" id="id26">Version 1.01 (09.01.2009)</a></li>
+<li><a class="reference internal" href="#version-1-0-15-11-2008" id="id27">Version 1.0 (15.11.2008)</a></li>
+</ul>
+</li>
+</ul>
+</div>
+<div class="section" id="introduction">
+<h1><a class="toc-backref" href="#id1">Introduction</a></h1>
+<div class="section" id="what-is-pycparser">
+<h2><a class="toc-backref" href="#id2">What is pycparser?</a></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><a class="toc-backref" href="#id3">What is it good for?</a></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><a class="toc-backref" href="#id4">Which version of C does pycparser support?</a></h2>
+<p>At the moment, <tt class="docutils literal"><span class="pre">pycparser</span></tt> supports ANSI/ISO C89, the language described by Kernighan and Ritchie in &quot;The C Programming language, 2nd edition&quot; (K&amp;R2), with only selected extensions from C99. The currently supported C99 features are:</p>
+<ul class="simple">
+<li>Allowing a comma after the last value in an enumeration list</li>
+</ul>
+<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><a class="toc-backref" href="#id5">What grammar does pycparser follow?</a></h2>
+<p><tt class="docutils literal"><span class="pre">pycparser</span></tt> very closely follows the ANSI C grammar provided in the end of K&amp;R2. Listings of this grammar (often in Yacc syntax) can be easily found by a simple web search. Google for <cite>ansi c grammar</cite> to get started.</p>
+</div>
+<div class="section" id="what-is-an-ast">
+<h2><a class="toc-backref" href="#id6">What is an AST?</a></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><a class="toc-backref" href="#id7">How is pycparser licensed?</a></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><a class="toc-backref" href="#id8">Contact details</a></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>.</p>
+</div>
+</div>
+<div class="section" id="installing">
+<h1><a class="toc-backref" href="#id9">Installing</a></h1>
+<div class="section" id="prerequisites">
+<h2><a class="toc-backref" href="#id10">Prerequisites</a></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. You'll also need to install PLY version 3.2 (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><a class="toc-backref" href="#id11">Installation process</a></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><a class="toc-backref" href="#id12">Using</a></h1>
+<div class="section" id="interaction-with-the-c-preprocessor">
+<h2><a class="toc-backref" href="#id13">Interaction with the C preprocessor</a></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><a class="toc-backref" href="#id14">What about the standard C library headers?</a></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 compilation 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><a class="toc-backref" href="#id15">Basic usage</a></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><a class="toc-backref" href="#id16">Advanced usage</a></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><a class="toc-backref" href="#id17">Modifying</a></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><a class="toc-backref" href="#id18">Package contents</a></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="changelog">
+<h1><a class="toc-backref" href="#id19">Changelog</a></h1>
+<div class="section" id="version-1-07-18-05-2010">
+<h2><a class="toc-backref" href="#id20">Version 1.07 (18.05.2010)</a></h2>
+<ul class="simple">
+<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>
+</div>
+<div class="section" id="version-1-06-10-04-2010">
+<h2><a class="toc-backref" href="#id21">Version 1.06 (10.04.2010)</a></h2>
+<ul class="simple">
+<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>
+</div>
+<div class="section" id="version-1-05-16-10-2009">
+<h2><a class="toc-backref" href="#id22">Version 1.05 (16.10.2009)</a></h2>
+<ul class="simple">
+<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>
+</div>
+<div class="section" id="version-1-04-22-05-2009">
+<h2><a class="toc-backref" href="#id23">Version 1.04 (22.05.2009)</a></h2>
+<ul class="simple">
+<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>
+</div>
+<div class="section" id="version-1-03-31-01-2009">
+<h2><a class="toc-backref" href="#id24">Version 1.03 (31.01.2009)</a></h2>
+<ul class="simple">
+<li>Accept enumeration lists with a comma after the last item (C99 feature).</li>
+</ul>
+</div>
+<div class="section" id="version-1-02-16-01-2009">
+<h2><a class="toc-backref" href="#id25">Version 1.02 (16.01.2009)</a></h2>
+<ul class="simple">
+<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>
+</div>
+<div class="section" id="version-1-01-09-01-2009">
+<h2><a class="toc-backref" href="#id26">Version 1.01 (09.01.2009)</a></h2>
+<ul class="simple">
+<li>Fixed subprocess invocation in the helper function parse_file - now it's more portable</li>
+</ul>
+</div>
+<div class="section" id="version-1-0-15-11-2008">
+<h2><a class="toc-backref" href="#id27">Version 1.0 (15.11.2008)</a></h2>
+<ul class="simple">
+<li>Initial release</li>
+<li>Support for ANSI C89</li>
+</ul>
+</div>
+</div>
+</div>
+</body>
+</html>
+===============
+pycparser v1.06
+===============
+
+:Author: `Eli Bendersky <http://eli.thegreenplace.net>`_
+
+
+.. contents::
+
+Introduction
+============
+
+What is pycparser?
+------------------
+
+``pycparser`` 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.
+
+What is it good for?
+--------------------
+
+Anything that needs C code to be parsed. The following are some uses for ``pycparser``, taken from real user reports:
+
+* C code obfuscator
+* Front-end for various specialized C compilers
+* Static code checker
+* Automatic unit-test discovery
+* Adding specialized extensions to the C language
+
+``pycparser`` 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, ``pycparser``'s code will be simple to understand.
+
+
+Which version of C does pycparser support?
+------------------------------------------
+
+At the moment, ``pycparser`` supports ANSI/ISO C89, the language described by Kernighan and Ritchie in "The C Programming language, 2nd edition" (K&R2), with only selected extensions from C99. The currently supported C99 features are:
+
+* Allowing a comma after the last value in an enumeration list
+
+``pycparser`` doesn't support any GCC extensions.
+
+What grammar does pycparser follow?
+-----------------------------------
+
+``pycparser`` very closely follows the ANSI C grammar provided in the end of K&R2. Listings of this grammar (often in Yacc syntax) can be easily found by a simple web search. Google for `ansi c grammar` to get started.
+
+
+What is an AST?
+---------------
+
+`AST <http://en.wikipedia.org/wiki/Abstract_syntax_tree>`_ - 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.
+
+How is pycparser licensed?
+--------------------------
+
+`LGPL <http://www.gnu.org/licenses/lgpl.html>`_
+
+Contact details
+---------------
+
+Drop me an email to eliben@gmail.com for any questions regarding ``pycparser``.
+
+
+Installing
+==========
+
+Prerequisites
+-------------
+
+* ``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. You'll also need to install PLY version 3.2 (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.
+
+
+Using
+=====
+
+Interaction with the C preprocessor
+-----------------------------------
+
+In order to be compilable, C code must be preprocessed by the C preprocessor - ``cpp``. ``cpp`` handles preprocessing directives like ``#include`` and ``#define``, removes comments, and does other minor tasks that prepare the C code for compilation.
+
+For all but the most trivial snippets of C code, ``pycparser``, like a C compiler, must receive preprocessed C code in order to function correctly. If you import the top-level ``parse_file`` function from the ``pycparser`` package, it will interact with ``cpp`` for you, as long as it's in your PATH, or you provide a path to it. 
+
+On the vast majority of Linux systems, ``cpp`` is installed and is in the PATH. If you're on Windows and don't have ``cpp`` somewhere, you can use the one provided in the ``utils`` directory in ``pycparser``'s distribution. This ``cpp`` executable was compiled from the `LCC distribution <http://www.cs.princeton.edu/software/lcc/>`_, and is provided under LCC's license terms.
+
+What about the standard C library headers?
+------------------------------------------
+
+C code almost always includes various header files from the standard C library, like ``stdio.h``. While, with some effort, ``pycparser`` can be made to parse the standard headers from any C compiler, it's much simpler to use the provided "fake" standard in includes in ``utils/fake_libc_include``. These are standard C header files that contain only the bare necessities to allow valid compilation of the files that use them. As a bonus, since they're minimal, it can significantly improve the performance of parsing C files.
+
+See the ``using_cpp_libc.py`` example for more details.
+
+Basic usage
+-----------
+
+Take a look at the ``examples`` directory of the distribution for a few examples of using ``pycparser``. These should be enough to get you started.
+
+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``.
+
+In any case, you can always drop me an `email <eliben@gmail.com>`_ for help.
+
+Modifying
+=========
+
+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.
+* 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
+================
+
+Once you unzip the ``pycparser`` package, you'll see the following files and directories:
+
+README.txt/html:
+  This README file.
+
+setup.py:
+  Installation script
+
+examples/:
+  A directory with some examples of using ``pycparser``
+
+pycparser/:
+  The ``pycparser`` module source code.
+
+tests/:
+  Unit tests.
+
+utils/cpp.exe:
+  A Windows executable of the C pre-processor suitable for working with pycparser
+
+utils/fake_libc_include:
+  Minimal standard C library include files that should allow to parse any C code.
+
+utils/internal/:
+  Internal utilities for my own use. You probably don't need them.
+
+
+Changelog
+=========
+
+Version 1.07 (18.05.2010)
+-------------------------
+
+* Python 3.1 compatibility: ``pycparser`` was modified to run on Python 3.1 as well as 2.6
+
+
+Version 1.06 (10.04.2010)
+-------------------------
+
+* Bug fixes: 
+
+  + coord not propagated to FuncCall nodes
+  + lexing of the ^= token (XOREQUALS)
+  + parsing failed on some abstract declarator rules
+
+* Linux compatibility: fixed end-of-line and ``cpp`` path issues to allow all tests and examples run on Linux
+
+
+Version 1.05 (16.10.2009)
+-------------------------
+
+* Fixed the ``parse_file`` auxiliary function to handle multiple arguments to ``cpp`` correctly
+
+Version 1.04 (22.05.2009)
+-------------------------
+
+* Added the ``fake_libc_include`` directory to allow parsing of C code that uses standard C library include files without dependency on a real C library.
+* Tested with Python 2.6 and PLY 3.2
+
+
+Version 1.03 (31.01.2009)
+-------------------------
+
+* Accept enumeration lists with a comma after the last item (C99 feature).
+
+Version 1.02 (16.01.2009)
+-------------------------
+
+* Fixed problem of parsing struct/enum/union names that were named similarly to previously defined ``typedef`` types. 
+
+Version 1.01 (09.01.2009)
+-------------------------
+
+* Fixed subprocess invocation in the helper function parse_file - now it's more portable
+
+Version 1.0 (15.11.2008)
+------------------------
+
+* Initial release
+* Support for ANSI C89
+
+
+
+
+Fixes since last:
+------------------
+
+
+
+Version Update
+--------------
+
+setup.py, __init__.py, README.txt
+
+
+
+rst2html readme.txt > readme.html
+
+setup.py sdist
+
+
+
+
+
+yacc optimization: 
+- If parsetab.py/pyc doesn't exist in the path, the table will be reconstructed anyway, regardless of the optimize parameter
+- If it does exist:
+  - If optimize=True, the table will be loaded unconditionally
+  - If optimize=False, the table will be loaded only if it's older than the grammar
+
+lex optimization:
+- If optimize=False, the lexical table is re-computed and is not saved to a lextab file
+- If optimize=True:
+  - If lextab.py/pyc exists in the path, it will be loaded unconditionally
+  - If lextab.py/pyc doesn't exist, it will be created and loaded
+
+

examples/c_files/funky.c

+char foo(void)
+{
+    return '1';
+}
+
+int maxout_in(int paste, char** matrix)
+{
+    char o = foo();
+    return (int) matrix[1][2] * 5 - paste;
+}
+
+int main()
+{
+    auto char* multi = "a multi";
+    
+    
+}
+
+
+

examples/c_files/hash.c

+/*
+** C implementation of a hash table ADT
+*/
+typedef enum tagReturnCode {SUCCESS, FAIL} ReturnCode;
+
+
+typedef struct tagEntry
+{
+    char* key;
+    char* value;
+} Entry;
+
+
+
+typedef struct tagNode
+{
+    Entry* entry;
+
+    struct tagNode* next;
+} Node;
+
+
+typedef struct tagHash
+{
+    unsigned int table_size;
+
+    Node** heads; 
+
+} Hash;
+
+
+static unsigned int hash_func(const char* str, unsigned int table_size)
+{
+    unsigned int hash_value;
+    unsigned int a = 127;
+
+    for (hash_value = 0; *str != 0; ++str)
+        hash_value = (a*hash_value + *str) % table_size;
+
+    return hash_value;
+}
+
+
+ReturnCode HashCreate(Hash** hash, unsigned int table_size)
+{
+    unsigned int i;
+
+    if (table_size < 1)
+        return FAIL;
+
+    //
+    // Allocate space for the Hash
+    //
+    if (((*hash) = malloc(sizeof(**hash))) == NULL)
+        return FAIL;
+
+    //
+    // Allocate space for the array of list heads
+    //
+    if (((*hash)->heads = malloc(table_size*sizeof(*((*hash)->heads)))) == NULL)
+        return FAIL;
+
+    //
+    // Initialize Hash info
+    //
+    for (i = 0; i < table_size; ++i)
+    {
+        (*hash)->heads[i] = NULL;
+    }
+
+    (*hash)->table_size = table_size;
+
+    return SUCCESS;
+}
+
+
+ReturnCode HashInsert(Hash* hash, const Entry* entry)
+{
+    unsigned int index = hash_func(entry->key, hash->table_size);
+    Node* temp = hash->heads[index];
+
+    HashRemove(hash, entry->key);
+
+    if ((hash->heads[index] = malloc(sizeof(Node))) == NULL)
+        return FAIL;
+
+    hash->heads[index]->entry = malloc(sizeof(Entry));
+    hash->heads[index]->entry->key = malloc(strlen(entry->key)+1);
+    hash->heads[index]->entry->value = malloc(strlen(entry->value)+1);
+    strcpy(hash->heads[index]->entry->key, entry->key);
+    strcpy(hash->heads[index]->entry->value, entry->value);
+
+    hash->heads[index]->next = temp;
+
+    return SUCCESS;
+}
+
+
+
+const Entry* HashFind(const Hash* hash, const char* key)
+{
+    unsigned int index = hash_func(key, hash->table_size);
+    Node* temp = hash->heads[index];
+
+    while (temp != NULL)
+    {
+        if (!strcmp(key, temp->entry->key))
+            return temp->entry;
+
+        temp = temp->next;
+    }
+
+    return NULL;
+}
+
+
+ReturnCode HashRemove(Hash* hash, const char* key)
+{
+    unsigned int index = hash_func(key, hash->table_size);
+    Node* temp1 = hash->heads[index];
+    Node* temp2 = temp1;
+
+    while (temp1 != NULL)
+    {
+        if (!strcmp(key, temp1->entry->key))
+        {
+            if (temp1 == hash->heads[index])
+                hash->heads[index] = hash->heads[index]->next;
+            else
+                temp2->next = temp1->next;
+
+            free(temp1->entry->key);
+            free(temp1->entry->value);
+            free(temp1->entry);
+            free(temp1);
+            temp1 = NULL;
+
+            return SUCCESS;
+        }
+        
+        temp2 = temp1;
+        temp1 = temp1->next;
+    }
+
+    return FAIL;
+}
+
+
+void HashPrint(Hash* hash, void (*PrintFunc)(char*, char*))
+{
+    unsigned int i;
+
+    if (hash == NULL || hash->heads == NULL)
+        return;
+
+    for (i = 0; i < hash->table_size; ++i)
+    {
+        Node* temp = hash->heads[i];
+
+        while (temp != NULL)
+        {
+            PrintFunc(temp->entry->key, temp->entry->value);
+            temp = temp->next;
+        }
+    }
+}
+
+
+
+void HashDestroy(Hash* hash)
+{
+    unsigned int i;
+
+    if (hash == NULL)
+        return;
+
+    for (i = 0; i < hash->table_size; ++i)
+    {
+        Node* temp = hash->heads[i];
+
+        while (temp != NULL)
+        {
+            Node* temp2 = temp;
+
+            free(temp->entry->key);
+            free(temp->entry->value);
+            free(temp->entry);
+
+            temp = temp->next;
+            
+            free(temp2);
+        }
+    }    
+
+    free(hash->heads);
+    hash->heads = NULL;
+
+    free(hash);
+}
+

examples/c_files/memmgr.c

+//----------------------------------------------------------------
+// Statically-allocated memory manager
+//
+// by Eli Bendersky (eliben@gmail.com)
+//  
+// This code is in the public domain.
+//----------------------------------------------------------------
+#include "memmgr.h"
+
+typedef ulong Align;
+
+union mem_header_union
+{
+    struct 
+    {
+        // Pointer to the next block in the free list
+        //
+        union mem_header_union* next;
+
+        // Size of the block (in quantas of sizeof(mem_header_t))
+        //
+        ulong size; 
+    } s;
+
+    // Used to align headers in memory to a boundary
+    //
+    Align align_dummy;
+};
+
+typedef union mem_header_union mem_header_t;
+
+// Initial empty list
+//
+static mem_header_t base;
+
+// Start of free list
+//
+static mem_header_t* freep = 0;
+
+// Static pool for new allocations
+//
+static byte pool[POOL_SIZE] = {0};
+static ulong pool_free_pos = 0;
+
+
+void memmgr_init()
+{
+    base.s.next = 0;
+    base.s.size = 0;
+    freep = 0;
+    pool_free_pos = 0;
+}
+
+
+static mem_header_t* get_mem_from_pool(ulong nquantas)
+{
+    ulong total_req_size;
+
+    mem_header_t* h;
+
+    if (nquantas < MIN_POOL_ALLOC_QUANTAS)
+        nquantas = MIN_POOL_ALLOC_QUANTAS;
+
+    total_req_size = nquantas * sizeof(mem_header_t);
+
+    if (pool_free_pos + total_req_size <= POOL_SIZE)
+    {
+        h = (mem_header_t*) (pool + pool_free_pos);
+        h->s.size = nquantas;
+        memmgr_free((void*) (h + 1));
+        pool_free_pos += total_req_size;
+    }
+    else
+    {
+        return 0;
+    }
+
+    return freep;
+}
+
+
+// Allocations are done in 'quantas' of header size.
+// The search for a free block of adequate size begins at the point 'freep' 
+// where the last block was found.
+// If a too-big block is found, it is split and the tail is returned (this 
+// way the header of the original needs only to have its size adjusted).
+// The pointer returned to the user points to the free space within the block,
+// which begins one quanta after the header.
+//
+void* memmgr_alloc(ulong nbytes)
+{
+    mem_header_t* p;
+    mem_header_t* prevp;
+
+    // Calculate how many quantas are required: we need enough to house all
+    // the requested bytes, plus the header. The -1 and +1 are there to make sure
+    // that if nbytes is a multiple of nquantas, we don't allocate too much
+    //
+    ulong nquantas = (nbytes + sizeof(mem_header_t) - 1) / sizeof(mem_header_t) + 1;
+
+    // First alloc call, and no free list yet ? Use 'base' for an initial
+    // denegerate block of size 0, which points to itself
+    // 
+    if ((prevp = freep) == 0)
+    {
+        base.s.next = freep = prevp = &base;
+        base.s.size = 0;
+    }
+
+    for (p = prevp->s.next; ; prevp = p, p = p->s.next)
+    {
+        // big enough ?
+        if (p->s.size >= nquantas) 
+        {
+            // exactly ?
+            if (p->s.size == nquantas)
+            {
+                // just eliminate this block from the free list by pointing
+                // its prev's next to its next
+                //
+                prevp->s.next = p->s.next;
+            }
+            else // too big
+            {
+                p->s.size -= nquantas;
+                p += p->s.size;
+                p->s.size = nquantas;
+            }
+
+            freep = prevp;
+            return (void*) (p + 1);
+        }
+        // Reached end of free list ?
+        // Try to allocate the block from the pool. If that succeeds,
+        // get_mem_from_pool adds the new block to the free list and
+        // it will be found in the following iterations. If the call
+        // to get_mem_from_pool doesn't succeed, we've run out of
+        // memory
+        //
+        else if (p == freep)
+        {
+            if ((p = get_mem_from_pool(nquantas)) == 0)
+            {
+                #ifdef DEBUG_MEMMGR_FATAL
+                printf("!! Memory allocation failed !!\n");
+                #endif
+                return 0;
+            }
+        }
+    }
+}
+
+
+// Scans the free list, starting at freep, looking the the place to insert the 
+// free block. This is either between two existing blocks or at the end of the
+// list. In any case, if the block being freed is adjacent to either neighbor,
+// the adjacent blocks are combined.
+//
+void memmgr_free(void* ap)
+{
+    mem_header_t* block;
+    mem_header_t* p;
+
+    // acquire pointer to block header
+    block = ((mem_header_t*) ap) - 1;
+
+    // Find the correct place to place the block in (the free list is sorted by
+    // address, increasing order)
+    //
+    for (p = freep; !(block > p && block < p->s.next); p = p->s.next)
+    {
+        // Since the free list is circular, there is one link where a 
+        // higher-addressed block points to a lower-addressed block. 
+        // This condition checks if the block should be actually 
+        // inserted between them
+        //
+        if (p >= p->s.next && (block > p || block < p->s.next))
+            break;
+    }
+
+    // Try to combine with the higher neighbor
+    //
+    if (block + block->s.size == p->s.next)
+    {
+        block->s.size += p->s.next->s.size;
+        block->s.next = p->s.next->s.next;
+    }
+    else
+    {
+        block->s.next = p->s.next;
+    }
+
+    // Try to combine with the lower neighbor
+    //
+    if (p + p->s.size == block)
+    {
+        p->s.size += block->s.size;
+        p->s.next = block->s.next;
+    }
+    else
+    {
+        p->s.next = block;
+    }
+
+    freep = p;
+}

examples/c_files/memmgr.h

+//----------------------------------------------------------------
+// Statically-allocated memory manager
+//
+// by Eli Bendersky (eliben@gmail.com)
+//  
+// This code is in the public domain.
+//----------------------------------------------------------------
+#ifndef MEMMGR_H
+#define MEMMGR_H
+
+//
+// Memory manager: dynamically allocates memory from 
+// a fixed pool that is allocated statically at link-time.
+// 
+// Usage: after calling memmgr_init() in your 
+// initialization routine, just use memmgr_alloc() instead
+// of malloc() and memmgr_free() instead of free().
+// Naturally, you can use the preprocessor to define 
+// malloc() and free() as aliases to memmgr_alloc() and 
+// memmgr_free(). This way the manager will be a drop-in 
+// replacement for the standard C library allocators, and can
+// be useful for debugging memory allocation problems and 
+// leaks.
+//
+// Preprocessor flags you can define to customize the 
+// memory manager:
+//
+// DEBUG_MEMMGR_FATAL
+//    Allow printing out a message when allocations fail
+//
+// DEBUG_MEMMGR_SUPPORT_STATS
+//    Allow printing out of stats in function 
+//    memmgr_print_stats When this is disabled, 
+//    memmgr_print_stats does nothing.
+//
+// Note that in production code on an embedded system 
+// you'll probably want to keep those undefined, because
+// they cause printf to be called.
+//
+// POOL_SIZE
+//    Size of the pool for new allocations. This is 
+//    effectively the heap size of the application, and can 
+//    be changed in accordance with the available memory 
+//    resources.
+//
+// MIN_POOL_ALLOC_QUANTAS
+//    Internally, the memory manager allocates memory in
+//    quantas roughly the size of two ulong objects. To
+//    minimize pool fragmentation in case of multiple allocations
+//    and deallocations, it is advisable to not allocate
+//    blocks that are too small.
+//    This flag sets the minimal ammount of quantas for 
+//    an allocation. If the size of a ulong is 4 and you
+//    set this flag to 16, the minimal size of an allocation
+//    will be 4 * 2 * 16 = 128 bytes
+//    If you have a lot of small allocations, keep this value
+//    low to conserve memory. If you have mostly large 
+//    allocations, it is best to make it higher, to avoid 
+//    fragmentation.
+//
+// Notes:
+// 1. This memory manager is *not thread safe*. Use it only
+//    for single thread/task applications.
+// 
+
+#define DEBUG_MEMMGR_SUPPORT_STATS 1
+
+#define POOL_SIZE 8 * 1024
+#define MIN_POOL_ALLOC_QUANTAS 16
+
+
+typedef unsigned char byte;
+typedef unsigned long ulong;
+
+
+
+// Initialize the memory manager. This function should be called
+// only once in the beginning of the program.
+//
+void memmgr_init();
+
+// 'malloc' clone
+//
+void* memmgr_alloc(ulong nbytes);
+
+// 'free' clone
+//
+void memmgr_free(void* ap);
+
+// Prints statistics about the current state of the memory
+// manager
+//
+void memmgr_print_stats();
+
+
+#endif // MEMMGR_H

examples/c_files/year.c

+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+void convert(int thousands, int hundreds, int tens, int ones)
+{
+char *num[] = {"", "One", "Two", "Three", "Four", "Five", "Six",
+	       "Seven", "Eight", "Nine"};
+
+char *for_ten[] = {"", "", "Twenty", "Thirty", "Fourty", "Fifty", "Sixty",
+		   "Seventy", "Eighty", "Ninty"};
+
+char *af_ten[] = {"Ten", "Eleven", "Twelve", "Thirteen", "Fourteen",
+		  "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Ninteen"};
+
+  printf("\nThe year in words is:\n");
+
+  printf("%s thousand", num[thousands]);
+  if (hundreds != 0)
+    printf(" %s hundred", num[hundreds]);
+
+  if (tens != 1)
+    printf(" %s %s", for_ten[tens], num[ones]);
+  else
+    printf(" %s", af_ten[ones]);
+}
+
+
+int main()
+{
+int year;
+int n1000, n100, n10, n1;
+
+  printf("\nEnter the year (4 digits): ");
+  scanf("%d", &year);
+
+  if (year > 9999 || year < 1000)
+  {
+    printf("\nError !! The year must contain 4 digits.");
+    exit(EXIT_FAILURE);
+  }
+
+  n1000 = year/1000;
+  n100 = ((year)%1000)/100;
+  n10 = (year%100)/10;
+  n1 = ((year%10)%10);
+
+  convert(n1000, n100, n10, n1);
+
+return 0;
+}
+
+

examples/cdecl.py

+#-----------------------------------------------------------------
+# 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, 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
+
+
+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
+        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])
+
+
+def _explain_decl_node(decl_node):
+    """ 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))
+
+
+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)])

examples/explore_ast.py

+#-----------------------------------------------------------------
+# pycparser: explore_ast.py
+#
+# This example demonstrates how to "explore" the AST created by
+# pycparser to understand its structure. The AST is a n-nary tree
+# of nodes, each node having several children, each with a name.
+# Just read the code, and let the comments guide you. The lines
+# beginning with #~ can be uncommented to print out useful 
+# information from the AST.
+# It helps to have the _c_ast.yaml file in front of you.
+#
+# Copyright (C) 2008, 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
+
+# This is some C source to parse. Note that pycparser must begin
+# at the top level of the C file, i.e. with either declarations
+# or function definitions (this is called "external declarations"
+# in C grammar lingo)
+#
+# Also, a C parser must have all the types declared in order to
+# build the correct AST. It doesn't matter what they're declared
+# to, so I've inserted the dummy typedef in the code to let the
+# parser know Hash and Node are types. You don't need to do it 
+# when parsing real, correct C code.
+#
+text = r"""
+    typedef int Node, Hash;
+
+    void HashPrint(Hash* hash, void (*PrintFunc)(char*, char*))
+    {
+        unsigned int i;
+
+        if (hash == NULL || hash->heads == NULL)
+            return;
+
+        for (i = 0; i < hash->table_size; ++i)
+        {
+            Node* temp = hash->heads[i];
+
+            while (temp != NULL)
+            {
+                PrintFunc(temp->entry->key, temp->entry->value);
+                temp = temp->next;
+            }
+        }
+    }
+"""
+
+# Create the parser and ask to parse the text. parse() will throw
+# a ParseError if there's an error in the code
+#
+parser = c_parser.CParser()
+ast = parser.parse(text, filename='<none>')
+
+# Uncomment the following line to see the AST in a nice, human
+# readable way. show() is the most useful tool in exploring ASTs
+# created by pycparser. See the c_ast.py file for the options you
+# can pass it.
+#
+#~ ast.show()
+
+# OK, we've seen that the top node is FileAST. This is always the
+# top node of the AST. Its children are "external declarations",
+# and are stored in a list called ext[] (see _c_ast.yaml for the
+# names and types of Nodes and their children).
+# As you see from the printout, our AST has two Typedef children
+# and one FuncDef child.
+# Let's explore FuncDef more closely. As I've mentioned, the list
+# ext[] holds the children of FileAST. Since the function 
+# definition is the third child, it's ext[2]. Uncomment the 
+# following line to show it:
+#
+#~ ast.ext[2].show()
+
+# A FuncDef consists of a declaration, a list of parameter 
+# declarations (for K&R style function definitions), and a body.
+# Let's focus on the body for this example. The body is of 
+# type Compound, which is a placeholder for a block surrounded
+# by {} (You should be reading _c_ast.yaml parallel to this 
+# explanation and seeing these things by your own eyes).
+#
+# Let's see the block's declarations:
+#
+function_body = ast.ext[2].body
+
+# The following displays the variable declarations in the function
+# body
+#
+#~ for decl in function_body.decls:
+    #~ decl.show()
+
+# We can see a single variable, i, declared to be a simple type
+# declaration of type 'unsigned int'.
+#
+# Let's look at the statemts now:
+#
+#~ for stmt in function_body.stmts:
+    #~ stmt.show()
+
+# stmts is a list, so the second element is the For statement:
+#
+for_stmt = function_body.stmts[1]
+#~ for_stmt.show()
+
+# As you can see in _c_ast.yaml, For's children are 'init, cond,
+# next' for the respective parts of the 'for' loop specifier,
+# and stmt, which is either a single stmt or a Compound if there's
+# a block.
+#
+# Let's dig deeper, to the while statement inside the for loop:
+#
+while_stmt = for_stmt.stmt.stmts[0]
+#~ while_stmt.show()
+
+# While is simpler, it only has a condition node and a stmt node.
+# The condition:
+#
+while_cond = while_stmt.cond
+#~ while_cond.show()
+
+# Note that it's a BinaryOp node - the basic constituent of 
+# expressions in our AST. BinaryOp is the expression tree, with
+# left and right nodes as children. It also has the op attribute,
+# which is just the string representation of the operator.
+#
+#~ print while_cond.op
+#~ while_cond.left.show()
+#~ while_cond.right.show()
+
+#
+# That's if for the example. I hope you now see how easy it is to
+# explore the AST created by pycparser. Although on the surface it
+# is quite complex and has a lot of node types, this is the 
+# inherent complexity of the C language every parser/compiler 
+# designer has to cope with.
+# Using the tools provided by the c_ast package it's easy to
+# explore the structure of AST nodes and write code that processes
+# them.
+# Specifically, see the cdecl.py example for a non-trivial 
+# demonstration of what you can do by recursively going through
+# the AST.
+#
+
+

examples/func_calls.py

+#-----------------------------------------------------------------
+# pycparser: func_defs.py
+#
+# Using pycparser for printing out all the calls of some function
+# in a C file.
+#
+# Copyright (C) 2008, 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, parse_file
+from pycparser.portability import printme
+
+
+# A visitor with some state information (the funcname it's 
+# looking for)
+#
+class FuncCallVisitor(c_ast.NodeVisitor):
+    def __init__(self, funcname):
+        self.funcname = funcname
+
+    def visit_FuncCall(self, node):
+        if node.name.name == self.funcname:
+            printme('%s called at %s\n' % (
+                    self.funcname, node.name.coord))
+
+
+def show_func_calls(filename, funcname):
+    ast = parse_file(filename, use_cpp=True)        
+    v = FuncCallVisitor(funcname)
+    v.visit(ast)
+
+
+if __name__ == "__main__":
+    if len(sys.argv) > 2:
+        filename  = sys.argv[1]
+        func = sys.argv[2]
+    else:
+        filename = 'c_files/hash.c'
+        func = 'malloc'
+
+    show_func_calls(filename, func)
+
+
+

examples/func_defs.py

+#-----------------------------------------------------------------
+# pycparser: func_defs.py
+#
+# Using pycparser for printing out all the functions defined in a 
+# C file.
+#
+# This is a simple example of traversing the AST generated by
+# pycparser.
+#
+# Copyright (C) 2008-2009, 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, parse_file
+from pycparser.portability import printme
+
+
+# A simple visitor for FuncDef nodes that prints the names and 
+# locations of function definitions.
+#
+class FuncDefVisitor(c_ast.NodeVisitor):
+    def visit_FuncDef(self, node):
+        printme('%s at %s\n' % (node.decl.name, node.decl.coord))
+
+
+def show_func_defs(filename):
+    # Note that cpp is used. Provide a path to your own cpp or 
+    # make sure one exists in PATH.
+    #
+    ast = parse_file(filename, use_cpp=True)    
+    
+    v = FuncDefVisitor()
+    v.visit(ast)
+
+
+if __name__ == "__main__":
+    if len(sys.argv) > 1:
+        filename  = sys.argv[1]
+    else:
+        filename = 'c_files/memmgr.c'
+
+    show_func_defs(filename)
+
+
+

examples/using_cpp_libc.py

+#-----------------------------------------------------------------
+# pycparser: use_cpp_libc.py
+#
+# Shows how to use the provided 'cpp' (on Windows, substitute for
+# the 'real' cpp if you're on Linux/Unix) and "fake" libc includes
+# to parse a file that includes standard C headers.
+#
+# Copyright (C) 2008-2009, 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, '..')
+
+# Portable cpp path for Windows and Linux/Unix
+CPPPATH = '../utils/cpp.exe' if sys.platform == 'win32' else 'cpp'
+
+from pycparser import parse_file
+
+
+if __name__ == "__main__":
+    if len(sys.argv) > 1:
+        filename  = sys.argv[1]
+    else:
+        filename = 'c_files/year.c'
+
+    ast = parse_file(filename, use_cpp=True,
+            cpp_path=CPPPATH, 
+            cpp_args=r'-I../utils/fake_libc_include')
+    
+    ast.show()
+

pycparser/__init__.py

+#-----------------------------------------------------------------
+# pycparser: __init__.py
+#
+# This package file exports some convenience functions for 
+# interacting with pycparser
+#
+# Copyright (C) 2008-2009, Eli Bendersky
+# License: LGPL
+#-----------------------------------------------------------------
+
+__all__ = ['c_lexer', 'c_parser', 'c_ast']
+__version__ = '1.07'
+
+from subprocess import Popen, PIPE
+
+from .c_parser import CParser
+
+
+def parse_file( filename, use_cpp=False, 
+                cpp_path='cpp', cpp_args=''):
+    """ Parse a C file using pycparser.
+    
+        filename:
+            Name of the file you want to parse.
+        
+        use_cpp:
+            Set to True if you want to execute the C pre-processor
+            on the file prior to parsing it.
+        
+        cpp_path:
+            If use_cpp is True, this is the path to 'cpp' on your
+            system. If no path is provided, it attempts to just
+            execute 'cpp', so it must be in your PATH.
+        
+        cpp_args:
+            If use_cpp is True, set this to the command line 
+            arguments strings to cpp. Be careful with quotes - 
+            it's best to pass a raw string (r'') here. 
+            For example:
+            r'-I../utils/fake_libc_include'
+            If several arguments are required, pass a list of 
+            strings.
+        
+        When successful, an AST is returned. ParseError can be 
+        thrown if the file doesn't parse successfully.
+        
+        Errors from cpp will be printed out. 
+    """
+    if use_cpp:   
+        path_list = [cpp_path]
+        if isinstance(cpp_args, list):
+            path_list += cpp_args
+        elif cpp_args != '': 
+            path_list += [cpp_args]
+        path_list += [filename]
+        
+        # Note the use of universal_newlines to treat all newlines
+        # as \n for Python's purpose
+        #
+        pipe = Popen(   path_list, 
+                        stdout=PIPE, 
+                        universal_newlines=True)
+        text = pipe.communicate()[0]
+    else:
+        text = open(filename, 'rU').read()
+    
+    parser = CParser()
+    return parser.parse(text, filename)
+    
+
+if __name__ == "__main__":
+    pass
+    
+

pycparser/_ast_gen.py

+#-----------------------------------------------------------------
+# _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-2009, Eli Bendersky
+# License: LGPL
+#-----------------------------------------------------------------
+
+import pprint
+from string import Template
+
+import yaml
+
+
+class ASTCodeGenerator(object):
+    def __init__(self, cfg_filename='_c_ast.yaml'):
+        """ 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'
+        
+        file.write(src)
+
+
+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:
+                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
+    
+    ast_gen = ASTCodeGenerator('_c_ast.yaml')
+    ast_gen.generate(open('c_ast.py', 'w'))
+    
+    
+    

pycparser/_build_tables.py

+#-----------------------------------------------------------------
+# pycparser: _build_tables.py
+#
+# 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.
+#
+# Copyright (C) 2008, Eli Bendersky
+# License: LGPL
+#-----------------------------------------------------------------
+
+# Generate c_ast.py
+#
+from _ast_gen import ASTCodeGenerator
+ast_gen = ASTCodeGenerator('_c_ast.yaml')
+ast_gen.generate(open('c_ast.py', 'w'))
+
+import c_parser
+
+# Generates the tables
+#
+c_parser.CParser(
+    lex_optimize=True, 
+    yacc_debug=False, 
+    yacc_optimize=True)
+
+# Load to compile into .pyc
+#
+import lextab
+import yacctab
+import c_ast

pycparser/_c_ast.yaml

+#-----------------------------------------------------------------
+# pycparser: _c_ast_gen.yaml
+#
+# Defines the AST Node classes used in pycparser.
+# 
+# Each ent