diff options
-rw-r--r-- | .hgignore | 1 | ||||
-rw-r--r-- | MANIFEST.in | 2 | ||||
-rw-r--r-- | README.html | 1049 | ||||
-rw-r--r-- | README.txt | 15 | ||||
-rw-r--r-- | examples/cdecl.py | 204 | ||||
-rw-r--r-- | pycparser/__init__.py | 2 | ||||
-rw-r--r-- | pycparser/_ast_gen.py | 495 | ||||
-rw-r--r-- | pycparser/_build_tables.py | 5 | ||||
-rw-r--r-- | pycparser/c_ast.py | 2474 | ||||
-rw-r--r-- | pycparser/c_parser.py | 2681 | ||||
-rw-r--r-- | setup.py | 4 |
11 files changed, 3477 insertions, 3455 deletions
@@ -3,6 +3,7 @@ syntax: glob *.pyc tests/parser.out tests/*tab.py +build diff --git a/MANIFEST.in b/MANIFEST.in index 22fa7fb..91b4533 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,6 +1,6 @@ recursive-include examples *.c *.h *.py
recursive-include tests *.c *.h *.py
-recursive-include pycparser *.py *.yaml
+recursive-include pycparser *.py *.cfg
include utils/*.exe
include utils/fake_libc_include/*.h
include README.*
diff --git a/README.html b/README.html index 3c4b4ff..3480054 100644 --- a/README.html +++ b/README.html @@ -1,523 +1,526 @@ -<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-<meta name="generator" content="Docutils 0.6: http://docutils.sourceforge.net/" />
-<title>pycparser v2.00</title>
-<meta name="author" content="Eli Bendersky" />
-<style type="text/css">
-
-/*
-:Author: David Goodger (goodger@python.org)
-:Id: $Id: html4css1.css 5951 2009-05-18 18:03:10Z milde $
-:Copyright: This stylesheet has been placed in the public domain.
-
-Default cascading style sheet for the HTML output of Docutils.
-
-See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
-customize this style sheet.
-*/
-
-/* used to remove borders from tables and images */
-.borderless, table.borderless td, table.borderless th {
- border: 0 }
-
-table.borderless td, table.borderless th {
- /* Override padding for "table.docutils td" with "! important".
- The right padding separates the table cells. */
- padding: 0 0.5em 0 0 ! important }
-
-.first {
- /* Override more specific margin styles with "! important". */
- margin-top: 0 ! important }
-
-.last, .with-subtitle {
- margin-bottom: 0 ! important }
-
-.hidden {
- display: none }
-
-a.toc-backref {
- text-decoration: none ;
- color: black }
-
-blockquote.epigraph {
- margin: 2em 5em ; }
-
-dl.docutils dd {
- margin-bottom: 0.5em }
-
-/* Uncomment (and remove this text!) to get bold-faced definition list terms
-dl.docutils dt {
- font-weight: bold }
-*/
-
-div.abstract {
- margin: 2em 5em }
-
-div.abstract p.topic-title {
- font-weight: bold ;
- text-align: center }
-
-div.admonition, div.attention, div.caution, div.danger, div.error,
-div.hint, div.important, div.note, div.tip, div.warning {
- margin: 2em ;
- border: medium outset ;
- padding: 1em }
-
-div.admonition p.admonition-title, div.hint p.admonition-title,
-div.important p.admonition-title, div.note p.admonition-title,
-div.tip p.admonition-title {
- font-weight: bold ;
- font-family: sans-serif }
-
-div.attention p.admonition-title, div.caution p.admonition-title,
-div.danger p.admonition-title, div.error p.admonition-title,
-div.warning p.admonition-title {
- color: red ;
- font-weight: bold ;
- font-family: sans-serif }
-
-/* Uncomment (and remove this text!) to get reduced vertical space in
- compound paragraphs.
-div.compound .compound-first, div.compound .compound-middle {
- margin-bottom: 0.5em }
-
-div.compound .compound-last, div.compound .compound-middle {
- margin-top: 0.5em }
-*/
-
-div.dedication {
- margin: 2em 5em ;
- text-align: center ;
- font-style: italic }
-
-div.dedication p.topic-title {
- font-weight: bold ;
- font-style: normal }
-
-div.figure {
- margin-left: 2em ;
- margin-right: 2em }
-
-div.footer, div.header {
- clear: both;
- font-size: smaller }
-
-div.line-block {
- display: block ;
- margin-top: 1em ;
- margin-bottom: 1em }
-
-div.line-block div.line-block {
- margin-top: 0 ;
- margin-bottom: 0 ;
- margin-left: 1.5em }
-
-div.sidebar {
- margin: 0 0 0.5em 1em ;
- border: medium outset ;
- padding: 1em ;
- background-color: #ffffee ;
- width: 40% ;
- float: right ;
- clear: right }
-
-div.sidebar p.rubric {
- font-family: sans-serif ;
- font-size: medium }
-
-div.system-messages {
- margin: 5em }
-
-div.system-messages h1 {
- color: red }
-
-div.system-message {
- border: medium outset ;
- padding: 1em }
-
-div.system-message p.system-message-title {
- color: red ;
- font-weight: bold }
-
-div.topic {
- margin: 2em }
-
-h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
-h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
- margin-top: 0.4em }
-
-h1.title {
- text-align: center }
-
-h2.subtitle {
- text-align: center }
-
-hr.docutils {
- width: 75% }
-
-img.align-left, .figure.align-left{
- clear: left ;
- float: left ;
- margin-right: 1em }
-
-img.align-right, .figure.align-right {
- clear: right ;
- float: right ;
- margin-left: 1em }
-
-.align-left {
- text-align: left }
-
-.align-center {
- clear: both ;
- text-align: center }
-
-.align-right {
- text-align: right }
-
-/* reset inner alignment in figures */
-div.align-right {
- text-align: left }
-
-/* div.align-center * { */
-/* text-align: left } */
-
-ol.simple, ul.simple {
- margin-bottom: 1em }
-
-ol.arabic {
- list-style: decimal }
-
-ol.loweralpha {
- list-style: lower-alpha }
-
-ol.upperalpha {
- list-style: upper-alpha }
-
-ol.lowerroman {
- list-style: lower-roman }
-
-ol.upperroman {
- list-style: upper-roman }
-
-p.attribution {
- text-align: right ;
- margin-left: 50% }
-
-p.caption {
- font-style: italic }
-
-p.credits {
- font-style: italic ;
- font-size: smaller }
-
-p.label {
- white-space: nowrap }
-
-p.rubric {
- font-weight: bold ;
- font-size: larger ;
- color: maroon ;
- text-align: center }
-
-p.sidebar-title {
- font-family: sans-serif ;
- font-weight: bold ;
- font-size: larger }
-
-p.sidebar-subtitle {
- font-family: sans-serif ;
- font-weight: bold }
-
-p.topic-title {
- font-weight: bold }
-
-pre.address {
- margin-bottom: 0 ;
- margin-top: 0 ;
- font: inherit }
-
-pre.literal-block, pre.doctest-block {
- margin-left: 2em ;
- margin-right: 2em }
-
-span.classifier {
- font-family: sans-serif ;
- font-style: oblique }
-
-span.classifier-delimiter {
- font-family: sans-serif ;
- font-weight: bold }
-
-span.interpreted {
- font-family: sans-serif }
-
-span.option {
- white-space: nowrap }
-
-span.pre {
- white-space: pre }
-
-span.problematic {
- color: red }
-
-span.section-subtitle {
- /* font-size relative to parent (h1..h6 element) */
- font-size: 80% }
-
-table.citation {
- border-left: solid 1px gray;
- margin-left: 1px }
-
-table.docinfo {
- margin: 2em 4em }
-
-table.docutils {
- margin-top: 0.5em ;
- margin-bottom: 0.5em }
-
-table.footnote {
- border-left: solid 1px black;
- margin-left: 1px }
-
-table.docutils td, table.docutils th,
-table.docinfo td, table.docinfo th {
- padding-left: 0.5em ;
- padding-right: 0.5em ;
- vertical-align: top }
-
-table.docutils th.field-name, table.docinfo th.docinfo-name {
- font-weight: bold ;
- text-align: left ;
- white-space: nowrap ;
- padding-left: 0 }
-
-h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
-h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
- font-size: 100% }
-
-ul.auto-toc {
- list-style-type: none }
-
-</style>
-</head>
-<body>
-<div class="document" id="pycparser-v2-00">
-<h1 class="title">pycparser v2.00</h1>
-<table class="docinfo" frame="void" rules="none">
-<col class="docinfo-name" />
-<col class="docinfo-content" />
-<tbody valign="top">
-<tr><th class="docinfo-name">Author:</th>
-<td><a class="first reference external" href="http://eli.thegreenplace.net">Eli Bendersky</a></td></tr>
-</tbody>
-</table>
-<div class="contents topic" id="contents">
-<p class="topic-title first">Contents</p>
-<ul class="auto-toc simple">
-<li><a class="reference internal" href="#introduction" id="id2">1 Introduction</a><ul class="auto-toc">
-<li><a class="reference internal" href="#what-is-pycparser" id="id3">1.1 What is pycparser?</a></li>
-<li><a class="reference internal" href="#what-is-it-good-for" id="id4">1.2 What is it good for?</a></li>
-<li><a class="reference internal" href="#which-version-of-c-does-pycparser-support" id="id5">1.3 Which version of C does pycparser support?</a></li>
-<li><a class="reference internal" href="#what-grammar-does-pycparser-follow" id="id6">1.4 What grammar does pycparser follow?</a></li>
-<li><a class="reference internal" href="#what-is-an-ast" id="id7">1.5 What is an AST?</a></li>
-<li><a class="reference internal" href="#how-is-pycparser-licensed" id="id8">1.6 How is pycparser licensed?</a></li>
-<li><a class="reference internal" href="#contact-details" id="id9">1.7 Contact details</a></li>
-</ul>
-</li>
-<li><a class="reference internal" href="#installing" id="id10">2 Installing</a><ul class="auto-toc">
-<li><a class="reference internal" href="#prerequisites" id="id11">2.1 Prerequisites</a></li>
-<li><a class="reference internal" href="#installation-process" id="id12">2.2 Installation process</a></li>
-</ul>
-</li>
-<li><a class="reference internal" href="#using" id="id13">3 Using</a><ul class="auto-toc">
-<li><a class="reference internal" href="#interaction-with-the-c-preprocessor" id="id14">3.1 Interaction with the C preprocessor</a></li>
-<li><a class="reference internal" href="#what-about-the-standard-c-library-headers" id="id15">3.2 What about the standard C library headers?</a></li>
-<li><a class="reference internal" href="#basic-usage" id="id16">3.3 Basic usage</a></li>
-<li><a class="reference internal" href="#advanced-usage" id="id17">3.4 Advanced usage</a></li>
-</ul>
-</li>
-<li><a class="reference internal" href="#modifying" id="id18">4 Modifying</a></li>
-<li><a class="reference internal" href="#package-contents" id="id19">5 Package contents</a></li>
-<li><a class="reference internal" href="#contributors" id="id20">6 Contributors</a></li>
-<li><a class="reference internal" href="#changelog" id="id21">7 Changelog</a></li>
-</ul>
-</div>
-<div class="section" id="introduction">
-<h1>1 Introduction</h1>
-<div class="section" id="what-is-pycparser">
-<h2>1.1 What is pycparser?</h2>
-<p><tt class="docutils literal"><span class="pre">pycparser</span></tt> is a parser for the C language, written in pure Python. It is a module designed to be easily integrated into applications that need to parse C source code.</p>
-</div>
-<div class="section" id="what-is-it-good-for">
-<h2>1.2 What is it good for?</h2>
-<p>Anything that needs C code to be parsed. The following are some uses for <tt class="docutils literal"><span class="pre">pycparser</span></tt>, taken from real user reports:</p>
-<ul class="simple">
-<li>C code obfuscator</li>
-<li>Front-end for various specialized C compilers</li>
-<li>Static code checker</li>
-<li>Automatic unit-test discovery</li>
-<li>Adding specialized extensions to the C language</li>
-</ul>
-<p><tt class="docutils literal"><span class="pre">pycparser</span></tt> is unique in the sense that it's written in pure Python - a very high level language that's easy to experiment with and tweak. To people familiar with Lex and Yacc, <tt class="docutils literal"><span class="pre">pycparser</span></tt>'s code will be simple to understand.</p>
-</div>
-<div class="section" id="which-version-of-c-does-pycparser-support">
-<h2>1.3 Which version of C does pycparser support?</h2>
-<p><tt class="docutils literal"><span class="pre">pycparser</span></tt> aims to support the full C99 language (according to the standard ISO/IEC 9899). This is a new feature in the version 2.x series - earlier versions only supported C89. For more information on the change, read <a class="reference external" href="http://code.google.com/p/pycparser/wiki/C99support">this wiki page</a>.</p>
-<p><tt class="docutils literal"><span class="pre">pycparser</span></tt> doesn't support any GCC extensions.</p>
-</div>
-<div class="section" id="what-grammar-does-pycparser-follow">
-<h2>1.4 What grammar does pycparser follow?</h2>
-<p><tt class="docutils literal"><span class="pre">pycparser</span></tt> very closely follows the C grammar provided in the end of the C99 standard document</p>
-</div>
-<div class="section" id="what-is-an-ast">
-<h2>1.5 What is an AST?</h2>
-<p><a class="reference external" href="http://en.wikipedia.org/wiki/Abstract_syntax_tree">AST</a> - Abstract Syntax Tree. It is a tree representation of the syntax of source code - a convenient hierarchical data structure that's built from the code and is readily suitable for exploration and manipulation.</p>
-</div>
-<div class="section" id="how-is-pycparser-licensed">
-<h2>1.6 How is pycparser licensed?</h2>
-<p><a class="reference external" href="http://www.gnu.org/licenses/lgpl.html">LGPL</a></p>
-</div>
-<div class="section" id="contact-details">
-<h2>1.7 Contact details</h2>
-<p>Drop me an email to <a class="reference external" href="mailto:eliben@gmail.com">eliben@gmail.com</a> for any questions regarding <tt class="docutils literal"><span class="pre">pycparser</span></tt>. For reporting problems with <tt class="docutils literal"><span class="pre">pycparser</span></tt> or submitting feature requests, the best way is to open an issue on the <a class="reference external" href="http://code.google.com/p/pycparser/">pycparser page at Google Code</a>.</p>
-</div>
-</div>
-<div class="section" id="installing">
-<h1>2 Installing</h1>
-<div class="section" id="prerequisites">
-<h2>2.1 Prerequisites</h2>
-<ul class="simple">
-<li><tt class="docutils literal"><span class="pre">pycparser</span></tt> was tested on Python 2.5, 2.6 and 3.1, on both Linux and Windows</li>
-<li><tt class="docutils literal"><span class="pre">pycparser</span></tt> uses the PLY module for the actual lexer and parser construction. Install PLY version 3.3 (earlier versions work at least since 2.5) from <a class="reference external" href="http://www.dabeaz.com/ply/">its website</a>.</li>
-<li>If you want to modify <tt class="docutils literal"><span class="pre">pycparser</span></tt>'s code, you'll need to install <a class="reference external" href="http://pyyaml.org/">PyYAML</a>, since it's used by <tt class="docutils literal"><span class="pre">pycparser</span></tt> to store the AST configuration in a YAML file.</li>
-</ul>
-</div>
-<div class="section" id="installation-process">
-<h2>2.2 Installation process</h2>
-<p>Installing <tt class="docutils literal"><span class="pre">pycparser</span></tt> is very simple. Once you download it from its <a class="reference external" href="http://code.google.com/p/pycparser/">website</a> and unzip the package, you just have to execute the standard <tt class="docutils literal"><span class="pre">python</span> <span class="pre">setup.py</span> <span class="pre">install</span></tt>. The setup script will then place the <tt class="docutils literal"><span class="pre">pycparser</span></tt> module into <tt class="docutils literal"><span class="pre">site-packages</span></tt> in your Python's installation library.</p>
-<p>It's recommended to run <tt class="docutils literal"><span class="pre">_build_tables.py</span></tt> in the <tt class="docutils literal"><span class="pre">pycparser</span></tt> code directory to make sure the parsing tables of PLY are pre-generated. This can make your code run faster.</p>
-</div>
-</div>
-<div class="section" id="using">
-<h1>3 Using</h1>
-<div class="section" id="interaction-with-the-c-preprocessor">
-<h2>3.1 Interaction with the C preprocessor</h2>
-<p>In order to be compilable, C code must be preprocessed by the C preprocessor - <tt class="docutils literal"><span class="pre">cpp</span></tt>. <tt class="docutils literal"><span class="pre">cpp</span></tt> handles preprocessing directives like <tt class="docutils literal"><span class="pre">#include</span></tt> and <tt class="docutils literal"><span class="pre">#define</span></tt>, removes comments, and does other minor tasks that prepare the C code for compilation.</p>
-<p>For all but the most trivial snippets of C code, <tt class="docutils literal"><span class="pre">pycparser</span></tt>, like a C compiler, must receive preprocessed C code in order to function correctly. If you import the top-level <tt class="docutils literal"><span class="pre">parse_file</span></tt> function from the <tt class="docutils literal"><span class="pre">pycparser</span></tt> package, it will interact with <tt class="docutils literal"><span class="pre">cpp</span></tt> for you, as long as it's in your PATH, or you provide a path to it.</p>
-<p>On the vast majority of Linux systems, <tt class="docutils literal"><span class="pre">cpp</span></tt> is installed and is in the PATH. If you're on Windows and don't have <tt class="docutils literal"><span class="pre">cpp</span></tt> somewhere, you can use the one provided in the <tt class="docutils literal"><span class="pre">utils</span></tt> directory in <tt class="docutils literal"><span class="pre">pycparser</span></tt>'s distribution. This <tt class="docutils literal"><span class="pre">cpp</span></tt> executable was compiled from the <a class="reference external" href="http://www.cs.princeton.edu/software/lcc/">LCC distribution</a>, and is provided under LCC's license terms.</p>
-</div>
-<div class="section" id="what-about-the-standard-c-library-headers">
-<h2>3.2 What about the standard C library headers?</h2>
-<p>C code almost always includes various header files from the standard C library, like <tt class="docutils literal"><span class="pre">stdio.h</span></tt>. While, with some effort, <tt class="docutils literal"><span class="pre">pycparser</span></tt> can be made to parse the standard headers from any C compiler, it's much simpler to use the provided "fake" standard in includes in <tt class="docutils literal"><span class="pre">utils/fake_libc_include</span></tt>. These are standard C header files that contain only the bare necessities to allow valid parsing of the files that use them. As a bonus, since they're minimal, it can significantly improve the performance of parsing C files.</p>
-<p>See the <tt class="docutils literal"><span class="pre">using_cpp_libc.py</span></tt> example for more details.</p>
-</div>
-<div class="section" id="basic-usage">
-<h2>3.3 Basic usage</h2>
-<p>Take a look at the <tt class="docutils literal"><span class="pre">examples</span></tt> directory of the distribution for a few examples of using <tt class="docutils literal"><span class="pre">pycparser</span></tt>. These should be enough to get you started.</p>
-</div>
-<div class="section" id="advanced-usage">
-<h2>3.4 Advanced usage</h2>
-<p>The public interface of <tt class="docutils literal"><span class="pre">pycparser</span></tt> is well documented with comments in <tt class="docutils literal"><span class="pre">pycparser/c_parser.py</span></tt>. For a detailed overview of the various AST nodes created by the parser, see <tt class="docutils literal"><span class="pre">pycparser/_c_ast.yaml</span></tt>.</p>
-<p>In any case, you can always drop me an <a class="reference external" href="mailto:eliben@gmail.com">email</a> for help.</p>
-</div>
-</div>
-<div class="section" id="modifying">
-<h1>4 Modifying</h1>
-<p>There are a few points to keep in mind when modifying <tt class="docutils literal"><span class="pre">pycparser</span></tt>:</p>
-<ul class="simple">
-<li>The code for <tt class="docutils literal"><span class="pre">pycparser</span></tt>'s AST nodes is automatically generated from a YAML configuration file - <tt class="docutils literal"><span class="pre">_c_ast.yaml</span></tt>, by <tt class="docutils literal"><span class="pre">_ast_gen.py</span></tt>. If you modify the AST configuration, make sure to re-generate the code.</li>
-<li>Make sure you understand the optimized mode of <tt class="docutils literal"><span class="pre">pycparser</span></tt> - for that you must read the docstring in the constructor of the <tt class="docutils literal"><span class="pre">CParser</span></tt> class. For development you should create the parser without optimizations, so that it will regenerate the Yacc and Lex tables when you change the grammar.</li>
-<li>The script <tt class="docutils literal"><span class="pre">_build_tables.py</span></tt> can be helpful - it regenerates all the tables needed by <tt class="docutils literal"><span class="pre">pycparser</span></tt>, and the AST code from YAML.</li>
-</ul>
-</div>
-<div class="section" id="package-contents">
-<h1>5 Package contents</h1>
-<p>Once you unzip the <tt class="docutils literal"><span class="pre">pycparser</span></tt> package, you'll see the following files and directories:</p>
-<dl class="docutils">
-<dt>README.txt/html:</dt>
-<dd>This README file.</dd>
-<dt>setup.py:</dt>
-<dd>Installation script</dd>
-<dt>examples/:</dt>
-<dd>A directory with some examples of using <tt class="docutils literal"><span class="pre">pycparser</span></tt></dd>
-<dt>pycparser/:</dt>
-<dd>The <tt class="docutils literal"><span class="pre">pycparser</span></tt> module source code.</dd>
-<dt>tests/:</dt>
-<dd>Unit tests.</dd>
-<dt>utils/cpp.exe:</dt>
-<dd>A Windows executable of the C pre-processor suitable for working with pycparser</dd>
-<dt>utils/fake_libc_include:</dt>
-<dd>Minimal standard C library include files that should allow to parse any C code.</dd>
-<dt>utils/internal/:</dt>
-<dd>Internal utilities for my own use. You probably don't need them.</dd>
-</dl>
-</div>
-<div class="section" id="contributors">
-<h1>6 Contributors</h1>
-<p>Some people have contributed to <tt class="docutils literal"><span class="pre">pycparser</span></tt> by opening issues on bugs they've found and/or submitting patches. The list of contributors is at <a class="reference external" href="http://code.google.com/p/pycparser/wiki/Contributors">this pycparser Wiki page</a>.</p>
-</div>
-<div class="section" id="changelog">
-<h1>7 Changelog</h1>
-<ul class="simple">
-<li>Version 2.00 (31.10.2010)<ul>
-<li>Support for C99 (read <a class="reference external" href="http://code.google.com/p/pycparser/wiki/C99support">this wiki page</a> for more information).</li>
-</ul>
-</li>
-<li>Version 1.08 (09.10.2010)<ul>
-<li>Bug fixes:<ul>
-<li>Correct handling of <tt class="docutils literal"><span class="pre">do{}</span> <span class="pre">...</span> <span class="pre">while</span></tt> statements in some cases</li>
-<li>Issues 6 & 7: Concatenation of string literals</li>
-<li>Issue 9: Support for unnamed bitfields in structs</li>
-</ul>
-</li>
-</ul>
-</li>
-<li>Version 1.07 (18.05.2010)<ul>
-<li>Python 3.1 compatibility: <tt class="docutils literal"><span class="pre">pycparser</span></tt> was modified to run on Python 3.1 as well as 2.6</li>
-</ul>
-</li>
-<li>Version 1.06 (10.04.2010)<ul>
-<li>Bug fixes:<ul>
-<li>coord not propagated to FuncCall nodes</li>
-<li>lexing of the ^= token (XOREQUALS)</li>
-<li>parsing failed on some abstract declarator rules</li>
-</ul>
-</li>
-<li>Linux compatibility: fixed end-of-line and <tt class="docutils literal"><span class="pre">cpp</span></tt> path issues to allow all tests and examples run on Linux</li>
-</ul>
-</li>
-<li>Version 1.05 (16.10.2009)<ul>
-<li>Fixed the <tt class="docutils literal"><span class="pre">parse_file</span></tt> auxiliary function to handle multiple arguments to <tt class="docutils literal"><span class="pre">cpp</span></tt> correctly</li>
-</ul>
-</li>
-<li>Version 1.04 (22.05.2009)<ul>
-<li>Added the <tt class="docutils literal"><span class="pre">fake_libc_include</span></tt> directory to allow parsing of C code that uses standard C library include files without dependency on a real C library.</li>
-<li>Tested with Python 2.6 and PLY 3.2</li>
-</ul>
-</li>
-<li>Version 1.03 (31.01.2009)<ul>
-<li>Accept enumeration lists with a comma after the last item (C99 feature).</li>
-</ul>
-</li>
-<li>Version 1.02 (16.01.2009)<ul>
-<li>Fixed problem of parsing struct/enum/union names that were named similarly to previously defined <tt class="docutils literal"><span class="pre">typedef</span></tt> types.</li>
-</ul>
-</li>
-<li>Version 1.01 (09.01.2009)<ul>
-<li>Fixed subprocess invocation in the helper function parse_file - now it's more portable</li>
-</ul>
-</li>
-<li>Version 1.0 (15.11.2008)<ul>
-<li>Initial release</li>
-<li>Support for ANSI C89</li>
-</ul>
-</li>
-</ul>
-</div>
-</div>
-</body>
-</html>
+<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> +<meta name="generator" content="Docutils 0.6: http://docutils.sourceforge.net/" /> +<title>pycparser v2.01</title> +<meta name="author" content="Eli Bendersky" /> +<style type="text/css"> + +/* +:Author: David Goodger (goodger@python.org) +:Id: $Id: html4css1.css 5951 2009-05-18 18:03:10Z milde $ +:Copyright: This stylesheet has been placed in the public domain. + +Default cascading style sheet for the HTML output of Docutils. + +See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to +customize this style sheet. +*/ + +/* used to remove borders from tables and images */ +.borderless, table.borderless td, table.borderless th { + border: 0 } + +table.borderless td, table.borderless th { + /* Override padding for "table.docutils td" with "! important". + The right padding separates the table cells. */ + padding: 0 0.5em 0 0 ! important } + +.first { + /* Override more specific margin styles with "! important". */ + margin-top: 0 ! important } + +.last, .with-subtitle { + margin-bottom: 0 ! important } + +.hidden { + display: none } + +a.toc-backref { + text-decoration: none ; + color: black } + +blockquote.epigraph { + margin: 2em 5em ; } + +dl.docutils dd { + margin-bottom: 0.5em } + +/* Uncomment (and remove this text!) to get bold-faced definition list terms +dl.docutils dt { + font-weight: bold } +*/ + +div.abstract { + margin: 2em 5em } + +div.abstract p.topic-title { + font-weight: bold ; + text-align: center } + +div.admonition, div.attention, div.caution, div.danger, div.error, +div.hint, div.important, div.note, div.tip, div.warning { + margin: 2em ; + border: medium outset ; + padding: 1em } + +div.admonition p.admonition-title, div.hint p.admonition-title, +div.important p.admonition-title, div.note p.admonition-title, +div.tip p.admonition-title { + font-weight: bold ; + font-family: sans-serif } + +div.attention p.admonition-title, div.caution p.admonition-title, +div.danger p.admonition-title, div.error p.admonition-title, +div.warning p.admonition-title { + color: red ; + font-weight: bold ; + font-family: sans-serif } + +/* Uncomment (and remove this text!) to get reduced vertical space in + compound paragraphs. +div.compound .compound-first, div.compound .compound-middle { + margin-bottom: 0.5em } + +div.compound .compound-last, div.compound .compound-middle { + margin-top: 0.5em } +*/ + +div.dedication { + margin: 2em 5em ; + text-align: center ; + font-style: italic } + +div.dedication p.topic-title { + font-weight: bold ; + font-style: normal } + +div.figure { + margin-left: 2em ; + margin-right: 2em } + +div.footer, div.header { + clear: both; + font-size: smaller } + +div.line-block { + display: block ; + margin-top: 1em ; + margin-bottom: 1em } + +div.line-block div.line-block { + margin-top: 0 ; + margin-bottom: 0 ; + margin-left: 1.5em } + +div.sidebar { + margin: 0 0 0.5em 1em ; + border: medium outset ; + padding: 1em ; + background-color: #ffffee ; + width: 40% ; + float: right ; + clear: right } + +div.sidebar p.rubric { + font-family: sans-serif ; + font-size: medium } + +div.system-messages { + margin: 5em } + +div.system-messages h1 { + color: red } + +div.system-message { + border: medium outset ; + padding: 1em } + +div.system-message p.system-message-title { + color: red ; + font-weight: bold } + +div.topic { + margin: 2em } + +h1.section-subtitle, h2.section-subtitle, h3.section-subtitle, +h4.section-subtitle, h5.section-subtitle, h6.section-subtitle { + margin-top: 0.4em } + +h1.title { + text-align: center } + +h2.subtitle { + text-align: center } + +hr.docutils { + width: 75% } + +img.align-left, .figure.align-left{ + clear: left ; + float: left ; + margin-right: 1em } + +img.align-right, .figure.align-right { + clear: right ; + float: right ; + margin-left: 1em } + +.align-left { + text-align: left } + +.align-center { + clear: both ; + text-align: center } + +.align-right { + text-align: right } + +/* reset inner alignment in figures */ +div.align-right { + text-align: left } + +/* div.align-center * { */ +/* text-align: left } */ + +ol.simple, ul.simple { + margin-bottom: 1em } + +ol.arabic { + list-style: decimal } + +ol.loweralpha { + list-style: lower-alpha } + +ol.upperalpha { + list-style: upper-alpha } + +ol.lowerroman { + list-style: lower-roman } + +ol.upperroman { + list-style: upper-roman } + +p.attribution { + text-align: right ; + margin-left: 50% } + +p.caption { + font-style: italic } + +p.credits { + font-style: italic ; + font-size: smaller } + +p.label { + white-space: nowrap } + +p.rubric { + font-weight: bold ; + font-size: larger ; + color: maroon ; + text-align: center } + +p.sidebar-title { + font-family: sans-serif ; + font-weight: bold ; + font-size: larger } + +p.sidebar-subtitle { + font-family: sans-serif ; + font-weight: bold } + +p.topic-title { + font-weight: bold } + +pre.address { + margin-bottom: 0 ; + margin-top: 0 ; + font: inherit } + +pre.literal-block, pre.doctest-block { + margin-left: 2em ; + margin-right: 2em } + +span.classifier { + font-family: sans-serif ; + font-style: oblique } + +span.classifier-delimiter { + font-family: sans-serif ; + font-weight: bold } + +span.interpreted { + font-family: sans-serif } + +span.option { + white-space: nowrap } + +span.pre { + white-space: pre } + +span.problematic { + color: red } + +span.section-subtitle { + /* font-size relative to parent (h1..h6 element) */ + font-size: 80% } + +table.citation { + border-left: solid 1px gray; + margin-left: 1px } + +table.docinfo { + margin: 2em 4em } + +table.docutils { + margin-top: 0.5em ; + margin-bottom: 0.5em } + +table.footnote { + border-left: solid 1px black; + margin-left: 1px } + +table.docutils td, table.docutils th, +table.docinfo td, table.docinfo th { + padding-left: 0.5em ; + padding-right: 0.5em ; + vertical-align: top } + +table.docutils th.field-name, table.docinfo th.docinfo-name { + font-weight: bold ; + text-align: left ; + white-space: nowrap ; + padding-left: 0 } + +h1 tt.docutils, h2 tt.docutils, h3 tt.docutils, +h4 tt.docutils, h5 tt.docutils, h6 tt.docutils { + font-size: 100% } + +ul.auto-toc { + list-style-type: none } + +</style> +</head> +<body> +<div class="document" id="pycparser-v2-01"> +<h1 class="title">pycparser v2.01</h1> +<table class="docinfo" frame="void" rules="none"> +<col class="docinfo-name" /> +<col class="docinfo-content" /> +<tbody valign="top"> +<tr><th class="docinfo-name">Author:</th> +<td><a class="first reference external" href="http://eli.thegreenplace.net">Eli Bendersky</a></td></tr> +</tbody> +</table> +<div class="contents topic" id="contents"> +<p class="topic-title first">Contents</p> +<ul class="auto-toc simple"> +<li><a class="reference internal" href="#introduction" id="id2">1 Introduction</a><ul class="auto-toc"> +<li><a class="reference internal" href="#what-is-pycparser" id="id3">1.1 What is pycparser?</a></li> +<li><a class="reference internal" href="#what-is-it-good-for" id="id4">1.2 What is it good for?</a></li> +<li><a class="reference internal" href="#which-version-of-c-does-pycparser-support" id="id5">1.3 Which version of C does pycparser support?</a></li> +<li><a class="reference internal" href="#what-grammar-does-pycparser-follow" id="id6">1.4 What grammar does pycparser follow?</a></li> +<li><a class="reference internal" href="#what-is-an-ast" id="id7">1.5 What is an AST?</a></li> +<li><a class="reference internal" href="#how-is-pycparser-licensed" id="id8">1.6 How is pycparser licensed?</a></li> +<li><a class="reference internal" href="#contact-details" id="id9">1.7 Contact details</a></li> +</ul> +</li> +<li><a class="reference internal" href="#installing" id="id10">2 Installing</a><ul class="auto-toc"> +<li><a class="reference internal" href="#prerequisites" id="id11">2.1 Prerequisites</a></li> +<li><a class="reference internal" href="#installation-process" id="id12">2.2 Installation process</a></li> +</ul> +</li> +<li><a class="reference internal" href="#using" id="id13">3 Using</a><ul class="auto-toc"> +<li><a class="reference internal" href="#interaction-with-the-c-preprocessor" id="id14">3.1 Interaction with the C preprocessor</a></li> +<li><a class="reference internal" href="#what-about-the-standard-c-library-headers" id="id15">3.2 What about the standard C library headers?</a></li> +<li><a class="reference internal" href="#basic-usage" id="id16">3.3 Basic usage</a></li> +<li><a class="reference internal" href="#advanced-usage" id="id17">3.4 Advanced usage</a></li> +</ul> +</li> +<li><a class="reference internal" href="#modifying" id="id18">4 Modifying</a></li> +<li><a class="reference internal" href="#package-contents" id="id19">5 Package contents</a></li> +<li><a class="reference internal" href="#contributors" id="id20">6 Contributors</a></li> +<li><a class="reference internal" href="#changelog" id="id21">7 Changelog</a></li> +</ul> +</div> +<div class="section" id="introduction"> +<h1>1 Introduction</h1> +<div class="section" id="what-is-pycparser"> +<h2>1.1 What is pycparser?</h2> +<p><tt class="docutils literal">pycparser</tt> is a parser for the C language, written in pure Python. It is a module designed to be easily integrated into applications that need to parse C source code.</p> +</div> +<div class="section" id="what-is-it-good-for"> +<h2>1.2 What is it good for?</h2> +<p>Anything that needs C code to be parsed. The following are some uses for <tt class="docutils literal">pycparser</tt>, taken from real user reports:</p> +<ul class="simple"> +<li>C code obfuscator</li> +<li>Front-end for various specialized C compilers</li> +<li>Static code checker</li> +<li>Automatic unit-test discovery</li> +<li>Adding specialized extensions to the C language</li> +</ul> +<p><tt class="docutils literal">pycparser</tt> is unique in the sense that it's written in pure Python - a very high level language that's easy to experiment with and tweak. To people familiar with Lex and Yacc, <tt class="docutils literal">pycparser</tt>'s code will be simple to understand.</p> +</div> +<div class="section" id="which-version-of-c-does-pycparser-support"> +<h2>1.3 Which version of C does pycparser support?</h2> +<p><tt class="docutils literal">pycparser</tt> aims to support the full C99 language (according to the standard ISO/IEC 9899). This is a new feature in the version 2.x series - earlier versions only supported C89. For more information on the change, read <a class="reference external" href="http://code.google.com/p/pycparser/wiki/C99support">this wiki page</a>.</p> +<p><tt class="docutils literal">pycparser</tt> doesn't support any GCC extensions.</p> +</div> +<div class="section" id="what-grammar-does-pycparser-follow"> +<h2>1.4 What grammar does pycparser follow?</h2> +<p><tt class="docutils literal">pycparser</tt> very closely follows the C grammar provided in the end of the C99 standard document</p> +</div> +<div class="section" id="what-is-an-ast"> +<h2>1.5 What is an AST?</h2> +<p><a class="reference external" href="http://en.wikipedia.org/wiki/Abstract_syntax_tree">AST</a> - Abstract Syntax Tree. It is a tree representation of the syntax of source code - a convenient hierarchical data structure that's built from the code and is readily suitable for exploration and manipulation.</p> +</div> +<div class="section" id="how-is-pycparser-licensed"> +<h2>1.6 How is pycparser licensed?</h2> +<p><a class="reference external" href="http://www.gnu.org/licenses/lgpl.html">LGPL</a></p> +</div> +<div class="section" id="contact-details"> +<h2>1.7 Contact details</h2> +<p>Drop me an email to <a class="reference external" href="mailto:eliben@gmail.com">eliben@gmail.com</a> for any questions regarding <tt class="docutils literal">pycparser</tt>. For reporting problems with <tt class="docutils literal">pycparser</tt> or submitting feature requests, the best way is to open an issue on the <a class="reference external" href="http://code.google.com/p/pycparser/">pycparser page at Google Code</a>.</p> +</div> +</div> +<div class="section" id="installing"> +<h1>2 Installing</h1> +<div class="section" id="prerequisites"> +<h2>2.1 Prerequisites</h2> +<ul class="simple"> +<li><tt class="docutils literal">pycparser</tt> was tested on Python 2.5, 2.6 and 3.1, on both Linux and Windows</li> +<li><tt class="docutils literal">pycparser</tt> uses the PLY module for the actual lexer and parser construction. Install PLY version 3.3 (earlier versions work at least since 2.5) from <a class="reference external" href="http://www.dabeaz.com/ply/">its website</a>.</li> +</ul> +</div> +<div class="section" id="installation-process"> +<h2>2.2 Installation process</h2> +<p>Installing <tt class="docutils literal">pycparser</tt> is very simple. Once you download it from its <a class="reference external" href="http://code.google.com/p/pycparser/">website</a> and unzip the package, you just have to execute the standard <tt class="docutils literal">python setup.py install</tt>. The setup script will then place the <tt class="docutils literal">pycparser</tt> module into <tt class="docutils literal"><span class="pre">site-packages</span></tt> in your Python's installation library.</p> +<p>It's recommended to run <tt class="docutils literal">_build_tables.py</tt> in the <tt class="docutils literal">pycparser</tt> code directory after installation to make sure the parsing tables of PLY are pre-generated. This can make your code run faster.</p> +</div> +</div> +<div class="section" id="using"> +<h1>3 Using</h1> +<div class="section" id="interaction-with-the-c-preprocessor"> +<h2>3.1 Interaction with the C preprocessor</h2> +<p>In order to be compilable, C code must be preprocessed by the C preprocessor - <tt class="docutils literal">cpp</tt>. <tt class="docutils literal">cpp</tt> handles preprocessing directives like <tt class="docutils literal">#include</tt> and <tt class="docutils literal">#define</tt>, removes comments, and does other minor tasks that prepare the C code for compilation.</p> +<p>For all but the most trivial snippets of C code, <tt class="docutils literal">pycparser</tt>, like a C compiler, must receive preprocessed C code in order to function correctly. If you import the top-level <tt class="docutils literal">parse_file</tt> function from the <tt class="docutils literal">pycparser</tt> package, it will interact with <tt class="docutils literal">cpp</tt> for you, as long as it's in your PATH, or you provide a path to it.</p> +<p>On the vast majority of Linux systems, <tt class="docutils literal">cpp</tt> is installed and is in the PATH. If you're on Windows and don't have <tt class="docutils literal">cpp</tt> somewhere, you can use the one provided in the <tt class="docutils literal">utils</tt> directory in <tt class="docutils literal">pycparser</tt>'s distribution. This <tt class="docutils literal">cpp</tt> executable was compiled from the <a class="reference external" href="http://www.cs.princeton.edu/software/lcc/">LCC distribution</a>, and is provided under LCC's license terms.</p> +</div> +<div class="section" id="what-about-the-standard-c-library-headers"> +<h2>3.2 What about the standard C library headers?</h2> +<p>C code almost always includes various header files from the standard C library, like <tt class="docutils literal">stdio.h</tt>. While, with some effort, <tt class="docutils literal">pycparser</tt> can be made to parse the standard headers from any C compiler, it's much simpler to use the provided "fake" standard in includes in <tt class="docutils literal">utils/fake_libc_include</tt>. These are standard C header files that contain only the bare necessities to allow valid parsing of the files that use them. As a bonus, since they're minimal, it can significantly improve the performance of parsing C files.</p> +<p>See the <tt class="docutils literal">using_cpp_libc.py</tt> example for more details.</p> +</div> +<div class="section" id="basic-usage"> +<h2>3.3 Basic usage</h2> +<p>Take a look at the <tt class="docutils literal">examples</tt> directory of the distribution for a few examples of using <tt class="docutils literal">pycparser</tt>. These should be enough to get you started.</p> +</div> +<div class="section" id="advanced-usage"> +<h2>3.4 Advanced usage</h2> +<p>The public interface of <tt class="docutils literal">pycparser</tt> is well documented with comments in <tt class="docutils literal">pycparser/c_parser.py</tt>. For a detailed overview of the various AST nodes created by the parser, see <tt class="docutils literal">pycparser/_c_ast.cfg</tt>.</p> +<p>In any case, you can always drop me an <a class="reference external" href="mailto:eliben@gmail.com">email</a> for help.</p> +</div> +</div> +<div class="section" id="modifying"> +<h1>4 Modifying</h1> +<p>There are a few points to keep in mind when modifying <tt class="docutils literal">pycparser</tt>:</p> +<ul class="simple"> +<li>The code for <tt class="docutils literal">pycparser</tt>'s AST nodes is automatically generated from a configuration file - <tt class="docutils literal">_c_ast.cfg</tt>, by <tt class="docutils literal">_ast_gen.py</tt>. If you modify the AST configuration, make sure to re-generate the code.</li> +<li>Make sure you understand the optimized mode of <tt class="docutils literal">pycparser</tt> - for that you must read the docstring in the constructor of the <tt class="docutils literal">CParser</tt> class. For development you should create the parser without optimizations, so that it will regenerate the Yacc and Lex tables when you change the grammar.</li> +</ul> +</div> +<div class="section" id="package-contents"> +<h1>5 Package contents</h1> +<p>Once you unzip the <tt class="docutils literal">pycparser</tt> package, you'll see the following files and directories:</p> +<dl class="docutils"> +<dt>README.txt/html:</dt> +<dd>This README file.</dd> +<dt>setup.py:</dt> +<dd>Installation script</dd> +<dt>examples/:</dt> +<dd>A directory with some examples of using <tt class="docutils literal">pycparser</tt></dd> +<dt>pycparser/:</dt> +<dd>The <tt class="docutils literal">pycparser</tt> module source code.</dd> +<dt>tests/:</dt> +<dd>Unit tests.</dd> +<dt>utils/cpp.exe:</dt> +<dd>A Windows executable of the C pre-processor suitable for working with pycparser</dd> +<dt>utils/fake_libc_include:</dt> +<dd>Minimal standard C library include files that should allow to parse any C code.</dd> +<dt>utils/internal/:</dt> +<dd>Internal utilities for my own use. You probably don't need them.</dd> +</dl> +</div> +<div class="section" id="contributors"> +<h1>6 Contributors</h1> +<p>Some people have contributed to <tt class="docutils literal">pycparser</tt> by opening issues on bugs they've found and/or submitting patches. The list of contributors is at <a class="reference external" href="http://code.google.com/p/pycparser/wiki/Contributors">this pycparser Wiki page</a>.</p> +</div> +<div class="section" id="changelog"> +<h1>7 Changelog</h1> +<ul class="simple"> +<li>Version 2.01 (04.12.2010)<ul> +<li>Removed dependency on YAML. Parsing of the AST node configuration file is done with a simple parser.</li> +<li>Fixed issue 12: installation problems</li> +</ul> +</li> +<li>Version 2.00 (31.10.2010)<ul> +<li>Support for C99 (read <a class="reference external" href="http://code.google.com/p/pycparser/wiki/C99support">this wiki page</a> for more information).</li> +</ul> +</li> +<li>Version 1.08 (09.10.2010)<ul> +<li>Bug fixes:<ul> +<li>Correct handling of <tt class="docutils literal">do{} ... while</tt> statements in some cases</li> +<li>Issues 6 & 7: Concatenation of string literals</li> +<li>Issue 9: Support for unnamed bitfields in structs</li> +</ul> +</li> +</ul> +</li> +<li>Version 1.07 (18.05.2010)<ul> +<li>Python 3.1 compatibility: <tt class="docutils literal">pycparser</tt> was modified to run on Python 3.1 as well as 2.6</li> +</ul> +</li> +<li>Version 1.06 (10.04.2010)<ul> +<li>Bug fixes:<ul> +<li>coord not propagated to FuncCall nodes</li> +<li>lexing of the ^= token (XOREQUALS)</li> +<li>parsing failed on some abstract declarator rules</li> +</ul> +</li> +<li>Linux compatibility: fixed end-of-line and <tt class="docutils literal">cpp</tt> path issues to allow all tests and examples run on Linux</li> +</ul> +</li> +<li>Version 1.05 (16.10.2009)<ul> +<li>Fixed the <tt class="docutils literal">parse_file</tt> auxiliary function to handle multiple arguments to <tt class="docutils literal">cpp</tt> correctly</li> +</ul> +</li> +<li>Version 1.04 (22.05.2009)<ul> +<li>Added the <tt class="docutils literal">fake_libc_include</tt> directory to allow parsing of C code that uses standard C library include files without dependency on a real C library.</li> +<li>Tested with Python 2.6 and PLY 3.2</li> +</ul> +</li> +<li>Version 1.03 (31.01.2009)<ul> +<li>Accept enumeration lists with a comma after the last item (C99 feature).</li> +</ul> +</li> +<li>Version 1.02 (16.01.2009)<ul> +<li>Fixed problem of parsing struct/enum/union names that were named similarly to previously defined <tt class="docutils literal">typedef</tt> types.</li> +</ul> +</li> +<li>Version 1.01 (09.01.2009)<ul> +<li>Fixed subprocess invocation in the helper function parse_file - now it's more portable</li> +</ul> +</li> +<li>Version 1.0 (15.11.2008)<ul> +<li>Initial release</li> +<li>Support for ANSI C89</li> +</ul> +</li> +</ul> +</div> +</div> +</body> +</html> @@ -1,5 +1,5 @@ ===============
-pycparser v2.00
+pycparser v2.01
===============
:Author: `Eli Bendersky <http://eli.thegreenplace.net>`_
@@ -70,14 +70,13 @@ 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. Install PLY version 3.3 (earlier versions work at least since 2.5) from `its website <http://www.dabeaz.com/ply/>`_.
-* If you want to modify ``pycparser``'s code, you'll need to install `PyYAML <http://pyyaml.org/>`_, since it's used by ``pycparser`` to store the AST configuration in a YAML file.
Installation process
--------------------
Installing ``pycparser`` is very simple. Once you download it from its `website <http://code.google.com/p/pycparser/>`_ and unzip the package, you just have to execute the standard ``python setup.py install``. The setup script will then place the ``pycparser`` module into ``site-packages`` in your Python's installation library.
-It's recommended to run ``_build_tables.py`` in the ``pycparser`` code directory to make sure the parsing tables of PLY are pre-generated. This can make your code run faster.
+It's recommended to run ``_build_tables.py`` in the ``pycparser`` code directory after installation to make sure the parsing tables of PLY are pre-generated. This can make your code run faster.
Using
@@ -107,7 +106,7 @@ Take a look at the ``examples`` directory of the distribution for a few examples Advanced usage
--------------
-The public interface of ``pycparser`` is well documented with comments in ``pycparser/c_parser.py``. For a detailed overview of the various AST nodes created by the parser, see ``pycparser/_c_ast.yaml``.
+The public interface of ``pycparser`` is well documented with comments in ``pycparser/c_parser.py``. For a detailed overview of the various AST nodes created by the parser, see ``pycparser/_c_ast.cfg``.
In any case, you can always drop me an `email <eliben@gmail.com>`_ for help.
@@ -116,9 +115,8 @@ 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.
+* The code for ``pycparser``'s AST nodes is automatically generated from a configuration file - ``_c_ast.cfg``, by ``_ast_gen.py``. If you modify the AST configuration, make sure to re-generate the code.
* Make sure you understand the optimized mode of ``pycparser`` - for that you must read the docstring in the constructor of the ``CParser`` class. For development you should create the parser without optimizations, so that it will regenerate the Yacc and Lex tables when you change the grammar.
-* The script ``_build_tables.py`` can be helpful - it regenerates all the tables needed by ``pycparser``, and the AST code from YAML.
Package contents
@@ -158,6 +156,11 @@ Some people have contributed to ``pycparser`` by opening issues on bugs they've Changelog
=========
++ Version 2.01 (04.12.2010)
+
+ * Removed dependency on YAML. Parsing of the AST node configuration file is done with a simple parser.
+ * Fixed issue 12: installation problems
+
+ Version 2.00 (31.10.2010)
* Support for C99 (read `this wiki page <http://code.google.com/p/pycparser/wiki/C99support>`_ for more information).
diff --git a/examples/cdecl.py b/examples/cdecl.py index 3df6efc..23148f8 100644 --- a/examples/cdecl.py +++ b/examples/cdecl.py @@ -1,108 +1,108 @@ -#-----------------------------------------------------------------
-# pycparser: cdecl.py
-#
-# Example of the CDECL tool using pycparser. CDECL "explains"
-# C type declarations in plain English.
-#
-# The AST generated by pycparser from the given declaration is
-# traversed recursively to build the explanation.
-# Note that the declaration must be a valid external declaration
-# in C. All the types used in it must be defined with typedef,
-# or parsing will fail. The definition can be arbitrary, it isn't
-# really used - by pycparser must know which tokens are types.
-#
-# For example:
-#
-# 'typedef int Node; const Node* (*ar)[10];'
-# =>
-# ar is a pointer to array[10] of pointer to const Node
-#
-# Copyright (C) 2008-2010, Eli Bendersky
-# License: LGPL
-#-----------------------------------------------------------------
-import sys
-
-# This is not required if you've installed pycparser into
-# your site-packages/ with setup.py
-#
-sys.path.insert(0, '..')
-
-from pycparser import c_parser, c_ast
-from pycparser.portability import printme
-
-
+#----------------------------------------------------------------- +# pycparser: cdecl.py +# +# Example of the CDECL tool using pycparser. CDECL "explains" +# C type declarations in plain English. +# +# The AST generated by pycparser from the given declaration is +# traversed recursively to build the explanation. +# Note that the declaration must be a valid external declaration +# in C. All the types used in it must be defined with typedef, +# or parsing will fail. The definition can be arbitrary, it isn't +# really used - by pycparser must know which tokens are types. +# +# For example: +# +# 'typedef int Node; const Node* (*ar)[10];' +# => +# ar is a pointer to array[10] of pointer to const Node +# +# Copyright (C) 2008-2010, Eli Bendersky +# License: LGPL +#----------------------------------------------------------------- +import sys + +# This is not required if you've installed pycparser into +# your site-packages/ with setup.py +# +sys.path.insert(0, '..') + +from pycparser import c_parser, c_ast + + def explain_c_declaration(c_decl): - """ Parses the declaration in c_decl and returns a text
- explanation as a string.
-
- The last external node of the string is used, to allow
+ """ Parses the declaration in c_decl and returns a text + explanation as a string. + + The last external node of the string is used, to allow earlier typedefs for used types. - """
- parser = c_parser.CParser()
-
- try:
- node = parser.parse(c_decl, filename='<stdin>')
- except c_parser.ParseError:
- e = sys.exc_info()[1]
- return "Parse error:" + str(e)
-
- if ( not isinstance(node, c_ast.FileAST) or
- not isinstance(node.ext[-1], c_ast.Decl)):
- return "Not a valid declaration"
-
- return _explain_decl_node(node.ext[-1])
-
-
+ """ + parser = c_parser.CParser() + + try: + node = parser.parse(c_decl, filename='<stdin>') + except c_parser.ParseError: + e = sys.exc_info()[1] + return "Parse error:" + str(e) + + if ( not isinstance(node, c_ast.FileAST) or + not isinstance(node.ext[-1], c_ast.Decl)): + return "Not a valid declaration" + + return _explain_decl_node(node.ext[-1]) + + def _explain_decl_node(decl_node): - """ Receives a c_ast.Decl note and returns its explanation in
+ """ Receives a c_ast.Decl note and returns its explanation in English. - """
- #~ print decl_node.show()
- storage = ' '.join(decl_node.storage) + ' ' if decl_node.storage else ''
-
- return (decl_node.name +
- " is a " +
- storage +
- _explain_type(decl_node.type))
-
-
+ """ + #~ print decl_node.show() + storage = ' '.join(decl_node.storage) + ' ' if decl_node.storage else '' + + return (decl_node.name + + " is a " + + storage + + _explain_type(decl_node.type)) + + def _explain_type(decl): """ Recursively explains a type decl node - """
- typ = type(decl)
-
- if typ == c_ast.TypeDecl:
- quals = ' '.join(decl.quals) + ' ' if decl.quals else ''
- return quals + _explain_type(decl.type)
- elif typ == c_ast.Typename or typ == c_ast.Decl:
- return _explain_type(decl.type)
- elif typ == c_ast.IdentifierType:
- return ' '.join(decl.names)
- elif typ == c_ast.PtrDecl:
- quals = ' '.join(decl.quals) + ' ' if decl.quals else ''
- return quals + 'pointer to ' + _explain_type(decl.type)
- elif typ == c_ast.ArrayDecl:
- arr = 'array'
- if decl.dim: arr += '[%s]' % decl.dim.value
-
- return arr + " of " + _explain_type(decl.type)
-
- elif typ == c_ast.FuncDecl:
- if decl.args:
- params = [_explain_type(param) for param in decl.args.params]
- args = ', '.join(params)
- else:
- args = ''
-
- return ('function(%s) returning ' % (args) +
- _explain_type(decl.type))
-
-
-if __name__ == "__main__":
- if len(sys.argv) > 1:
- c_decl = sys.argv[1]
- else:
- c_decl = "char *(*(**foo[][8])())[];"
-
- printme(["Explaining the declaration:", c_decl])
- printme(["\n", explain_c_declaration(c_decl)])
+ """ + typ = type(decl) + + if typ == c_ast.TypeDecl: + quals = ' '.join(decl.quals) + ' ' if decl.quals else '' + return quals + _explain_type(decl.type) + elif typ == c_ast.Typename or typ == c_ast.Decl: + return _explain_type(decl.type) + elif typ == c_ast.IdentifierType: + return ' '.join(decl.names) + elif typ == c_ast.PtrDecl: + quals = ' '.join(decl.quals) + ' ' if decl.quals else '' + return quals + 'pointer to ' + _explain_type(decl.type) + elif typ == c_ast.ArrayDecl: + arr = 'array' + if decl.dim: arr += '[%s]' % decl.dim.value + + return arr + " of " + _explain_type(decl.type) + + elif typ == c_ast.FuncDecl: + if decl.args: + params = [_explain_type(param) for param in decl.args.params] + args = ', '.join(params) + else: + args = '' + + return ('function(%s) returning ' % (args) + + _explain_type(decl.type)) + + +if __name__ == "__main__": + if len(sys.argv) > 1: + c_decl = sys.argv[1] + else: + c_decl = "char *(*(**foo[][8])())[];" + + print("Explaining the declaration: " + c_decl + "\n") + print(explain_c_declaration(c_decl) + "\n") + diff --git a/pycparser/__init__.py b/pycparser/__init__.py index 7d91134..a51239b 100644 --- a/pycparser/__init__.py +++ b/pycparser/__init__.py @@ -9,7 +9,7 @@ #-----------------------------------------------------------------
__all__ = ['c_lexer', 'c_parser', 'c_ast']
-__version__ = '2.00'
+__version__ = '2.01'
from subprocess import Popen, PIPE
diff --git a/pycparser/_ast_gen.py b/pycparser/_ast_gen.py index 68904d1..2bef0fb 100644 --- a/pycparser/_ast_gen.py +++ b/pycparser/_ast_gen.py @@ -1,249 +1,264 @@ -#-----------------------------------------------------------------
-# _ast_gen.py
-#
-# Generates the AST Node classes from a specification given in
-# a .yaml file
-#
-# The design of this module was inspired by astgen.py from the
-# Python 2.5 code-base.
-#
-# Copyright (C) 2008-2010, Eli Bendersky
-# License: LGPL
-#-----------------------------------------------------------------
-
-import pprint
-from string import Template
-
-import yaml
-
-
+#----------------------------------------------------------------- +# _ast_gen.py +# +# Generates the AST Node classes from a specification given in +# a .yaml file +# +# The design of this module was inspired by astgen.py from the +# Python 2.5 code-base. +# +# Copyright (C) 2008-2010, Eli Bendersky +# License: LGPL +#----------------------------------------------------------------- +import pprint +from string import Template + + class ASTCodeGenerator(object): - def __init__(self, cfg_filename='_c_ast.yaml'):
- """ Initialize the code generator from a configuration
+ def __init__(self, cfg_filename='_c_ast.cfg'): + """ Initialize the code generator from a configuration file. - """
- self.cfg_filename = cfg_filename
- cfg = yaml.load(open(cfg_filename).read())
- self.node_cfg = [NodeCfg(name, cfg[name]) for name in cfg]
-
- #~ pprint.pprint(self.node_cfg)
- #~ print ''
-
- def generate(self, file=None):
- """ Generates the code into file, an open file buffer.
- """
- src = Template(_PROLOGUE_COMMENT).substitute(
- cfg_filename=self.cfg_filename)
-
- src += _PROLOGUE_CODE
- for node_cfg in self.node_cfg:
- src += node_cfg.generate_source() + '\n\n'
-
+ """ + self.cfg_filename = cfg_filename + self.node_cfg = [NodeCfg(name, contents) for (name, contents) in self.parse_cfgfile(cfg_filename)] + + def generate(self, file=None): + """ Generates the code into file, an open file buffer. + """ + src = Template(_PROLOGUE_COMMENT).substitute( + cfg_filename=self.cfg_filename) + + src += _PROLOGUE_CODE + for node_cfg in self.node_cfg: + src += node_cfg.generate_source() + '\n\n' + file.write(src) -
-
+ + def parse_cfgfile(self, filename): + """ Parse the configuration file and yield pairs of + (name, contents) for each node. + """ + with open(filename, "r") as f: + for line in f: + line = line.strip() + if not line or line.startswith('#'): + continue + colon_i = line.find(':') + lbracket_i = line.find('[') + rbracket_i = line.find(']') + if colon_i < 1 or lbracket_i <= colon_i or rbracket_i <= lbracket_i: + raise RuntimeError("Invalid line in %s:\n%s\n" % (filename, line)) + + name = line[:colon_i] + val = line[lbracket_i + 1:rbracket_i] + vallist = [v.strip() for v in val.split(',')] if val else [] + yield name, vallist + + class NodeCfg(object): - def __init__(self, name, contents):
- self.name = name
- self.all_entries = []
- self.attr = []
- self.child = []
- self.seq_child = []
-
- for entry in contents:
- clean_entry = entry.rstrip('*')
- self.all_entries.append(clean_entry)
-
- if entry.endswith('**'):
- self.seq_child.append(clean_entry)
- elif entry.endswith('*'):
- self.child.append(clean_entry)
- else:
+ """ Node configuration. + + name: node name + contents: a list of contents - attributes and child nodes + See comment at the top of the configuration file for details. + """ + def __init__(self, name, contents): + self.name = name + self.all_entries = [] + self.attr = [] + self.child = [] + self.seq_child = [] + + for entry in contents: + clean_entry = entry.rstrip('*') + self.all_entries.append(clean_entry) + + if entry.endswith('**'): + self.seq_child.append(clean_entry) + elif entry.endswith('*'): + self.child.append(clean_entry) + else: self.attr.append(entry) -
+ def generate_source(self): - src = self._gen_init()
- src += '\n' + self._gen_children()
- src += '\n' + self._gen_show()
- return src
-
+ 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
-
+ 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
-
+ 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'))
-
-
-
+ src = ' def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):\n' + src += " lead = ' ' * offset\n" + + src += " buf.write(lead + '%s: ')\n\n" % self.name + + if self.attr: + src += " if attrnames:\n" + src += " attrstr = ', '.join('%s=%s' % nv for nv in [" + src += ', '.join('("%s", repr(%s))' % (nv, 'self.%s' % nv) for nv in self.attr) + src += '])\n' + src += " else:\n" + src += " attrstr = ', '.join('%s' % v for v in [" + src += ', '.join('self.%s' % v for v in self.attr) + src += '])\n' + src += " buf.write(attrstr)\n\n" + + src += " if showcoord:\n" + src += " buf.write(' (at %s)' % self.coord)\n" + src += " buf.write('\\n')\n\n" + + src += " for c in self.children():\n" + src += " c.show(buf, offset + 2, attrnames, showcoord)\n" + + return src + + +_PROLOGUE_COMMENT = \ +r'''#----------------------------------------------------------------- +# ** ATTENTION ** +# This code was automatically generated from the file: +# $cfg_filename +# +# Do not modify it directly. Modify the configuration file and +# run the generator again. +# ** ** *** ** ** +# +# pycparser: c_ast.py +# +# AST Node classes. +# +# Copyright (C) 2008-2010, Eli Bendersky +# License: LGPL +#----------------------------------------------------------------- + +''' + +_PROLOGUE_CODE = r''' +import sys + + +class Node(object): + """ Abstract base class for AST nodes. + """ + def children(self): + """ A sequence of all children that are Nodes + """ + pass + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + """ Pretty print the Node and all its attributes and + children (recursively) to a buffer. + + file: + Open IO buffer into which the Node is printed. + + offset: + Initial offset (amount of leading spaces) + + attrnames: + True if you want to see the attribute names in + name=value pairs. False to only see the values. + + showcoord: + Do you want the coordinates of each Node to be + displayed. + """ + pass + + +class NodeVisitor(object): + """ A base NodeVisitor class for visiting c_ast nodes. + Subclass it and define your own visit_XXX methods, where + XXX is the class name you want to visit with these + methods. + + For example: + + class ConstantVisitor(NodeVisitor): + def __init__(self): + self.values = [] + + def visit_Constant(self, node): + self.values.append(node.value) + + Creates a list of values of all the constant nodes + encountered below the given node. To use it: + + cv = ConstantVisitor() + cv.visit(node) + + Notes: + + * generic_visit() will be called for AST nodes for which + no visit_XXX method was defined. + * The children of nodes for which a visit_XXX was + defined will not be visited - if you need this, call + generic_visit() on the node. + You can use: + NodeVisitor.generic_visit(self, node) + * Modeled after Python's own AST visiting facilities + (the ast module of Python 3.0) + """ + def visit(self, node): + """ Visit a node. + """ + method = 'visit_' + node.__class__.__name__ + visitor = getattr(self, method, self.generic_visit) + return visitor(node) + + def generic_visit(self, node): + """ Called if no explicit visitor function exists for a + node. Implements preorder visiting of the node. + """ + for c in node.children(): + self.visit(c) + + +''' + + +if __name__ == "__main__": + import sys + ast_gen = ASTCodeGenerator('_c_ast.cfg') + ast_gen.generate(open('c_ast.py', 'w')) + diff --git a/pycparser/_build_tables.py b/pycparser/_build_tables.py index 902773e..04524e0 100644 --- a/pycparser/_build_tables.py +++ b/pycparser/_build_tables.py @@ -3,7 +3,8 @@ # # A dummy for generating the lexing/parsing tables and and # compiling them into .pyc for faster execution in optimized mode. -# Also generates AST code from the _c_ast.yaml configuration file. +# Also generates AST code from the configuration file. +# Should be called from the installation directory. # # Copyright (C) 2008-2010, Eli Bendersky # License: LGPL @@ -12,7 +13,7 @@ # Generate c_ast.py # from _ast_gen import ASTCodeGenerator -ast_gen = ASTCodeGenerator('_c_ast.yaml') +ast_gen = ASTCodeGenerator('_c_ast.cfg') ast_gen.generate(open('c_ast.py', 'w')) from pycparser import c_parser diff --git a/pycparser/c_ast.py b/pycparser/c_ast.py index 12d690c..532fa8e 100644 --- a/pycparser/c_ast.py +++ b/pycparser/c_ast.py @@ -1,1237 +1,1237 @@ -#-----------------------------------------------------------------
-# ** ATTENTION **
-# This code was automatically generated from the file:
-# _c_ast.yaml
-#
-# Do not modify it directly. Modify the configuration file and
-# run the generator again.
-# ** ** *** ** **
-#
-# pycparser: c_ast.py
-#
-# AST Node classes.
-#
-# Copyright (C) 2008, Eli Bendersky
-# License: LGPL
-#-----------------------------------------------------------------
-
-
-import sys
-
-
-class Node(object):
- """ Abstract base class for AST nodes.
- """
- def children(self):
- """ A sequence of all children that are Nodes
- """
- pass
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- """ Pretty print the Node and all its attributes and
- children (recursively) to a buffer.
-
- file:
- Open IO buffer into which the Node is printed.
-
- offset:
- Initial offset (amount of leading spaces)
-
- attrnames:
- True if you want to see the attribute names in
- name=value pairs. False to only see the values.
-
- showcoord:
- Do you want the coordinates of each Node to be
- displayed.
- """
- pass
-
-
-class NodeVisitor(object):
- """ A base NodeVisitor class for visiting c_ast nodes.
- Subclass it and define your own visit_XXX methods, where
- XXX is the class name you want to visit with these
- methods.
-
- For example:
-
- class ConstantVisitor(NodeVisitor):
- def __init__(self):
- self.values = []
-
- def visit_Constant(self, node):
- self.values.append(node.value)
-
- Creates a list of values of all the constant nodes
- encountered below the given node. To use it:
-
- cv = ConstantVisitor()
- cv.visit(node)
-
- Notes:
-
- * generic_visit() will be called for AST nodes for which
- no visit_XXX method was defined.
- * The children of nodes for which a visit_XXX was
- defined will not be visited - if you need this, call
- generic_visit() on the node.
- You can use:
- NodeVisitor.generic_visit(self, node)
- * Modeled after Python's own AST visiting facilities
- (the ast module of Python 3.0)
- """
- def visit(self, node):
- """ Visit a node.
- """
- method = 'visit_' + node.__class__.__name__
- visitor = getattr(self, method, self.generic_visit)
- return visitor(node)
-
- def generic_visit(self, node):
- """ Called if no explicit visitor function exists for a
- node. Implements preorder visiting of the node.
- """
- for c in node.children():
- self.visit(c)
-
-
-class Typedef(Node):
- def __init__(self, name, quals, storage, type, coord=None):
- self.name = name
- self.quals = quals
- self.storage = storage
- self.type = type
- self.coord = coord
-
- def children(self):
- nodelist = []
- if self.type is not None: nodelist.append(self.type)
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'Typedef: ')
-
- if attrnames:
- attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name)), ("quals", repr(self.quals)), ("storage", repr(self.storage))])
- else:
- attrstr = ', '.join('%s' % v for v in [self.name, self.quals, self.storage])
- buf.write(attrstr)
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class Struct(Node):
- def __init__(self, name, decls, coord=None):
- self.name = name
- self.decls = decls
- self.coord = coord
-
- def children(self):
- nodelist = []
- if self.decls is not None: nodelist.extend(self.decls)
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'Struct: ')
-
- if attrnames:
- attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))])
- else:
- attrstr = ', '.join('%s' % v for v in [self.name])
- buf.write(attrstr)
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class For(Node):
- def __init__(self, init, cond, next, stmt, coord=None):
- self.init = init
- self.cond = cond
- self.next = next
- self.stmt = stmt
- self.coord = coord
-
- def children(self):
- nodelist = []
- if self.init is not None: nodelist.append(self.init)
- if self.cond is not None: nodelist.append(self.cond)
- if self.next is not None: nodelist.append(self.next)
- if self.stmt is not None: nodelist.append(self.stmt)
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'For: ')
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class UnaryOp(Node):
- def __init__(self, op, expr, coord=None):
- self.op = op
- self.expr = expr
- self.coord = coord
-
- def children(self):
- nodelist = []
- if self.expr is not None: nodelist.append(self.expr)
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'UnaryOp: ')
-
- if attrnames:
- attrstr = ', '.join('%s=%s' % nv for nv in [("op", repr(self.op))])
- else:
- attrstr = ', '.join('%s' % v for v in [self.op])
- buf.write(attrstr)
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class Union(Node):
- def __init__(self, name, decls, coord=None):
- self.name = name
- self.decls = decls
- self.coord = coord
-
- def children(self):
- nodelist = []
- if self.decls is not None: nodelist.extend(self.decls)
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'Union: ')
-
- if attrnames:
- attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))])
- else:
- attrstr = ', '.join('%s' % v for v in [self.name])
- buf.write(attrstr)
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class CompoundLiteral(Node):
- def __init__(self, type, init, coord=None):
- self.type = type
- self.init = init
- self.coord = coord
-
- def children(self):
- nodelist = []
- if self.type is not None: nodelist.append(self.type)
- if self.init is not None: nodelist.append(self.init)
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'CompoundLiteral: ')
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class TernaryOp(Node):
- def __init__(self, cond, iftrue, iffalse, coord=None):
- self.cond = cond
- self.iftrue = iftrue
- self.iffalse = iffalse
- self.coord = coord
-
- def children(self):
- nodelist = []
- if self.cond is not None: nodelist.append(self.cond)
- if self.iftrue is not None: nodelist.append(self.iftrue)
- if self.iffalse is not None: nodelist.append(self.iffalse)
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'TernaryOp: ')
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class Label(Node):
- def __init__(self, name, stmt, coord=None):
- self.name = name
- self.stmt = stmt
- self.coord = coord
-
- def children(self):
- nodelist = []
- if self.stmt is not None: nodelist.append(self.stmt)
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'Label: ')
-
- if attrnames:
- attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))])
- else:
- attrstr = ', '.join('%s' % v for v in [self.name])
- buf.write(attrstr)
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class IdentifierType(Node):
- def __init__(self, names, coord=None):
- self.names = names
- self.coord = coord
-
- def children(self):
- nodelist = []
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'IdentifierType: ')
-
- if attrnames:
- attrstr = ', '.join('%s=%s' % nv for nv in [("names", repr(self.names))])
- else:
- attrstr = ', '.join('%s' % v for v in [self.names])
- buf.write(attrstr)
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class FuncDef(Node):
- def __init__(self, decl, param_decls, body, coord=None):
- self.decl = decl
- self.param_decls = param_decls
- self.body = body
- self.coord = coord
-
- def children(self):
- nodelist = []
- if self.decl is not None: nodelist.append(self.decl)
- if self.body is not None: nodelist.append(self.body)
- if self.param_decls is not None: nodelist.extend(self.param_decls)
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'FuncDef: ')
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class DeclList(Node):
- def __init__(self, decls, coord=None):
- self.decls = decls
- self.coord = coord
-
- def children(self):
- nodelist = []
- if self.decls is not None: nodelist.extend(self.decls)
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'DeclList: ')
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class Enumerator(Node):
- def __init__(self, name, value, coord=None):
- self.name = name
- self.value = value
- self.coord = coord
-
- def children(self):
- nodelist = []
- if self.value is not None: nodelist.append(self.value)
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'Enumerator: ')
-
- if attrnames:
- attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))])
- else:
- attrstr = ', '.join('%s' % v for v in [self.name])
- buf.write(attrstr)
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class FuncCall(Node):
- def __init__(self, name, args, coord=None):
- self.name = name
- self.args = args
- self.coord = coord
-
- def children(self):
- nodelist = []
- if self.name is not None: nodelist.append(self.name)
- if self.args is not None: nodelist.append(self.args)
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'FuncCall: ')
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class Assignment(Node):
- def __init__(self, op, lvalue, rvalue, coord=None):
- self.op = op
- self.lvalue = lvalue
- self.rvalue = rvalue
- self.coord = coord
-
- def children(self):
- nodelist = []
- if self.lvalue is not None: nodelist.append(self.lvalue)
- if self.rvalue is not None: nodelist.append(self.rvalue)
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'Assignment: ')
-
- if attrnames:
- attrstr = ', '.join('%s=%s' % nv for nv in [("op", repr(self.op))])
- else:
- attrstr = ', '.join('%s' % v for v in [self.op])
- buf.write(attrstr)
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class FuncDecl(Node):
- def __init__(self, args, type, coord=None):
- self.args = args
- self.type = type
- self.coord = coord
-
- def children(self):
- nodelist = []
- if self.args is not None: nodelist.append(self.args)
- if self.type is not None: nodelist.append(self.type)
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'FuncDecl: ')
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class Enum(Node):
- def __init__(self, name, values, coord=None):
- self.name = name
- self.values = values
- self.coord = coord
-
- def children(self):
- nodelist = []
- if self.values is not None: nodelist.append(self.values)
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'Enum: ')
-
- if attrnames:
- attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))])
- else:
- attrstr = ', '.join('%s' % v for v in [self.name])
- buf.write(attrstr)
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class ExprList(Node):
- def __init__(self, exprs, coord=None):
- self.exprs = exprs
- self.coord = coord
-
- def children(self):
- nodelist = []
- if self.exprs is not None: nodelist.extend(self.exprs)
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'ExprList: ')
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class Break(Node):
- def __init__(self, coord=None):
- self.coord = coord
-
- def children(self):
- return ()
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'Break: ')
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class DoWhile(Node):
- def __init__(self, cond, stmt, coord=None):
- self.cond = cond
- self.stmt = stmt
- self.coord = coord
-
- def children(self):
- nodelist = []
- if self.cond is not None: nodelist.append(self.cond)
- if self.stmt is not None: nodelist.append(self.stmt)
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'DoWhile: ')
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class StructRef(Node):
- def __init__(self, name, type, field, coord=None):
- self.name = name
- self.type = type
- self.field = field
- self.coord = coord
-
- def children(self):
- nodelist = []
- if self.name is not None: nodelist.append(self.name)
- if self.field is not None: nodelist.append(self.field)
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'StructRef: ')
-
- if attrnames:
- attrstr = ', '.join('%s=%s' % nv for nv in [("type", repr(self.type))])
- else:
- attrstr = ', '.join('%s' % v for v in [self.type])
- buf.write(attrstr)
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class BinaryOp(Node):
- def __init__(self, op, left, right, coord=None):
- self.op = op
- self.left = left
- self.right = right
- self.coord = coord
-
- def children(self):
- nodelist = []
- if self.left is not None: nodelist.append(self.left)
- if self.right is not None: nodelist.append(self.right)
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'BinaryOp: ')
-
- if attrnames:
- attrstr = ', '.join('%s=%s' % nv for nv in [("op", repr(self.op))])
- else:
- attrstr = ', '.join('%s' % v for v in [self.op])
- buf.write(attrstr)
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class Compound(Node):
- def __init__(self, block_items, coord=None):
- self.block_items = block_items
- self.coord = coord
-
- def children(self):
- nodelist = []
- if self.block_items is not None: nodelist.extend(self.block_items)
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'Compound: ')
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class ArrayDecl(Node):
- def __init__(self, type, dim, coord=None):
- self.type = type
- self.dim = dim
- self.coord = coord
-
- def children(self):
- nodelist = []
- if self.type is not None: nodelist.append(self.type)
- if self.dim is not None: nodelist.append(self.dim)
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'ArrayDecl: ')
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class Case(Node):
- def __init__(self, expr, stmt, coord=None):
- self.expr = expr
- self.stmt = stmt
- self.coord = coord
-
- def children(self):
- nodelist = []
- if self.expr is not None: nodelist.append(self.expr)
- if self.stmt is not None: nodelist.append(self.stmt)
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'Case: ')
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class Cast(Node):
- def __init__(self, to_type, expr, coord=None):
- self.to_type = to_type
- self.expr = expr
- self.coord = coord
-
- def children(self):
- nodelist = []
- if self.to_type is not None: nodelist.append(self.to_type)
- if self.expr is not None: nodelist.append(self.expr)
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'Cast: ')
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class TypeDecl(Node):
- def __init__(self, declname, quals, type, coord=None):
- self.declname = declname
- self.quals = quals
- self.type = type
- self.coord = coord
-
- def children(self):
- nodelist = []
- if self.type is not None: nodelist.append(self.type)
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'TypeDecl: ')
-
- if attrnames:
- attrstr = ', '.join('%s=%s' % nv for nv in [("declname", repr(self.declname)), ("quals", repr(self.quals))])
- else:
- attrstr = ', '.join('%s' % v for v in [self.declname, self.quals])
- buf.write(attrstr)
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class Default(Node):
- def __init__(self, stmt, coord=None):
- self.stmt = stmt
- self.coord = coord
-
- def children(self):
- nodelist = []
- if self.stmt is not None: nodelist.append(self.stmt)
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'Default: ')
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class PtrDecl(Node):
- def __init__(self, quals, type, coord=None):
- self.quals = quals
- self.type = type
- self.coord = coord
-
- def children(self):
- nodelist = []
- if self.type is not None: nodelist.append(self.type)
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'PtrDecl: ')
-
- if attrnames:
- attrstr = ', '.join('%s=%s' % nv for nv in [("quals", repr(self.quals))])
- else:
- attrstr = ', '.join('%s' % v for v in [self.quals])
- buf.write(attrstr)
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class Switch(Node):
- def __init__(self, cond, stmt, coord=None):
- self.cond = cond
- self.stmt = stmt
- self.coord = coord
-
- def children(self):
- nodelist = []
- if self.cond is not None: nodelist.append(self.cond)
- if self.stmt is not None: nodelist.append(self.stmt)
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'Switch: ')
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class Continue(Node):
- def __init__(self, coord=None):
- self.coord = coord
-
- def children(self):
- return ()
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'Continue: ')
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class ParamList(Node):
- def __init__(self, params, coord=None):
- self.params = params
- self.coord = coord
-
- def children(self):
- nodelist = []
- if self.params is not None: nodelist.extend(self.params)
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'ParamList: ')
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class Return(Node):
- def __init__(self, expr, coord=None):
- self.expr = expr
- self.coord = coord
-
- def children(self):
- nodelist = []
- if self.expr is not None: nodelist.append(self.expr)
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'Return: ')
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class Typename(Node):
- def __init__(self, quals, type, coord=None):
- self.quals = quals
- self.type = type
- self.coord = coord
-
- def children(self):
- nodelist = []
- if self.type is not None: nodelist.append(self.type)
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'Typename: ')
-
- if attrnames:
- attrstr = ', '.join('%s=%s' % nv for nv in [("quals", repr(self.quals))])
- else:
- attrstr = ', '.join('%s' % v for v in [self.quals])
- buf.write(attrstr)
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class ID(Node):
- def __init__(self, name, coord=None):
- self.name = name
- self.coord = coord
-
- def children(self):
- nodelist = []
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'ID: ')
-
- if attrnames:
- attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))])
- else:
- attrstr = ', '.join('%s' % v for v in [self.name])
- buf.write(attrstr)
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class Goto(Node):
- def __init__(self, name, coord=None):
- self.name = name
- self.coord = coord
-
- def children(self):
- nodelist = []
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'Goto: ')
-
- if attrnames:
- attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))])
- else:
- attrstr = ', '.join('%s' % v for v in [self.name])
- buf.write(attrstr)
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class Decl(Node):
- def __init__(self, name, quals, storage, funcspec, type, init, bitsize, coord=None):
- self.name = name
- self.quals = quals
- self.storage = storage
- self.funcspec = funcspec
- self.type = type
- self.init = init
- self.bitsize = bitsize
- self.coord = coord
-
- def children(self):
- nodelist = []
- if self.type is not None: nodelist.append(self.type)
- if self.init is not None: nodelist.append(self.init)
- if self.bitsize is not None: nodelist.append(self.bitsize)
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'Decl: ')
-
- if attrnames:
- attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name)), ("quals", repr(self.quals)), ("storage", repr(self.storage)), ("funcspec", repr(self.funcspec))])
- else:
- attrstr = ', '.join('%s' % v for v in [self.name, self.quals, self.storage, self.funcspec])
- buf.write(attrstr)
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class Constant(Node):
- def __init__(self, type, value, coord=None):
- self.type = type
- self.value = value
- self.coord = coord
-
- def children(self):
- nodelist = []
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'Constant: ')
-
- if attrnames:
- attrstr = ', '.join('%s=%s' % nv for nv in [("type", repr(self.type)), ("value", repr(self.value))])
- else:
- attrstr = ', '.join('%s' % v for v in [self.type, self.value])
- buf.write(attrstr)
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class FileAST(Node):
- def __init__(self, ext, coord=None):
- self.ext = ext
- self.coord = coord
-
- def children(self):
- nodelist = []
- if self.ext is not None: nodelist.extend(self.ext)
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'FileAST: ')
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class ArrayRef(Node):
- def __init__(self, name, subscript, coord=None):
- self.name = name
- self.subscript = subscript
- self.coord = coord
-
- def children(self):
- nodelist = []
- if self.name is not None: nodelist.append(self.name)
- if self.subscript is not None: nodelist.append(self.subscript)
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'ArrayRef: ')
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class While(Node):
- def __init__(self, cond, stmt, coord=None):
- self.cond = cond
- self.stmt = stmt
- self.coord = coord
-
- def children(self):
- nodelist = []
- if self.cond is not None: nodelist.append(self.cond)
- if self.stmt is not None: nodelist.append(self.stmt)
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'While: ')
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class NamedInitializer(Node):
- def __init__(self, name, expr, coord=None):
- self.name = name
- self.expr = expr
- self.coord = coord
-
- def children(self):
- nodelist = []
- if self.expr is not None: nodelist.append(self.expr)
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'NamedInitializer: ')
-
- if attrnames:
- attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))])
- else:
- attrstr = ', '.join('%s' % v for v in [self.name])
- buf.write(attrstr)
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class EnumeratorList(Node):
- def __init__(self, enumerators, coord=None):
- self.enumerators = enumerators
- self.coord = coord
-
- def children(self):
- nodelist = []
- if self.enumerators is not None: nodelist.extend(self.enumerators)
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'EnumeratorList: ')
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class EllipsisParam(Node):
- def __init__(self, coord=None):
- self.coord = coord
-
- def children(self):
- return ()
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'EllipsisParam: ')
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
-class If(Node):
- def __init__(self, cond, iftrue, iffalse, coord=None):
- self.cond = cond
- self.iftrue = iftrue
- self.iffalse = iffalse
- self.coord = coord
-
- def children(self):
- nodelist = []
- if self.cond is not None: nodelist.append(self.cond)
- if self.iftrue is not None: nodelist.append(self.iftrue)
- if self.iffalse is not None: nodelist.append(self.iffalse)
- return tuple(nodelist)
-
- def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False):
- lead = ' ' * offset
- buf.write(lead + 'If: ')
-
- if showcoord:
- buf.write(' (at %s)' % self.coord)
- buf.write('\n')
-
- for c in self.children():
- c.show(buf, offset + 2, attrnames, showcoord)
-
-
+#----------------------------------------------------------------- +# ** ATTENTION ** +# This code was automatically generated from the file: +# _c_ast.cfg +# +# Do not modify it directly. Modify the configuration file and +# run the generator again. +# ** ** *** ** ** +# +# pycparser: c_ast.py +# +# AST Node classes. +# +# Copyright (C) 2008-2010, Eli Bendersky +# License: LGPL +#----------------------------------------------------------------- + + +import sys + + +class Node(object): + """ Abstract base class for AST nodes. + """ + def children(self): + """ A sequence of all children that are Nodes + """ + pass + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + """ Pretty print the Node and all its attributes and + children (recursively) to a buffer. + + file: + Open IO buffer into which the Node is printed. + + offset: + Initial offset (amount of leading spaces) + + attrnames: + True if you want to see the attribute names in + name=value pairs. False to only see the values. + + showcoord: + Do you want the coordinates of each Node to be + displayed. + """ + pass + + +class NodeVisitor(object): + """ A base NodeVisitor class for visiting c_ast nodes. + Subclass it and define your own visit_XXX methods, where + XXX is the class name you want to visit with these + methods. + + For example: + + class ConstantVisitor(NodeVisitor): + def __init__(self): + self.values = [] + + def visit_Constant(self, node): + self.values.append(node.value) + + Creates a list of values of all the constant nodes + encountered below the given node. To use it: + + cv = ConstantVisitor() + cv.visit(node) + + Notes: + + * generic_visit() will be called for AST nodes for which + no visit_XXX method was defined. + * The children of nodes for which a visit_XXX was + defined will not be visited - if you need this, call + generic_visit() on the node. + You can use: + NodeVisitor.generic_visit(self, node) + * Modeled after Python's own AST visiting facilities + (the ast module of Python 3.0) + """ + def visit(self, node): + """ Visit a node. + """ + method = 'visit_' + node.__class__.__name__ + visitor = getattr(self, method, self.generic_visit) + return visitor(node) + + def generic_visit(self, node): + """ Called if no explicit visitor function exists for a + node. Implements preorder visiting of the node. + """ + for c in node.children(): + self.visit(c) + + +class ArrayDecl(Node): + def __init__(self, type, dim, coord=None): + self.type = type + self.dim = dim + self.coord = coord + + def children(self): + nodelist = [] + if self.type is not None: nodelist.append(self.type) + if self.dim is not None: nodelist.append(self.dim) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'ArrayDecl: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class ArrayRef(Node): + def __init__(self, name, subscript, coord=None): + self.name = name + self.subscript = subscript + self.coord = coord + + def children(self): + nodelist = [] + if self.name is not None: nodelist.append(self.name) + if self.subscript is not None: nodelist.append(self.subscript) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'ArrayRef: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class Assignment(Node): + def __init__(self, op, lvalue, rvalue, coord=None): + self.op = op + self.lvalue = lvalue + self.rvalue = rvalue + self.coord = coord + + def children(self): + nodelist = [] + if self.lvalue is not None: nodelist.append(self.lvalue) + if self.rvalue is not None: nodelist.append(self.rvalue) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Assignment: ') + + if attrnames: + attrstr = ', '.join('%s=%s' % nv for nv in [("op", repr(self.op))]) + else: + attrstr = ', '.join('%s' % v for v in [self.op]) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class BinaryOp(Node): + def __init__(self, op, left, right, coord=None): + self.op = op + self.left = left + self.right = right + self.coord = coord + + def children(self): + nodelist = [] + if self.left is not None: nodelist.append(self.left) + if self.right is not None: nodelist.append(self.right) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'BinaryOp: ') + + if attrnames: + attrstr = ', '.join('%s=%s' % nv for nv in [("op", repr(self.op))]) + else: + attrstr = ', '.join('%s' % v for v in [self.op]) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class Break(Node): + def __init__(self, coord=None): + self.coord = coord + + def children(self): + return () + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Break: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class Case(Node): + def __init__(self, expr, stmt, coord=None): + self.expr = expr + self.stmt = stmt + self.coord = coord + + def children(self): + nodelist = [] + if self.expr is not None: nodelist.append(self.expr) + if self.stmt is not None: nodelist.append(self.stmt) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Case: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class Cast(Node): + def __init__(self, to_type, expr, coord=None): + self.to_type = to_type + self.expr = expr + self.coord = coord + + def children(self): + nodelist = [] + if self.to_type is not None: nodelist.append(self.to_type) + if self.expr is not None: nodelist.append(self.expr) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Cast: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class Compound(Node): + def __init__(self, block_items, coord=None): + self.block_items = block_items + self.coord = coord + + def children(self): + nodelist = [] + if self.block_items is not None: nodelist.extend(self.block_items) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Compound: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class CompoundLiteral(Node): + def __init__(self, type, init, coord=None): + self.type = type + self.init = init + self.coord = coord + + def children(self): + nodelist = [] + if self.type is not None: nodelist.append(self.type) + if self.init is not None: nodelist.append(self.init) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'CompoundLiteral: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class Constant(Node): + def __init__(self, type, value, coord=None): + self.type = type + self.value = value + self.coord = coord + + def children(self): + nodelist = [] + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Constant: ') + + if attrnames: + attrstr = ', '.join('%s=%s' % nv for nv in [("type", repr(self.type)), ("value", repr(self.value))]) + else: + attrstr = ', '.join('%s' % v for v in [self.type, self.value]) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class Continue(Node): + def __init__(self, coord=None): + self.coord = coord + + def children(self): + return () + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Continue: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class Decl(Node): + def __init__(self, name, quals, storage, funcspec, type, init, bitsize, coord=None): + self.name = name + self.quals = quals + self.storage = storage + self.funcspec = funcspec + self.type = type + self.init = init + self.bitsize = bitsize + self.coord = coord + + def children(self): + nodelist = [] + if self.type is not None: nodelist.append(self.type) + if self.init is not None: nodelist.append(self.init) + if self.bitsize is not None: nodelist.append(self.bitsize) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Decl: ') + + if attrnames: + attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name)), ("quals", repr(self.quals)), ("storage", repr(self.storage)), ("funcspec", repr(self.funcspec))]) + else: + attrstr = ', '.join('%s' % v for v in [self.name, self.quals, self.storage, self.funcspec]) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class DeclList(Node): + def __init__(self, decls, coord=None): + self.decls = decls + self.coord = coord + + def children(self): + nodelist = [] + if self.decls is not None: nodelist.extend(self.decls) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'DeclList: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class Default(Node): + def __init__(self, stmt, coord=None): + self.stmt = stmt + self.coord = coord + + def children(self): + nodelist = [] + if self.stmt is not None: nodelist.append(self.stmt) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Default: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class DoWhile(Node): + def __init__(self, cond, stmt, coord=None): + self.cond = cond + self.stmt = stmt + self.coord = coord + + def children(self): + nodelist = [] + if self.cond is not None: nodelist.append(self.cond) + if self.stmt is not None: nodelist.append(self.stmt) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'DoWhile: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class EllipsisParam(Node): + def __init__(self, coord=None): + self.coord = coord + + def children(self): + return () + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'EllipsisParam: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class Enum(Node): + def __init__(self, name, values, coord=None): + self.name = name + self.values = values + self.coord = coord + + def children(self): + nodelist = [] + if self.values is not None: nodelist.append(self.values) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Enum: ') + + if attrnames: + attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))]) + else: + attrstr = ', '.join('%s' % v for v in [self.name]) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class Enumerator(Node): + def __init__(self, name, value, coord=None): + self.name = name + self.value = value + self.coord = coord + + def children(self): + nodelist = [] + if self.value is not None: nodelist.append(self.value) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Enumerator: ') + + if attrnames: + attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))]) + else: + attrstr = ', '.join('%s' % v for v in [self.name]) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class EnumeratorList(Node): + def __init__(self, enumerators, coord=None): + self.enumerators = enumerators + self.coord = coord + + def children(self): + nodelist = [] + if self.enumerators is not None: nodelist.extend(self.enumerators) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'EnumeratorList: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class ExprList(Node): + def __init__(self, exprs, coord=None): + self.exprs = exprs + self.coord = coord + + def children(self): + nodelist = [] + if self.exprs is not None: nodelist.extend(self.exprs) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'ExprList: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class FileAST(Node): + def __init__(self, ext, coord=None): + self.ext = ext + self.coord = coord + + def children(self): + nodelist = [] + if self.ext is not None: nodelist.extend(self.ext) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'FileAST: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class For(Node): + def __init__(self, init, cond, next, stmt, coord=None): + self.init = init + self.cond = cond + self.next = next + self.stmt = stmt + self.coord = coord + + def children(self): + nodelist = [] + if self.init is not None: nodelist.append(self.init) + if self.cond is not None: nodelist.append(self.cond) + if self.next is not None: nodelist.append(self.next) + if self.stmt is not None: nodelist.append(self.stmt) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'For: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class FuncCall(Node): + def __init__(self, name, args, coord=None): + self.name = name + self.args = args + self.coord = coord + + def children(self): + nodelist = [] + if self.name is not None: nodelist.append(self.name) + if self.args is not None: nodelist.append(self.args) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'FuncCall: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class FuncDecl(Node): + def __init__(self, args, type, coord=None): + self.args = args + self.type = type + self.coord = coord + + def children(self): + nodelist = [] + if self.args is not None: nodelist.append(self.args) + if self.type is not None: nodelist.append(self.type) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'FuncDecl: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class FuncDef(Node): + def __init__(self, decl, param_decls, body, coord=None): + self.decl = decl + self.param_decls = param_decls + self.body = body + self.coord = coord + + def children(self): + nodelist = [] + if self.decl is not None: nodelist.append(self.decl) + if self.body is not None: nodelist.append(self.body) + if self.param_decls is not None: nodelist.extend(self.param_decls) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'FuncDef: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class Goto(Node): + def __init__(self, name, coord=None): + self.name = name + self.coord = coord + + def children(self): + nodelist = [] + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Goto: ') + + if attrnames: + attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))]) + else: + attrstr = ', '.join('%s' % v for v in [self.name]) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class ID(Node): + def __init__(self, name, coord=None): + self.name = name + self.coord = coord + + def children(self): + nodelist = [] + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'ID: ') + + if attrnames: + attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))]) + else: + attrstr = ', '.join('%s' % v for v in [self.name]) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class IdentifierType(Node): + def __init__(self, names, coord=None): + self.names = names + self.coord = coord + + def children(self): + nodelist = [] + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'IdentifierType: ') + + if attrnames: + attrstr = ', '.join('%s=%s' % nv for nv in [("names", repr(self.names))]) + else: + attrstr = ', '.join('%s' % v for v in [self.names]) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class If(Node): + def __init__(self, cond, iftrue, iffalse, coord=None): + self.cond = cond + self.iftrue = iftrue + self.iffalse = iffalse + self.coord = coord + + def children(self): + nodelist = [] + if self.cond is not None: nodelist.append(self.cond) + if self.iftrue is not None: nodelist.append(self.iftrue) + if self.iffalse is not None: nodelist.append(self.iffalse) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'If: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class Label(Node): + def __init__(self, name, stmt, coord=None): + self.name = name + self.stmt = stmt + self.coord = coord + + def children(self): + nodelist = [] + if self.stmt is not None: nodelist.append(self.stmt) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Label: ') + + if attrnames: + attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))]) + else: + attrstr = ', '.join('%s' % v for v in [self.name]) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class NamedInitializer(Node): + def __init__(self, name, expr, coord=None): + self.name = name + self.expr = expr + self.coord = coord + + def children(self): + nodelist = [] + if self.expr is not None: nodelist.append(self.expr) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'NamedInitializer: ') + + if attrnames: + attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))]) + else: + attrstr = ', '.join('%s' % v for v in [self.name]) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class ParamList(Node): + def __init__(self, params, coord=None): + self.params = params + self.coord = coord + + def children(self): + nodelist = [] + if self.params is not None: nodelist.extend(self.params) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'ParamList: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class PtrDecl(Node): + def __init__(self, quals, type, coord=None): + self.quals = quals + self.type = type + self.coord = coord + + def children(self): + nodelist = [] + if self.type is not None: nodelist.append(self.type) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'PtrDecl: ') + + if attrnames: + attrstr = ', '.join('%s=%s' % nv for nv in [("quals", repr(self.quals))]) + else: + attrstr = ', '.join('%s' % v for v in [self.quals]) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class Return(Node): + def __init__(self, expr, coord=None): + self.expr = expr + self.coord = coord + + def children(self): + nodelist = [] + if self.expr is not None: nodelist.append(self.expr) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Return: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class Struct(Node): + def __init__(self, name, decls, coord=None): + self.name = name + self.decls = decls + self.coord = coord + + def children(self): + nodelist = [] + if self.decls is not None: nodelist.extend(self.decls) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Struct: ') + + if attrnames: + attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))]) + else: + attrstr = ', '.join('%s' % v for v in [self.name]) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class StructRef(Node): + def __init__(self, name, type, field, coord=None): + self.name = name + self.type = type + self.field = field + self.coord = coord + + def children(self): + nodelist = [] + if self.name is not None: nodelist.append(self.name) + if self.field is not None: nodelist.append(self.field) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'StructRef: ') + + if attrnames: + attrstr = ', '.join('%s=%s' % nv for nv in [("type", repr(self.type))]) + else: + attrstr = ', '.join('%s' % v for v in [self.type]) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class Switch(Node): + def __init__(self, cond, stmt, coord=None): + self.cond = cond + self.stmt = stmt + self.coord = coord + + def children(self): + nodelist = [] + if self.cond is not None: nodelist.append(self.cond) + if self.stmt is not None: nodelist.append(self.stmt) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Switch: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class TernaryOp(Node): + def __init__(self, cond, iftrue, iffalse, coord=None): + self.cond = cond + self.iftrue = iftrue + self.iffalse = iffalse + self.coord = coord + + def children(self): + nodelist = [] + if self.cond is not None: nodelist.append(self.cond) + if self.iftrue is not None: nodelist.append(self.iftrue) + if self.iffalse is not None: nodelist.append(self.iffalse) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'TernaryOp: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class TypeDecl(Node): + def __init__(self, declname, quals, type, coord=None): + self.declname = declname + self.quals = quals + self.type = type + self.coord = coord + + def children(self): + nodelist = [] + if self.type is not None: nodelist.append(self.type) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'TypeDecl: ') + + if attrnames: + attrstr = ', '.join('%s=%s' % nv for nv in [("declname", repr(self.declname)), ("quals", repr(self.quals))]) + else: + attrstr = ', '.join('%s' % v for v in [self.declname, self.quals]) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class Typedef(Node): + def __init__(self, name, quals, storage, type, coord=None): + self.name = name + self.quals = quals + self.storage = storage + self.type = type + self.coord = coord + + def children(self): + nodelist = [] + if self.type is not None: nodelist.append(self.type) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Typedef: ') + + if attrnames: + attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name)), ("quals", repr(self.quals)), ("storage", repr(self.storage))]) + else: + attrstr = ', '.join('%s' % v for v in [self.name, self.quals, self.storage]) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class Typename(Node): + def __init__(self, quals, type, coord=None): + self.quals = quals + self.type = type + self.coord = coord + + def children(self): + nodelist = [] + if self.type is not None: nodelist.append(self.type) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Typename: ') + + if attrnames: + attrstr = ', '.join('%s=%s' % nv for nv in [("quals", repr(self.quals))]) + else: + attrstr = ', '.join('%s' % v for v in [self.quals]) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class UnaryOp(Node): + def __init__(self, op, expr, coord=None): + self.op = op + self.expr = expr + self.coord = coord + + def children(self): + nodelist = [] + if self.expr is not None: nodelist.append(self.expr) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'UnaryOp: ') + + if attrnames: + attrstr = ', '.join('%s=%s' % nv for nv in [("op", repr(self.op))]) + else: + attrstr = ', '.join('%s' % v for v in [self.op]) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class Union(Node): + def __init__(self, name, decls, coord=None): + self.name = name + self.decls = decls + self.coord = coord + + def children(self): + nodelist = [] + if self.decls is not None: nodelist.extend(self.decls) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'Union: ') + + if attrnames: + attrstr = ', '.join('%s=%s' % nv for nv in [("name", repr(self.name))]) + else: + attrstr = ', '.join('%s' % v for v in [self.name]) + buf.write(attrstr) + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + +class While(Node): + def __init__(self, cond, stmt, coord=None): + self.cond = cond + self.stmt = stmt + self.coord = coord + + def children(self): + nodelist = [] + if self.cond is not None: nodelist.append(self.cond) + if self.stmt is not None: nodelist.append(self.stmt) + return tuple(nodelist) + + def show(self, buf=sys.stdout, offset=0, attrnames=False, showcoord=False): + lead = ' ' * offset + buf.write(lead + 'While: ') + + if showcoord: + buf.write(' (at %s)' % self.coord) + buf.write('\n') + + for c in self.children(): + c.show(buf, offset + 2, attrnames, showcoord) + + diff --git a/pycparser/c_parser.py b/pycparser/c_parser.py index e9d0403..38c80b3 100644 --- a/pycparser/c_parser.py +++ b/pycparser/c_parser.py @@ -1,1354 +1,1353 @@ -#-----------------------------------------------------------------
-# pycparser: c_parser.py
-#
-# CParser class: Parser and AST builder for the C language
-#
-# Copyright (C) 2008-2010, Eli Bendersky
-# License: LGPL
-#-----------------------------------------------------------------
-
-import re
-
-import ply.yacc
-
-from . import c_ast
-from .c_lexer import CLexer
-from .plyparser import PLYParser, Coord, ParseError
-
-
-class CParser(PLYParser):
- def __init__(
- self,
- lex_optimize=True,
- lextab='pycparser.lextab',
- yacc_optimize=True,
- yacctab='pycparser.yacctab',
- yacc_debug=False):
- """ Create a new CParser.
-
- Some arguments for controlling the debug/optimization
- level of the parser are provided. The defaults are
- tuned for release/performance mode.
- The simple rules for using them are:
- *) When tweaking CParser/CLexer, set these to False
- *) When releasing a stable parser, set to True
-
- lex_optimize:
- Set to False when you're modifying the lexer.
- Otherwise, changes in the lexer won't be used, if
- some lextab.py file exists.
- When releasing with a stable lexer, set to True
- to save the re-generation of the lexer table on
- each run.
-
- lextab:
- Points to the lex table that's used for optimized
- mode. Only if you're modifying the lexer and want
- some tests to avoid re-generating the table, make
- this point to a local lex table file (that's been
- earlier generated with lex_optimize=True)
-
- yacc_optimize:
- Set to False when you're modifying the parser.
- Otherwise, changes in the parser won't be used, if
- some parsetab.py file exists.
- When releasing with a stable parser, set to True
- to save the re-generation of the parser table on
- each run.
-
- yacctab:
- Points to the yacc table that's used for optimized
- mode. Only if you're modifying the parser, make
- this point to a local yacc table file
-
- yacc_debug:
- Generate a parser.out file that explains how yacc
- built the parsing table from the grammar.
- """
- self.clex = CLexer(
- error_func=self._lex_error_func,
- type_lookup_func=self._lex_type_lookup_func)
-
- self.clex.build(
- optimize=lex_optimize,
- lextab=lextab)
- self.tokens = self.clex.tokens
-
- rules_with_opt = [
- 'abstract_declarator',
- 'assignment_expression',
- 'declaration_list',
- 'declaration_specifiers',
- 'designation',
- 'expression',
- 'identifier_list',
- 'init_declarator_list',
- 'parameter_type_list',
- 'specifier_qualifier_list',
- 'block_item_list',
- 'type_qualifier_list',
- ]
-
- for rule in rules_with_opt:
- self._create_opt_rule(rule)
-
- self.cparser = ply.yacc.yacc(
- module=self,
- start='translation_unit',
- debug=yacc_debug,
- optimize=yacc_optimize,
- tabmodule=yacctab)
-
- # A table of identifiers defined as typedef types during
- # parsing.
- #
- self.typedef_table = set([])
-
- def parse(self, text, filename='', debuglevel=0):
- """ Parses C code and returns an AST.
-
- text:
- A string containing the C source code
-
- filename:
- Name of the file being parsed (for meaningful
- error messages)
-
- debuglevel:
- Debug level to yacc
- """
- self.clex.filename = filename
- self.clex.reset_lineno()
- self.typedef_table = set([])
- return self.cparser.parse(text, lexer=self.clex, debug=debuglevel)
-
- ######################-- PRIVATE --######################
-
- def _lex_error_func(self, msg, line, column):
- self._parse_error(msg, self._coord(line, column))
-
- def _lex_type_lookup_func(self, name):
- """ Looks up types that were previously defined with
- typedef.
- Passed to the lexer for recognizing identifiers that
- are types.
- """
- return name in self.typedef_table
-
- def _add_typedef_type(self, name):
- """ Adds names that were defined as new types with
- typedef.
- """
- self.typedef_table.add(name)
-
- # To understand what's going on here, read sections A.8.5 and
- # A.8.6 of K&R2 very carefully.
- #
- # A C type consists of a basic type declaration, with a list
- # of modifiers. For example:
- #
- # int *c[5];
- #
- # The basic declaration here is 'int x', and the pointer and
- # the array are the modifiers.
- #
- # Basic declarations are represented by TypeDecl (from module
- # c_ast) and the modifiers are FuncDecl, PtrDecl and
- # ArrayDecl.
- #
- # The standard states that whenever a new modifier is parsed,
- # it should be added to the end of the list of modifiers. For
- # example:
- #
- # K&R2 A.8.6.2: Array Declarators
- #
- # In a declaration T D where D has the form
- # D1 [constant-expression-opt]
- # and the type of the identifier in the declaration T D1 is
- # "type-modifier T", the type of the
- # identifier of D is "type-modifier array of T"
- #
- # This is what this method does. The declarator it receives
- # can be a list of declarators ending with TypeDecl. It
- # tacks the modifier to the end of this list, just before
- # the TypeDecl.
- #
- # Additionally, the modifier may be a list itself. This is
- # useful for pointers, that can come as a chain from the rule
- # p_pointer. In this case, the whole modifier list is spliced
- # into the new location.
- #
- def _type_modify_decl(self, decl, modifier):
- """ Tacks a type modifier on a declarator, and returns
- the modified declarator.
-
- Note: the declarator and modifier may be modified
- """
- #~ print '****'
- #~ decl.show(offset=3)
- #~ modifier.show(offset=3)
- #~ print '****'
-
- modifier_head = modifier
- modifier_tail = modifier
-
- # The modifier may be a nested list. Reach its tail.
- #
- while modifier_tail.type:
- modifier_tail = modifier_tail.type
-
- # If the decl is a basic type, just tack the modifier onto
- # it
- #
- if isinstance(decl, c_ast.TypeDecl):
- modifier_tail.type = decl
- return modifier
- else:
- # Otherwise, the decl is a list of modifiers. Reach
- # its tail and splice the modifier onto the tail,
- # pointing to the underlying basic type.
- #
- decl_tail = decl
-
- while not isinstance(decl_tail.type, c_ast.TypeDecl):
- decl_tail = decl_tail.type
-
- modifier_tail.type = decl_tail.type
- decl_tail.type = modifier_head
- return decl
-
- # Due to the order in which declarators are constructed,
- # they have to be fixed in order to look like a normal AST.
- #
- # When a declaration arrives from syntax construction, it has
- # these problems:
- # * The innermost TypeDecl has no type (because the basic
- # type is only known at the uppermost declaration level)
- # * The declaration has no variable name, since that is saved
- # in the innermost TypeDecl
- # * The typename of the declaration is a list of type
- # specifiers, and not a node. Here, basic identifier types
- # should be separated from more complex types like enums
- # and structs.
- #
- # This method fixes these problem.
- #
- def _fix_decl_name_type(self, decl, typename):
- """ Fixes a declaration. Modifies decl.
- """
- # Reach the underlying basic type
- #
- type = decl
- while not isinstance(type, c_ast.TypeDecl):
- type = type.type
-
- decl.name = type.declname
- type.quals = decl.quals
-
- # The typename is a list of types. If any type in this
- # list isn't a simple string type, it must be the only
- # type in the list (it's illegal to declare "int enum .."
- # If all the types are basic, they're collected in the
- # IdentifierType holder.
- #
- for tn in typename:
- if not isinstance(tn, str):
- if len(typename) > 1:
- self._parse_error(
- "Invalid multiple types specified", tn.coord)
- else:
- type.type = tn
- return decl
-
- type.type = c_ast.IdentifierType(typename)
- return decl
-
- def _add_declaration_specifier(self, declspec, newspec, kind):
- """ Declaration specifiers are represented by a dictionary
- with the entries:
- * qual: a list of type qualifiers
- * storage: a list of storage type qualifiers
- * type: a list of type specifiers
- * function: a list of function specifiers
-
- This method is given a declaration specifier, and a
- new specifier of a given kind.
- Returns the declaration specifier, with the new
- specifier incorporated.
- """
- spec = declspec or dict(qual=[], storage=[], type=[], function=[])
- spec[kind].append(newspec)
- return spec
-
- def _build_function_definition(self, decl, spec, param_decls, body):
- """ Builds a function definition.
- """
- declaration = c_ast.Decl(
- name=None,
- quals=spec['qual'],
- storage=spec['storage'],
- funcspec=spec['function'],
- type=decl,
- init=None,
- bitsize=None,
- coord=decl.coord)
-
- typename = spec['type']
- declaration = self._fix_decl_name_type(declaration, typename)
- return c_ast.FuncDef(
- decl=declaration,
- param_decls=param_decls,
- body=body,
- coord=decl.coord)
-
- def _select_struct_union_class(self, token):
- """ Given a token (either STRUCT or UNION), selects the
- appropriate AST class.
- """
- if token == 'struct':
- return c_ast.Struct
- else:
- return c_ast.Union
-
- ##
- ## Precedence and associativity of operators
- ##
- precedence = (
- ('left', 'LOR'),
- ('left', 'LAND'),
- ('left', 'OR'),
- ('left', 'XOR'),
- ('left', 'AND'),
- ('left', 'EQ', 'NE'),
- ('left', 'GT', 'GE', 'LT', 'LE'),
- ('left', 'RSHIFT', 'LSHIFT'),
- ('left', 'PLUS', 'MINUS'),
- ('left', 'TIMES', 'DIVIDE', 'MOD')
- )
-
- ##
- ## Grammar productions
- ## Implementation of the BNF defined in K&R2 A.13
- ##
- def p_translation_unit_1(self, p):
- """ translation_unit : external_declaration
- """
- # Note: external_declaration is already a list
- #
- p[0] = c_ast.FileAST(p[1])
-
- def p_translation_unit_2(self, p):
- """ translation_unit : translation_unit external_declaration
- """
- p[1].ext.extend(p[2])
- p[0] = p[1]
-
- # Declarations always come as lists (because they can be
- # several in one line), so we wrap the function definition
- # into a list as well, to make the return value of
- # external_declaration homogenous.
- #
- def p_external_declaration_1(self, p):
- """ external_declaration : function_definition
- """
- p[0] = [p[1]]
-
- def p_external_declaration_2(self, p):
- """ external_declaration : declaration
- """
- p[0] = p[1]
-
- def p_external_declaration_3(self, p):
- """ external_declaration : pp_directive
- """
- p[0] = p[1]
-
- def p_pp_directive(self, p):
- """ pp_directive : PPHASH
- """
- self._parse_error('Directives not supported yet',
- self._coord(p.lineno(1)))
-
- # In function definitions, the declarator can be followed by
- # a declaration list, for old "K&R style" function definitios.
- #
- def p_function_definition_1(self, p):
- """ function_definition : declarator declaration_list_opt compound_statement
- """
- # no declaration specifiers
- spec = dict(qual=[], storage=[], type=[])
-
- p[0] = self._build_function_definition(
- decl=p[1],
- spec=spec,
- param_decls=p[2],
- body=p[3])
-
- def p_function_definition_2(self, p):
- """ function_definition : declaration_specifiers declarator declaration_list_opt compound_statement
- """
- spec = p[1]
-
- p[0] = self._build_function_definition(
- decl=p[2],
- spec=spec,
- param_decls=p[3],
- body=p[4])
-
- def p_statement(self, p):
- """ statement : labeled_statement
- | expression_statement
- | compound_statement
- | selection_statement
- | iteration_statement
- | jump_statement
- """
- p[0] = p[1]
-
- # In C, declarations can come several in a line:
- # int x, *px, romulo = 5;
- #
- # However, for the AST, we will split them to separate Decl
- # nodes.
- #
- # This rule splits its declarations and always returns a list
- # of Decl nodes, even if it's one element long.
- #
- def p_decl_body(self, p):
- """ decl_body : declaration_specifiers init_declarator_list_opt
- """
- spec = p[1]
- is_typedef = 'typedef' in spec['storage']
- decls = []
-
- # p[2] (init_declarator_list_opt) is either a list or None
- #
- if p[2] is None:
- # Then it's a declaration of a struct / enum tag,
- # without an actual declarator.
- #
- type = spec['type']
- if len(type) > 1:
- coord = '?'
- for t in type:
- if hasattr(t, 'coord'):
- coord = t.coord
- break
-
- self._parse_error('Multiple type specifiers with a type tag', coord)
-
- decl = c_ast.Decl(
- name=None,
- quals=spec['qual'],
- storage=spec['storage'],
- funcspec=spec['function'],
- type=type[0],
- init=None,
- bitsize=None,
- coord=type[0].coord)
- decls = [decl]
- else:
- for decl, init in p[2] or []:
- if is_typedef:
- decl = c_ast.Typedef(
- name=None,
- quals=spec['qual'],
- storage=spec['storage'],
- type=decl,
- coord=decl.coord)
- else:
- decl = c_ast.Decl(
- name=None,
- quals=spec['qual'],
- storage=spec['storage'],
- funcspec=spec['function'],
- type=decl,
- init=init,
- bitsize=None,
- coord=decl.coord)
-
- typename = spec['type']
- fixed_decl = self._fix_decl_name_type(decl, typename)
-
- # Add the type name defined by typedef to a
- # symbol table (for usage in the lexer)
- #
- if is_typedef:
- self._add_typedef_type(fixed_decl.name)
-
- decls.append(fixed_decl)
-
- p[0] = decls
-
- # The declaration has been split to a decl_body sub-rule and
- # SEMI, because having them in a single rule created a problem
- # for defining typedefs.
- #
- # If a typedef line was directly followed by a line using the
- # type defined with the typedef, the type would not be
- # recognized. This is because to reduce the declaration rule,
- # the parser's lookahead asked for the token after SEMI, which
- # was the type from the next line, and the lexer had no chance
- # to see the updated type symbol table.
- #
- # Splitting solves this problem, because after seeing SEMI,
- # the parser reduces decl_body, which actually adds the new
- # type into the table to be seen by the lexer before the next
- # line is reached.
- #
- def p_declaration(self, p):
- """ declaration : decl_body SEMI
- """
- p[0] = p[1]
-
- # Since each declaration is a list of declarations, this
- # rule will combine all the declarations and return a single
- # list
- #
- def p_declaration_list(self, p):
- """ declaration_list : declaration
- | declaration_list declaration
- """
- p[0] = p[1] if len(p) == 2 else p[1] + p[2]
-
- def p_declaration_specifiers_1(self, p):
- """ declaration_specifiers : type_qualifier declaration_specifiers_opt
- """
- p[0] = self._add_declaration_specifier(p[2], p[1], 'qual')
-
- def p_declaration_specifiers_2(self, p):
- """ declaration_specifiers : type_specifier declaration_specifiers_opt
- """
- p[0] = self._add_declaration_specifier(p[2], p[1], 'type')
-
- def p_declaration_specifiers_3(self, p):
- """ declaration_specifiers : storage_class_specifier declaration_specifiers_opt
- """
- p[0] = self._add_declaration_specifier(p[2], p[1], 'storage')
-
- def p_declaration_specifiers_4(self, p):
- """ declaration_specifiers : function_specifier declaration_specifiers_opt
- """
- p[0] = self._add_declaration_specifier(p[2], p[1], 'function')
-
- def p_storage_class_specifier(self, p):
- """ storage_class_specifier : AUTO
- | REGISTER
- | STATIC
- | EXTERN
- | TYPEDEF
- """
- p[0] = p[1]
-
+#----------------------------------------------------------------- +# pycparser: c_parser.py +# +# CParser class: Parser and AST builder for the C language +# +# Copyright (C) 2008-2010, Eli Bendersky +# License: LGPL +#----------------------------------------------------------------- +import re + +import ply.yacc + +from . import c_ast +from .c_lexer import CLexer +from .plyparser import PLYParser, Coord, ParseError + + +class CParser(PLYParser): + def __init__( + self, + lex_optimize=True, + lextab='pycparser.lextab', + yacc_optimize=True, + yacctab='pycparser.yacctab', + yacc_debug=False): + """ Create a new CParser. + + Some arguments for controlling the debug/optimization + level of the parser are provided. The defaults are + tuned for release/performance mode. + The simple rules for using them are: + *) When tweaking CParser/CLexer, set these to False + *) When releasing a stable parser, set to True + + lex_optimize: + Set to False when you're modifying the lexer. + Otherwise, changes in the lexer won't be used, if + some lextab.py file exists. + When releasing with a stable lexer, set to True + to save the re-generation of the lexer table on + each run. + + lextab: + Points to the lex table that's used for optimized + mode. Only if you're modifying the lexer and want + some tests to avoid re-generating the table, make + this point to a local lex table file (that's been + earlier generated with lex_optimize=True) + + yacc_optimize: + Set to False when you're modifying the parser. + Otherwise, changes in the parser won't be used, if + some parsetab.py file exists. + When releasing with a stable parser, set to True + to save the re-generation of the parser table on + each run. + + yacctab: + Points to the yacc table that's used for optimized + mode. Only if you're modifying the parser, make + this point to a local yacc table file + + yacc_debug: + Generate a parser.out file that explains how yacc + built the parsing table from the grammar. + """ + self.clex = CLexer( + error_func=self._lex_error_func, + type_lookup_func=self._lex_type_lookup_func) + + self.clex.build( + optimize=lex_optimize, + lextab=lextab) + self.tokens = self.clex.tokens + + rules_with_opt = [ + 'abstract_declarator', + 'assignment_expression', + 'declaration_list', + 'declaration_specifiers', + 'designation', + 'expression', + 'identifier_list', + 'init_declarator_list', + 'parameter_type_list', + 'specifier_qualifier_list', + 'block_item_list', + 'type_qualifier_list', + ] + + for rule in rules_with_opt: + self._create_opt_rule(rule) + + self.cparser = ply.yacc.yacc( + module=self, + start='translation_unit', + debug=yacc_debug, + optimize=yacc_optimize, + tabmodule=yacctab) + + # A table of identifiers defined as typedef types during + # parsing. + # + self.typedef_table = set([]) + + def parse(self, text, filename='', debuglevel=0): + """ Parses C code and returns an AST. + + text: + A string containing the C source code + + filename: + Name of the file being parsed (for meaningful + error messages) + + debuglevel: + Debug level to yacc + """ + self.clex.filename = filename + self.clex.reset_lineno() + self.typedef_table = set([]) + return self.cparser.parse(text, lexer=self.clex, debug=debuglevel) + + ######################-- PRIVATE --###################### + + def _lex_error_func(self, msg, line, column): + self._parse_error(msg, self._coord(line, column)) + + def _lex_type_lookup_func(self, name): + """ Looks up types that were previously defined with + typedef. + Passed to the lexer for recognizing identifiers that + are types. + """ + return name in self.typedef_table + + def _add_typedef_type(self, name): + """ Adds names that were defined as new types with + typedef. + """ + self.typedef_table.add(name) + + # To understand what's going on here, read sections A.8.5 and + # A.8.6 of K&R2 very carefully. + # + # A C type consists of a basic type declaration, with a list + # of modifiers. For example: + # + # int *c[5]; + # + # The basic declaration here is 'int x', and the pointer and + # the array are the modifiers. + # + # Basic declarations are represented by TypeDecl (from module + # c_ast) and the modifiers are FuncDecl, PtrDecl and + # ArrayDecl. + # + # The standard states that whenever a new modifier is parsed, + # it should be added to the end of the list of modifiers. For + # example: + # + # K&R2 A.8.6.2: Array Declarators + # + # In a declaration T D where D has the form + # D1 [constant-expression-opt] + # and the type of the identifier in the declaration T D1 is + # "type-modifier T", the type of the + # identifier of D is "type-modifier array of T" + # + # This is what this method does. The declarator it receives + # can be a list of declarators ending with TypeDecl. It + # tacks the modifier to the end of this list, just before + # the TypeDecl. + # + # Additionally, the modifier may be a list itself. This is + # useful for pointers, that can come as a chain from the rule + # p_pointer. In this case, the whole modifier list is spliced + # into the new location. + # + def _type_modify_decl(self, decl, modifier): + """ Tacks a type modifier on a declarator, and returns + the modified declarator. + + Note: the declarator and modifier may be modified + """ + #~ print '****' + #~ decl.show(offset=3) + #~ modifier.show(offset=3) + #~ print '****' + + modifier_head = modifier + modifier_tail = modifier + + # The modifier may be a nested list. Reach its tail. + # + while modifier_tail.type: + modifier_tail = modifier_tail.type + + # If the decl is a basic type, just tack the modifier onto + # it + # + if isinstance(decl, c_ast.TypeDecl): + modifier_tail.type = decl + return modifier + else: + # Otherwise, the decl is a list of modifiers. Reach + # its tail and splice the modifier onto the tail, + # pointing to the underlying basic type. + # + decl_tail = decl + + while not isinstance(decl_tail.type, c_ast.TypeDecl): + decl_tail = decl_tail.type + + modifier_tail.type = decl_tail.type + decl_tail.type = modifier_head + return decl + + # Due to the order in which declarators are constructed, + # they have to be fixed in order to look like a normal AST. + # + # When a declaration arrives from syntax construction, it has + # these problems: + # * The innermost TypeDecl has no type (because the basic + # type is only known at the uppermost declaration level) + # * The declaration has no variable name, since that is saved + # in the innermost TypeDecl + # * The typename of the declaration is a list of type + # specifiers, and not a node. Here, basic identifier types + # should be separated from more complex types like enums + # and structs. + # + # This method fixes these problem. + # + def _fix_decl_name_type(self, decl, typename): + """ Fixes a declaration. Modifies decl. + """ + # Reach the underlying basic type + # + type = decl + while not isinstance(type, c_ast.TypeDecl): + type = type.type + + decl.name = type.declname + type.quals = decl.quals + + # The typename is a list of types. If any type in this + # list isn't a simple string type, it must be the only + # type in the list (it's illegal to declare "int enum .." + # If all the types are basic, they're collected in the + # IdentifierType holder. + # + for tn in typename: + if not isinstance(tn, str): + if len(typename) > 1: + self._parse_error( + "Invalid multiple types specified", tn.coord) + else: + type.type = tn + return decl + + type.type = c_ast.IdentifierType(typename) + return decl + + def _add_declaration_specifier(self, declspec, newspec, kind): + """ Declaration specifiers are represented by a dictionary + with the entries: + * qual: a list of type qualifiers + * storage: a list of storage type qualifiers + * type: a list of type specifiers + * function: a list of function specifiers + + This method is given a declaration specifier, and a + new specifier of a given kind. + Returns the declaration specifier, with the new + specifier incorporated. + """ + spec = declspec or dict(qual=[], storage=[], type=[], function=[]) + spec[kind].append(newspec) + return spec + + def _build_function_definition(self, decl, spec, param_decls, body): + """ Builds a function definition. + """ + declaration = c_ast.Decl( + name=None, + quals=spec['qual'], + storage=spec['storage'], + funcspec=spec['function'], + type=decl, + init=None, + bitsize=None, + coord=decl.coord) + + typename = spec['type'] + declaration = self._fix_decl_name_type(declaration, typename) + return c_ast.FuncDef( + decl=declaration, + param_decls=param_decls, + body=body, + coord=decl.coord) + + def _select_struct_union_class(self, token): + """ Given a token (either STRUCT or UNION), selects the + appropriate AST class. + """ + if token == 'struct': + return c_ast.Struct + else: + return c_ast.Union + + ## + ## Precedence and associativity of operators + ## + precedence = ( + ('left', 'LOR'), + ('left', 'LAND'), + ('left', 'OR'), + ('left', 'XOR'), + ('left', 'AND'), + ('left', 'EQ', 'NE'), + ('left', 'GT', 'GE', 'LT', 'LE'), + ('left', 'RSHIFT', 'LSHIFT'), + ('left', 'PLUS', 'MINUS'), + ('left', 'TIMES', 'DIVIDE', 'MOD') + ) + + ## + ## Grammar productions + ## Implementation of the BNF defined in K&R2 A.13 + ## + def p_translation_unit_1(self, p): + """ translation_unit : external_declaration + """ + # Note: external_declaration is already a list + # + p[0] = c_ast.FileAST(p[1]) + + def p_translation_unit_2(self, p): + """ translation_unit : translation_unit external_declaration + """ + p[1].ext.extend(p[2]) + p[0] = p[1] + + # Declarations always come as lists (because they can be + # several in one line), so we wrap the function definition + # into a list as well, to make the return value of + # external_declaration homogenous. + # + def p_external_declaration_1(self, p): + """ external_declaration : function_definition + """ + p[0] = [p[1]] + + def p_external_declaration_2(self, p): + """ external_declaration : declaration + """ + p[0] = p[1] + + def p_external_declaration_3(self, p): + """ external_declaration : pp_directive + """ + p[0] = p[1] + + def p_pp_directive(self, p): + """ pp_directive : PPHASH + """ + self._parse_error('Directives not supported yet', + self._coord(p.lineno(1))) + + # In function definitions, the declarator can be followed by + # a declaration list, for old "K&R style" function definitios. + # + def p_function_definition_1(self, p): + """ function_definition : declarator declaration_list_opt compound_statement + """ + # no declaration specifiers + spec = dict(qual=[], storage=[], type=[]) + + p[0] = self._build_function_definition( + decl=p[1], + spec=spec, + param_decls=p[2], + body=p[3]) + + def p_function_definition_2(self, p): + """ function_definition : declaration_specifiers declarator declaration_list_opt compound_statement + """ + spec = p[1] + + p[0] = self._build_function_definition( + decl=p[2], + spec=spec, + param_decls=p[3], + body=p[4]) + + def p_statement(self, p): + """ statement : labeled_statement + | expression_statement + | compound_statement + | selection_statement + | iteration_statement + | jump_statement + """ + p[0] = p[1] + + # In C, declarations can come several in a line: + # int x, *px, romulo = 5; + # + # However, for the AST, we will split them to separate Decl + # nodes. + # + # This rule splits its declarations and always returns a list + # of Decl nodes, even if it's one element long. + # + def p_decl_body(self, p): + """ decl_body : declaration_specifiers init_declarator_list_opt + """ + spec = p[1] + is_typedef = 'typedef' in spec['storage'] + decls = [] + + # p[2] (init_declarator_list_opt) is either a list or None + # + if p[2] is None: + # Then it's a declaration of a struct / enum tag, + # without an actual declarator. + # + type = spec['type'] + if len(type) > 1: + coord = '?' + for t in type: + if hasattr(t, 'coord'): + coord = t.coord + break + + self._parse_error('Multiple type specifiers with a type tag', coord) + + decl = c_ast.Decl( + name=None, + quals=spec['qual'], + storage=spec['storage'], + funcspec=spec['function'], + type=type[0], + init=None, + bitsize=None, + coord=type[0].coord) + decls = [decl] + else: + for decl, init in p[2] or []: + if is_typedef: + decl = c_ast.Typedef( + name=None, + quals=spec['qual'], + storage=spec['storage'], + type=decl, + coord=decl.coord) + else: + decl = c_ast.Decl( + name=None, + quals=spec['qual'], + storage=spec['storage'], + funcspec=spec['function'], + type=decl, + init=init, + bitsize=None, + coord=decl.coord) + + typename = spec['type'] + fixed_decl = self._fix_decl_name_type(decl, typename) + + # Add the type name defined by typedef to a + # symbol table (for usage in the lexer) + # + if is_typedef: + self._add_typedef_type(fixed_decl.name) + + decls.append(fixed_decl) + + p[0] = decls + + # The declaration has been split to a decl_body sub-rule and + # SEMI, because having them in a single rule created a problem + # for defining typedefs. + # + # If a typedef line was directly followed by a line using the + # type defined with the typedef, the type would not be + # recognized. This is because to reduce the declaration rule, + # the parser's lookahead asked for the token after SEMI, which + # was the type from the next line, and the lexer had no chance + # to see the updated type symbol table. + # + # Splitting solves this problem, because after seeing SEMI, + # the parser reduces decl_body, which actually adds the new + # type into the table to be seen by the lexer before the next + # line is reached. + # + def p_declaration(self, p): + """ declaration : decl_body SEMI + """ + p[0] = p[1] + + # Since each declaration is a list of declarations, this + # rule will combine all the declarations and return a single + # list + # + def p_declaration_list(self, p): + """ declaration_list : declaration + | declaration_list declaration + """ + p[0] = p[1] if len(p) == 2 else p[1] + p[2] + + def p_declaration_specifiers_1(self, p): + """ declaration_specifiers : type_qualifier declaration_specifiers_opt + """ + p[0] = self._add_declaration_specifier(p[2], p[1], 'qual') + + def p_declaration_specifiers_2(self, p): + """ declaration_specifiers : type_specifier declaration_specifiers_opt + """ + p[0] = self._add_declaration_specifier(p[2], p[1], 'type') + + def p_declaration_specifiers_3(self, p): + """ declaration_specifiers : storage_class_specifier declaration_specifiers_opt + """ + p[0] = self._add_declaration_specifier(p[2], p[1], 'storage') + + def p_declaration_specifiers_4(self, p): + """ declaration_specifiers : function_specifier declaration_specifiers_opt + """ + p[0] = self._add_declaration_specifier(p[2], p[1], 'function') + + def p_storage_class_specifier(self, p): + """ storage_class_specifier : AUTO + | REGISTER + | STATIC + | EXTERN + | TYPEDEF + """ + p[0] = p[1] + def p_function_specifier(self, p): """ function_specifier : INLINE - """
- p[0] = p[1]
-
- def p_type_specifier_1(self, p):
- """ type_specifier : VOID
- | CHAR
- | SHORT
- | INT
- | LONG
- | FLOAT
- | DOUBLE
- | SIGNED
- | UNSIGNED
- | typedef_name
- | enum_specifier
- | struct_or_union_specifier
- """
- p[0] = p[1]
-
- def p_type_qualifier(self, p):
- """ type_qualifier : CONST
- | RESTRICT
- | VOLATILE
- """
- p[0] = p[1]
-
- def p_init_declarator_list(self, p):
- """ init_declarator_list : init_declarator
- | init_declarator_list COMMA init_declarator
- """
- p[0] = p[1] + [p[3]] if len(p) == 4 else [p[1]]
-
- # Returns a (declarator, initializer) pair
- # If there's no initializer, returns (declarator, None)
- #
- def p_init_declarator(self, p):
- """ init_declarator : declarator
- | declarator EQUALS initializer
- """
- p[0] = (p[1], p[3] if len(p) > 2 else None)
-
- def p_specifier_qualifier_list_1(self, p):
- """ specifier_qualifier_list : type_qualifier specifier_qualifier_list_opt
- """
- p[0] = self._add_declaration_specifier(p[2], p[1], 'qual')
-
- def p_specifier_qualifier_list_2(self, p):
- """ specifier_qualifier_list : type_specifier specifier_qualifier_list_opt
- """
- p[0] = self._add_declaration_specifier(p[2], p[1], 'type')
-
- # TYPEID is allowed here (and in other struct/enum related tag names), because
- # struct/enum tags reside in their own namespace and can be named the same as types
- #
- def p_struct_or_union_specifier_1(self, p):
- """ struct_or_union_specifier : struct_or_union ID
- | struct_or_union TYPEID
- """
- klass = self._select_struct_union_class(p[1])
- p[0] = klass(
- name=p[2],
- decls=None,
- coord=self._coord(p.lineno(2)))
-
- def p_struct_or_union_specifier_2(self, p):
- """ struct_or_union_specifier : struct_or_union LBRACE struct_declaration_list RBRACE
- """
- klass = self._select_struct_union_class(p[1])
- p[0] = klass(
- name=None,
- decls=p[3],
- coord=self._coord(p.lineno(2)))
-
- def p_struct_or_union_specifier_3(self, p):
- """ struct_or_union_specifier : struct_or_union ID LBRACE struct_declaration_list RBRACE
- | struct_or_union TYPEID LBRACE struct_declaration_list RBRACE
- """
- klass = self._select_struct_union_class(p[1])
- p[0] = klass(
- name=p[2],
- decls=p[4],
- coord=self._coord(p.lineno(2)))
-
- def p_struct_or_union(self, p):
- """ struct_or_union : STRUCT
- | UNION
- """
- p[0] = p[1]
-
- # Combine all declarations into a single list
- #
- def p_struct_declaration_list(self, p):
- """ struct_declaration_list : struct_declaration
- | struct_declaration_list struct_declaration
- """
- p[0] = p[1] if len(p) == 2 else p[1] + p[2]
-
- def p_struct_declaration_1(self, p):
- """ struct_declaration : specifier_qualifier_list struct_declarator_list SEMI
- """
- spec = p[1]
- decls = []
-
- for struct_decl in p[2]:
- if struct_decl['decl'] is not None:
- decl_coord = struct_decl['decl'].coord
- else:
- decl_coord = struct_decl['bitsize'].coord
-
- decl = c_ast.Decl(
- name=None,
- quals=spec['qual'],
- funcspec=spec['function'],
- storage=spec['storage'],
- type=struct_decl['decl'],
- init=None,
- bitsize=struct_decl['bitsize'],
- coord=decl_coord)
-
- typename = spec['type']
- decls.append(self._fix_decl_name_type(decl, typename))
-
- p[0] = decls
-
- def p_struct_declarator_list(self, p):
- """ struct_declarator_list : struct_declarator
- | struct_declarator_list COMMA struct_declarator
- """
- p[0] = p[1] + [p[3]] if len(p) == 4 else [p[1]]
-
- # struct_declarator passes up a dict with the keys: decl (for
- # the underlying declarator) and bitsize (for the bitsize)
- #
- def p_struct_declarator_1(self, p):
- """ struct_declarator : declarator
- """
- p[0] = {'decl': p[1], 'bitsize': None}
-
- def p_struct_declarator_2(self, p):
- """ struct_declarator : declarator COLON constant_expression
- | COLON constant_expression
- """
- if len(p) > 3:
- p[0] = {'decl': p[1], 'bitsize': p[3]}
- else:
- p[0] = {'decl': c_ast.TypeDecl(None, None, None), 'bitsize': p[2]}
-
- def p_enum_specifier_1(self, p):
- """ enum_specifier : ENUM ID
- | ENUM TYPEID
- """
- p[0] = c_ast.Enum(p[2], None, self._coord(p.lineno(1)))
-
- def p_enum_specifier_2(self, p):
- """ enum_specifier : ENUM LBRACE enumerator_list RBRACE
- """
- p[0] = c_ast.Enum(None, p[3], self._coord(p.lineno(1)))
-
- def p_enum_specifier_3(self, p):
- """ enum_specifier : ENUM ID LBRACE enumerator_list RBRACE
- | ENUM TYPEID LBRACE enumerator_list RBRACE
- """
- p[0] = c_ast.Enum(p[2], p[4], self._coord(p.lineno(1)))
-
- def p_enumerator_list(self, p):
- """ enumerator_list : enumerator
- | enumerator_list COMMA
- | enumerator_list COMMA enumerator
- """
- if len(p) == 2:
- p[0] = c_ast.EnumeratorList([p[1]], p[1].coord)
- elif len(p) == 3:
- p[0] = p[1]
- else:
- p[1].enumerators.append(p[3])
- p[0] = p[1]
-
- def p_enumerator(self, p):
- """ enumerator : ID
- | ID EQUALS constant_expression
- """
- if len(p) == 2:
- p[0] = c_ast.Enumerator(
- p[1], None,
- self._coord(p.lineno(1)))
- else:
- p[0] = c_ast.Enumerator(
- p[1], p[3],
- self._coord(p.lineno(1)))
-
- def p_declarator_1(self, p):
- """ declarator : direct_declarator
- """
- p[0] = p[1]
-
- def p_declarator_2(self, p):
- """ declarator : pointer direct_declarator
- """
- p[0] = self._type_modify_decl(p[2], p[1])
-
- def p_direct_declarator_1(self, p):
- """ direct_declarator : ID
- """
- p[0] = c_ast.TypeDecl(
- declname=p[1],
- type=None,
- quals=None,
- coord=self._coord(p.lineno(1)))
-
- def p_direct_declarator_2(self, p):
- """ direct_declarator : LPAREN declarator RPAREN
- """
- p[0] = p[2]
-
- def p_direct_declarator_3(self, p):
- """ direct_declarator : direct_declarator LBRACKET assignment_expression_opt RBRACKET
- """
- arr = c_ast.ArrayDecl(
- type=None,
- dim=p[3],
- coord=p[1].coord)
-
- p[0] = self._type_modify_decl(decl=p[1], modifier=arr)
-
- # Special for VLAs
- #
- def p_direct_declarator_4(self, p):
- """ direct_declarator : direct_declarator LBRACKET TIMES RBRACKET
- """
- arr = c_ast.ArrayDecl(
- type=None,
- dim=c_ast.ID(p[3], self._coord(p.lineno(3))),
- coord=p[1].coord)
-
- p[0] = self._type_modify_decl(decl=p[1], modifier=arr)
-
- def p_direct_declarator_5(self, p):
- """ direct_declarator : direct_declarator LPAREN parameter_type_list RPAREN
- | direct_declarator LPAREN identifier_list_opt RPAREN
- """
- func = c_ast.FuncDecl(
- args=p[3],
- type=None,
- coord=p[1].coord)
-
- p[0] = self._type_modify_decl(decl=p[1], modifier=func)
-
- def p_pointer(self, p):
- """ pointer : TIMES type_qualifier_list_opt
- | TIMES type_qualifier_list_opt pointer
- """
- coord = self._coord(p.lineno(1))
-
- p[0] = c_ast.PtrDecl(
- quals=p[2] or [],
- type=p[3] if len(p) > 3 else None,
- coord=coord)
-
- def p_type_qualifier_list(self, p):
- """ type_qualifier_list : type_qualifier
- | type_qualifier_list type_qualifier
- """
- p[0] = [p[1]] if len(p) == 2 else p[1] + [p[2]]
-
- def p_parameter_type_list(self, p):
- """ parameter_type_list : parameter_list
- | parameter_list COMMA ELLIPSIS
- """
- if len(p) > 2:
- p[1].params.append(c_ast.EllipsisParam())
-
- p[0] = p[1]
-
- def p_parameter_list(self, p):
- """ parameter_list : parameter_declaration
- | parameter_list COMMA parameter_declaration
- """
- if len(p) == 2: # single parameter
- p[0] = c_ast.ParamList([p[1]], p[1].coord)
- else:
- p[1].params.append(p[3])
- p[0] = p[1]
-
- def p_parameter_declaration_1(self, p):
- """ parameter_declaration : declaration_specifiers declarator
- """
- spec = p[1]
- decl = p[2]
-
- decl = c_ast.Decl(
- name=None,
- quals=spec['qual'],
- storage=spec['storage'],
- funcspec=spec['function'],
- type=decl,
- init=None,
- bitsize=None,
- coord=decl.coord)
-
- typename = spec['type'] or ['int']
- p[0] = self._fix_decl_name_type(decl, typename)
-
- def p_parameter_declaration_2(self, p):
- """ parameter_declaration : declaration_specifiers abstract_declarator_opt
- """
- spec = p[1]
- decl = c_ast.Typename(
- quals=spec['qual'],
- type=p[2] or c_ast.TypeDecl(None, None, None))
-
- typename = spec['type'] or ['int']
- p[0] = self._fix_decl_name_type(decl, typename)
-
- def p_identifier_list(self, p):
- """ identifier_list : identifier
- | identifier_list COMMA identifier
- """
- if len(p) == 2: # single parameter
- p[0] = c_ast.ParamList([p[1]], p[1].coord)
- else:
- p[1].params.append(p[3])
- p[0] = p[1]
-
- def p_initializer_1(self, p):
- """ initializer : assignment_expression
- """
- p[0] = p[1]
-
- def p_initializer_2(self, p):
- """ initializer : LBRACE initializer_list RBRACE
- | LBRACE initializer_list COMMA RBRACE
- """
- p[0] = p[2]
-
- def p_initializer_list(self, p):
- """ initializer_list : designation_opt initializer
- | initializer_list COMMA designation_opt initializer
- """
- if len(p) == 3: # single initializer
- init = p[2] if p[1] is None else c_ast.NamedInitializer(p[1], p[2])
- p[0] = c_ast.ExprList([init], p[2].coord)
- else:
- init = p[4] if p[3] is None else c_ast.NamedInitializer(p[3], p[4])
- p[1].exprs.append(init)
- p[0] = p[1]
-
+ """ + p[0] = p[1] + + def p_type_specifier_1(self, p): + """ type_specifier : VOID + | CHAR + | SHORT + | INT + | LONG + | FLOAT + | DOUBLE + | SIGNED + | UNSIGNED + | typedef_name + | enum_specifier + | struct_or_union_specifier + """ + p[0] = p[1] + + def p_type_qualifier(self, p): + """ type_qualifier : CONST + | RESTRICT + | VOLATILE + """ + p[0] = p[1] + + def p_init_declarator_list(self, p): + """ init_declarator_list : init_declarator + | init_declarator_list COMMA init_declarator + """ + p[0] = p[1] + [p[3]] if len(p) == 4 else [p[1]] + + # Returns a (declarator, initializer) pair + # If there's no initializer, returns (declarator, None) + # + def p_init_declarator(self, p): + """ init_declarator : declarator + | declarator EQUALS initializer + """ + p[0] = (p[1], p[3] if len(p) > 2 else None) + + def p_specifier_qualifier_list_1(self, p): + """ specifier_qualifier_list : type_qualifier specifier_qualifier_list_opt + """ + p[0] = self._add_declaration_specifier(p[2], p[1], 'qual') + + def p_specifier_qualifier_list_2(self, p): + """ specifier_qualifier_list : type_specifier specifier_qualifier_list_opt + """ + p[0] = self._add_declaration_specifier(p[2], p[1], 'type') + + # TYPEID is allowed here (and in other struct/enum related tag names), because + # struct/enum tags reside in their own namespace and can be named the same as types + # + def p_struct_or_union_specifier_1(self, p): + """ struct_or_union_specifier : struct_or_union ID + | struct_or_union TYPEID + """ + klass = self._select_struct_union_class(p[1]) + p[0] = klass( + name=p[2], + decls=None, + coord=self._coord(p.lineno(2))) + + def p_struct_or_union_specifier_2(self, p): + """ struct_or_union_specifier : struct_or_union LBRACE struct_declaration_list RBRACE + """ + klass = self._select_struct_union_class(p[1]) + p[0] = klass( + name=None, + decls=p[3], + coord=self._coord(p.lineno(2))) + + def p_struct_or_union_specifier_3(self, p): + """ struct_or_union_specifier : struct_or_union ID LBRACE struct_declaration_list RBRACE + | struct_or_union TYPEID LBRACE struct_declaration_list RBRACE + """ + klass = self._select_struct_union_class(p[1]) + p[0] = klass( + name=p[2], + decls=p[4], + coord=self._coord(p.lineno(2))) + + def p_struct_or_union(self, p): + """ struct_or_union : STRUCT + | UNION + """ + p[0] = p[1] + + # Combine all declarations into a single list + # + def p_struct_declaration_list(self, p): + """ struct_declaration_list : struct_declaration + | struct_declaration_list struct_declaration + """ + p[0] = p[1] if len(p) == 2 else p[1] + p[2] + + def p_struct_declaration_1(self, p): + """ struct_declaration : specifier_qualifier_list struct_declarator_list SEMI + """ + spec = p[1] + decls = [] + + for struct_decl in p[2]: + if struct_decl['decl'] is not None: + decl_coord = struct_decl['decl'].coord + else: + decl_coord = struct_decl['bitsize'].coord + + decl = c_ast.Decl( + name=None, + quals=spec['qual'], + funcspec=spec['function'], + storage=spec['storage'], + type=struct_decl['decl'], + init=None, + bitsize=struct_decl['bitsize'], + coord=decl_coord) + + typename = spec['type'] + decls.append(self._fix_decl_name_type(decl, typename)) + + p[0] = decls + + def p_struct_declarator_list(self, p): + """ struct_declarator_list : struct_declarator + | struct_declarator_list COMMA struct_declarator + """ + p[0] = p[1] + [p[3]] if len(p) == 4 else [p[1]] + + # struct_declarator passes up a dict with the keys: decl (for + # the underlying declarator) and bitsize (for the bitsize) + # + def p_struct_declarator_1(self, p): + """ struct_declarator : declarator + """ + p[0] = {'decl': p[1], 'bitsize': None} + + def p_struct_declarator_2(self, p): + """ struct_declarator : declarator COLON constant_expression + | COLON constant_expression + """ + if len(p) > 3: + p[0] = {'decl': p[1], 'bitsize': p[3]} + else: + p[0] = {'decl': c_ast.TypeDecl(None, None, None), 'bitsize': p[2]} + + def p_enum_specifier_1(self, p): + """ enum_specifier : ENUM ID + | ENUM TYPEID + """ + p[0] = c_ast.Enum(p[2], None, self._coord(p.lineno(1))) + + def p_enum_specifier_2(self, p): + """ enum_specifier : ENUM LBRACE enumerator_list RBRACE + """ + p[0] = c_ast.Enum(None, p[3], self._coord(p.lineno(1))) + + def p_enum_specifier_3(self, p): + """ enum_specifier : ENUM ID LBRACE enumerator_list RBRACE + | ENUM TYPEID LBRACE enumerator_list RBRACE + """ + p[0] = c_ast.Enum(p[2], p[4], self._coord(p.lineno(1))) + + def p_enumerator_list(self, p): + """ enumerator_list : enumerator + | enumerator_list COMMA + | enumerator_list COMMA enumerator + """ + if len(p) == 2: + p[0] = c_ast.EnumeratorList([p[1]], p[1].coord) + elif len(p) == 3: + p[0] = p[1] + else: + p[1].enumerators.append(p[3]) + p[0] = p[1] + + def p_enumerator(self, p): + """ enumerator : ID + | ID EQUALS constant_expression + """ + if len(p) == 2: + p[0] = c_ast.Enumerator( + p[1], None, + self._coord(p.lineno(1))) + else: + p[0] = c_ast.Enumerator( + p[1], p[3], + self._coord(p.lineno(1))) + + def p_declarator_1(self, p): + """ declarator : direct_declarator + """ + p[0] = p[1] + + def p_declarator_2(self, p): + """ declarator : pointer direct_declarator + """ + p[0] = self._type_modify_decl(p[2], p[1]) + + def p_direct_declarator_1(self, p): + """ direct_declarator : ID + """ + p[0] = c_ast.TypeDecl( + declname=p[1], + type=None, + quals=None, + coord=self._coord(p.lineno(1))) + + def p_direct_declarator_2(self, p): + """ direct_declarator : LPAREN declarator RPAREN + """ + p[0] = p[2] + + def p_direct_declarator_3(self, p): + """ direct_declarator : direct_declarator LBRACKET assignment_expression_opt RBRACKET + """ + arr = c_ast.ArrayDecl( + type=None, + dim=p[3], + coord=p[1].coord) + + p[0] = self._type_modify_decl(decl=p[1], modifier=arr) + + # Special for VLAs + # + def p_direct_declarator_4(self, p): + """ direct_declarator : direct_declarator LBRACKET TIMES RBRACKET + """ + arr = c_ast.ArrayDecl( + type=None, + dim=c_ast.ID(p[3], self._coord(p.lineno(3))), + coord=p[1].coord) + + p[0] = self._type_modify_decl(decl=p[1], modifier=arr) + + def p_direct_declarator_5(self, p): + """ direct_declarator : direct_declarator LPAREN parameter_type_list RPAREN + | direct_declarator LPAREN identifier_list_opt RPAREN + """ + func = c_ast.FuncDecl( + args=p[3], + type=None, + coord=p[1].coord) + + p[0] = self._type_modify_decl(decl=p[1], modifier=func) + + def p_pointer(self, p): + """ pointer : TIMES type_qualifier_list_opt + | TIMES type_qualifier_list_opt pointer + """ + coord = self._coord(p.lineno(1)) + + p[0] = c_ast.PtrDecl( + quals=p[2] or [], + type=p[3] if len(p) > 3 else None, + coord=coord) + + def p_type_qualifier_list(self, p): + """ type_qualifier_list : type_qualifier + | type_qualifier_list type_qualifier + """ + p[0] = [p[1]] if len(p) == 2 else p[1] + [p[2]] + + def p_parameter_type_list(self, p): + """ parameter_type_list : parameter_list + | parameter_list COMMA ELLIPSIS + """ + if len(p) > 2: + p[1].params.append(c_ast.EllipsisParam()) + + p[0] = p[1] + + def p_parameter_list(self, p): + """ parameter_list : parameter_declaration + | parameter_list COMMA parameter_declaration + """ + if len(p) == 2: # single parameter + p[0] = c_ast.ParamList([p[1]], p[1].coord) + else: + p[1].params.append(p[3]) + p[0] = p[1] + + def p_parameter_declaration_1(self, p): + """ parameter_declaration : declaration_specifiers declarator + """ + spec = p[1] + decl = p[2] + + decl = c_ast.Decl( + name=None, + quals=spec['qual'], + storage=spec['storage'], + funcspec=spec['function'], + type=decl, + init=None, + bitsize=None, + coord=decl.coord) + + typename = spec['type'] or ['int'] + p[0] = self._fix_decl_name_type(decl, typename) + + def p_parameter_declaration_2(self, p): + """ parameter_declaration : declaration_specifiers abstract_declarator_opt + """ + spec = p[1] + decl = c_ast.Typename( + quals=spec['qual'], + type=p[2] or c_ast.TypeDecl(None, None, None)) + + typename = spec['type'] or ['int'] + p[0] = self._fix_decl_name_type(decl, typename) + + def p_identifier_list(self, p): + """ identifier_list : identifier + | identifier_list COMMA identifier + """ + if len(p) == 2: # single parameter + p[0] = c_ast.ParamList([p[1]], p[1].coord) + else: + p[1].params.append(p[3]) + p[0] = p[1] + + def p_initializer_1(self, p): + """ initializer : assignment_expression + """ + p[0] = p[1] + + def p_initializer_2(self, p): + """ initializer : LBRACE initializer_list RBRACE + | LBRACE initializer_list COMMA RBRACE + """ + p[0] = p[2] + + def p_initializer_list(self, p): + """ initializer_list : designation_opt initializer + | initializer_list COMMA designation_opt initializer + """ + if len(p) == 3: # single initializer + init = p[2] if p[1] is None else c_ast.NamedInitializer(p[1], p[2]) + p[0] = c_ast.ExprList([init], p[2].coord) + else: + init = p[4] if p[3] is None else c_ast.NamedInitializer(p[3], p[4]) + p[1].exprs.append(init) + p[0] = p[1] + def p_designation(self, p): """ designation : designator_list EQUALS - """
- p[0] = p[1]
-
- # Designators are represented as a list of nodes, in the order in which
- # they're written in the code.
- #
+ """ + p[0] = p[1] + + # Designators are represented as a list of nodes, in the order in which + # they're written in the code. + # def p_designator_list(self, p): - """ designator_list : designator
+ """ designator_list : designator | designator_list designator - """
- p[0] = [p[1]] if len(p) == 2 else p[1] + [p[2]]
-
+ """ + p[0] = [p[1]] if len(p) == 2 else p[1] + [p[2]] + def p_designator(self, p): - """ designator : LBRACKET constant_expression RBRACKET
+ """ designator : LBRACKET constant_expression RBRACKET | PERIOD identifier - """
- p[0] = p[2]
-
- def p_type_name(self, p):
- """ type_name : specifier_qualifier_list abstract_declarator_opt
- """
- #~ print '=========='
- #~ print p[1]
- #~ print p[2]
- #~ print p[2].children()
- #~ print '=========='
-
- typename = c_ast.Typename(
- quals=p[1]['qual'],
- type=p[2] or c_ast.TypeDecl(None, None, None))
-
- p[0] = self._fix_decl_name_type(typename, p[1]['type'])
-
- def p_abstract_declarator_1(self, p):
- """ abstract_declarator : pointer
- """
- dummytype = c_ast.TypeDecl(None, None, None)
- p[0] = self._type_modify_decl(
- decl=dummytype,
- modifier=p[1])
-
- def p_abstract_declarator_2(self, p):
- """ abstract_declarator : pointer direct_abstract_declarator
- """
- p[0] = self._type_modify_decl(p[2], p[1])
-
- def p_abstract_declarator_3(self, p):
- """ abstract_declarator : direct_abstract_declarator
- """
- p[0] = p[1]
-
- # Creating and using direct_abstract_declarator_opt here
- # instead of listing both direct_abstract_declarator and the
- # lack of it in the beginning of _1 and _2 caused two
- # shift/reduce errors.
- #
- def p_direct_abstract_declarator_1(self, p):
- """ direct_abstract_declarator : LPAREN abstract_declarator RPAREN """
- p[0] = p[2]
-
- def p_direct_abstract_declarator_2(self, p):
- """ direct_abstract_declarator : direct_abstract_declarator LBRACKET assignment_expression_opt RBRACKET
- """
- arr = c_ast.ArrayDecl(
- type=None,
- dim=p[3],
- coord=p[1].coord)
-
- p[0] = self._type_modify_decl(decl=p[1], modifier=arr)
-
- def p_direct_abstract_declarator_3(self, p):
- """ direct_abstract_declarator : LBRACKET assignment_expression_opt RBRACKET
- """
- p[0] = c_ast.ArrayDecl(
- type=c_ast.TypeDecl(None, None, None),
- dim=p[2],
- coord=self._coord(p.lineno(1)))
-
- def p_direct_abstract_declarator_4(self, p):
- """ direct_abstract_declarator : direct_abstract_declarator LBRACKET TIMES RBRACKET
- """
- arr = c_ast.ArrayDecl(
- type=None,
- dim=c_ast.ID(p[3], self._coord(p.lineno(3))),
- coord=p[1].coord)
-
- p[0] = self._type_modify_decl(decl=p[1], modifier=arr)
-
- def p_direct_abstract_declarator_5(self, p):
- """ direct_abstract_declarator : LBRACKET TIMES RBRACKET
- """
- p[0] = c_ast.ArrayDecl(
- type=c_ast.TypeDecl(None, None, None),
- dim=c_ast.ID(p[3], self._coord(p.lineno(3))),
- coord=self._coord(p.lineno(1)))
-
- def p_direct_abstract_declarator_6(self, p):
- """ direct_abstract_declarator : direct_abstract_declarator LPAREN parameter_type_list_opt RPAREN
- """
- func = c_ast.FuncDecl(
- args=p[3],
- type=None,
- coord=p[1].coord)
-
- p[0] = self._type_modify_decl(decl=p[1], modifier=func)
-
- def p_direct_abstract_declarator_7(self, p):
- """ direct_abstract_declarator : LPAREN parameter_type_list_opt RPAREN
- """
- p[0] = c_ast.FuncDecl(
- args=p[2],
- type=c_ast.TypeDecl(None, None, None),
- coord=self._coord(p.lineno(1)))
-
- # declaration is a list, statement isn't. To make it consistent, block_item
- # will always be a list
- #
+ """ + p[0] = p[2] + + def p_type_name(self, p): + """ type_name : specifier_qualifier_list abstract_declarator_opt + """ + #~ print '==========' + #~ print p[1] + #~ print p[2] + #~ print p[2].children() + #~ print '==========' + + typename = c_ast.Typename( + quals=p[1]['qual'], + type=p[2] or c_ast.TypeDecl(None, None, None)) + + p[0] = self._fix_decl_name_type(typename, p[1]['type']) + + def p_abstract_declarator_1(self, p): + """ abstract_declarator : pointer + """ + dummytype = c_ast.TypeDecl(None, None, None) + p[0] = self._type_modify_decl( + decl=dummytype, + modifier=p[1]) + + def p_abstract_declarator_2(self, p): + """ abstract_declarator : pointer direct_abstract_declarator + """ + p[0] = self._type_modify_decl(p[2], p[1]) + + def p_abstract_declarator_3(self, p): + """ abstract_declarator : direct_abstract_declarator + """ + p[0] = p[1] + + # Creating and using direct_abstract_declarator_opt here + # instead of listing both direct_abstract_declarator and the + # lack of it in the beginning of _1 and _2 caused two + # shift/reduce errors. + # + def p_direct_abstract_declarator_1(self, p): + """ direct_abstract_declarator : LPAREN abstract_declarator RPAREN """ + p[0] = p[2] + + def p_direct_abstract_declarator_2(self, p): + """ direct_abstract_declarator : direct_abstract_declarator LBRACKET assignment_expression_opt RBRACKET + """ + arr = c_ast.ArrayDecl( + type=None, + dim=p[3], + coord=p[1].coord) + + p[0] = self._type_modify_decl(decl=p[1], modifier=arr) + + def p_direct_abstract_declarator_3(self, p): + """ direct_abstract_declarator : LBRACKET assignment_expression_opt RBRACKET + """ + p[0] = c_ast.ArrayDecl( + type=c_ast.TypeDecl(None, None, None), + dim=p[2], + coord=self._coord(p.lineno(1))) + + def p_direct_abstract_declarator_4(self, p): + """ direct_abstract_declarator : direct_abstract_declarator LBRACKET TIMES RBRACKET + """ + arr = c_ast.ArrayDecl( + type=None, + dim=c_ast.ID(p[3], self._coord(p.lineno(3))), + coord=p[1].coord) + + p[0] = self._type_modify_decl(decl=p[1], modifier=arr) + + def p_direct_abstract_declarator_5(self, p): + """ direct_abstract_declarator : LBRACKET TIMES RBRACKET + """ + p[0] = c_ast.ArrayDecl( + type=c_ast.TypeDecl(None, None, None), + dim=c_ast.ID(p[3], self._coord(p.lineno(3))), + coord=self._coord(p.lineno(1))) + + def p_direct_abstract_declarator_6(self, p): + """ direct_abstract_declarator : direct_abstract_declarator LPAREN parameter_type_list_opt RPAREN + """ + func = c_ast.FuncDecl( + args=p[3], + type=None, + coord=p[1].coord) + + p[0] = self._type_modify_decl(decl=p[1], modifier=func) + + def p_direct_abstract_declarator_7(self, p): + """ direct_abstract_declarator : LPAREN parameter_type_list_opt RPAREN + """ + p[0] = c_ast.FuncDecl( + args=p[2], + type=c_ast.TypeDecl(None, None, None), + coord=self._coord(p.lineno(1))) + + # declaration is a list, statement isn't. To make it consistent, block_item + # will always be a list + # def p_block_item(self, p): - """ block_item : declaration
+ """ block_item : declaration | statement - """
- p[0] = p[1] if isinstance(p[1], list) else [p[1]]
-
- # Since we made block_item a list, this just combines lists
- #
- def p_block_item_list(self, p):
- """ block_item_list : block_item
- | block_item_list block_item
- """
- p[0] = p[1] if len(p) == 2 else p[1] + p[2]
-
- def p_compound_statement_1(self, p):
- """ compound_statement : LBRACE block_item_list_opt RBRACE """
- p[0] = c_ast.Compound(
- block_items=p[2],
- coord=self._coord(p.lineno(1)))
-
- def p_labeled_statement_1(self, p):
- """ labeled_statement : ID COLON statement """
- p[0] = c_ast.Label(p[1], p[3], self._coord(p.lineno(1)))
-
- def p_labeled_statement_2(self, p):
- """ labeled_statement : CASE constant_expression COLON statement """
- p[0] = c_ast.Case(p[2], p[4], self._coord(p.lineno(1)))
-
- def p_labeled_statement_3(self, p):
- """ labeled_statement : DEFAULT COLON statement """
- p[0] = c_ast.Default(p[3], self._coord(p.lineno(1)))
-
- def p_selection_statement_1(self, p):
- """ selection_statement : IF LPAREN expression RPAREN statement """
- p[0] = c_ast.If(p[3], p[5], None, self._coord(p.lineno(1)))
-
- def p_selection_statement_2(self, p):
- """ selection_statement : IF LPAREN expression RPAREN statement ELSE statement """
- p[0] = c_ast.If(p[3], p[5], p[7], self._coord(p.lineno(1)))
-
- def p_selection_statement_3(self, p):
- """ selection_statement : SWITCH LPAREN expression RPAREN statement """
- p[0] = c_ast.Switch(p[3], p[5], self._coord(p.lineno(1)))
-
- def p_iteration_statement_1(self, p):
- """ iteration_statement : WHILE LPAREN expression RPAREN statement """
- p[0] = c_ast.While(p[3], p[5], self._coord(p.lineno(1)))
-
- def p_iteration_statement_2(self, p):
- """ iteration_statement : DO statement WHILE LPAREN expression RPAREN SEMI """
- p[0] = c_ast.DoWhile(p[5], p[2], self._coord(p.lineno(1)))
-
- def p_iteration_statement_3(self, p):
- """ iteration_statement : FOR LPAREN expression_opt SEMI expression_opt SEMI expression_opt RPAREN statement """
- p[0] = c_ast.For(p[3], p[5], p[7], p[9], self._coord(p.lineno(1)))
-
- def p_iteration_statement_4(self, p):
- """ iteration_statement : FOR LPAREN declaration expression_opt SEMI expression_opt RPAREN statement """
- p[0] = c_ast.For(c_ast.DeclList(p[3]), p[4], p[6], p[8], self._coord(p.lineno(1)))
-
- def p_jump_statement_1(self, p):
- """ jump_statement : GOTO ID SEMI """
- p[0] = c_ast.Goto(p[2], self._coord(p.lineno(1)))
-
- def p_jump_statement_2(self, p):
- """ jump_statement : BREAK SEMI """
- p[0] = c_ast.Break(self._coord(p.lineno(1)))
-
- def p_jump_statement_3(self, p):
- """ jump_statement : CONTINUE SEMI """
- p[0] = c_ast.Continue(self._coord(p.lineno(1)))
-
- def p_jump_statement_4(self, p):
- """ jump_statement : RETURN expression SEMI
- | RETURN SEMI
- """
- p[0] = c_ast.Return(p[2] if len(p) == 4 else None, self._coord(p.lineno(1)))
-
- def p_expression_statement(self, p):
- """ expression_statement : expression_opt SEMI """
- p[0] = p[1]
-
- def p_expression(self, p):
- """ expression : assignment_expression
- | expression COMMA assignment_expression
- """
- if len(p) == 2:
- p[0] = p[1]
- else:
- if not isinstance(p[1], c_ast.ExprList):
- p[1] = c_ast.ExprList([p[1]], p[1].coord)
-
- p[1].exprs.append(p[3])
- p[0] = p[1]
-
- def p_typedef_name(self, p):
- """ typedef_name : TYPEID """
- p[0] = p[1]
-
- def p_assignment_expression(self, p):
- """ assignment_expression : conditional_expression
- | unary_expression assignment_operator assignment_expression
- """
- if len(p) == 2:
- p[0] = p[1]
- else:
- p[0] = c_ast.Assignment(p[2], p[1], p[3], p[1].coord)
-
- # K&R2 defines these as many separate rules, to encode
- # precedence and associativity. Why work hard ? I'll just use
- # the built in precedence/associativity specification feature
- # of PLY. (see precedence declaration above)
- #
- def p_assignment_operator(self, p):
- """ assignment_operator : EQUALS
- | XOREQUAL
- | TIMESEQUAL
- | DIVEQUAL
- | MODEQUAL
- | PLUSEQUAL
- | MINUSEQUAL
- | LSHIFTEQUAL
- | RSHIFTEQUAL
- | ANDEQUAL
- | OREQUAL
- """
- p[0] = p[1]
-
- def p_constant_expression(self, p):
- """ constant_expression : conditional_expression """
- p[0] = p[1]
-
- def p_conditional_expression(self, p):
- """ conditional_expression : binary_expression
- | binary_expression CONDOP expression COLON conditional_expression
- """
- if len(p) == 2:
- p[0] = p[1]
- else:
- p[0] = c_ast.TernaryOp(p[1], p[3], p[5], p[1].coord)
-
- def p_binary_expression(self, p):
- """ binary_expression : cast_expression
- | binary_expression TIMES binary_expression
- | binary_expression DIVIDE binary_expression
- | binary_expression MOD binary_expression
- | binary_expression PLUS binary_expression
- | binary_expression MINUS binary_expression
- | binary_expression RSHIFT binary_expression
- | binary_expression LSHIFT binary_expression
- | binary_expression LT binary_expression
- | binary_expression LE binary_expression
- | binary_expression GE binary_expression
- | binary_expression GT binary_expression
- | binary_expression EQ binary_expression
- | binary_expression NE binary_expression
- | binary_expression AND binary_expression
- | binary_expression OR binary_expression
- | binary_expression XOR binary_expression
- | binary_expression LAND binary_expression
- | binary_expression LOR binary_expression
- """
- if len(p) == 2:
- p[0] = p[1]
- else:
- p[0] = c_ast.BinaryOp(p[2], p[1], p[3], p[1].coord)
-
- def p_cast_expression_1(self, p):
- """ cast_expression : unary_expression """
- p[0] = p[1]
-
- def p_cast_expression_2(self, p):
- """ cast_expression : LPAREN type_name RPAREN cast_expression """
- p[0] = c_ast.Cast(p[2], p[4], p[2].coord)
-
- def p_unary_expression_1(self, p):
- """ unary_expression : postfix_expression """
- p[0] = p[1]
-
- def p_unary_expression_2(self, p):
- """ unary_expression : PLUSPLUS unary_expression
- | MINUSMINUS unary_expression
- | unary_operator cast_expression
- """
- p[0] = c_ast.UnaryOp(p[1], p[2], p[2].coord)
-
- def p_unary_expression_3(self, p):
- """ unary_expression : SIZEOF unary_expression
- | SIZEOF LPAREN type_name RPAREN
- """
- p[0] = c_ast.UnaryOp(
- p[1],
- p[2] if len(p) == 3 else p[3],
- self._coord(p.lineno(1)))
-
- def p_unary_operator(self, p):
- """ unary_operator : AND
- | TIMES
- | PLUS
- | MINUS
- | NOT
- | LNOT
- """
- p[0] = p[1]
-
- def p_postfix_exptession_1(self, p):
- """ postfix_expression : primary_expression """
- p[0] = p[1]
-
- def p_postfix_exptession_2(self, p):
- """ postfix_expression : postfix_expression LBRACKET expression RBRACKET """
- p[0] = c_ast.ArrayRef(p[1], p[3], p[1].coord)
-
- def p_postfix_exptession_3(self, p):
- """ postfix_expression : postfix_expression LPAREN argument_expression_list RPAREN
- | postfix_expression LPAREN RPAREN
- """
- p[0] = c_ast.FuncCall(p[1], p[3] if len(p) == 5 else None, p[1].coord)
-
- def p_postfix_expression_4(self, p):
- """ postfix_expression : postfix_expression PERIOD identifier
- | postfix_expression ARROW identifier
- """
- p[0] = c_ast.StructRef(p[1], p[2], p[3], p[1].coord)
-
- def p_postfix_expression_5(self, p):
- """ postfix_expression : postfix_expression PLUSPLUS
- | postfix_expression MINUSMINUS
- """
- p[0] = c_ast.UnaryOp('p' + p[2], p[1], p[1].coord)
-
+ """ + p[0] = p[1] if isinstance(p[1], list) else [p[1]] + + # Since we made block_item a list, this just combines lists + # + def p_block_item_list(self, p): + """ block_item_list : block_item + | block_item_list block_item + """ + p[0] = p[1] if len(p) == 2 else p[1] + p[2] + + def p_compound_statement_1(self, p): + """ compound_statement : LBRACE block_item_list_opt RBRACE """ + p[0] = c_ast.Compound( + block_items=p[2], + coord=self._coord(p.lineno(1))) + + def p_labeled_statement_1(self, p): + """ labeled_statement : ID COLON statement """ + p[0] = c_ast.Label(p[1], p[3], self._coord(p.lineno(1))) + + def p_labeled_statement_2(self, p): + """ labeled_statement : CASE constant_expression COLON statement """ + p[0] = c_ast.Case(p[2], p[4], self._coord(p.lineno(1))) + + def p_labeled_statement_3(self, p): + """ labeled_statement : DEFAULT COLON statement """ + p[0] = c_ast.Default(p[3], self._coord(p.lineno(1))) + + def p_selection_statement_1(self, p): + """ selection_statement : IF LPAREN expression RPAREN statement """ + p[0] = c_ast.If(p[3], p[5], None, self._coord(p.lineno(1))) + + def p_selection_statement_2(self, p): + """ selection_statement : IF LPAREN expression RPAREN statement ELSE statement """ + p[0] = c_ast.If(p[3], p[5], p[7], self._coord(p.lineno(1))) + + def p_selection_statement_3(self, p): + """ selection_statement : SWITCH LPAREN expression RPAREN statement """ + p[0] = c_ast.Switch(p[3], p[5], self._coord(p.lineno(1))) + + def p_iteration_statement_1(self, p): + """ iteration_statement : WHILE LPAREN expression RPAREN statement """ + p[0] = c_ast.While(p[3], p[5], self._coord(p.lineno(1))) + + def p_iteration_statement_2(self, p): + """ iteration_statement : DO statement WHILE LPAREN expression RPAREN SEMI """ + p[0] = c_ast.DoWhile(p[5], p[2], self._coord(p.lineno(1))) + + def p_iteration_statement_3(self, p): + """ iteration_statement : FOR LPAREN expression_opt SEMI expression_opt SEMI expression_opt RPAREN statement """ + p[0] = c_ast.For(p[3], p[5], p[7], p[9], self._coord(p.lineno(1))) + + def p_iteration_statement_4(self, p): + """ iteration_statement : FOR LPAREN declaration expression_opt SEMI expression_opt RPAREN statement """ + p[0] = c_ast.For(c_ast.DeclList(p[3]), p[4], p[6], p[8], self._coord(p.lineno(1))) + + def p_jump_statement_1(self, p): + """ jump_statement : GOTO ID SEMI """ + p[0] = c_ast.Goto(p[2], self._coord(p.lineno(1))) + + def p_jump_statement_2(self, p): + """ jump_statement : BREAK SEMI """ + p[0] = c_ast.Break(self._coord(p.lineno(1))) + + def p_jump_statement_3(self, p): + """ jump_statement : CONTINUE SEMI """ + p[0] = c_ast.Continue(self._coord(p.lineno(1))) + + def p_jump_statement_4(self, p): + """ jump_statement : RETURN expression SEMI + | RETURN SEMI + """ + p[0] = c_ast.Return(p[2] if len(p) == 4 else None, self._coord(p.lineno(1))) + + def p_expression_statement(self, p): + """ expression_statement : expression_opt SEMI """ + p[0] = p[1] + + def p_expression(self, p): + """ expression : assignment_expression + | expression COMMA assignment_expression + """ + if len(p) == 2: + p[0] = p[1] + else: + if not isinstance(p[1], c_ast.ExprList): + p[1] = c_ast.ExprList([p[1]], p[1].coord) + + p[1].exprs.append(p[3]) + p[0] = p[1] + + def p_typedef_name(self, p): + """ typedef_name : TYPEID """ + p[0] = p[1] + + def p_assignment_expression(self, p): + """ assignment_expression : conditional_expression + | unary_expression assignment_operator assignment_expression + """ + if len(p) == 2: + p[0] = p[1] + else: + p[0] = c_ast.Assignment(p[2], p[1], p[3], p[1].coord) + + # K&R2 defines these as many separate rules, to encode + # precedence and associativity. Why work hard ? I'll just use + # the built in precedence/associativity specification feature + # of PLY. (see precedence declaration above) + # + def p_assignment_operator(self, p): + """ assignment_operator : EQUALS + | XOREQUAL + | TIMESEQUAL + | DIVEQUAL + | MODEQUAL + | PLUSEQUAL + | MINUSEQUAL + | LSHIFTEQUAL + | RSHIFTEQUAL + | ANDEQUAL + | OREQUAL + """ + p[0] = p[1] + + def p_constant_expression(self, p): + """ constant_expression : conditional_expression """ + p[0] = p[1] + + def p_conditional_expression(self, p): + """ conditional_expression : binary_expression + | binary_expression CONDOP expression COLON conditional_expression + """ + if len(p) == 2: + p[0] = p[1] + else: + p[0] = c_ast.TernaryOp(p[1], p[3], p[5], p[1].coord) + + def p_binary_expression(self, p): + """ binary_expression : cast_expression + | binary_expression TIMES binary_expression + | binary_expression DIVIDE binary_expression + | binary_expression MOD binary_expression + | binary_expression PLUS binary_expression + | binary_expression MINUS binary_expression + | binary_expression RSHIFT binary_expression + | binary_expression LSHIFT binary_expression + | binary_expression LT binary_expression + | binary_expression LE binary_expression + | binary_expression GE binary_expression + | binary_expression GT binary_expression + | binary_expression EQ binary_expression + | binary_expression NE binary_expression + | binary_expression AND binary_expression + | binary_expression OR binary_expression + | binary_expression XOR binary_expression + | binary_expression LAND binary_expression + | binary_expression LOR binary_expression + """ + if len(p) == 2: + p[0] = p[1] + else: + p[0] = c_ast.BinaryOp(p[2], p[1], p[3], p[1].coord) + + def p_cast_expression_1(self, p): + """ cast_expression : unary_expression """ + p[0] = p[1] + + def p_cast_expression_2(self, p): + """ cast_expression : LPAREN type_name RPAREN cast_expression """ + p[0] = c_ast.Cast(p[2], p[4], p[2].coord) + + def p_unary_expression_1(self, p): + """ unary_expression : postfix_expression """ + p[0] = p[1] + + def p_unary_expression_2(self, p): + """ unary_expression : PLUSPLUS unary_expression + | MINUSMINUS unary_expression + | unary_operator cast_expression + """ + p[0] = c_ast.UnaryOp(p[1], p[2], p[2].coord) + + def p_unary_expression_3(self, p): + """ unary_expression : SIZEOF unary_expression + | SIZEOF LPAREN type_name RPAREN + """ + p[0] = c_ast.UnaryOp( + p[1], + p[2] if len(p) == 3 else p[3], + self._coord(p.lineno(1))) + + def p_unary_operator(self, p): + """ unary_operator : AND + | TIMES + | PLUS + | MINUS + | NOT + | LNOT + """ + p[0] = p[1] + + def p_postfix_exptession_1(self, p): + """ postfix_expression : primary_expression """ + p[0] = p[1] + + def p_postfix_exptession_2(self, p): + """ postfix_expression : postfix_expression LBRACKET expression RBRACKET """ + p[0] = c_ast.ArrayRef(p[1], p[3], p[1].coord) + + def p_postfix_exptession_3(self, p): + """ postfix_expression : postfix_expression LPAREN argument_expression_list RPAREN + | postfix_expression LPAREN RPAREN + """ + p[0] = c_ast.FuncCall(p[1], p[3] if len(p) == 5 else None, p[1].coord) + + def p_postfix_expression_4(self, p): + """ postfix_expression : postfix_expression PERIOD identifier + | postfix_expression ARROW identifier + """ + p[0] = c_ast.StructRef(p[1], p[2], p[3], p[1].coord) + + def p_postfix_expression_5(self, p): + """ postfix_expression : postfix_expression PLUSPLUS + | postfix_expression MINUSMINUS + """ + p[0] = c_ast.UnaryOp('p' + p[2], p[1], p[1].coord) + def p_postfix_expression_6(self, p): - """ postfix_expression : LPAREN type_name RPAREN LBRACE initializer_list RBRACE
- | LPAREN type_name RPAREN LBRACE initializer_list COMMA RBRACE
- """
- p[0] = c_ast.CompoundLiteral(p[2], p[5])
-
- def p_primary_expression_1(self, p):
- """ primary_expression : identifier """
- p[0] = p[1]
-
- def p_primary_expression_2(self, p):
- """ primary_expression : constant """
- p[0] = p[1]
-
- def p_primary_expression_3(self, p):
- """ primary_expression : unified_string_literal
- | unified_wstring_literal
- """
- p[0] = p[1]
-
- def p_primary_expression_4(self, p):
- """ primary_expression : LPAREN expression RPAREN """
- p[0] = p[2]
-
- def p_argument_expression_list(self, p):
- """ argument_expression_list : assignment_expression
- | argument_expression_list COMMA assignment_expression
- """
- if len(p) == 2: # single expr
- p[0] = c_ast.ExprList([p[1]], p[1].coord)
- else:
- p[1].exprs.append(p[3])
- p[0] = p[1]
-
- def p_identifier(self, p):
- """ identifier : ID """
- p[0] = c_ast.ID(p[1], self._coord(p.lineno(1)))
-
- def p_constant_1(self, p):
- """ constant : INT_CONST_DEC
- | INT_CONST_OCT
- | INT_CONST_HEX
- """
- p[0] = c_ast.Constant(
- 'int', p[1], self._coord(p.lineno(1)))
-
- def p_constant_2(self, p):
- """ constant : FLOAT_CONST """
- p[0] = c_ast.Constant(
- 'float', p[1], self._coord(p.lineno(1)))
-
- def p_constant_3(self, p):
- """ constant : CHAR_CONST
- | WCHAR_CONST
- """
- p[0] = c_ast.Constant(
- 'char', p[1], self._coord(p.lineno(1)))
-
- # The "unified" string and wstring literal rules are for supporting
- # concatenation of adjacent string literals.
- # I.e. "hello " "world" is seen by the C compiler as a single string literal
- # with the value "hello world"
- #
+ """ postfix_expression : LPAREN type_name RPAREN LBRACE initializer_list RBRACE + | LPAREN type_name RPAREN LBRACE initializer_list COMMA RBRACE + """ + p[0] = c_ast.CompoundLiteral(p[2], p[5]) + + def p_primary_expression_1(self, p): + """ primary_expression : identifier """ + p[0] = p[1] + + def p_primary_expression_2(self, p): + """ primary_expression : constant """ + p[0] = p[1] + + def p_primary_expression_3(self, p): + """ primary_expression : unified_string_literal + | unified_wstring_literal + """ + p[0] = p[1] + + def p_primary_expression_4(self, p): + """ primary_expression : LPAREN expression RPAREN """ + p[0] = p[2] + + def p_argument_expression_list(self, p): + """ argument_expression_list : assignment_expression + | argument_expression_list COMMA assignment_expression + """ + if len(p) == 2: # single expr + p[0] = c_ast.ExprList([p[1]], p[1].coord) + else: + p[1].exprs.append(p[3]) + p[0] = p[1] + + def p_identifier(self, p): + """ identifier : ID """ + p[0] = c_ast.ID(p[1], self._coord(p.lineno(1))) + + def p_constant_1(self, p): + """ constant : INT_CONST_DEC + | INT_CONST_OCT + | INT_CONST_HEX + """ + p[0] = c_ast.Constant( + 'int', p[1], self._coord(p.lineno(1))) + + def p_constant_2(self, p): + """ constant : FLOAT_CONST """ + p[0] = c_ast.Constant( + 'float', p[1], self._coord(p.lineno(1))) + + def p_constant_3(self, p): + """ constant : CHAR_CONST + | WCHAR_CONST + """ + p[0] = c_ast.Constant( + 'char', p[1], self._coord(p.lineno(1))) + + # The "unified" string and wstring literal rules are for supporting + # concatenation of adjacent string literals. + # I.e. "hello " "world" is seen by the C compiler as a single string literal + # with the value "hello world" + # def p_unified_string_literal(self, p): - """ unified_string_literal : STRING_LITERAL
+ """ unified_string_literal : STRING_LITERAL | unified_string_literal STRING_LITERAL - """
- if len(p) == 2: # single literal
- p[0] = c_ast.Constant(
- 'string', p[1], self._coord(p.lineno(1)))
- else:
- p[1].value = p[1].value[:-1] + p[2][1:]
- p[0] = p[1]
-
- def p_unified_wstring_literal(self, p):
- """ unified_wstring_literal : WSTRING_LITERAL
- | unified_wstring_literal WSTRING_LITERAL
- """
- if len(p) == 2: # single literal
- p[0] = c_ast.Constant(
- 'string', p[1], self._coord(p.lineno(1)))
- else:
- p[1].value = p[1].value.rstrip[:-1] + p[2][1:]
- p[0] = p[1]
-
- def p_empty(self, p):
- 'empty : '
- p[0] = None
-
- def p_error(self, p):
- if p:
- self._parse_error(
- 'before: %s' % p.value,
- self._coord(p.lineno))
- else:
- self._parse_error('At end of input', '')
-
-
-if __name__ == "__main__":
- import pprint
- import time
- from portability import printme
-
- t1 = time.time()
- parser = CParser(lex_optimize=True, yacc_debug=True, yacc_optimize=False)
- printme(time.time() - t1)
-
- buf = '''
- int (*k)(int);
- '''
-
- # set debuglevel to 2 for debugging
- t = parser.parse(buf, 'x.c', debuglevel=0)
- t.show(showcoord=True)
+ """ + if len(p) == 2: # single literal + p[0] = c_ast.Constant( + 'string', p[1], self._coord(p.lineno(1))) + else: + p[1].value = p[1].value[:-1] + p[2][1:] + p[0] = p[1] + + def p_unified_wstring_literal(self, p): + """ unified_wstring_literal : WSTRING_LITERAL + | unified_wstring_literal WSTRING_LITERAL + """ + if len(p) == 2: # single literal + p[0] = c_ast.Constant( + 'string', p[1], self._coord(p.lineno(1))) + else: + p[1].value = p[1].value.rstrip[:-1] + p[2][1:] + p[0] = p[1] + + def p_empty(self, p): + 'empty : ' + p[0] = None + + def p_error(self, p): + if p: + self._parse_error( + 'before: %s' % p.value, + self._coord(p.lineno)) + else: + self._parse_error('At end of input', '') + + +if __name__ == "__main__": + import pprint + import time + from portability import printme + + t1 = time.time() + parser = CParser(lex_optimize=True, yacc_debug=True, yacc_optimize=False) + printme(time.time() - t1) + + buf = ''' + int (*k)(int); + ''' + + # set debuglevel to 2 for debugging + t = parser.parse(buf, 'x.c', debuglevel=0) + t.show(showcoord=True) @@ -13,7 +13,7 @@ setup( C compilers or analysis tools.
""",
license='LGPL',
- version='2.00',
+ version='2.01',
author='Eli Bendersky',
maintainer='Eli Bendersky',
author_email='eliben@gmail.com',
@@ -21,7 +21,7 @@ setup( platforms='Cross Platform',
packages=['pycparser'],
- package_data={'pycparser': ['*.yaml']},
+ package_data={'pycparser': ['*.cfg']},
)
|