aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEli Bendersky <eliben@gmail.com>2010-05-21 09:05:39 +0300
committerEli Bendersky <eliben@gmail.com>2010-05-21 09:05:39 +0300
commit3921e8e23ef7952e2e118e9d534cfc4a221e2450 (patch)
tree60efcf9f007a5657422a75ed0aad28cb97cb3fa2
downloadpycparser-3921e8e23ef7952e2e118e9d534cfc4a221e2450.tar.gz
initial import from SVN
-rw-r--r--MANIFEST.in9
-rw-r--r--README.html532
-rw-r--r--README.txt208
-rw-r--r--TODO.txt33
-rw-r--r--examples/c_files/funky.c20
-rw-r--r--examples/c_files/hash.c200
-rw-r--r--examples/c_files/memmgr.c206
-rw-r--r--examples/c_files/memmgr.h96
-rw-r--r--examples/c_files/year.c53
-rw-r--r--examples/cdecl.py108
-rw-r--r--examples/explore_ast.py153
-rw-r--r--examples/func_calls.py51
-rw-r--r--examples/func_defs.py51
-rw-r--r--examples/using_cpp_libc.py35
-rw-r--r--pycparser/__init__.py74
-rw-r--r--pycparser/_ast_gen.py249
-rw-r--r--pycparser/_build_tables.py31
-rw-r--r--pycparser/_c_ast.yaml164
-rw-r--r--pycparser/c_ast.py1163
-rw-r--r--pycparser/c_lexer.py445
-rw-r--r--pycparser/c_parser.py1258
-rw-r--r--pycparser/plyparser.py55
-rw-r--r--pycparser/portability.py18
-rw-r--r--setup.py26
-rw-r--r--tests/all_tests.py15
-rw-r--r--tests/c_files/cppd_with_stdio_h.c5038
-rw-r--r--tests/c_files/example_c_file.c12
-rw-r--r--tests/c_files/memmgr.c206
-rw-r--r--tests/c_files/memmgr.h96
-rw-r--r--tests/c_files/memmgr_with_h.c350
-rw-r--r--tests/c_files/year.c53
-rw-r--r--tests/test_c_ast.py89
-rw-r--r--tests/test_c_lexer.py327
-rw-r--r--tests/test_c_parser.py1028
-rw-r--r--tests/test_general.py37
-rw-r--r--utils/cpp.exebin0 -> 196608 bytes
-rw-r--r--utils/fake_libc_include/_ansi.h2
-rw-r--r--utils/fake_libc_include/_fake_defines.h28
-rw-r--r--utils/fake_libc_include/_fake_typedefs.h80
-rw-r--r--utils/fake_libc_include/_syslist.h2
-rw-r--r--utils/fake_libc_include/alloca.h2
-rw-r--r--utils/fake_libc_include/ar.h2
-rw-r--r--utils/fake_libc_include/argz.h2
-rw-r--r--utils/fake_libc_include/assert.h2
-rw-r--r--utils/fake_libc_include/ctype.h2
-rw-r--r--utils/fake_libc_include/dirent.h2
-rw-r--r--utils/fake_libc_include/envz.h2
-rw-r--r--utils/fake_libc_include/errno.h2
-rw-r--r--utils/fake_libc_include/fastmath.h2
-rw-r--r--utils/fake_libc_include/fcntl.h2
-rw-r--r--utils/fake_libc_include/getopt.h2
-rw-r--r--utils/fake_libc_include/grp.h2
-rw-r--r--utils/fake_libc_include/iconv.h2
-rw-r--r--utils/fake_libc_include/ieeefp.h2
-rw-r--r--utils/fake_libc_include/inttypes.h2
-rw-r--r--utils/fake_libc_include/langinfo.h2
-rw-r--r--utils/fake_libc_include/libgen.h2
-rw-r--r--utils/fake_libc_include/limits.h2
-rw-r--r--utils/fake_libc_include/locale.h2
-rw-r--r--utils/fake_libc_include/malloc.h2
-rw-r--r--utils/fake_libc_include/math.h2
-rw-r--r--utils/fake_libc_include/newlib.h2
-rw-r--r--utils/fake_libc_include/paths.h2
-rw-r--r--utils/fake_libc_include/process.h2
-rw-r--r--utils/fake_libc_include/pthread.h2
-rw-r--r--utils/fake_libc_include/pwd.h2
-rw-r--r--utils/fake_libc_include/reent.h2
-rw-r--r--utils/fake_libc_include/regdef.h2
-rw-r--r--utils/fake_libc_include/sched.h2
-rw-r--r--utils/fake_libc_include/search.h2
-rw-r--r--utils/fake_libc_include/setjmp.h2
-rw-r--r--utils/fake_libc_include/signal.h2
-rw-r--r--utils/fake_libc_include/stdarg.h2
-rw-r--r--utils/fake_libc_include/stddef.h2
-rw-r--r--utils/fake_libc_include/stdint.h2
-rw-r--r--utils/fake_libc_include/stdio.h2
-rw-r--r--utils/fake_libc_include/stdlib.h2
-rw-r--r--utils/fake_libc_include/string.h2
-rw-r--r--utils/fake_libc_include/tar.h2
-rw-r--r--utils/fake_libc_include/termios.h2
-rw-r--r--utils/fake_libc_include/time.h2
-rw-r--r--utils/fake_libc_include/unctrl.h2
-rw-r--r--utils/fake_libc_include/unistd.h2
-rw-r--r--utils/fake_libc_include/utime.h2
-rw-r--r--utils/fake_libc_include/utmp.h2
-rw-r--r--utils/fake_libc_include/wchar.h2
-rw-r--r--utils/fake_libc_include/wctype.h2
-rw-r--r--utils/internal/cppify.bat3
-rw-r--r--utils/internal/example_c_file.c25
-rw-r--r--utils/internal/fake_includes.py13
-rw-r--r--utils/internal/make_fake_typedefs.py21
-rw-r--r--utils/internal/zc.c107
-rw-r--r--utils/internal/zz_parse.py10
-rw-r--r--z_test.py75
94 files changed, 12949 insertions, 0 deletions
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..22fa7fb
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,9 @@
+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.*
diff --git a/README.html b/README.html
new file mode 100644
index 0000000..279ff59
--- /dev/null
+++ b/README.html
@@ -0,0 +1,532 @@
+<?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>
diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000..4674782
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,208 @@
+===============
+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
+
+
+
+
diff --git a/TODO.txt b/TODO.txt
new file mode 100644
index 0000000..4b85109
--- /dev/null
+++ b/TODO.txt
@@ -0,0 +1,33 @@
+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
+
+
diff --git a/examples/c_files/funky.c b/examples/c_files/funky.c
new file mode 100644
index 0000000..252375f
--- /dev/null
+++ b/examples/c_files/funky.c
@@ -0,0 +1,20 @@
+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";
+
+
+}
+
+
+
diff --git a/examples/c_files/hash.c b/examples/c_files/hash.c
new file mode 100644
index 0000000..7ec500e
--- /dev/null
+++ b/examples/c_files/hash.c
@@ -0,0 +1,200 @@
+/*
+** 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);
+}
+
diff --git a/examples/c_files/memmgr.c b/examples/c_files/memmgr.c
new file mode 100644
index 0000000..6036ec6
--- /dev/null
+++ b/examples/c_files/memmgr.c
@@ -0,0 +1,206 @@
+//----------------------------------------------------------------
+// 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;
+}
diff --git a/examples/c_files/memmgr.h b/examples/c_files/memmgr.h
new file mode 100644
index 0000000..ae8212d
--- /dev/null
+++ b/examples/c_files/memmgr.h
@@ -0,0 +1,96 @@
+//----------------------------------------------------------------
+// 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
diff --git a/examples/c_files/year.c b/examples/c_files/year.c
new file mode 100644
index 0000000..c0f583d
--- /dev/null
+++ b/examples/c_files/year.c
@@ -0,0 +1,53 @@
+#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;
+}
+
+
diff --git a/examples/cdecl.py b/examples/cdecl.py
new file mode 100644
index 0000000..1db5149
--- /dev/null
+++ b/examples/cdecl.py
@@ -0,0 +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, 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)])
diff --git a/examples/explore_ast.py b/examples/explore_ast.py
new file mode 100644
index 0000000..7daf15b
--- /dev/null
+++ b/examples/explore_ast.py
@@ -0,0 +1,153 @@
+#-----------------------------------------------------------------
+# 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.
+#
+
+
diff --git a/examples/func_calls.py b/examples/func_calls.py
new file mode 100644
index 0000000..eaa3a67
--- /dev/null
+++ b/examples/func_calls.py
@@ -0,0 +1,51 @@
+#-----------------------------------------------------------------
+# 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)
+
+
+
diff --git a/examples/func_defs.py b/examples/func_defs.py
new file mode 100644
index 0000000..fa15b38
--- /dev/null
+++ b/examples/func_defs.py
@@ -0,0 +1,51 @@
+#-----------------------------------------------------------------
+# 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)
+
+
+
diff --git a/examples/using_cpp_libc.py b/examples/using_cpp_libc.py
new file mode 100644
index 0000000..e7c5daa
--- /dev/null
+++ b/examples/using_cpp_libc.py
@@ -0,0 +1,35 @@
+#-----------------------------------------------------------------
+# 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()
+
diff --git a/pycparser/__init__.py b/pycparser/__init__.py
new file mode 100644
index 0000000..1489b68
--- /dev/null
+++ b/pycparser/__init__.py
@@ -0,0 +1,74 @@
+#-----------------------------------------------------------------
+# 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
+
+
diff --git a/pycparser/_ast_gen.py b/pycparser/_ast_gen.py
new file mode 100644
index 0000000..47ba148
--- /dev/null
+++ b/pycparser/_ast_gen.py
@@ -0,0 +1,249 @@
+#-----------------------------------------------------------------
+# _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'))
+
+
+
diff --git a/pycparser/_build_tables.py b/pycparser/_build_tables.py
new file mode 100644
index 0000000..0f02387
--- /dev/null
+++ b/pycparser/_build_tables.py
@@ -0,0 +1,31 @@
+#-----------------------------------------------------------------
+# 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
diff --git a/pycparser/_c_ast.yaml b/pycparser/_c_ast.yaml
new file mode 100644
index 0000000..c954e38
--- /dev/null
+++ b/pycparser/_c_ast.yaml
@@ -0,0 +1,164 @@
+#-----------------------------------------------------------------
+# pycparser: _c_ast_gen.yaml
+#
+# Defines the AST Node classes used in pycparser.
+#
+# Each entry is a Node sub-class name, listing the attributes
+# and child nodes of the class:
+# <name>* - a child node
+# <name>** - a sequence of child nodes
+# <name> - an attribute
+#
+# Copyright (C) 2008-2009, Eli Bendersky
+# License: LGPL
+#-----------------------------------------------------------------
+
+
+ArrayDecl: [type*, dim*]
+
+ArrayRef: [name*, subscript*]
+
+# op: =, +=, /= etc.
+#
+Assignment: [op, lvalue*, rvalue*]
+
+BinaryOp: [op, left*, right*]
+
+Break: []
+
+Case: [expr*, stmt*]
+
+Cast: [to_type*, expr*]
+
+# Compound statement: { declarations... statements...}
+#
+Compound: [decls**, stmts**]
+
+# type: int, char, float, etc. see CLexer for constant token types
+#
+Constant: [type, value]
+
+Continue: []
+
+# name: the variable being declared
+# quals: list of qualifiers (const, volatile)
+# storage: list of storage specifiers (extern, register, etc.)
+# type: declaration type (probably nested with all the modifiers)
+# init: initialization value, or None
+# bitsize: bit field size, or None
+#
+Decl: [name, quals, storage, type*, init*, bitsize*]
+
+Default: [stmt*]
+
+DoWhile: [cond*, stmt*]
+
+# Represents the ellipsis (...) parameter in a function
+# declaration
+#
+EllipsisParam: []
+
+# Enumeration type specifier
+# name: an optional ID
+# values: an EnumeratorList
+#
+Enum: [name, values*]
+
+# A name/value pair for enumeration values
+#
+Enumerator: [name, value*]
+
+# A list of enumerators
+#
+EnumeratorList: [enumerators**]
+
+# a list of comma separated expressions
+#
+ExprList: [exprs**]
+
+# This is the top of the AST, representing a single C file (a
+# translation unit in K&R jargon). It contains a list of
+# "external-declaration"s, which is either declarations (Decl),
+# Typedef or function definitions (FuncDef).
+#
+FileAST: [ext**]
+
+# for (init; cond; next) stmt
+#
+For: [init*, cond*, next*, stmt*]
+
+# name: Id
+# args: ExprList
+#
+FuncCall: [name*, args*]
+
+# type <decl>(args)
+#
+FuncDecl: [args*, type*]
+
+# Function definition: a declarator for the function name and
+# a body, which is a compound statement.
+# There's an optional list of parameter declarations for old
+# K&R-style definitions
+#
+FuncDef: [decl*, param_decls**, body*]
+
+Goto: [name]
+
+ID: [name]
+
+# Holder for types that are a simple identifier (e.g. the built
+# ins void, char etc. and typedef-defined types)
+#
+IdentifierType: [names]
+
+If: [cond*, iftrue*, iffalse*]
+
+Label: [name, stmt*]
+
+# a list of comma separated function parameter declarations
+#
+ParamList: [params**]
+
+PtrDecl: [quals, type*]
+
+Return: [expr*]
+
+# name: struct tag name
+# decls: declaration of members
+#
+Struct: [name, decls**]
+
+# type: . or ->
+# name.field or name->field
+#
+StructRef: [name*, type, field*]
+
+Switch: [cond*, stmt*]
+
+# cond ? iftrue : iffalse
+#
+TernaryOp: [cond*, iftrue*, iffalse*]
+
+# A base type declaration
+#
+TypeDecl: [declname, quals, type*]
+
+# A typedef declaration.
+# Very similar to Decl, but without some attributes
+#
+Typedef: [name, quals, storage, type*]
+
+Typename: [quals, type*]
+
+UnaryOp: [op, expr*]
+
+# name: union tag name
+# decls: declaration of members
+#
+Union: [name, decls**]
+
+While: [cond*, stmt*]
+
+
+
diff --git a/pycparser/c_ast.py b/pycparser/c_ast.py
new file mode 100644
index 0000000..90cfb79
--- /dev/null
+++ b/pycparser/c_ast.py
@@ -0,0 +1,1163 @@
+#-----------------------------------------------------------------
+# ** 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 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 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 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 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 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 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, decls, stmts, coord=None):
+ self.decls = decls
+ self.stmts = stmts
+ self.coord = coord
+
+ def children(self):
+ nodelist = []
+ if self.decls is not None: nodelist.extend(self.decls)
+ if self.stmts is not None: nodelist.extend(self.stmts)
+ 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, type, init, bitsize, coord=None):
+ self.name = name
+ self.quals = quals
+ self.storage = storage
+ 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))])
+ 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 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 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)
+
+
diff --git a/pycparser/c_lexer.py b/pycparser/c_lexer.py
new file mode 100644
index 0000000..b5327cb
--- /dev/null
+++ b/pycparser/c_lexer.py
@@ -0,0 +1,445 @@
+#-----------------------------------------------------------------
+# pycparser: c_lexer.py
+#
+# CLexer class: lexer for the C language
+#
+# Copyright (C) 2008-2010, Eli Bendersky
+# License: LGPL
+#-----------------------------------------------------------------
+
+import re
+import sys
+
+import ply.lex
+from ply.lex import TOKEN
+
+
+class CLexer(object):
+ """ A lexer for the C language. After building it, set the
+ input text with input(), and call token() to get new
+ tokens.
+
+ The public attribute filename can be set to an initial
+ filaneme, but the lexer will update it upon #line
+ directives.
+ """
+ def __init__(self, error_func, type_lookup_func):
+ """ Create a new Lexer.
+
+ error_func:
+ An error function. Will be called with an error
+ message, line and column as arguments, in case of
+ an error during lexing.
+
+ type_lookup_func:
+ A type lookup function. Given a string, it must
+ return True IFF this string is a name of a type
+ that was defined with a typedef earlier.
+ """
+ self.error_func = error_func
+ self.type_lookup_func = type_lookup_func
+ self.filename = ''
+
+ # Allow either "# line" or "# <num>" to support GCC's
+ # cpp output
+ #
+ self.line_pattern = re.compile('([ \t]*line\W)|([ \t]*\d+)')
+
+ def build(self, **kwargs):
+ """ Builds the lexer from the specification. Must be
+ called after the lexer object is created.
+
+ This method exists separately, because the PLY
+ manual warns against calling lex.lex inside
+ __init__
+ """
+ self.lexer = ply.lex.lex(object=self, **kwargs)
+
+ def reset_lineno(self):
+ """ Resets the internal line number counter of the lexer.
+ """
+ self.lexer.lineno = 1
+
+ def input(self, text):
+ self.lexer.input(text)
+
+ def token(self):
+ g = self.lexer.token()
+ return g
+
+ ######################-- PRIVATE --######################
+
+ ##
+ ## Internal auxiliary methods
+ ##
+ def _error(self, msg, token):
+ location = self._make_tok_location(token)
+ self.error_func(msg, location[0], location[1])
+ self.lexer.skip(1)
+
+ def _find_tok_column(self, token):
+ i = token.lexpos
+ while i > 0:
+ if self.lexer.lexdata[i] == '\n': break
+ i -= 1
+ return (token.lexpos - i) + 1
+
+ def _make_tok_location(self, token):
+ return (token.lineno, self._find_tok_column(token))
+
+ ##
+ ## Reserved keywords
+ ##
+ keywords = (
+ 'AUTO', 'BREAK', 'CASE', 'CHAR', 'CONST', 'CONTINUE',
+ 'DEFAULT', 'DO', 'DOUBLE', 'ELSE', 'ENUM', 'EXTERN',
+ 'FLOAT', 'FOR', 'GOTO', 'IF', 'INT', 'LONG', 'REGISTER',
+ 'RETURN', 'SHORT', 'SIGNED', 'SIZEOF', 'STATIC', 'STRUCT',
+ 'SWITCH', 'TYPEDEF', 'UNION', 'UNSIGNED', 'VOID',
+ 'VOLATILE', 'WHILE',
+ )
+
+ keyword_map = {}
+ for r in keywords:
+ keyword_map[r.lower()] = r
+
+ ##
+ ## All the tokens recognized by the lexer
+ ##
+ tokens = keywords + (
+ # Identifiers
+ 'ID',
+
+ # Type identifiers (identifiers previously defined as
+ # types with typedef)
+ 'TYPEID',
+
+ # constants
+ 'INT_CONST_DEC', 'INT_CONST_OCT', 'INT_CONST_HEX',
+ 'FLOAT_CONST',
+ 'CHAR_CONST',
+ 'WCHAR_CONST',
+
+ # String literals
+ 'STRING_LITERAL',
+ 'WSTRING_LITERAL',
+
+ # Operators
+ 'PLUS', 'MINUS', 'TIMES', 'DIVIDE', 'MOD',
+ 'OR', 'AND', 'NOT', 'XOR', 'LSHIFT', 'RSHIFT',
+ 'LOR', 'LAND', 'LNOT',
+ 'LT', 'LE', 'GT', 'GE', 'EQ', 'NE',
+
+ # Assignment
+ 'EQUALS', 'TIMESEQUAL', 'DIVEQUAL', 'MODEQUAL',
+ 'PLUSEQUAL', 'MINUSEQUAL',
+ 'LSHIFTEQUAL','RSHIFTEQUAL', 'ANDEQUAL', 'XOREQUAL',
+ 'OREQUAL',
+
+ # Increment/decrement
+ 'PLUSPLUS', 'MINUSMINUS',
+
+ # Structure dereference (->)
+ 'ARROW',
+
+ # Conditional operator (?)
+ 'CONDOP',
+
+ # Delimeters
+ 'LPAREN', 'RPAREN', # ( )
+ 'LBRACKET', 'RBRACKET', # [ ]
+ 'LBRACE', 'RBRACE', # { }
+ 'COMMA', 'PERIOD', # . ,
+ 'SEMI', 'COLON', # ; :
+
+ # Ellipsis (...)
+ 'ELLIPSIS',
+
+ # pre-processor
+ 'PPHASH', # '#'
+ )
+
+ ##
+ ## Regexes for use in tokens
+ ##
+ ##
+
+ # valid C identifiers (K&R2: A.2.3)
+ identifier = r'[a-zA-Z_][0-9a-zA-Z_]*'
+
+ # integer constants (K&R2: A.2.5.1)
+ integer_suffix_opt = r'(([uU][lL])|([lL][uU])|[uU]|[lL])?'
+ decimal_constant = '(0'+integer_suffix_opt+')|([1-9][0-9]*'+integer_suffix_opt+')'
+ octal_constant = '0[0-7]*'+integer_suffix_opt
+ hex_constant = '0[xX][0-9a-fA-F]+'+integer_suffix_opt
+
+ bad_octal_constant = '0[0-7]*[89]'
+
+ # character constants (K&R2: A.2.5.2)
+ # Note: a-zA-Z are allowed as escape chars to support #line
+ # directives with Windows paths as filenames (\dir\file...)
+ #
+ simple_escape = r"""([a-zA-Z\\?'"])"""
+ octal_escape = r"""([0-7]{1,3})"""
+ hex_escape = r"""(x[0-9a-fA-F]+)"""
+ bad_escape = r"""([\\][^a-zA-Z\\?'"x0-7])"""
+
+ escape_sequence = r"""(\\("""+simple_escape+'|'+octal_escape+'|'+hex_escape+'))'
+ cconst_char = r"""([^'\\\n]|"""+escape_sequence+')'
+ char_const = "'"+cconst_char+"'"
+ wchar_const = 'L'+char_const
+ unmatched_quote = "('"+cconst_char+"*\\n)|('"+cconst_char+"*$)"
+ bad_char_const = r"""('"""+cconst_char+"""[^'\n]+')|('')|('"""+bad_escape+r"""[^'\n]*')"""
+
+ # string literals (K&R2: A.2.6)
+ string_char = r"""([^"\\\n]|"""+escape_sequence+')'
+ string_literal = '"'+string_char+'*"'
+ wstring_literal = 'L'+string_literal
+ bad_string_literal = '"'+string_char+'*'+bad_escape+string_char+'*"'
+
+ # floating constants (K&R2: A.2.5.3)
+ exponent_part = r"""([eE][-+]?[0-9]+)"""
+ fractional_constant = r"""([0-9]*\.[0-9]+)|([0-9]+\.)"""
+ floating_constant = '(((('+fractional_constant+')'+exponent_part+'?)|([0-9]+'+exponent_part+'))[FfLl]?)'
+
+ ##
+ ## Lexer states
+ ##
+ states = (
+ # ppline: preprocessor line directives
+ #
+ ('ppline', 'exclusive'),
+ )
+
+ def t_PPHASH(self, t):
+ r'[ \t]*\#'
+ m = self.line_pattern.match(
+ t.lexer.lexdata, pos=t.lexer.lexpos)
+
+ if m:
+ t.lexer.begin('ppline')
+ self.pp_line = self.pp_filename = None
+ #~ print "ppline starts on line %s" % t.lexer.lineno
+ else:
+ t.type = 'PPHASH'
+ return t
+
+ ##
+ ## Rules for the ppline state
+ ##
+ @TOKEN(string_literal)
+ def t_ppline_FILENAME(self, t):
+ if self.pp_line is None:
+ self._error('filename before line number in #line', t)
+ else:
+ self.pp_filename = t.value.lstrip('"').rstrip('"')
+ #~ print "PP got filename: ", self.pp_filename
+
+ @TOKEN(decimal_constant)
+ def t_ppline_LINE_NUMBER(self, t):
+ if self.pp_line is None:
+ self.pp_line = t.value
+ else:
+ # Ignore: GCC's cpp sometimes inserts a numeric flag
+ # after the file name
+ pass
+
+ def t_ppline_NEWLINE(self, t):
+ r'\n'
+
+ if self.pp_line is None:
+ self._error('line number missing in #line', t)
+ else:
+ self.lexer.lineno = int(self.pp_line)
+
+ if self.pp_filename is not None:
+ self.filename = self.pp_filename
+
+ t.lexer.begin('INITIAL')
+
+ def t_ppline_PPLINE(self, t):
+ r'line'
+ pass
+
+ t_ppline_ignore = ' \t'
+
+ def t_ppline_error(self, t):
+ msg = 'invalid #line directive'
+ self._error(msg, t)
+
+ ##
+ ## Rules for the normal state
+ ##
+ t_ignore = ' \t'
+
+ # Newlines
+ def t_NEWLINE(self, t):
+ r'\n+'
+ t.lexer.lineno += t.value.count("\n")
+
+ # Operators
+ t_PLUS = r'\+'
+ t_MINUS = r'-'
+ t_TIMES = r'\*'
+ t_DIVIDE = r'/'
+ t_MOD = r'%'
+ t_OR = r'\|'
+ t_AND = r'&'
+ t_NOT = r'~'
+ t_XOR = r'\^'
+ t_LSHIFT = r'<<'
+ t_RSHIFT = r'>>'
+ t_LOR = r'\|\|'
+ t_LAND = r'&&'
+ t_LNOT = r'!'
+ t_LT = r'<'
+ t_GT = r'>'
+ t_LE = r'<='
+ t_GE = r'>='
+ t_EQ = r'=='
+ t_NE = r'!='
+
+ # Assignment operators
+ t_EQUALS = r'='
+ t_TIMESEQUAL = r'\*='
+ t_DIVEQUAL = r'/='
+ t_MODEQUAL = r'%='
+ t_PLUSEQUAL = r'\+='
+ t_MINUSEQUAL = r'-='
+ t_LSHIFTEQUAL = r'<<='
+ t_RSHIFTEQUAL = r'>>='
+ t_ANDEQUAL = r'&='
+ t_OREQUAL = r'\|='
+ t_XOREQUAL = r'\^='
+
+ # Increment/decrement
+ t_PLUSPLUS = r'\+\+'
+ t_MINUSMINUS = r'--'
+
+ # ->
+ t_ARROW = r'->'
+
+ # ?
+ t_CONDOP = r'\?'
+
+ # Delimeters
+ t_LPAREN = r'\('
+ t_RPAREN = r'\)'
+ t_LBRACKET = r'\['
+ t_RBRACKET = r'\]'
+ t_LBRACE = r'\{'
+ t_RBRACE = r'\}'
+ t_COMMA = r','
+ t_PERIOD = r'\.'
+ t_SEMI = r';'
+ t_COLON = r':'
+ t_ELLIPSIS = r'\.\.\.'
+
+ t_STRING_LITERAL = string_literal
+
+ # The following floating and integer constants are defined as
+ # functions to impose a strict order (otherwise, decimal
+ # is placed before the others because its regex is longer,
+ # and this is bad)
+ #
+ @TOKEN(floating_constant)
+ def t_FLOAT_CONST(self, t):
+ return t
+
+ @TOKEN(hex_constant)
+ def t_INT_CONST_HEX(self, t):
+ return t
+
+ @TOKEN(bad_octal_constant)
+ def t_BAD_CONST_OCT(self, t):
+ msg = "Invalid octal constant"
+ self._error(msg, t)
+
+ @TOKEN(octal_constant)
+ def t_INT_CONST_OCT(self, t):
+ return t
+
+ @TOKEN(decimal_constant)
+ def t_INT_CONST_DEC(self, t):
+ return t
+
+ # Must come before bad_char_const, to prevent it from
+ # catching valid char constants as invalid
+ #
+ @TOKEN(char_const)
+ def t_CHAR_CONST(self, t):
+ return t
+
+ @TOKEN(wchar_const)
+ def t_WCHAR_CONST(self, t):
+ return t
+
+ @TOKEN(unmatched_quote)
+ def t_UNMATCHED_QUOTE(self, t):
+ msg = "Unmatched '"
+ self._error(msg, t)
+
+ @TOKEN(bad_char_const)
+ def t_BAD_CHAR_CONST(self, t):
+ msg = "Invalid char constant %s" % t.value
+ self._error(msg, t)
+
+ @TOKEN(wstring_literal)
+ def t_WSTRING_LITERAL(self, t):
+ return t
+
+ # unmatched string literals are caught by the preprocessor
+
+ @TOKEN(bad_string_literal)
+ def t_BAD_STRING_LITERAL(self, t):
+ msg = "String contains invalid escape code"
+ self._error(msg, t)
+
+ @TOKEN(identifier)
+ def t_ID(self, t):
+ t.type = self.keyword_map.get(t.value, "ID")
+
+ if t.type == 'ID' and self.type_lookup_func(t.value):
+ t.type = "TYPEID"
+
+ return t
+
+ def t_error(self, t):
+ msg = 'Illegal character %s' % repr(t.value[0])
+ self._error(msg, t)
+
+
+if __name__ == "__main__":
+ from portability import printme
+ filename = '../zp.c'
+ text = open(filename).read()
+
+ #~ text = '"'+r"""ka \p ka"""+'"'
+ text = r"""
+ 546
+ #line 66 "kwas\df.h"
+ id 4
+ # 5
+ dsf
+ """
+
+ def errfoo(msg, a, b):
+ printme(msg)
+ sys.exit()
+
+ def typelookup(namd):
+ return False
+
+ clex = CLexer(errfoo, typelookup)
+ clex.build()
+ clex.input(text)
+
+ while 1:
+ tok = clex.token()
+ if not tok: break
+
+ #~ print type(tok)
+ printme([tok.value, tok.type, tok.lineno, clex.filename, tok.lexpos])
+
+
+
diff --git a/pycparser/c_parser.py b/pycparser/c_parser.py
new file mode 100644
index 0000000..8e75519
--- /dev/null
+++ b/pycparser/c_parser.py
@@ -0,0 +1,1258 @@
+#-----------------------------------------------------------------
+# 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',
+ 'constant_expression',
+ 'declaration_list',
+ 'declaration_specifiers',
+ 'expression',
+ 'identifier_list',
+ 'init_declarator_list',
+ 'parameter_type_list',
+ 'specifier_qualifier_list',
+ 'statement_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 3 entries:
+ * qual: a list of type qualifiers
+ * storage: a list of storage type qualifiers
+ * type: a list of type 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=[])
+ 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'],
+ 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'],
+ 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'],
+ 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_storage_class_specifier(self, p):
+ """ storage_class_specifier : AUTO
+ | REGISTER
+ | STATIC
+ | EXTERN
+ | TYPEDEF
+ """
+ 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
+ | 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, intializer) 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]:
+ decl = c_ast.Decl(
+ name=None,
+ quals=spec['qual'],
+ storage=spec['storage'],
+ type=struct_decl['decl'],
+ init=None,
+ bitsize=struct_decl['bitsize'],
+ coord=struct_decl['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': 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 constant_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_declarator_4(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'],
+ 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 : initializer
+ | initializer_list COMMA initializer
+ """
+ if len(p) == 2: # single initializer
+ p[0] = c_ast.ExprList([p[1]], p[1].coord)
+ else:
+ p[1].exprs.append(p[3])
+ p[0] = p[1]
+
+ 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 constant_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 constant_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 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_5(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)))
+
+ def p_compound_statement_1(self, p):
+ """ compound_statement : LBRACE statement_list_opt RBRACE """
+ p[0] = c_ast.Compound(
+ decls=None,
+ stmts=p[2],
+ coord=self._coord(p.lineno(1)))
+
+ def p_compound_statement_2(self, p):
+ """ compound_statement : LBRACE declaration_list RBRACE """
+ p[0] = c_ast.Compound(
+ decls=p[2],
+ stmts=None,
+ coord=self._coord(p.lineno(1)))
+
+ def p_compound_statement_3(self, p):
+ """ compound_statement : LBRACE declaration_list statement_list RBRACE """
+ #~ print '(((((('
+ #~ print p[2]
+ #~ print p[3]
+ #~ print '(((((('
+ p[0] = c_ast.Compound(
+ decls=p[2],
+ stmts=p[3],
+ coord=self._coord(p.lineno(1)))
+
+ # Note: this doesn't create an AST node, but a list of AST
+ # nodes that will be used as the statement list of a compound
+ #
+ def p_statement_list(self, p):
+ """ statement_list : statement
+ | statement_list statement
+ """
+ if len(p) == 2: # single expr
+ p[0] = [p[1]] if p[1] else []
+ else:
+ p[0] = p[1] + ([p[2]] if p[2] else [])
+
+ 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 """
+ 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_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_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 : STRING_LITERAL
+ | WSTRING_LITERAL
+ """
+ p[0] = c_ast.Constant(
+ 'string', p[1], self._coord(p.lineno(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)))
+
+ 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/pycparser/plyparser.py b/pycparser/plyparser.py
new file mode 100644
index 0000000..107b317
--- /dev/null
+++ b/pycparser/plyparser.py
@@ -0,0 +1,55 @@
+#-----------------------------------------------------------------
+# plyparser.py
+#
+# PLYParser class and other utilites for simplifying programming
+# parsers with PLY
+#
+# Copyright (C) 2008-2009, Eli Bendersky
+# License: LGPL
+#-----------------------------------------------------------------
+
+
+class Coord(object):
+ """ Coordinates of a syntactic element. Consists of:
+ - File name
+ - Line number
+ - (optional) column number, for the Lexer
+ """
+ def __init__(self, file, line, column=None):
+ self.file = file
+ self.line = line
+ self.column = column
+
+ def __str__(self):
+ str = "%s:%s" % (self.file, self.line)
+ if self.column: str += ":%s" % self.column
+ return str
+
+
+class ParseError(Exception): pass
+
+
+class PLYParser(object):
+ def _create_opt_rule(self, rulename):
+ """ Given a rule name, creates an optional ply.yacc rule
+ for it. The name of the optional rule is
+ <rulename>_opt
+ """
+ optname = rulename + '_opt'
+
+ def optrule(self, p):
+ p[0] = p[1]
+
+ optrule.__doc__ = '%s : empty\n| %s' % (optname, rulename)
+ optrule.__name__ = 'p_%s' % optname
+ setattr(self.__class__, optrule.__name__, optrule)
+
+ def _coord(self, lineno, column=None):
+ return Coord(
+ file=self.clex.filename,
+ line=lineno,
+ column=column)
+
+ def _parse_error(self, msg, coord):
+ raise ParseError("%s: %s" % (coord, msg))
+
diff --git a/pycparser/portability.py b/pycparser/portability.py
new file mode 100644
index 0000000..3893cec
--- /dev/null
+++ b/pycparser/portability.py
@@ -0,0 +1,18 @@
+#-----------------------------------------------------------------
+# pycparser: portability.py
+#
+# Portability code for working with different versions of Python
+#
+# Copyright (C) 2008-2010, Eli Bendersky
+# License: LGPL
+#----------------------
+import sys
+
+
+def printme(s):
+ sys.stdout.write(str(s))
+
+
+
+
+ \ No newline at end of file
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..442c7d0
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,26 @@
+import os, sys
+from distutils.core import setup
+
+
+setup(
+ # metadata
+ name='pycparser',
+ description='C parser in Python',
+ long_description="""
+ pycparser is a complete parser of the C language, written in
+ pure Python using the PLY parsing library.
+ It parses C code into an AST and can serve as a front-end for
+ C compilers or analysis tools.
+ """,
+ license='LGPL',
+ version='1.07',
+ author='Eli Bendersky',
+ maintainer='Eli Bendersky',
+ author_email='eliben@gmail.com',
+ url='http://code.google.com/p/pycparser/',
+ platforms='Cross Platform',
+
+ packages=['pycparser'],
+)
+
+
diff --git a/tests/all_tests.py b/tests/all_tests.py
new file mode 100644
index 0000000..0ed455c
--- /dev/null
+++ b/tests/all_tests.py
@@ -0,0 +1,15 @@
+#!/usr/bin/env python
+
+import unittest
+
+
+suite = unittest.TestLoader().loadTestsFromNames(
+ [
+ 'test_c_lexer',
+ 'test_c_ast',
+ 'test_general',
+ 'test_c_parser',
+ ]
+)
+
+unittest.TextTestRunner(verbosity=1).run(suite)
diff --git a/tests/c_files/cppd_with_stdio_h.c b/tests/c_files/cppd_with_stdio_h.c
new file mode 100644
index 0000000..ab1426a
--- /dev/null
+++ b/tests/c_files/cppd_with_stdio_h.c
@@ -0,0 +1,5038 @@
+#line 1 "example_c_file.c"
+
+
+#line 1 "D:\eli\cpp_stuff\libc_include/stdio.h"
+
+#line 19 "D:\eli\cpp_stuff\libc_include/stdio.h"
+
+
+#line 25 "D:\eli\cpp_stuff\libc_include/stdio.h"
+
+
+
+
+#line 1 "D:\eli\cpp_stuff\libc_include/_ansi.h"
+
+
+
+#line 11 "D:\eli\cpp_stuff\libc_include/_ansi.h"
+
+
+
+
+#line 1 "D:\eli\cpp_stuff\libc_include/newlib.h"
+
+#line 3 "D:\eli\cpp_stuff\libc_include/newlib.h"
+#line 16 "D:\eli\cpp_stuff\libc_include/_ansi.h"
+#line 1 "D:\eli\cpp_stuff\libc_include/sys/config.h"
+
+
+
+#line 1 "D:\eli\cpp_stuff\libc_include/machine/ieeefp.h"
+
+
+
+
+#line 52 "D:\eli\cpp_stuff\libc_include/machine/ieeefp.h"
+
+
+
+#line 58 "D:\eli\cpp_stuff\libc_include/machine/ieeefp.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 83 "D:\eli\cpp_stuff\libc_include/machine/ieeefp.h"
+
+#line 86 "D:\eli\cpp_stuff\libc_include/machine/ieeefp.h"
+
+#line 89 "D:\eli\cpp_stuff\libc_include/machine/ieeefp.h"
+
+
+#line 95 "D:\eli\cpp_stuff\libc_include/machine/ieeefp.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 5 "D:\eli\cpp_stuff\libc_include/sys/config.h"
+
+
+
+
+
+#line 11 "D:\eli\cpp_stuff\libc_include/sys/config.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 143 "D:\eli\cpp_stuff\libc_include/sys/config.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 157 "D:\eli\cpp_stuff\libc_include/sys/config.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 195 "D:\eli\cpp_stuff\libc_include/sys/config.h"
+
+
+
+
+
+
+
+
+
+
+
+#line 207 "D:\eli\cpp_stuff\libc_include/sys/config.h"
+
+
+
+
+
+
+
+#line 17 "D:\eli\cpp_stuff\libc_include/_ansi.h"
+
+
+
+#line 21 "D:\eli\cpp_stuff\libc_include/_ansi.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 30 "D:\eli\cpp_stuff\libc_include/stdio.h"
+
+
+
+
+#line 1 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+#line 19 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+#line 26 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+#line 30 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+#line 35 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+#line 39 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+#line 42 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+
+
+
+
+
+#line 53 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+#line 56 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+
+
+
+
+#line 67 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+
+
+
+#line 76 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 98 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+#line 108 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 126 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+#line 131 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 170 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+typedef long unsigned int size_t;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 243 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+#line 246 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 290 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+
+
+
+
+#line 302 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+
+#line 310 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 361 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+#line 365 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 418 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+#line 422 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+#line 427 "D:\eli\cpp_stuff\libc_include/stddef.h"
+#line 35 "D:\eli\cpp_stuff\libc_include/stdio.h"
+
+
+#line 1 "D:\eli\cpp_stuff\libc_include/stdarg.h"
+
+#line 19 "D:\eli\cpp_stuff\libc_include/stdarg.h"
+
+
+#line 26 "D:\eli\cpp_stuff\libc_include/stdarg.h"
+
+
+#line 30 "D:\eli\cpp_stuff\libc_include/stdarg.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+typedef char* __builtin_va_list;
+typedef __builtin_va_list __gnuc_va_list;
+
+
+
+#line 50 "D:\eli\cpp_stuff\libc_include/stdarg.h"
+
+
+
+
+
+
+
+
+
+
+
+
+#line 66 "D:\eli\cpp_stuff\libc_include/stdarg.h"
+
+
+
+
+
+
+
+
+
+
+
+#line 80 "D:\eli\cpp_stuff\libc_include/stdarg.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 98 "D:\eli\cpp_stuff\libc_include/stdarg.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 38 "D:\eli\cpp_stuff\libc_include/stdio.h"
+
+
+#line 44 "D:\eli\cpp_stuff\libc_include/stdio.h"
+
+#line 1 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+
+#line 6 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+
+
+
+
+
+#line 1 "D:\eli\cpp_stuff\libc_include/_ansi.h"
+
+
+
+#line 11 "D:\eli\cpp_stuff\libc_include/_ansi.h"
+
+
+
+
+
+
+
+
+
+#line 21 "D:\eli\cpp_stuff\libc_include/_ansi.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 14 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+#line 1 "D:\eli\cpp_stuff\libc_include/sys/_types.h"
+
+
+
+#line 8 "D:\eli\cpp_stuff\libc_include/sys/_types.h"
+
+
+
+
+#line 1 "D:\eli\cpp_stuff\libc_include/machine/_types.h"
+
+#line 4 "D:\eli\cpp_stuff\libc_include/machine/_types.h"
+
+
+
+#line 1 "D:\eli\cpp_stuff\libc_include/machine/_default_types.h"
+
+#line 4 "D:\eli\cpp_stuff\libc_include/machine/_default_types.h"
+
+
+
+
+
+
+
+
+
+#line 15 "D:\eli\cpp_stuff\libc_include/machine/_default_types.h"
+
+#line 17 "D:\eli\cpp_stuff\libc_include/machine/_default_types.h"
+
+
+
+
+
+#line 1 "D:\eli\cpp_stuff\libc_include/limits.h"
+
+
+
+#line 1 "D:\eli\cpp_stuff\libc_include/newlib.h"
+
+#line 3 "D:\eli\cpp_stuff\libc_include/newlib.h"
+#line 5 "D:\eli\cpp_stuff\libc_include/limits.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 19 "D:\eli\cpp_stuff\libc_include/limits.h"
+
+
+
+
+
+#line 1 "D:\eli\cpp_stuff\libc_include/sys/config.h"
+
+
+
+
+
+
+
+
+
+#line 11 "D:\eli\cpp_stuff\libc_include/sys/config.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 143 "D:\eli\cpp_stuff\libc_include/sys/config.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 157 "D:\eli\cpp_stuff\libc_include/sys/config.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 195 "D:\eli\cpp_stuff\libc_include/sys/config.h"
+
+
+
+
+
+
+
+
+
+
+
+#line 207 "D:\eli\cpp_stuff\libc_include/sys/config.h"
+
+
+
+
+
+
+
+#line 25 "D:\eli\cpp_stuff\libc_include/limits.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 79 "D:\eli\cpp_stuff\libc_include/limits.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 23 "D:\eli\cpp_stuff\libc_include/machine/_default_types.h"
+
+
+
+typedef signed char __int8_t ;
+typedef unsigned char __uint8_t ;
+
+
+
+
+
+
+
+
+typedef signed short __int16_t;
+typedef unsigned short __uint16_t;
+
+
+
+
+
+
+
+
+typedef __int16_t __int_least16_t;
+typedef __uint16_t __uint_least16_t;
+
+
+
+
+
+
+
+
+
+
+typedef signed int __int32_t;
+typedef unsigned int __uint32_t;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+typedef __int32_t __int_least32_t;
+typedef __uint32_t __uint_least32_t;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 8 "D:\eli\cpp_stuff\libc_include/machine/_types.h"
+
+#line 13 "D:\eli\cpp_stuff\libc_include/sys/_types.h"
+#line 1 "D:\eli\cpp_stuff\libc_include/sys/lock.h"
+
+
+
+
+
+typedef int _LOCK_T;
+typedef int _LOCK_RECURSIVE_T;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 14 "D:\eli\cpp_stuff\libc_include/sys/_types.h"
+
+
+typedef long _off_t;
+
+
+
+
+
+
+
+typedef short __dev_t;
+
+
+
+
+typedef unsigned short __uid_t;
+
+
+typedef unsigned short __gid_t;
+
+
+
+ typedef long long _off64_t;
+
+
+
+#line 43 "D:\eli\cpp_stuff\libc_include/sys/_types.h"
+
+typedef long _fpos_t;
+
+
+
+
+
+
+
+
+
+
+
+typedef int _ssize_t;
+
+
+
+
+
+
+#line 1 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+#line 19 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+#line 26 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+#line 30 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+#line 35 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+#line 39 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+#line 42 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+
+
+
+
+
+#line 53 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+#line 56 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+
+
+
+
+#line 67 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+
+
+
+#line 76 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 98 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+#line 108 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 126 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+#line 131 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 170 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 243 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+#line 246 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 290 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+
+
+
+
+#line 302 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+
+#line 310 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+typedef unsigned int wint_t;
+
+
+
+
+
+#line 361 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+#line 365 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 418 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+#line 422 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+#line 427 "D:\eli\cpp_stuff\libc_include/stddef.h"
+#line 64 "D:\eli\cpp_stuff\libc_include/sys/_types.h"
+
+
+
+typedef struct
+{
+ int __count;
+ union
+ {
+ wint_t __wch;
+ unsigned char __wchb[4];
+ } __value;
+} _mbstate_t;
+
+
+
+typedef _LOCK_RECURSIVE_T _flock_t;
+
+
+
+
+typedef void *_iconv_t;
+
+
+
+#line 15 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+
+
+
+
+typedef unsigned long __ULong;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+struct _reent;
+
+
+#line 43 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+struct _Bigint
+{
+ struct _Bigint *_next;
+ int _k, _maxwds, _sign, _wds;
+ __ULong _x[1];
+};
+
+
+struct __tm
+{
+ int __tm_sec;
+ int __tm_min;
+ int __tm_hour;
+ int __tm_mday;
+ int __tm_mon;
+ int __tm_year;
+ int __tm_wday;
+ int __tm_yday;
+ int __tm_isdst;
+};
+
+
+#line 68 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+
+struct _on_exit_args {
+ void * _fnargs[32];
+ void * _dso_handle[32];
+
+ __ULong _fntypes;
+#line 77 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+ __ULong _is_cxa;
+};
+
+
+
+
+
+
+
+
+
+struct _atexit {
+ struct _atexit *_next;
+ int _ind;
+
+ void (*_fns[32])(void);
+ struct _on_exit_args _on_exit_args;
+};
+
+
+
+#line 104 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+struct __sbuf {
+ unsigned char *_base;
+ int _size;
+};
+
+
+#line 134 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+
+#line 141 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+struct __sFILE {
+ unsigned char *_p;
+ int _r;
+ int _w;
+ short _flags;
+ short _file;
+ struct __sbuf _bf;
+ int _lbfsize;
+
+
+
+
+
+
+ char * _cookie;
+
+ int(*_read)();
+#line 176 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+ int(*_write)();
+#line 178 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+ _fpos_t(*_seek)();
+ int(*_close)();
+
+
+ struct __sbuf _ub;
+ unsigned char *_up;
+ int _ur;
+
+
+ unsigned char _ubuf[3];
+ unsigned char _nbuf[1];
+
+
+ struct __sbuf _lb;
+
+
+ int _blksize;
+ int _offset;
+
+
+ struct _reent *_data;
+
+
+
+ _flock_t _lock;
+
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+typedef struct __sFILE __FILE;
+
+
+
+struct _glue
+{
+ struct _glue *_next;
+ int _niobs;
+ __FILE *_iobs;
+};
+
+
+#line 284 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+
+
+
+
+
+struct _rand48 {
+ unsigned short _seed[3];
+ unsigned short _mult[3];
+ unsigned short _add;
+
+
+
+
+};
+
+
+
+
+
+
+
+#line 313 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 344 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+
+
+#line 350 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 420 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+#line 452 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 474 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+#line 478 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+#line 482 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+
+#line 494 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+#line 496 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+#line 503 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+#line 505 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+#line 508 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+#line 531 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+#line 533 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+#line 536 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+struct _reent
+{
+ int _errno;
+
+
+#line 571 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+ __FILE *_stdin, *_stdout, *_stderr;
+
+ int _inc;
+ char _emergency[25];
+
+ int _current_category;
+ char *_current_locale;
+
+ int __sdidinit;
+
+ void(*__cleanup)();
+
+
+ struct _Bigint *_result;
+ int _result_k;
+ struct _Bigint *_p5s;
+ struct _Bigint **_freelist;
+
+
+ int _cvtlen;
+ char *_cvtbuf;
+
+ union
+ {
+ struct
+ {
+ unsigned int _unused_rand;
+ char * _strtok_last;
+ char _asctime_buf[26];
+ struct __tm _localtime_buf;
+ int _gamma_signgam;
+ unsigned long long _rand_next;
+ struct _rand48 _r48;
+ _mbstate_t _mblen_state;
+ _mbstate_t _mbtowc_state;
+ _mbstate_t _wctomb_state;
+ char _l64a_buf[8];
+ char _signal_buf[24];
+ int _getdate_err;
+ _mbstate_t _mbrlen_state;
+ _mbstate_t _mbrtowc_state;
+ _mbstate_t _mbsrtowcs_state;
+ _mbstate_t _wcrtomb_state;
+ _mbstate_t _wcsrtombs_state;
+ } _reent;
+
+#line 619 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+ struct
+ {
+
+ unsigned char * _nextf[30];
+ unsigned int _nmalloc[30];
+ } _unused;
+ } _new;
+
+
+ struct _atexit *_atexit;
+ struct _atexit _atexit0;
+
+
+ void (**(_sig_func))(int);
+
+
+#line 637 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+ struct _glue __sglue;
+ __FILE __sf[3];
+};
+
+
+#line 689 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+#line 751 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 791 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+
+
+
+extern struct _reent *_impure_ptr;
+extern struct _reent * _global_impure_ptr;
+
+void _reclaim_reent();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 46 "D:\eli\cpp_stuff\libc_include/stdio.h"
+#line 1 "D:\eli\cpp_stuff\libc_include/sys/types.h"
+
+#line 17 "D:\eli\cpp_stuff\libc_include/sys/types.h"
+
+
+
+#line 1 "D:\eli\cpp_stuff\libc_include/_ansi.h"
+
+
+
+#line 11 "D:\eli\cpp_stuff\libc_include/_ansi.h"
+
+
+
+
+
+
+
+
+
+#line 21 "D:\eli\cpp_stuff\libc_include/_ansi.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 21 "D:\eli\cpp_stuff\libc_include/sys/types.h"
+
+
+
+
+#line 1 "D:\eli\cpp_stuff\libc_include/machine/_types.h"
+
+#line 4 "D:\eli\cpp_stuff\libc_include/machine/_types.h"
+
+
+
+
+
+#line 26 "D:\eli\cpp_stuff\libc_include/sys/types.h"
+
+
+
+#line 33 "D:\eli\cpp_stuff\libc_include/sys/types.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 1 "D:\eli\cpp_stuff\libc_include/sys/_types.h"
+
+
+
+#line 8 "D:\eli\cpp_stuff\libc_include/sys/_types.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 43 "D:\eli\cpp_stuff\libc_include/sys/_types.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 62 "D:\eli\cpp_stuff\libc_include/sys/types.h"
+
+
+
+
+
+
+
+#line 1 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+#line 19 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+#line 26 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+#line 30 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+#line 35 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+#line 39 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+#line 42 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+
+
+
+
+
+#line 53 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+#line 56 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+
+
+
+
+#line 67 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+
+
+
+#line 76 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 98 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+#line 108 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 126 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+#line 131 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+typedef long int ptrdiff_t;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 170 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 243 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+#line 246 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 290 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+
+
+
+
+#line 302 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+
+#line 310 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+typedef int wchar_t;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 361 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+#line 365 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 418 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+#line 422 "D:\eli\cpp_stuff\libc_include/stddef.h"
+
+
+
+
+#line 427 "D:\eli\cpp_stuff\libc_include/stddef.h"
+#line 70 "D:\eli\cpp_stuff\libc_include/sys/types.h"
+#line 1 "D:\eli\cpp_stuff\libc_include/machine/types.h"
+
+
+
+
+#line 9 "D:\eli\cpp_stuff\libc_include/machine/types.h"
+
+
+
+
+
+
+
+
+
+
+typedef long int __off_t;
+typedef int __pid_t;
+
+
+
+typedef long int __loff_t;
+
+
+
+
+
+
+#line 71 "D:\eli\cpp_stuff\libc_include/sys/types.h"
+
+
+#line 79 "D:\eli\cpp_stuff\libc_include/sys/types.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+typedef unsigned char u_char;
+typedef unsigned short u_short;
+typedef unsigned int u_int;
+typedef unsigned long u_long;
+
+
+
+typedef unsigned short ushort;
+typedef unsigned int uint;
+
+
+
+typedef unsigned long clock_t;
+
+
+
+
+typedef long time_t;
+
+
+
+
+struct timespec {
+ time_t tv_sec;
+ long tv_nsec;
+};
+
+struct itimerspec {
+ struct timespec it_interval;
+ struct timespec it_value;
+};
+
+
+typedef long daddr_t;
+typedef char * caddr_t;
+
+
+
+#line 131 "D:\eli\cpp_stuff\libc_include/sys/types.h"
+
+
+typedef unsigned short ino_t;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 160 "D:\eli\cpp_stuff\libc_include/sys/types.h"
+
+
+typedef _off_t off_t;
+typedef __dev_t dev_t;
+typedef __uid_t uid_t;
+typedef __gid_t gid_t;
+
+
+typedef int pid_t;
+
+typedef long key_t;
+
+typedef _ssize_t ssize_t;
+
+
+
+
+
+
+
+
+
+
+
+
+
+typedef unsigned int mode_t;
+
+
+
+
+typedef unsigned short nlink_t;
+
+
+#line 200 "D:\eli\cpp_stuff\libc_include/sys/types.h"
+
+
+
+
+#line 209 "D:\eli\cpp_stuff\libc_include/sys/types.h"
+
+
+
+
+typedef long fd_mask;
+
+
+
+
+
+
+#line 221 "D:\eli\cpp_stuff\libc_include/sys/types.h"
+typedef struct _types_fd_set {
+ fd_mask fds_bits[(((64)+(((sizeof (fd_mask) * 8))-1))/((sizeof (fd_mask) * 8)))];
+} _types_fd_set;
+
+
+
+
+
+
+
+#line 236 "D:\eli\cpp_stuff\libc_include/sys/types.h"
+
+
+
+
+
+
+
+
+typedef unsigned long clockid_t;
+
+
+
+
+typedef unsigned long timer_t;
+
+
+
+typedef unsigned long useconds_t;
+typedef long suseconds_t;
+
+#line 1 "D:\eli\cpp_stuff\libc_include/sys/features.h"
+
+#line 20 "D:\eli\cpp_stuff\libc_include/sys/features.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 257 "D:\eli\cpp_stuff\libc_include/sys/types.h"
+
+
+
+#line 266 "D:\eli\cpp_stuff\libc_include/sys/types.h"
+
+
+
+
+
+#line 273 "D:\eli\cpp_stuff\libc_include/sys/types.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 47 "D:\eli\cpp_stuff\libc_include/stdio.h"
+
+
+
+typedef __FILE FILE;
+
+
+
+
+
+
+
+
+typedef _fpos_t fpos_t;
+
+
+
+
+
+#line 1 "D:\eli\cpp_stuff\libc_include/sys/stdio.h"
+
+
+
+#line 1 "D:\eli\cpp_stuff\libc_include/sys/lock.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 5 "D:\eli\cpp_stuff\libc_include/sys/stdio.h"
+#line 1 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+
+#line 6 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 43 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 68 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+
+
+
+
+
+
+#line 77 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 104 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+
+
+
+
+
+#line 134 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+
+#line 141 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 284 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 313 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 344 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+
+
+#line 350 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 420 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+#line 452 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 474 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+#line 478 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+#line 482 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+
+#line 494 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+#line 496 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+#line 503 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+#line 505 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+#line 508 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+#line 531 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+#line 533 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+#line 536 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 571 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 619 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 637 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+
+
+
+#line 689 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+#line 751 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 791 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 6 "D:\eli\cpp_stuff\libc_include/sys/stdio.h"
+
+
+#line 11 "D:\eli\cpp_stuff\libc_include/sys/stdio.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 66 "D:\eli\cpp_stuff\libc_include/stdio.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 96 "D:\eli\cpp_stuff\libc_include/stdio.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 163 "D:\eli\cpp_stuff\libc_include/stdio.h"
+
+
+
+
+
+
+
+FILE * tmpfile();
+char * tmpnam();
+int fclose();
+int fflush();
+FILE * freopen();
+void setbuf();
+int setvbuf();
+int fprintf();
+#line 179 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int fscanf();
+#line 181 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int printf();
+#line 183 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int scanf();
+#line 185 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int sscanf();
+#line 187 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int vfprintf();
+#line 189 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int vprintf();
+#line 191 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int vsprintf();
+#line 193 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int fgetc();
+char * fgets();
+int fputc();
+int fputs();
+int getc();
+int getchar();
+char * gets();
+int putc();
+int putchar();
+int puts();
+int ungetc();
+size_t fread();
+size_t fwrite();
+
+
+
+int fgetpos();
+
+int fseek();
+
+
+
+int fsetpos();
+
+long ftell();
+void rewind();
+void clearerr();
+int feof();
+int ferror();
+void perror();
+
+FILE * fopen();
+int sprintf();
+#line 227 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int remove();
+int rename();
+
+
+
+
+
+
+int fseeko();
+off_t ftello();
+
+
+int asiprintf();
+#line 241 "D:\eli\cpp_stuff\libc_include/stdio.h"
+char * asniprintf();
+#line 243 "D:\eli\cpp_stuff\libc_include/stdio.h"
+char * asnprintf();
+#line 245 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int asprintf();
+#line 247 "D:\eli\cpp_stuff\libc_include/stdio.h"
+
+int diprintf();
+#line 250 "D:\eli\cpp_stuff\libc_include/stdio.h"
+
+int fcloseall();
+int fiprintf();
+#line 254 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int fiscanf();
+#line 256 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int iprintf();
+#line 258 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int iscanf();
+#line 260 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int siprintf();
+#line 262 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int siscanf();
+#line 264 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int snprintf();
+#line 266 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int sniprintf();
+#line 268 "D:\eli\cpp_stuff\libc_include/stdio.h"
+char * tempnam();
+int vasiprintf();
+#line 271 "D:\eli\cpp_stuff\libc_include/stdio.h"
+char * vasniprintf();
+#line 273 "D:\eli\cpp_stuff\libc_include/stdio.h"
+char * vasnprintf();
+#line 275 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int vasprintf();
+#line 277 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int vdiprintf();
+#line 279 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int vfiprintf();
+#line 281 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int vfiscanf();
+#line 283 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int vfscanf();
+#line 285 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int viprintf();
+#line 287 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int viscanf();
+#line 289 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int vscanf();
+#line 291 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int vsiprintf();
+#line 293 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int vsiscanf();
+#line 295 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int vsniprintf();
+#line 297 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int vsnprintf();
+#line 299 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int vsscanf();
+#line 301 "D:\eli\cpp_stuff\libc_include/stdio.h"
+
+
+
+
+#line 307 "D:\eli\cpp_stuff\libc_include/stdio.h"
+
+
+
+FILE * fdopen();
+
+int fileno();
+int getw();
+int pclose();
+FILE * popen();
+int putw();
+void setbuffer();
+int setlinebuf();
+int getc_unlocked();
+int getchar_unlocked();
+void flockfile();
+int ftrylockfile();
+void funlockfile();
+int putc_unlocked();
+int putchar_unlocked();
+
+
+
+#line 331 "D:\eli\cpp_stuff\libc_include/stdio.h"
+
+
+
+
+int dprintf();
+#line 337 "D:\eli\cpp_stuff\libc_include/stdio.h"
+
+FILE * fmemopen();
+
+
+FILE * open_memstream();
+
+int vdprintf();
+#line 345 "D:\eli\cpp_stuff\libc_include/stdio.h"
+
+
+
+
+#line 351 "D:\eli\cpp_stuff\libc_include/stdio.h"
+
+int _asiprintf_r();
+#line 354 "D:\eli\cpp_stuff\libc_include/stdio.h"
+char * _asniprintf_r();
+#line 356 "D:\eli\cpp_stuff\libc_include/stdio.h"
+char * _asnprintf_r();
+#line 358 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int _asprintf_r();
+#line 360 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int _diprintf_r();
+#line 362 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int _dprintf_r();
+#line 364 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int _fclose_r();
+int _fcloseall_r();
+FILE * _fdopen_r();
+int _fflush_r();
+char * _fgets_r();
+int _fiprintf_r();
+#line 371 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int _fiscanf_r();
+#line 373 "D:\eli\cpp_stuff\libc_include/stdio.h"
+FILE * _fmemopen_r();
+FILE * _fopen_r();
+int _fprintf_r();
+#line 377 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int _fputc_r();
+int _fputs_r();
+size_t _fread_r();
+int _fscanf_r();
+#line 382 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int _fseek_r();
+long _ftell_r();
+size_t _fwrite_r();
+int _getc_r();
+int _getc_unlocked_r();
+int _getchar_r();
+int _getchar_unlocked_r();
+char * _gets_r();
+int _iprintf_r();
+#line 392 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int _iscanf_r();
+#line 394 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int _mkstemp_r();
+char * _mktemp_r();
+FILE * _open_memstream_r();
+void _perror_r();
+int _printf_r();
+#line 400 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int _putc_r();
+int _putc_unlocked_r();
+int _putchar_unlocked_r();
+int _putchar_r();
+int _puts_r();
+int _remove_r();
+int _rename_r();
+#line 408 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int _scanf_r();
+#line 410 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int _siprintf_r();
+#line 412 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int _siscanf_r();
+#line 414 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int _sniprintf_r();
+#line 416 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int _snprintf_r();
+#line 418 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int _sprintf_r();
+#line 420 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int _sscanf_r();
+#line 422 "D:\eli\cpp_stuff\libc_include/stdio.h"
+char * _tempnam_r();
+FILE * _tmpfile_r();
+char * _tmpnam_r();
+int _ungetc_r();
+int _vasiprintf_r();
+#line 428 "D:\eli\cpp_stuff\libc_include/stdio.h"
+char * _vasniprintf_r();
+#line 430 "D:\eli\cpp_stuff\libc_include/stdio.h"
+char * _vasnprintf_r();
+#line 432 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int _vasprintf_r();
+#line 434 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int _vdiprintf_r();
+#line 436 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int _vdprintf_r();
+#line 438 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int _vfiprintf_r();
+#line 440 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int _vfiscanf_r();
+#line 442 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int _vfprintf_r();
+#line 444 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int _vfscanf_r();
+#line 446 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int _viprintf_r();
+#line 448 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int _viscanf_r();
+#line 450 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int _vprintf_r();
+#line 452 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int _vscanf_r();
+#line 454 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int _vsiprintf_r();
+#line 456 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int _vsiscanf_r();
+#line 458 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int _vsniprintf_r();
+#line 460 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int _vsnprintf_r();
+#line 462 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int _vsprintf_r();
+#line 464 "D:\eli\cpp_stuff\libc_include/stdio.h"
+int _vsscanf_r();
+#line 466 "D:\eli\cpp_stuff\libc_include/stdio.h"
+
+ssize_t __getdelim();
+ssize_t __getline();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 493 "D:\eli\cpp_stuff\libc_include/stdio.h"
+
+int __srget_r();
+int __swbuf_r();
+
+
+#line 500 "D:\eli\cpp_stuff\libc_include/stdio.h"
+
+
+
+
+
+
+
+
+
+FILE * funopen();
+#line 514 "D:\eli\cpp_stuff\libc_include/stdio.h"
+
+
+
+#line 518 "D:\eli\cpp_stuff\libc_include/stdio.h"
+
+#line 520 "D:\eli\cpp_stuff\libc_include/stdio.h"
+
+typedef ssize_t cookie_read_function_t(void *__cookie, char *__buf, size_t __n);
+typedef ssize_t cookie_write_function_t(void *__cookie, const char *__buf,
+ size_t __n);
+
+
+
+
+typedef int cookie_seek_function_t(void *__cookie, off_t *__off, int __whence);
+
+typedef int cookie_close_function_t(void *__cookie);
+typedef struct
+{
+
+#line 535 "D:\eli\cpp_stuff\libc_include/stdio.h"
+ cookie_read_function_t *read;
+ cookie_write_function_t *write;
+ cookie_seek_function_t *seek;
+ cookie_close_function_t *close;
+} cookie_io_functions_t;
+FILE * fopencookie();
+#line 542 "D:\eli\cpp_stuff\libc_include/stdio.h"
+
+
+
+
+#line 549 "D:\eli\cpp_stuff\libc_include/stdio.h"
+
+
+
+
+#line 574 "D:\eli\cpp_stuff\libc_include/stdio.h"
+
+
+
+
+
+#line 580 "D:\eli\cpp_stuff\libc_include/stdio.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 603 "D:\eli\cpp_stuff\libc_include/stdio.h"
+
+
+
+
+
+
+
+
+#line 613 "D:\eli\cpp_stuff\libc_include/stdio.h"
+
+#line 621 "D:\eli\cpp_stuff\libc_include/stdio.h"
+
+
+#line 626 "D:\eli\cpp_stuff\libc_include/stdio.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 657 "D:\eli\cpp_stuff\libc_include/stdio.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#line 4 "example_c_file.c"
+
+#line 8 "example_c_file.c"
+
+char tav = 'b';
+char maav = L"'guruguru\n";
+char* moral = "ain't I \\\"\\\t\" a nice string?\"\"";
+char* comment_inside = "but you will /* see it */!!!!";
+char* i_have_newlines = "line one\nline two\nline three";
+
+int main()
+{
+ auto char* multi = "a multi";
+}
+
+
+
+
+
diff --git a/tests/c_files/example_c_file.c b/tests/c_files/example_c_file.c
new file mode 100644
index 0000000..17b2ac4
--- /dev/null
+++ b/tests/c_files/example_c_file.c
@@ -0,0 +1,12 @@
+char tav = 'b';
+char* moral = "ain't I \\\"\\\t\" a nice string?\"\"";
+char* comment_inside = "but you will /* see it */!!!!";
+char* i_have_newlines = "line one\nline two\nline three";
+
+int main()
+{
+ auto char* multi = "a multi";
+}
+
+
+
diff --git a/tests/c_files/memmgr.c b/tests/c_files/memmgr.c
new file mode 100644
index 0000000..6036ec6
--- /dev/null
+++ b/tests/c_files/memmgr.c
@@ -0,0 +1,206 @@
+//----------------------------------------------------------------
+// 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;
+}
diff --git a/tests/c_files/memmgr.h b/tests/c_files/memmgr.h
new file mode 100644
index 0000000..ae8212d
--- /dev/null
+++ b/tests/c_files/memmgr.h
@@ -0,0 +1,96 @@
+//----------------------------------------------------------------
+// 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
diff --git a/tests/c_files/memmgr_with_h.c b/tests/c_files/memmgr_with_h.c
new file mode 100644
index 0000000..8ea6ff6
--- /dev/null
+++ b/tests/c_files/memmgr_with_h.c
@@ -0,0 +1,350 @@
+#line 1 "memmgr.c"
+
+
+
+
+
+
+
+#line 1 "./memmgr.h"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+typedef unsigned char byte;
+typedef unsigned long ulong;
+
+
+
+
+
+
+void memmgr_init();
+
+
+
+void* memmgr_alloc(ulong nbytes);
+
+
+
+void memmgr_free(void* ap);
+
+
+
+
+void memmgr_print_stats();
+
+
+
+#line 9 "memmgr.c"
+
+typedef ulong Align;
+
+union mem_header_union
+{
+ struct
+ {
+
+
+ union mem_header_union* next;
+
+
+
+ ulong size;
+ } s;
+
+
+
+ Align align_dummy;
+};
+
+typedef union mem_header_union mem_header_t;
+
+
+
+static mem_header_t base;
+
+
+
+static mem_header_t* freep = 0;
+
+
+
+static byte pool[8 * 1024] = {0};
+static ulong pool_free_pos = 0;
+
+
+void memmgr_init()
+{
+ base.s.next = 0;
+ base.s.size = 0;
+ freep = 0;
+ pool_free_pos = 0;
+}
+
+
+void memmgr_print_stats()
+{
+
+ mem_header_t* p;
+
+ printf("------ Memory manager stats ------\n\n");
+ printf( "Pool: free_pos = %lu (%lu bytes left)\n\n",
+ pool_free_pos,8 * 1024 - pool_free_pos);
+
+ p = (mem_header_t*) pool;
+
+ while (p < (mem_header_t*) (pool + pool_free_pos))
+ {
+ printf( " * Addr: 0x%8lu; Size: %8lu\n",
+ p, p->s.size);
+
+ p += p->s.size;
+ }
+
+ printf("\nFree list:\n\n");
+
+ if (freep)
+ {
+ p = freep;
+
+ while (1)
+ {
+ printf( " * Addr: 0x%8lu; Size: %8lu; Next: 0x%8lu\n",
+ p, p->s.size, p->s.next);
+
+ p = p->s.next;
+
+ if (p == freep)
+ break;
+ }
+ }
+ else
+ {
+ printf("Empty\n");
+ }
+
+ printf("\n");
+
+}
+
+
+static mem_header_t* get_mem_from_pool(ulong nquantas)
+{
+ ulong total_req_size;
+
+ mem_header_t* h;
+
+ if (nquantas < 16)
+ nquantas = 16;
+
+ total_req_size = nquantas * sizeof(mem_header_t);
+
+ if (pool_free_pos + total_req_size <= 8 * 1024)
+ {
+ 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;
+}
+
+
+
+
+
+
+
+
+
+
+void* memmgr_alloc(ulong nbytes)
+{
+ mem_header_t* p;
+ mem_header_t* prevp;
+
+
+
+
+
+ ulong nquantas = (nbytes + sizeof(mem_header_t) - 1) / sizeof(mem_header_t) + 1;
+
+
+
+
+ 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)
+ {
+
+ if (p->s.size >= nquantas)
+ {
+
+ if (p->s.size == nquantas)
+ {
+
+
+
+ prevp->s.next = p->s.next;
+ }
+ else
+ {
+ p->s.size -= nquantas;
+ p += p->s.size;
+ p->s.size = nquantas;
+ }
+
+ freep = prevp;
+ return (void*) (p + 1);
+ }
+
+
+
+
+
+
+
+ else if (p == freep)
+ {
+ if ((p = get_mem_from_pool(nquantas)) == 0)
+ {
+
+
+
+ return 0;
+ }
+ }
+ }
+}
+
+
+
+
+
+
+
+void memmgr_free(void* ap)
+{
+ mem_header_t* block;
+ mem_header_t* p;
+
+
+ block = ((mem_header_t*) ap) - 1;
+
+
+
+
+ for (p = freep; !(block > p && block < p->s.next); p = p->s.next)
+ {
+
+
+
+
+
+ if (p >= p->s.next && (block > p || block < p->s.next))
+ break;
+ }
+
+
+
+ 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;
+ }
+
+
+
+ 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;
+}
diff --git a/tests/c_files/year.c b/tests/c_files/year.c
new file mode 100644
index 0000000..c0f583d
--- /dev/null
+++ b/tests/c_files/year.c
@@ -0,0 +1,53 @@
+#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;
+}
+
+
diff --git a/tests/test_c_ast.py b/tests/test_c_ast.py
new file mode 100644
index 0000000..d5794e1
--- /dev/null
+++ b/tests/test_c_ast.py
@@ -0,0 +1,89 @@
+import pprint
+import re
+import sys
+import unittest
+
+sys.path.insert(0, '..')
+import pycparser.c_ast as c_ast
+
+
+class Test_c_ast(unittest.TestCase):
+ def test_BinaryOp(self):
+ b1 = c_ast.BinaryOp(
+ op='+',
+ left=c_ast.Constant(type='int', value='6'),
+ right=c_ast.ID(name='joe'))
+
+ self.failUnless(isinstance(b1.left, c_ast.Constant))
+ self.assertEqual(b1.left.type, 'int')
+ self.assertEqual(b1.left.value, '6')
+
+ self.failUnless(isinstance(b1.right, c_ast.ID))
+ self.assertEqual(b1.right.name, 'joe')
+
+
+class TestNodeVisitor(unittest.TestCase):
+ class ConstantVisitor(c_ast.NodeVisitor):
+ def __init__(self):
+ self.values = []
+
+ def visit_Constant(self, node):
+ self.values.append(node.value)
+
+ def test_scalar_children(self):
+ b1 = c_ast.BinaryOp(
+ op='+',
+ left=c_ast.Constant(type='int', value='6'),
+ right=c_ast.ID(name='joe'))
+
+ cv = self.ConstantVisitor()
+ cv.visit(b1)
+
+ self.assertEqual(cv.values, ['6'])
+
+ b2 = c_ast.BinaryOp(
+ op='*',
+ left=c_ast.Constant(type='int', value='111'),
+ right=b1)
+
+ b3 = c_ast.BinaryOp(
+ op='^',
+ left=b2,
+ right=b1)
+
+ cv = self.ConstantVisitor()
+ cv.visit(b3)
+
+ self.assertEqual(cv.values, ['111', '6', '6'])
+
+ def tests_list_children(self):
+ c1 = c_ast.Constant(type='float', value='5.6')
+ c2 = c_ast.Constant(type='char', value='t')
+
+ b1 = c_ast.BinaryOp(
+ op='+',
+ left=c1,
+ right=c2)
+
+ b2 = c_ast.BinaryOp(
+ op='-',
+ left=b1,
+ right=c2)
+
+ comp = c_ast.Compound(
+ decls=[b1, b2],
+ stmts=[c1, c2])
+
+ cv = self.ConstantVisitor()
+ cv.visit(comp)
+
+ self.assertEqual(cv.values,
+ ['5.6', 't', '5.6', 't', 't', '5.6', 't'])
+
+
+if __name__ == '__main__':
+ unittest.main()
+
+
+
+
diff --git a/tests/test_c_lexer.py b/tests/test_c_lexer.py
new file mode 100644
index 0000000..6a2f42a
--- /dev/null
+++ b/tests/test_c_lexer.py
@@ -0,0 +1,327 @@
+import re
+import sys
+import unittest
+
+sys.path.insert(0, '..')
+from pycparser.c_lexer import CLexer
+
+
+def token_list(clex):
+ return list(iter(clex.token, None))
+
+
+def token_types(clex):
+ return [i.type for i in token_list(clex)]
+
+
+class TestCLexerNoErrors(unittest.TestCase):
+ """ Test lexing of strings that are not supposed to cause
+ errors. Therefore, the error_func passed to the lexer
+ raises an exception.
+ """
+ def error_func(self, msg, line, column):
+ self.fail(msg)
+
+ def type_lookup_func(self, typ):
+ if typ.startswith('mytype'):
+ return True
+ else:
+ return False
+
+ def setUp(self):
+ self.clex = CLexer(self.error_func, self.type_lookup_func)
+ self.clex.build(optimize=False)
+
+ def assertTokensTypes(self, str, types):
+ self.clex.input(str)
+ self.assertEqual(token_types(self.clex), types)
+
+ def test_trivial_tokens(self):
+ self.assertTokensTypes('1', ['INT_CONST_DEC'])
+ self.assertTokensTypes('-', ['MINUS'])
+ self.assertTokensTypes('volatile', ['VOLATILE'])
+ self.assertTokensTypes('...', ['ELLIPSIS'])
+ self.assertTokensTypes('++', ['PLUSPLUS'])
+ self.assertTokensTypes('case int', ['CASE', 'INT'])
+ self.assertTokensTypes('caseint', ['ID'])
+ self.assertTokensTypes('i ^= 1;', ['ID', 'XOREQUAL', 'INT_CONST_DEC', 'SEMI'])
+
+ def test_id_typeid(self):
+ self.assertTokensTypes('myt', ['ID'])
+ self.assertTokensTypes('mytype', ['TYPEID'])
+ self.assertTokensTypes('mytype6 var', ['TYPEID', 'ID'])
+
+ def test_integer_constants(self):
+ self.assertTokensTypes('12', ['INT_CONST_DEC'])
+ self.assertTokensTypes('12u', ['INT_CONST_DEC'])
+ self.assertTokensTypes('199872Ul', ['INT_CONST_DEC'])
+
+ self.assertTokensTypes('077', ['INT_CONST_OCT'])
+ self.assertTokensTypes('0123456L', ['INT_CONST_OCT'])
+
+ self.assertTokensTypes('0xf7', ['INT_CONST_HEX'])
+ self.assertTokensTypes('0x01202AAbbf7Ul', ['INT_CONST_HEX'])
+
+ # no 0 before x, so ID catches it
+ self.assertTokensTypes('xf7', ['ID'])
+
+ # - is MINUS, the rest a constnant
+ self.assertTokensTypes('-1', ['MINUS', 'INT_CONST_DEC'])
+
+ def test_floating_constants(self):
+ self.assertTokensTypes('1.5f', ['FLOAT_CONST'])
+ self.assertTokensTypes('01.5', ['FLOAT_CONST'])
+ self.assertTokensTypes('.15L', ['FLOAT_CONST'])
+ self.assertTokensTypes('0.', ['FLOAT_CONST'])
+
+ # but just a period is a period
+ self.assertTokensTypes('.', ['PERIOD'])
+
+ self.assertTokensTypes('3.3e-3', ['FLOAT_CONST'])
+ self.assertTokensTypes('.7e25L', ['FLOAT_CONST'])
+ self.assertTokensTypes('6.e+125f', ['FLOAT_CONST'])
+ self.assertTokensTypes('666e666', ['FLOAT_CONST'])
+ self.assertTokensTypes('00666e+3', ['FLOAT_CONST'])
+
+ # but this is a hex integer + 3
+ self.assertTokensTypes('0x0666e+3', ['INT_CONST_HEX', 'PLUS', 'INT_CONST_DEC'])
+
+ def test_char_constants(self):
+ self.assertTokensTypes(r"""'x'""", ['CHAR_CONST'])
+ self.assertTokensTypes(r"""L'x'""", ['WCHAR_CONST'])
+ self.assertTokensTypes(r"""'\t'""", ['CHAR_CONST'])
+ self.assertTokensTypes(r"""'\''""", ['CHAR_CONST'])
+ self.assertTokensTypes(r"""'\?'""", ['CHAR_CONST'])
+ self.assertTokensTypes(r"""'\012'""", ['CHAR_CONST'])
+ self.assertTokensTypes(r"""'\x2f'""", ['CHAR_CONST'])
+ self.assertTokensTypes(r"""'\x2f12'""", ['CHAR_CONST'])
+ self.assertTokensTypes(r"""L'\xaf'""", ['WCHAR_CONST'])
+
+ def test_string_literal(self):
+ self.assertTokensTypes('"a string"', ['STRING_LITERAL'])
+ self.assertTokensTypes('L"ing"', ['WSTRING_LITERAL'])
+ self.assertTokensTypes(
+ '"i am a string too \t"',
+ ['STRING_LITERAL'])
+ self.assertTokensTypes(
+ r'''"esc\ape \"\'\? \0234 chars \rule"''',
+ ['STRING_LITERAL'])
+ self.assertTokensTypes(
+ r'''"hello 'joe' wanna give it a \"go\"?"''',
+ ['STRING_LITERAL'])
+
+ def test_mess(self):
+ self.assertTokensTypes(
+ r'[{}]()',
+ ['LBRACKET',
+ 'LBRACE', 'RBRACE',
+ 'RBRACKET',
+ 'LPAREN', 'RPAREN'])
+
+ self.assertTokensTypes(
+ r'()||!C&~Z?J',
+ ['LPAREN', 'RPAREN',
+ 'LOR',
+ 'LNOT', 'ID',
+ 'AND',
+ 'NOT', 'ID',
+ 'CONDOP', 'ID'])
+
+ self.assertTokensTypes(
+ r'+-*/%|||&&&^><>=<===!=',
+ ['PLUS', 'MINUS', 'TIMES', 'DIVIDE', 'MOD',
+ 'LOR', 'OR',
+ 'LAND', 'AND',
+ 'XOR',
+ 'GT', 'LT', 'GE', 'LE', 'EQ', 'NE'])
+
+ self.assertTokensTypes(
+ r'++--->?.,;:',
+ ['PLUSPLUS', 'MINUSMINUS',
+ 'ARROW', 'CONDOP',
+ 'PERIOD', 'COMMA', 'SEMI', 'COLON'])
+
+ def test_exprs(self):
+ self.assertTokensTypes(
+ 'bb-cc',
+ ['ID', 'MINUS', 'ID'])
+
+ self.assertTokensTypes(
+ 'foo & 0xFF',
+ ['ID', 'AND', 'INT_CONST_HEX'])
+
+ self.assertTokensTypes(
+ '(2+k) * 62',
+ ['LPAREN', 'INT_CONST_DEC', 'PLUS', 'ID',
+ 'RPAREN', 'TIMES', 'INT_CONST_DEC'],)
+
+ self.assertTokensTypes(
+ 'x | y >> z',
+ ['ID', 'OR', 'ID', 'RSHIFT', 'ID'])
+
+ self.assertTokensTypes(
+ 'x <<= z << 5',
+ ['ID', 'LSHIFTEQUAL', 'ID', 'LSHIFT', 'INT_CONST_DEC'])
+
+ self.assertTokensTypes(
+ 'x = y > 0 ? y : -6',
+ ['ID', 'EQUALS',
+ 'ID', 'GT', 'INT_CONST_OCT',
+ 'CONDOP',
+ 'ID',
+ 'COLON',
+ 'MINUS', 'INT_CONST_DEC'])
+
+ self.assertTokensTypes(
+ 'a+++b',
+ ['ID', 'PLUSPLUS', 'PLUS', 'ID'])
+
+ def test_statements(self):
+ self.assertTokensTypes(
+ 'for (int i = 0; i < n; ++i)',
+ ['FOR', 'LPAREN',
+ 'INT', 'ID', 'EQUALS', 'INT_CONST_OCT', 'SEMI',
+ 'ID', 'LT', 'ID', 'SEMI',
+ 'PLUSPLUS', 'ID',
+ 'RPAREN'])
+
+ self.assertTokensTypes(
+ 'self: goto self;',
+ ['ID', 'COLON', 'GOTO', 'ID', 'SEMI'])
+
+ self.assertTokensTypes(
+ """ switch (typ)
+ {
+ case TYPE_ID:
+ m = 5;
+ break;
+ default:
+ m = 8;
+ }""",
+ ['SWITCH', 'LPAREN', 'ID', 'RPAREN',
+ 'LBRACE',
+ 'CASE', 'ID', 'COLON',
+ 'ID', 'EQUALS', 'INT_CONST_DEC', 'SEMI',
+ 'BREAK', 'SEMI',
+ 'DEFAULT', 'COLON',
+ 'ID', 'EQUALS', 'INT_CONST_DEC', 'SEMI',
+ 'RBRACE'])
+
+ def test_preprocessor(self):
+ self.assertTokensTypes('#abracadabra', ['PPHASH', 'ID'])
+
+ str = r"""
+ 546
+ #line 66 "kwas\df.h"
+ id 4
+ dsf
+ # 9
+ armo
+ """
+
+ #~ self.clex.filename
+ self.clex.input(str)
+ self.clex.reset_lineno()
+
+ t1 = self.clex.token()
+ self.assertEqual(t1.type, 'INT_CONST_DEC')
+ self.assertEqual(t1.lineno, 2)
+
+ t2 = self.clex.token()
+ self.assertEqual(t2.type, 'ID')
+ self.assertEqual(t2.value, 'id')
+ self.assertEqual(t2.lineno, 66)
+ self.assertEqual(self.clex.filename, r'kwas\df.h')
+
+ for i in range(3):
+ t = self.clex.token()
+
+ self.assertEqual(t.type, 'ID')
+ self.assertEqual(t.value, 'armo')
+ self.assertEqual(t.lineno, 9)
+ self.assertEqual(self.clex.filename, r'kwas\df.h')
+
+
+
+# Keeps all the errors the lexer spits in one place, to allow
+# easier modification if the error syntax changes.
+#
+ERR_ILLEGAL_CHAR = 'Illegal character'
+ERR_OCTAL = 'Invalid octal constant'
+ERR_UNMATCHED_QUOTE = 'Unmatched \''
+ERR_INVALID_CCONST = 'Invalid char constant'
+ERR_STRING_ESCAPE = 'String contains invalid escape'
+
+ERR_FILENAME_BEFORE_LINE = 'filename before line'
+ERR_LINENUM_MISSING = 'line number missing'
+ERR_INVALID_LINE_DIRECTIVE = 'invalid #line directive'
+
+
+class TestCLexerErrors(unittest.TestCase):
+ """ Test lexing of erroneous strings.
+ Works by passing an error functions that saves the error
+ in an attribute for later perusal.
+ """
+ def error_func(self, msg, line, column):
+ self.error = msg
+
+ def type_lookup_func(self, typ):
+ return False
+
+ def setUp(self):
+ self.clex = CLexer(self.error_func, self.type_lookup_func)
+ self.clex.build(optimize=False)
+ self.error = ""
+
+ def assertLexerError(self, str, error_like):
+ # feed the string to the lexer
+ self.clex.input(str)
+
+ # Pulls all tokens from the string. Errors will
+ # be written into self.error by the error_func
+ # callback
+ #
+ token_types(self.clex)
+
+ # compare the error to the expected
+ self.failUnless(re.search(error_like, self.error),
+ "\nExpected error matching: %s\nGot: %s" %
+ (error_like, self.error))
+
+ # clear last error, for the sake of subsequent invocations
+ self.error = ""
+
+ def test_trivial_tokens(self):
+ self.assertLexerError('@', ERR_ILLEGAL_CHAR)
+ self.assertLexerError('$', ERR_ILLEGAL_CHAR)
+ self.assertLexerError('`', ERR_ILLEGAL_CHAR)
+ self.assertLexerError('\\', ERR_ILLEGAL_CHAR)
+
+ def test_integer_constants(self):
+ self.assertLexerError('029', ERR_OCTAL)
+ self.assertLexerError('012345678', ERR_OCTAL)
+
+ def test_char_constants(self):
+ self.assertLexerError("'", ERR_UNMATCHED_QUOTE)
+ self.assertLexerError("'b\n", ERR_UNMATCHED_QUOTE)
+
+ self.assertLexerError("'jx'", ERR_INVALID_CCONST)
+ self.assertLexerError("'\*'", ERR_INVALID_CCONST)
+ self.assertLexerError("'\9'", ERR_INVALID_CCONST)
+ self.assertLexerError("L'\9'", ERR_INVALID_CCONST)
+
+ def test_string_literals(self):
+ self.assertLexerError('"jx\9"', ERR_STRING_ESCAPE)
+ self.assertLexerError('"hekllo\* on ix"', ERR_STRING_ESCAPE)
+ self.assertLexerError('L"hekllo\* on ix"', ERR_STRING_ESCAPE)
+
+ def test_preprocessor(self):
+ self.assertLexerError('#line "ka"', ERR_FILENAME_BEFORE_LINE)
+ self.assertLexerError('#line df', ERR_INVALID_LINE_DIRECTIVE)
+ self.assertLexerError('#line \n', ERR_LINENUM_MISSING)
+
+
+if __name__ == '__main__':
+ unittest.main()
+
+
diff --git a/tests/test_c_parser.py b/tests/test_c_parser.py
new file mode 100644
index 0000000..d57d8ee
--- /dev/null
+++ b/tests/test_c_parser.py
@@ -0,0 +1,1028 @@
+#!/usr/bin/env python
+
+import pprint
+import re
+import sys
+import unittest
+
+sys.path.insert(0, '..')
+
+from pycparser import c_parser
+from pycparser.c_ast import *
+from pycparser.c_parser import CParser, Coord, ParseError
+
+
+_c_parser = c_parser.CParser(
+ lex_optimize=False,
+ yacc_debug=True,
+ yacc_optimize=False,
+ yacctab='yacctab')
+
+
+def expand_decl(decl):
+ """ Converts the declaration into a nested list.
+ """
+ typ = type(decl)
+
+ if typ == TypeDecl:
+ return ['TypeDecl', expand_decl(decl.type)]
+ elif typ == IdentifierType:
+ return ['IdentifierType', decl.names]
+ elif typ == ID:
+ return ['ID', decl.name]
+ elif typ in [Struct, Union]:
+ decls = [expand_decl(d) for d in decl.decls or []]
+ return [typ.__name__, decl.name, decls]
+ else:
+ nested = expand_decl(decl.type)
+
+ if typ == Decl:
+ if decl.quals:
+ return ['Decl', decl.quals, decl.name, nested]
+ else:
+ return ['Decl', decl.name, nested]
+ elif typ == Typename: # for function parameters
+ if decl.quals:
+ return ['Typename', decl.quals, nested]
+ else:
+ return ['Typename', nested]
+ elif typ == ArrayDecl:
+ dimval = decl.dim.value if decl.dim else ''
+ return ['ArrayDecl', dimval, nested]
+ elif typ == PtrDecl:
+ return ['PtrDecl', nested]
+ elif typ == Typedef:
+ return ['Typedef', decl.name, nested]
+ elif typ == FuncDecl:
+ if decl.args:
+ params = [expand_decl(param) for param in decl.args.params]
+ else:
+ params = []
+ return ['FuncDecl', params, nested]
+
+
+def expand_init(init):
+ """ Converts an initialization into a nested list
+ """
+ typ = type(init)
+
+ if typ == Constant:
+ return ['Constant', init.type, init.value]
+ elif typ == ID:
+ return ['ID', init.name]
+ elif typ == ExprList:
+ return [expand_init(expr) for expr in init.exprs]
+
+
+class TestCParser_fundamentals(unittest.TestCase):
+ """ Tests for "fundamental features" of CParser. Testing
+ (mostly) each feature in a detailed manner.
+ """
+ def parse(self, txt, filename=''):
+ return self.cparser.parse(txt, filename)
+
+ def setUp(self):
+ self.cparser = _c_parser
+
+ def get_decl(self, txt, index=0):
+ """ Given a source and an index returns the expanded
+ declaration at that index.
+
+ FileAST holds a list of 'external declarations'.
+ index is the offset of the desired declaration in that
+ list.
+ """
+ t = self.parse(txt).ext[index]
+ return expand_decl(t)
+
+ def get_decl_init(self, txt, index=0):
+ """ Returns the expanded initializer of the declaration
+ at index.
+ """
+ t = self.parse(txt).ext[index]
+ return expand_init(t.init)
+
+ def test_FileAST(self):
+ t = self.parse('int a; char c;')
+ self.failUnless(isinstance(t, FileAST))
+ self.assertEqual(len(t.ext), 2)
+
+ """ Tests the "coordinates" of parsed elements - file
+ name and line numbers, with modification insterted by
+ #line directives.
+ """
+ def assert_coord(self, node, line, file=None):
+ self.assertEqual(node.coord.line, line)
+ if file:
+ self.assertEqual(node.coord.file, file)
+
+ def test_coords(self):
+ self.assert_coord(self.parse('int a;').ext[0], 1)
+
+ t1 = """
+ int a;
+ int b;\n\n
+ int c;
+ """
+ f1 = self.parse(t1, filename='test.c')
+ self.assert_coord(f1.ext[0], 2, 'test.c')
+ self.assert_coord(f1.ext[1], 3, 'test.c')
+ self.assert_coord(f1.ext[2], 6, 'test.c')
+
+ t1_1 = '''
+ int main() {
+ k = p;
+ printf("%d", b);
+ return 0;
+ }'''
+ f1_1 = self.parse(t1_1, filename='test.c')
+ self.assert_coord(f1_1.ext[0].body.stmts[0], 3, 'test.c')
+ self.assert_coord(f1_1.ext[0].body.stmts[1], 4, 'test.c')
+
+ t2 = """
+ #line 99
+ int c;
+ """
+ self.assert_coord(self.parse(t2).ext[0], 99)
+
+ t3 = """
+ int dsf;
+ char p;
+ #line 3000 "in.h"
+ char d;
+ """
+ f3 = self.parse(t3, filename='test.c')
+ self.assert_coord(f3.ext[0], 2, 'test.c')
+ self.assert_coord(f3.ext[1], 3, 'test.c')
+ self.assert_coord(f3.ext[2], 3000, 'in.h')
+
+ t4 = """
+ #line 20 "restore.h"
+ int maydler(char);
+
+ #line 30 "includes/daween.ph"
+ long j, k;
+
+ #line 50000
+ char* ro;
+ """
+ f4 = self.parse(t4, filename='myb.c')
+ self.assert_coord(f4.ext[0], 20, 'restore.h')
+ self.assert_coord(f4.ext[1], 30, 'includes/daween.ph')
+ self.assert_coord(f4.ext[2], 30, 'includes/daween.ph')
+ self.assert_coord(f4.ext[3], 50000, 'includes/daween.ph')
+
+ t5 = """
+ int
+ #line 99
+ c;
+ """
+ self.assert_coord(self.parse(t5).ext[0], 99)
+
+ def test_simple_decls(self):
+ self.assertEqual(self.get_decl('int a;'),
+ ['Decl', 'a', ['TypeDecl', ['IdentifierType', ['int']]]])
+
+ self.assertEqual(self.get_decl('unsigned int a;'),
+ ['Decl', 'a', ['TypeDecl', ['IdentifierType', ['int', 'unsigned']]]])
+
+ self.assertEqual(self.get_decl('char* string;'),
+ ['Decl', 'string',
+ ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]])
+
+ self.assertEqual(self.get_decl('long ar[15];'),
+ ['Decl', 'ar',
+ ['ArrayDecl', '15',
+ ['TypeDecl', ['IdentifierType', ['long']]]]])
+
+ self.assertEqual(self.get_decl('unsigned ar[];'),
+ ['Decl', 'ar',
+ ['ArrayDecl', '',
+ ['TypeDecl', ['IdentifierType', ['unsigned']]]]])
+
+ self.assertEqual(self.get_decl('int strlen(char* s);'),
+ ['Decl', 'strlen',
+ ['FuncDecl',
+ [['Decl', 's',
+ ['PtrDecl',
+ ['TypeDecl', ['IdentifierType', ['char']]]]]],
+ ['TypeDecl', ['IdentifierType', ['int']]]]])
+
+ self.assertEqual(self.get_decl('int strcmp(char* s1, char* s2);'),
+ ['Decl', 'strcmp',
+ ['FuncDecl',
+ [ ['Decl', 's1',
+ ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]],
+ ['Decl', 's2',
+ ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]]
+ ],
+ ['TypeDecl', ['IdentifierType', ['int']]]]])
+
+ def test_nested_decls(self): # the fun begins
+ self.assertEqual(self.get_decl('char** ar2D;'),
+ ['Decl', 'ar2D',
+ ['PtrDecl', ['PtrDecl',
+ ['TypeDecl', ['IdentifierType', ['char']]]]]])
+
+ self.assertEqual(self.get_decl('int (*a)[1][2];'),
+ ['Decl', 'a',
+ ['PtrDecl',
+ ['ArrayDecl', '1',
+ ['ArrayDecl', '2',
+ ['TypeDecl', ['IdentifierType', ['int']]]]]]])
+
+ self.assertEqual(self.get_decl('int *a[1][2];'),
+ ['Decl', 'a',
+ ['ArrayDecl', '1',
+ ['ArrayDecl', '2',
+ ['PtrDecl', ['TypeDecl', ['IdentifierType', ['int']]]]]]])
+
+ self.assertEqual(self.get_decl('char ***ar3D[40];'),
+ ['Decl', 'ar3D',
+ ['ArrayDecl', '40',
+ ['PtrDecl', ['PtrDecl', ['PtrDecl',
+ ['TypeDecl', ['IdentifierType', ['char']]]]]]]])
+
+ self.assertEqual(self.get_decl('char (***ar3D)[40];'),
+ ['Decl', 'ar3D',
+ ['PtrDecl', ['PtrDecl', ['PtrDecl',
+ ['ArrayDecl', '40', ['TypeDecl', ['IdentifierType', ['char']]]]]]]])
+
+ self.assertEqual(self.get_decl('int (*x[4])(char, int);'),
+ ['Decl', 'x',
+ ['ArrayDecl', '4',
+ ['PtrDecl',
+ ['FuncDecl',
+ [ ['Typename', ['TypeDecl', ['IdentifierType', ['char']]]],
+ ['Typename', ['TypeDecl', ['IdentifierType', ['int']]]]],
+ ['TypeDecl', ['IdentifierType', ['int']]]]]]])
+
+ self.assertEqual(self.get_decl('char *(*(**foo [][8])())[];'),
+ ['Decl', 'foo',
+ ['ArrayDecl', '',
+ ['ArrayDecl', '8',
+ ['PtrDecl', ['PtrDecl',
+ ['FuncDecl',
+ [],
+ ['PtrDecl',
+ ['ArrayDecl', '',
+ ['PtrDecl',
+ ['TypeDecl',
+ ['IdentifierType', ['char']]]]]]]]]]]])
+
+ # explore named and unnamed function pointer parameters,
+ # with and without qualifiers
+ #
+
+ # unnamed w/o quals
+ self.assertEqual(self.get_decl('int (*k)(int);'),
+ ['Decl', 'k',
+ ['PtrDecl',
+ ['FuncDecl',
+ [['Typename', ['TypeDecl', ['IdentifierType', ['int']]]]],
+ ['TypeDecl', ['IdentifierType', ['int']]]]]])
+
+ # unnamed w/ quals
+ self.assertEqual(self.get_decl('int (*k)(const int);'),
+ ['Decl', 'k',
+ ['PtrDecl',
+ ['FuncDecl',
+ [['Typename', ['const'], ['TypeDecl', ['IdentifierType', ['int']]]]],
+ ['TypeDecl', ['IdentifierType', ['int']]]]]])
+
+ # named w/o quals
+ self.assertEqual(self.get_decl('int (*k)(int q);'),
+ ['Decl', 'k',
+ ['PtrDecl',
+ ['FuncDecl',
+ [['Decl', 'q', ['TypeDecl', ['IdentifierType', ['int']]]]],
+ ['TypeDecl', ['IdentifierType', ['int']]]]]])
+
+ # named w/ quals
+ self.assertEqual(self.get_decl('int (*k)(const volatile int q);'),
+ ['Decl', 'k',
+ ['PtrDecl',
+ ['FuncDecl',
+ [['Decl', ['volatile', 'const'], 'q',
+ ['TypeDecl', ['IdentifierType', ['int']]]]],
+ ['TypeDecl', ['IdentifierType', ['int']]]]]])
+
+
+ def test_qualifiers_storage_specifiers(self):
+ def assert_qs(txt, index, quals, storage):
+ d = self.parse(txt).ext[index]
+ self.assertEqual(d.quals, quals)
+ self.assertEqual(d.storage, storage)
+
+ assert_qs("extern int p;", 0, [], ['extern'])
+ assert_qs("const long p = 6;", 0, ['const'], [])
+
+ d1 = "static const int p, q, r;"
+ for i in range(3):
+ assert_qs(d1, i, ['const'], ['static'])
+
+ d2 = "static char * const p;"
+ assert_qs(d2, 0, [], ['static'])
+ pdecl = self.parse(d2).ext[0].type
+ self.failUnless(isinstance(pdecl, PtrDecl))
+ self.assertEqual(pdecl.quals, ['const'])
+
+ def test_sizeof(self):
+ e = """
+ void foo()
+ {
+ int a = sizeof k;
+ int b = sizeof(int);
+ int c = sizeof(int**);
+
+ char* p = "just to make sure this parses w/o error...";
+ int d = sizeof(int());
+ }
+ """
+ compound = self.parse(e).ext[0].body
+
+ s1 = compound.decls[0].init
+ self.assertTrue(isinstance(s1, UnaryOp))
+ self.assertEqual(s1.op, 'sizeof')
+ self.assertTrue(isinstance(s1.expr, ID))
+ self.assertEqual(s1.expr.name, 'k')
+
+ s2 = compound.decls[1].init
+ self.assertEqual(expand_decl(s2.expr),
+ ['Typename', ['TypeDecl', ['IdentifierType', ['int']]]])
+
+ s3 = compound.decls[2].init
+ self.assertEqual(expand_decl(s3.expr),
+ ['Typename',
+ ['PtrDecl',
+ ['PtrDecl',
+ ['TypeDecl',
+ ['IdentifierType', ['int']]]]]])
+
+ def test_enums(self):
+ e1 = "enum mycolor op;"
+ e1_type = self.parse(e1).ext[0].type.type
+
+ self.assertTrue(isinstance(e1_type, Enum))
+ self.assertEqual(e1_type.name, 'mycolor')
+ self.assertEqual(e1_type.values, None)
+
+ e2 = "enum mysize {large=20, small, medium} shoes;"
+ e2_type = self.parse(e2).ext[0].type.type
+
+ self.assertTrue(isinstance(e2_type, Enum))
+ self.assertEqual(e2_type.name, 'mysize')
+
+ e2_elist = e2_type.values
+ self.assertTrue(isinstance(e2_elist, EnumeratorList))
+
+ for e2_eval in e2_elist.enumerators:
+ self.assertTrue(isinstance(e2_eval, Enumerator))
+
+ self.assertEqual(e2_elist.enumerators[0].name, 'large')
+ self.assertEqual(e2_elist.enumerators[0].value.value, '20')
+ self.assertEqual(e2_elist.enumerators[2].name, 'medium')
+ self.assertEqual(e2_elist.enumerators[2].value, None)
+
+ # enum with trailing comma (C99 feature)
+ e3 = """
+ enum
+ {
+ red,
+ blue,
+ green,
+ } color;
+ """
+
+ e3_type = self.parse(e3).ext[0].type.type
+ self.assertTrue(isinstance(e3_type, Enum))
+ e3_elist = e3_type.values
+ self.assertTrue(isinstance(e3_elist, EnumeratorList))
+
+ for e3_eval in e3_elist.enumerators:
+ self.assertTrue(isinstance(e3_eval, Enumerator))
+
+ self.assertEqual(e3_elist.enumerators[0].name, 'red')
+ self.assertEqual(e3_elist.enumerators[0].value, None)
+ self.assertEqual(e3_elist.enumerators[1].name, 'blue')
+ self.assertEqual(e3_elist.enumerators[2].name, 'green')
+
+ def test_typedef(self):
+ # without typedef, error
+ s1 = """
+ node k;
+ """
+ self.assertRaises(ParseError, self.parse, s1)
+
+ # now with typedef, works
+ s2 = """
+ typedef void* node;
+ node k;
+ """
+ ps2 = self.parse(s2)
+ self.assertEqual(expand_decl(ps2.ext[0]),
+ ['Typedef', 'node',
+ ['PtrDecl',
+ ['TypeDecl', ['IdentifierType', ['void']]]]])
+
+ self.assertEqual(expand_decl(ps2.ext[1]),
+ ['Decl', 'k',
+ ['TypeDecl', ['IdentifierType', ['node']]]])
+
+ s3 = """
+ typedef int T;
+ typedef T *pT;
+
+ pT aa, bb;
+ """
+ ps3 = self.parse(s3)
+ self.assertEqual(expand_decl(ps3.ext[3]),
+ ['Decl', 'bb',
+ ['TypeDecl', ['IdentifierType', ['pT']]]])
+
+ s4 = '''
+ typedef char* __builtin_va_list;
+ typedef __builtin_va_list __gnuc_va_list;
+ '''
+ ps4 = self.parse(s4)
+ self.assertEqual(expand_decl(ps4.ext[1]),
+ ['Typedef', '__gnuc_va_list',
+ ['TypeDecl',
+ ['IdentifierType', ['__builtin_va_list']]]])
+
+ s5 = '''typedef struct tagHash Hash;'''
+ ps5 = self.parse(s5)
+ self.assertEqual(expand_decl(ps5.ext[0]),
+ ['Typedef', 'Hash', ['TypeDecl', ['Struct', 'tagHash', []]]])
+
+ def test_struct_union(self):
+ s1 = """
+ struct {
+ int id;
+ char* name;
+ } joe;
+ """
+
+ self.assertEqual(expand_decl(self.parse(s1).ext[0]),
+ ['Decl', 'joe',
+ ['TypeDecl', ['Struct', None,
+ [ ['Decl', 'id',
+ ['TypeDecl',
+ ['IdentifierType', ['int']]]],
+ ['Decl', 'name',
+ ['PtrDecl',
+ ['TypeDecl',
+ ['IdentifierType', ['char']]]]]]]]])
+
+ s2 = """
+ struct node p;
+ """
+ self.assertEqual(expand_decl(self.parse(s2).ext[0]),
+ ['Decl', 'p',
+ ['TypeDecl', ['Struct', 'node', []]]])
+
+ s21 = """
+ union pri ra;
+ """
+ self.assertEqual(expand_decl(self.parse(s21).ext[0]),
+ ['Decl', 'ra',
+ ['TypeDecl', ['Union', 'pri', []]]])
+
+ s3 = """
+ struct node* p;
+ """
+ self.assertEqual(expand_decl(self.parse(s3).ext[0]),
+ ['Decl', 'p',
+ ['PtrDecl',
+ ['TypeDecl', ['Struct', 'node', []]]]])
+
+ s4 = """
+ struct node;
+ """
+ self.assertEqual(expand_decl(self.parse(s4).ext[0]),
+ ['Decl', None,
+ ['Struct', 'node', []]])
+
+ s5 = """
+ union
+ {
+ struct
+ {
+ int type;
+ } n;
+
+ struct
+ {
+ int type;
+ int intnode;
+ } ni;
+ } u;
+ """
+ self.assertEqual(expand_decl(self.parse(s5).ext[0]),
+ ['Decl', 'u',
+ ['TypeDecl',
+ ['Union', None,
+ [['Decl', 'n',
+ ['TypeDecl',
+ ['Struct', None,
+ [['Decl', 'type',
+ ['TypeDecl', ['IdentifierType', ['int']]]]]]]],
+ ['Decl', 'ni',
+ ['TypeDecl',
+ ['Struct', None,
+ [['Decl', 'type',
+ ['TypeDecl', ['IdentifierType', ['int']]]],
+ ['Decl', 'intnode',
+ ['TypeDecl', ['IdentifierType', ['int']]]]]]]]]]]])
+
+ s6 = """
+ typedef struct foo_tag
+ {
+ void* data;
+ } foo, *pfoo;
+ """
+ s6_ast = self.parse(s6)
+
+ self.assertEqual(expand_decl(s6_ast.ext[0]),
+ ['Typedef', 'foo',
+ ['TypeDecl',
+ ['Struct', 'foo_tag',
+ [['Decl', 'data',
+ ['PtrDecl', ['TypeDecl', ['IdentifierType', ['void']]]]]]]]])
+
+ self.assertEqual(expand_decl(s6_ast.ext[1]),
+ ['Typedef', 'pfoo',
+ ['PtrDecl',
+ ['TypeDecl',
+ ['Struct', 'foo_tag',
+ [['Decl', 'data',
+ ['PtrDecl', ['TypeDecl', ['IdentifierType', ['void']]]]]]]]]])
+
+ s7 = r"""
+ struct _on_exit_args {
+ void * _fnargs[32];
+ void * _dso_handle[32];
+
+ long _fntypes;
+ #line 77 "D:\eli\cpp_stuff\libc_include/sys/reent.h"
+
+ long _is_cxa;
+ };
+ """
+
+ s7_ast = self.parse(s7, filename='test.c')
+ self.assert_coord(s7_ast.ext[0].type.decls[2], 6, 'test.c')
+ self.assert_coord(s7_ast.ext[0].type.decls[3], 78,
+ r'D:\eli\cpp_stuff\libc_include/sys/reent.h')
+
+ s8 = """
+ 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;
+ """
+ s8_ast = self.parse(s8)
+ self.assertEqual(expand_decl(s8_ast.ext[3]),
+ ['Typedef', 'Hash',
+ ['TypeDecl', ['Struct', 'tagHash',
+ [['Decl', 'table_size',
+ ['TypeDecl', ['IdentifierType', ['int', 'unsigned']]]],
+ ['Decl', 'heads',
+ ['PtrDecl', ['PtrDecl', ['TypeDecl', ['IdentifierType', ['Node']]]]]]]]]])
+
+ def test_tags_namespace(self):
+ """ Tests that the tags of structs/unions/enums reside in a separate namespace and
+ can be named after existing types.
+ """
+ s1 = """
+ typedef int tagEntry;
+
+ struct tagEntry
+ {
+ char* key;
+ char* value;
+ } Entry;
+ """
+
+ s1_ast = self.parse(s1)
+ self.assertEqual(expand_decl(s1_ast.ext[1]),
+ ['Decl', 'Entry',
+ ['TypeDecl', ['Struct', 'tagEntry',
+ [['Decl', 'key',
+ ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]],
+ ['Decl', 'value',
+ ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]]]]]])
+
+ s2 = """
+ struct tagEntry;
+
+ typedef struct tagEntry tagEntry;
+
+ struct tagEntry
+ {
+ char* key;
+ char* value;
+ } Entry;
+ """
+
+ s2_ast = self.parse(s2)
+ self.assertEqual(expand_decl(s2_ast.ext[2]),
+ ['Decl', 'Entry',
+ ['TypeDecl', ['Struct', 'tagEntry',
+ [['Decl', 'key',
+ ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]],
+ ['Decl', 'value',
+ ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]]]]]])
+
+ s3 = """
+ typedef int mytag;
+
+ enum mytag {ABC, CDE};
+ enum mytag joe;
+ """
+
+ s3_type = self.parse(s3).ext[1].type
+
+ self.assertTrue(isinstance(s3_type, Enum))
+ self.assertEqual(s3_type.name, 'mytag')
+
+ def test_multi_decls(self):
+ d1 = 'int a, b;'
+
+ self.assertEqual(self.get_decl(d1, 0),
+ ['Decl', 'a', ['TypeDecl', ['IdentifierType', ['int']]]])
+ self.assertEqual(self.get_decl(d1, 1),
+ ['Decl', 'b', ['TypeDecl', ['IdentifierType', ['int']]]])
+
+ d2 = 'char* p, notp, ar[4];'
+ self.assertEqual(self.get_decl(d2, 0),
+ ['Decl', 'p',
+ ['PtrDecl',
+ ['TypeDecl', ['IdentifierType', ['char']]]]])
+ self.assertEqual(self.get_decl(d2, 1),
+ ['Decl', 'notp', ['TypeDecl', ['IdentifierType', ['char']]]])
+ self.assertEqual(self.get_decl(d2, 2),
+ ['Decl', 'ar',
+ ['ArrayDecl', '4',
+ ['TypeDecl', ['IdentifierType', ['char']]]]])
+
+ def test_invalid_multiple_types_error(self):
+ bad = [
+ 'int enum {ab, cd} fubr;',
+ 'enum kid char brbr;']
+
+ for b in bad:
+ self.assertRaises(ParseError, self.parse, b)
+
+ def test_decl_inits(self):
+ d1 = 'int a = 16;'
+ self.assertEqual(self.get_decl(d1),
+ ['Decl', 'a', ['TypeDecl', ['IdentifierType', ['int']]]])
+ self.assertEqual(self.get_decl_init(d1),
+ ['Constant', 'int', '16'])
+
+ d2 = 'long ar[] = {7, 8, 9};'
+ self.assertEqual(self.get_decl(d2),
+ ['Decl', 'ar',
+ ['ArrayDecl', '',
+ ['TypeDecl', ['IdentifierType', ['long']]]]])
+ self.assertEqual(self.get_decl_init(d2),
+ [ ['Constant', 'int', '7'],
+ ['Constant', 'int', '8'],
+ ['Constant', 'int', '9'],])
+
+ d3 = 'char p = j;'
+ self.assertEqual(self.get_decl(d3),
+ ['Decl', 'p', ['TypeDecl', ['IdentifierType', ['char']]]])
+ self.assertEqual(self.get_decl_init(d3),
+ ['ID', 'j'])
+
+ d4 = "char x = 'c', *p = {0, 1, 2, {4, 5}, 6};"
+ self.assertEqual(self.get_decl(d4, 0),
+ ['Decl', 'x', ['TypeDecl', ['IdentifierType', ['char']]]])
+ self.assertEqual(self.get_decl_init(d4, 0),
+ ['Constant', 'char', "'c'"])
+ self.assertEqual(self.get_decl(d4, 1),
+ ['Decl', 'p',
+ ['PtrDecl',
+ ['TypeDecl', ['IdentifierType', ['char']]]]])
+ self.assertEqual(self.get_decl_init(d4, 1),
+ [ ['Constant', 'int', '0'],
+ ['Constant', 'int', '1'],
+ ['Constant', 'int', '2'],
+ [ ['Constant', 'int', '4'],
+ ['Constant', 'int', '5']],
+ ['Constant', 'int', '6']])
+
+ def test_function_definitions(self):
+ def parse_fdef(str):
+ return self.parse(str).ext[0]
+
+ def fdef_decl(fdef):
+ return expand_decl(fdef.decl)
+
+ f1 = parse_fdef('''
+ int factorial(int p)
+ {
+ return 3;
+ }
+ ''')
+
+ self.assertEqual(fdef_decl(f1),
+ ['Decl', 'factorial',
+ ['FuncDecl',
+ [['Decl', 'p', ['TypeDecl', ['IdentifierType', ['int']]]]],
+ ['TypeDecl', ['IdentifierType', ['int']]]]])
+
+ self.assertEqual(type(f1.body.stmts[0]), Return)
+ self.assertEqual(f1.body.decls, None)
+
+ f2 = parse_fdef('''
+ char* zzz(int p, char* c)
+ {
+ int a;
+ char b;
+
+ a = b + 2;
+ return 3;
+ }
+ ''')
+
+ self.assertEqual(fdef_decl(f2),
+ ['Decl', 'zzz',
+ ['FuncDecl',
+ [ ['Decl', 'p', ['TypeDecl', ['IdentifierType', ['int']]]],
+ ['Decl', 'c', ['PtrDecl',
+ ['TypeDecl', ['IdentifierType', ['char']]]]]],
+ ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]]])
+
+ self.assertEqual(list(map(type, f2.body.stmts)),
+ [Assignment, Return])
+ self.assertEqual(len(f2.body.decls), 2)
+
+ f3 = parse_fdef('''
+ char* zzz(p, c)
+ long p, *c;
+ {
+ int a;
+ char b;
+
+ a = b + 2;
+ return 3;
+ }
+ ''')
+
+ self.assertEqual(fdef_decl(f3),
+ ['Decl', 'zzz',
+ ['FuncDecl',
+ [ ['ID', 'p'],
+ ['ID', 'c']],
+ ['PtrDecl', ['TypeDecl', ['IdentifierType', ['char']]]]]])
+
+ self.assertEqual(list(map(type, f3.body.stmts)),
+ [Assignment, Return])
+ self.assertEqual(len(f3.body.decls), 2)
+
+ self.assertEqual(expand_decl(f3.param_decls[0]),
+ ['Decl', 'p', ['TypeDecl', ['IdentifierType', ['long']]]])
+ self.assertEqual(expand_decl(f3.param_decls[1]),
+ ['Decl', 'c', ['PtrDecl', ['TypeDecl', ['IdentifierType', ['long']]]]])
+
+
+class TestCParser_whole_code(unittest.TestCase):
+ """ Testing of parsing whole chunks of code.
+
+ Since I don't want to rely on the structure of ASTs too
+ much, most of these tests are implemented with visitors.
+ """
+ def parse(self, txt, filename=''):
+ return self.cparser.parse(txt, filename)
+
+ def setUp(self):
+ self.cparser = _c_parser
+
+ # A simple helper visitor that lists the values of all the
+ # Constant nodes it sees.
+ #
+ class ConstantVisitor(NodeVisitor):
+ def __init__(self):
+ self.values = []
+
+ def visit_Constant(self, node):
+ self.values.append(node.value)
+
+ # This visitor counts the amount of references to the ID
+ # with the name provided to it in the constructor.
+ #
+ class IDNameCounter(NodeVisitor):
+ def __init__(self, name):
+ self.name = name
+ self.nrefs = 0
+
+ def visit_ID(self, node):
+ if node.name == self.name:
+ self.nrefs += 1
+
+ # Counts the amount of nodes of a given class
+ #
+ class NodeKlassCounter(NodeVisitor):
+ def __init__(self, node_klass):
+ self.klass = node_klass
+ self.n = 0
+
+ def generic_visit(self, node):
+ if node.__class__ == self.klass:
+ self.n += 1
+
+ NodeVisitor.generic_visit(self, node)
+
+ def assert_all_Constants(self, code, constants):
+ """ Asserts that the list of all Constant values (by
+ 'preorder' appearance) in the chunk of code is as
+ given.
+ """
+ parsed = self.parse(code)
+ cv = self.ConstantVisitor()
+ cv.visit(parsed)
+ self.assertEqual(cv.values, constants)
+
+ def assert_num_ID_refs(self, code, name, num):
+ """ Asserts the number of references to the ID with
+ the given name.
+ """
+ if isinstance(code, str):
+ parsed = self.parse(code)
+ else:
+ parsed = code
+
+ iv = self.IDNameCounter(name)
+ iv.visit(parsed)
+ self.assertEqual(iv.nrefs, num)
+
+ def assert_num_klass_nodes(self, code, klass, num):
+ """ Asserts the amount of klass nodes in the code.
+ """
+ if isinstance(code, str):
+ parsed = self.parse(code)
+ else:
+ parsed = code
+
+ cv = self.NodeKlassCounter(klass)
+ cv.visit(parsed)
+ self.assertEqual(cv.n, num)
+
+ def test_expressions(self):
+ e1 = '''int k = (r + 10.0) >> 6 + 8 << (3 & 0x14);'''
+ self.assert_all_Constants(e1, ['10.0', '6', '8', '3', '0x14'])
+
+ e2 = r'''char n = '\n', *prefix = "st_";'''
+ self.assert_all_Constants(e2, [r"'\n'", '"st_"'])
+
+ def test_statements(self):
+ s1 = r'''
+ void foo(){
+ if (sp == 1)
+ if (optind >= argc ||
+ argv[optind][0] != '-' || argv[optind][1] == '\0')
+ return -1;
+ else if (strcmp(argv[optind], "--") == 0) {
+ optind++;
+ return -1;
+ }
+ }
+ '''
+
+ self.assert_all_Constants(s1,
+ ['1', '0', r"'-'", '1', r"'\0'", '1', r'"--"', '0', '1'])
+
+ ps1 = self.parse(s1)
+ self.assert_num_ID_refs(ps1, 'argv', 3)
+ self.assert_num_ID_refs(ps1, 'optind', 5)
+
+ self.assert_num_klass_nodes(ps1, If, 3)
+ self.assert_num_klass_nodes(ps1, Return, 2)
+ self.assert_num_klass_nodes(ps1, FuncCall, 1) # strcmp
+ self.assert_num_klass_nodes(ps1, BinaryOp, 7)
+
+ # In the following code, Hash and Node were defined as
+ # int to pacify the parser that sees they're used as
+ # types
+ #
+ s2 = r'''
+ typedef int Hash, Node;
+
+ 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);
+ }
+ '''
+
+ ps2 = self.parse(s2)
+ self.assert_num_klass_nodes(ps2, FuncCall, 6)
+ self.assert_num_klass_nodes(ps2, FuncDef, 1)
+ self.assert_num_klass_nodes(ps2, For, 1)
+ self.assert_num_klass_nodes(ps2, While, 1)
+ self.assert_num_klass_nodes(ps2, StructRef, 10)
+
+ # declarations don't count
+ self.assert_num_ID_refs(ps2, 'hash', 6)
+ self.assert_num_ID_refs(ps2, 'i', 4)
+
+ def test_whole_file(self):
+ # See how pycparser handles a whole, real C file.
+ #
+ filename = 'c_files/memmgr_with_h.c'
+ code = open(filename, 'rU').read()
+ p = self.parse(code)
+
+ self.assert_num_klass_nodes(p, FuncDef, 5)
+
+ # each FuncDef also has a FuncDecl. 4 declarations
+ # + 5 definitions, overall 9
+ self.assert_num_klass_nodes(p, FuncDecl, 9)
+
+ self.assert_num_klass_nodes(p, Typedef, 4)
+
+ self.assertEqual(p.ext[4].coord.line, 88)
+ self.assertEqual(p.ext[4].coord.file, "./memmgr.h")
+
+ self.assertEqual(p.ext[6].coord.line, 10)
+ self.assertEqual(p.ext[6].coord.file, "memmgr.c")
+
+ def test_whole_file_with_stdio(self):
+ # Parse a whole file with stdio.h included by cpp
+ #
+ filename = 'c_files/cppd_with_stdio_h.c'
+ code = open(filename, 'rU').read()
+ p = self.parse(code)
+
+ self.failUnless(isinstance(p.ext[0], Typedef))
+ self.assertEqual(p.ext[0].coord.line, 213)
+ self.assertEqual(p.ext[0].coord.file, "D:\eli\cpp_stuff\libc_include/stddef.h")
+
+ self.failUnless(isinstance(p.ext[-1], FuncDef))
+ self.assertEqual(p.ext[-1].coord.line, 15)
+ self.assertEqual(p.ext[-1].coord.file, "example_c_file.c")
+
+ self.failUnless(isinstance(p.ext[-8], Typedef))
+ self.failUnless(isinstance(p.ext[-8].type, TypeDecl))
+ self.assertEqual(p.ext[-8].name, 'cookie_io_functions_t')
+
+
+if __name__ == '__main__':
+ #~ suite = unittest.TestLoader().loadTestsFromNames(
+ #~ ['test_c_parser.TestCParser_fundamentals.test_typedef'])
+
+ #~ suite = unittest.TestLoader().loadTestsFromNames(
+ #~ ['test_c_parser.TestCParser_whole_code.test_whole_file_with_stdio'])
+
+ #~ suite = unittest.TestLoader().loadTestsFromTestCase(
+ #~ TestCParser_whole_code)
+
+ #~ unittest.TextTestRunner(verbosity=2).run(suite)
+ unittest.main()
diff --git a/tests/test_general.py b/tests/test_general.py
new file mode 100644
index 0000000..882a1ed
--- /dev/null
+++ b/tests/test_general.py
@@ -0,0 +1,37 @@
+import sys
+import unittest
+
+sys.path.insert(0, '..')
+from pycparser import parse_file, c_ast
+
+# Portable cpp path for Windows and Linux/Unix
+CPPPATH = '../utils/cpp.exe' if sys.platform == 'win32' else 'cpp'
+
+
+# Test successful parsing
+#
+class TestParsing(unittest.TestCase):
+ def test_without_cpp(self):
+ ast = parse_file('c_files/example_c_file.c')
+ self.failUnless(isinstance(ast, c_ast.FileAST))
+
+ def test_with_cpp(self):
+ ast = parse_file('c_files/memmgr.c', use_cpp=True,
+ cpp_path=CPPPATH,
+ cpp_args=r'-I../utils/fake_libc_include')
+ self.failUnless(isinstance(ast, c_ast.FileAST))
+
+ ast2 = parse_file('c_files/year.c', use_cpp=True,
+ cpp_path=CPPPATH,
+ cpp_args=r'-I../utils/fake_libc_include')
+
+ self.failUnless(isinstance(ast2, c_ast.FileAST))
+
+
+if __name__ == '__main__':
+ unittest.main()
+
+
+
+
+
diff --git a/utils/cpp.exe b/utils/cpp.exe
new file mode 100644
index 0000000..60c7787
--- /dev/null
+++ b/utils/cpp.exe
Binary files differ
diff --git a/utils/fake_libc_include/_ansi.h b/utils/fake_libc_include/_ansi.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/_ansi.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/_fake_defines.h b/utils/fake_libc_include/_fake_defines.h
new file mode 100644
index 0000000..4a30792
--- /dev/null
+++ b/utils/fake_libc_include/_fake_defines.h
@@ -0,0 +1,28 @@
+#ifndef _FAKE_DEFINES_H
+#define _FAKE_DEFINES_H
+
+#define NULL 0
+#define BUFSIZ 1024
+#define FOPEN_MAX 20
+#define FILENAME_MAX 1024
+
+#ifndef SEEK_SET
+#define SEEK_SET 0 /* set file offset to offset */
+#endif
+#ifndef SEEK_CUR
+#define SEEK_CUR 1 /* set file offset to current plus offset */
+#endif
+#ifndef SEEK_END
+#define SEEK_END 2 /* set file offset to EOF plus offset */
+#endif
+
+
+#define EXIT_FAILURE 1
+#define EXIT_SUCCESS 0
+
+#define RAND_MAX 32767
+#define INT_MAX 32767
+
+
+
+#endif
diff --git a/utils/fake_libc_include/_fake_typedefs.h b/utils/fake_libc_include/_fake_typedefs.h
new file mode 100644
index 0000000..344cbc6
--- /dev/null
+++ b/utils/fake_libc_include/_fake_typedefs.h
@@ -0,0 +1,80 @@
+#ifndef _FAKE_TYPEDEFS_H
+#define _FAKE_TYPEDEFS_H
+
+typedef int size_t;
+typedef int __builtin_va_list;
+typedef int __gnuc_va_list;
+typedef int __int8_t;
+typedef int __uint8_t;
+typedef int __int16_t;
+typedef int __uint16_t;
+typedef int __int_least16_t;
+typedef int __uint_least16_t;
+typedef int __int32_t;
+typedef int __uint32_t;
+typedef int __int_least32_t;
+typedef int __uint_least32_t;
+typedef int _LOCK_T;
+typedef int _LOCK_RECURSIVE_T;
+typedef int _off_t;
+typedef int __dev_t;
+typedef int __uid_t;
+typedef int __gid_t;
+typedef int _off64_t;
+typedef int _fpos_t;
+typedef int _ssize_t;
+typedef int wint_t;
+typedef int _mbstate_t;
+typedef int _flock_t;
+typedef int _iconv_t;
+typedef int __ULong;
+typedef int __FILE;
+typedef int ptrdiff_t;
+typedef int wchar_t;
+typedef int __off_t;
+typedef int __pid_t;
+typedef int __loff_t;
+typedef int u_char;
+typedef int u_short;
+typedef int u_int;
+typedef int u_long;
+typedef int ushort;
+typedef int uint;
+typedef int clock_t;
+typedef int time_t;
+typedef int daddr_t;
+typedef int caddr_t;
+typedef int ino_t;
+typedef int off_t;
+typedef int dev_t;
+typedef int uid_t;
+typedef int gid_t;
+typedef int pid_t;
+typedef int key_t;
+typedef int ssize_t;
+typedef int mode_t;
+typedef int nlink_t;
+typedef int fd_mask;
+typedef int _types_fd_set;
+typedef int clockid_t;
+typedef int timer_t;
+typedef int useconds_t;
+typedef int suseconds_t;
+typedef int FILE;
+typedef int fpos_t;
+typedef int cookie_read_function_t;
+typedef int cookie_write_function_t;
+typedef int cookie_seek_function_t;
+typedef int cookie_close_function_t;
+typedef int cookie_io_functions_t;
+typedef int div_t;
+typedef int ldiv_t;
+typedef int lldiv_t;
+typedef int sigset_t;
+typedef int _sig_func_ptr;
+typedef int sig_atomic_t;
+typedef int __tzrule_type;
+typedef int __tzinfo_type;
+typedef int mbstate_t;
+
+#endif
diff --git a/utils/fake_libc_include/_syslist.h b/utils/fake_libc_include/_syslist.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/_syslist.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/alloca.h b/utils/fake_libc_include/alloca.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/alloca.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/ar.h b/utils/fake_libc_include/ar.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/ar.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/argz.h b/utils/fake_libc_include/argz.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/argz.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/assert.h b/utils/fake_libc_include/assert.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/assert.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/ctype.h b/utils/fake_libc_include/ctype.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/ctype.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/dirent.h b/utils/fake_libc_include/dirent.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/dirent.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/envz.h b/utils/fake_libc_include/envz.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/envz.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/errno.h b/utils/fake_libc_include/errno.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/errno.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/fastmath.h b/utils/fake_libc_include/fastmath.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/fastmath.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/fcntl.h b/utils/fake_libc_include/fcntl.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/fcntl.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/getopt.h b/utils/fake_libc_include/getopt.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/getopt.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/grp.h b/utils/fake_libc_include/grp.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/grp.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/iconv.h b/utils/fake_libc_include/iconv.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/iconv.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/ieeefp.h b/utils/fake_libc_include/ieeefp.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/ieeefp.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/inttypes.h b/utils/fake_libc_include/inttypes.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/inttypes.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/langinfo.h b/utils/fake_libc_include/langinfo.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/langinfo.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/libgen.h b/utils/fake_libc_include/libgen.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/libgen.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/limits.h b/utils/fake_libc_include/limits.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/limits.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/locale.h b/utils/fake_libc_include/locale.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/locale.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/malloc.h b/utils/fake_libc_include/malloc.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/malloc.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/math.h b/utils/fake_libc_include/math.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/math.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/newlib.h b/utils/fake_libc_include/newlib.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/newlib.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/paths.h b/utils/fake_libc_include/paths.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/paths.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/process.h b/utils/fake_libc_include/process.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/process.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/pthread.h b/utils/fake_libc_include/pthread.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/pthread.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/pwd.h b/utils/fake_libc_include/pwd.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/pwd.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/reent.h b/utils/fake_libc_include/reent.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/reent.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/regdef.h b/utils/fake_libc_include/regdef.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/regdef.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/sched.h b/utils/fake_libc_include/sched.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/sched.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/search.h b/utils/fake_libc_include/search.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/search.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/setjmp.h b/utils/fake_libc_include/setjmp.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/setjmp.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/signal.h b/utils/fake_libc_include/signal.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/signal.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/stdarg.h b/utils/fake_libc_include/stdarg.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/stdarg.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/stddef.h b/utils/fake_libc_include/stddef.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/stddef.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/stdint.h b/utils/fake_libc_include/stdint.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/stdint.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/stdio.h b/utils/fake_libc_include/stdio.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/stdio.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/stdlib.h b/utils/fake_libc_include/stdlib.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/stdlib.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/string.h b/utils/fake_libc_include/string.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/string.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/tar.h b/utils/fake_libc_include/tar.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/tar.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/termios.h b/utils/fake_libc_include/termios.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/termios.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/time.h b/utils/fake_libc_include/time.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/time.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/unctrl.h b/utils/fake_libc_include/unctrl.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/unctrl.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/unistd.h b/utils/fake_libc_include/unistd.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/unistd.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/utime.h b/utils/fake_libc_include/utime.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/utime.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/utmp.h b/utils/fake_libc_include/utmp.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/utmp.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/wchar.h b/utils/fake_libc_include/wchar.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/wchar.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/fake_libc_include/wctype.h b/utils/fake_libc_include/wctype.h
new file mode 100644
index 0000000..f2992f3
--- /dev/null
+++ b/utils/fake_libc_include/wctype.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/utils/internal/cppify.bat b/utils/internal/cppify.bat
new file mode 100644
index 0000000..fb16db5
--- /dev/null
+++ b/utils/internal/cppify.bat
@@ -0,0 +1,3 @@
+REM ~ ..\cpp -D__i386__ -I"D:\eli\cpp_stuff\libc_include" -D__extension__ example_c_file.c > example_c_file_pp.c
+REM ~ ..\cpp -D__i386__ -I"D:\eli\c_analyzing\pycparser-trunk\utils\fake_libc_include" example_c_file.c > example_c_file_pp.c
+..\cpp -D__i386__ -I"D:\eli\c_analyzing\pycparser-trunk\utils\fake_libc_include" zc.c > zc_pp.c
diff --git a/utils/internal/example_c_file.c b/utils/internal/example_c_file.c
new file mode 100644
index 0000000..44564ac
--- /dev/null
+++ b/utils/internal/example_c_file.c
@@ -0,0 +1,25 @@
+/* a comment / */
+/* "not a string" */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include <signal.h>
+#include <time.h>
+#include <wchar.h>
+
+/*
+ multiline comment
+ comment
+*/
+
+int main()
+{
+ auto char* multi = "a multi"; /* and a comment !*/
+}
+
+/* A final comment for good measure /* /* /* */
+
+
+
diff --git a/utils/internal/fake_includes.py b/utils/internal/fake_includes.py
new file mode 100644
index 0000000..b55f767
--- /dev/null
+++ b/utils/internal/fake_includes.py
@@ -0,0 +1,13 @@
+import os.path
+
+for cur_path, dirs, files in os.walk('.'):
+ if cur_path == '.':
+ for f in files:
+ if f.endswith('.h'):
+ print f
+ fo = open(f, 'w')
+ fo.write('#include "_fake_defines.h"\n')
+ fo.write('#include "_fake_typedefs.h"\n')
+ fo.close()
+
+
diff --git a/utils/internal/make_fake_typedefs.py b/utils/internal/make_fake_typedefs.py
new file mode 100644
index 0000000..68f57b3
--- /dev/null
+++ b/utils/internal/make_fake_typedefs.py
@@ -0,0 +1,21 @@
+import sys
+sys.path.insert(0, '../..')
+
+from pycparser import c_parser, c_ast, parse_file
+
+
+class MyVisitor(c_ast.NodeVisitor):
+ def visit_Typedef(self, node):
+ print 'typedef int %s;' % node.name
+
+
+
+def generate_fake_typedefs(filename):
+ ast = parse_file(filename, use_cpp=True, cpp_path="../cpp.exe")
+ v = MyVisitor()
+ v.visit(ast)
+
+
+if __name__ == "__main__":
+ generate_fake_typedefs('example_c_file_pp.c')
+
diff --git a/utils/internal/zc.c b/utils/internal/zc.c
new file mode 100644
index 0000000..eff94bd
--- /dev/null
+++ b/utils/internal/zc.c
@@ -0,0 +1,107 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+
+#define PACKAGE "wgram"
+#define VERSION "0.0.4"
+#define MAXLINE 1024
+#define MAXGRAM 32
+
+/* status epilepticus .. print help */
+void print_help(int exval);
+
+int main (int argc, char *argv[]) {
+ /* word delimeter for strtok() */
+ char delim[] = ".,:;`/\"+-_(){}[]<>*&^%$#@!?~/|\\=1234567890 \t\n";
+ char line[MAXLINE]; /* input buff, fgets() */
+ char *stray = NULL; /* returned value by strtok() */
+ char **strarray = NULL; /* array to hold all entrys */
+ int i = 0; /* general counter */
+ int strcount = 0; /* number of entrys in pointer array */
+ int N = 3, pos = 0; /* ngram size, 3 in this case */
+ int opt = 0; /* holds command line opt nr.. */
+ int word_flag = 0; /* print only the `raw' words */
+ FILE *fp = stdin; /* read input from `FILE', default is stdin */
+
+ while((opt = getopt(argc, argv, "hvn:wf:")) != -1) {
+ switch(opt) {
+ case 'h':
+ print_help(0);
+ break;
+ case 'v':
+ exit(0);
+ break;
+ case 'n':
+ N = atoi(optarg);
+ if(N > MAXGRAM || N < 2) {
+ fprintf(stderr, "%s: Error - Ngram length `%d' out of range `0-%d'\n",
+ PACKAGE, N, MAXGRAM);
+ return 1;
+ }
+ break;
+ case 'w':
+ word_flag = 1;
+ break;
+ case 'f':
+ if(freopen(optarg, "r", fp) == NULL) {
+ fprintf(stderr, "%s: Error - opening `%s'\n", PACKAGE, optarg);
+ return 1;
+ }
+ break;
+ case '?':
+ fprintf(stderr, "%s: Error - No such option: `%c'\n\n", PACKAGE, optopt);
+ print_help(1);
+ } /* switch */
+ } /* while */
+
+ /* start reading lines from file pointer, add all entrys to **strarray */
+ while((fgets(line, MAXLINE, fp)) != NULL) {
+ if(strlen(line) < 2)
+ continue;
+
+ stray = strtok(line, delim);
+ while(stray != NULL) {
+ strarray = (char **)realloc(strarray, (strcount + 1) * sizeof(char *));
+ strarray[strcount++] = strdup(stray);
+ stray = strtok(NULL, delim);
+ }
+ }
+
+ if(word_flag == 0) {
+ /*
+ // print the array of strings, jumping back each time
+ // (N - 1) positions if a whole ngram of words has been printed
+ */
+ for(i = 0, pos = N; i < strcount; i++, pos--) {
+ if(pos == 0) pos = N, i -= (N - 1), printf("\n");
+ printf("%s ", strarray[i]);
+ }
+ printf("\n");
+ } else {
+ /* print raw words */
+ for(i = 0; i < strcount; i++)
+ printf("%s\n", strarray[i]);
+ }
+
+ /* free the string array */
+ for(i = 0; i < strcount; i++)
+ free(strarray[i]);
+
+ free(strarray);
+ return 0;
+}
+
+/* status epilepticus .. print help */
+void print_help(int exval) {
+ printf("%s,%s extract N-grams from text data\n", PACKAGE, VERSION);
+ printf("Usage: %s [-h] [-v] [-n INT] [-w] [-f FILE]\n\n", PACKAGE);
+
+ printf(" -h print this help and exit\n");
+ printf(" -v print version and exit\n\n");
+
+ printf(" -n INT set ngram length (default=3)\n");
+ printf(" -w print only the extracted words\n");
+ printf(" -f FILE read input from `FILE' (default=stdin)\n\n");
+ exit(exval);
+}
diff --git a/utils/internal/zz_parse.py b/utils/internal/zz_parse.py
new file mode 100644
index 0000000..6251a9f
--- /dev/null
+++ b/utils/internal/zz_parse.py
@@ -0,0 +1,10 @@
+import sys
+sys.path.insert(0, '../..')
+
+from pycparser import c_parser, c_ast, parse_file
+
+
+if __name__ == "__main__":
+ ast = parse_file('zc_pp.c', use_cpp=True, cpp_path="../cpp.exe")
+
+
diff --git a/z_test.py b/z_test.py
new file mode 100644
index 0000000..1eec2a0
--- /dev/null
+++ b/z_test.py
@@ -0,0 +1,75 @@
+from pycparser.c_ast import *
+from pycparser.c_parser import CParser, Coord, ParseError
+
+
+def expand_decl(decl):
+ """ Converts the declaration into a nested list.
+ """
+ typ = type(decl)
+
+ if typ == TypeDecl:
+ return ['TypeDecl', expand_decl(decl.type)]
+ elif typ == IdentifierType:
+ return ['IdentifierType', decl.names]
+ elif typ == ID:
+ return ['ID', decl.name]
+ elif typ in [Struct, Union]:
+ decls = [expand_decl(d) for d in decl.decls or []]
+ return [typ.__name__, decl.name, decls]
+ else:
+ nested = expand_decl(decl.type)
+
+ if typ == Decl:
+ if decl.quals:
+ return ['Decl', decl.quals, decl.name, nested]
+ else:
+ return ['Decl', decl.name, nested]
+ elif typ == Typename: # for function parameters
+ if decl.quals:
+ return ['Typename', decl.quals, nested]
+ else:
+ return ['Typename', nested]
+ elif typ == ArrayDecl:
+ dimval = decl.dim.value if decl.dim else ''
+ return ['ArrayDecl', dimval, nested]
+ elif typ == PtrDecl:
+ return ['PtrDecl', nested]
+ elif typ == Typedef:
+ return ['Typedef', decl.name, nested]
+ elif typ == FuncDecl:
+ if decl.args:
+ params = [expand_decl(param) for param in decl.args.params]
+ else:
+ params = []
+ return ['FuncDecl', params, nested]
+
+#-----------------------------------------------------------------
+
+source_code = """
+int main()
+{
+ int a;
+ a = sizeof(int());
+}
+"""
+
+parser = CParser()
+ast = parser.parse(source_code)
+function_body = ast.ext[0].body #hardcoded to the main() function
+
+for stmt in function_body.stmts:
+ print stmt.coord, expand_decl(stmt.rvalue.expr.type)
+
+#~ class StructRefVisitor(c_ast.NodeVisitor):
+ #~ def visit_StructRef(self, node):
+ #~ print node.name.name, node.field.name
+
+
+#~ parser = c_parser.CParser()
+#~ ast = parser.parse(code)
+
+#~ ast.show()
+
+#~ v = StructRefVisitor()
+#~ v.visit(ast)
+