Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Make abstract syntax trees out of C code and save the world.
Ruby C
branch: master

This branch is 5 commits ahead of dlee:master

Fetching latest commit…

Cannot retrieve the latest commit at this time

Failed to load latest commit information.
ext/cast
lib
test
.gitignore
History.txt
Manifest.txt
README.rdoc
Rakefile
cast.gemspec

README.rdoc

CAST

cast.rubyforge.org

Description

CAST parses C code into an abstract syntax tree (AST), lets you break it, then vomit it out as code. The parser does C99.

This fork supports Ruby 1.9.3, gemspec, and requires Hoe. The Rubyforge page above is documentation for the original version, but most things should be the same.

Installation

gem install csquare-cast

Library Overview

Everything is in the module C.

  • There's the parser (Parser).

  • There's the tree (Node and its subclasses).

  • That's it.

Usage

You call Parser#parse, and it gives you a tree of Node objects. Watch:

require 'cast/cast'

# create a parser
parser = C::Parser.new

# (optional) set some settings...
parser.pos.filename = "toy.c"      # used for error messages
parser.type_names << 'LinkedList'  # treat these words as types

# gimme a tree
ugly_c_code = open("toy.c"){|f| f.read}
tree = parser.parse(ugly_c_code)

# what's the tree look like?
p tree

If there's a parse error, #parse raises a ParseError (which has a nice error message in #message).

The Parser

Here's a quiz: what does "a * b;" do?

I bet you said “why you l4m3r n00b, that's a statement that multiplies a by b and throws away the answer – now go take your meaningless snippetage to your computing 101 class and let me finish hurting this Java<sup>TM</sup> programmer.” Well, you'd be both mean and wrong. It was, of course, a trick question. I didn't say if any of a and b are types! If only a is a type, it's actually a declaration. And if b is a type, it's a syntax error.

So, the parser's gonna need to know which identifiers are type names. This is one of the bits of state that a Parser keeps. Here's the complete list (um, of two):

  • #type_names – a Set of Strings.

  • #pos – the Node::Pos this parser will start parsing at.

A Node::Pos has three read-write atts: #filename, #line_num, #col_num. Default is nil, 1, 0.

The Nodes

There are a couple of Node classes:

<div class=“node_classes”><table><tr>

<td>
  <ul>
    <li class="node_classes"><span class="node_classes_abstract">Node</span><ul>
      <li class="node_classes"><span class="node_classes_concrete">TranslationUnit</span></li>
      <li class="node_classes"><span class="node_classes_concrete">Declaration</span></li>
      <li class="node_classes"><span class="node_classes_concrete">Declarator</span></li>
      <li class="node_classes"><span class="node_classes_concrete">FunctionDef</span></li>
      <li class="node_classes"><span class="node_classes_concrete">Parameter</span></li>
      <li class="node_classes"><span class="node_classes_concrete">Enumerator</span></li>
      <li class="node_classes"><span class="node_classes_concrete">MemberInit</span></li>
      <li class="node_classes"><span class="node_classes_concrete">Member</span></li>
      <li class="node_classes"><span class="node_classes_abstract">Statement</span><ul>
        <li class="node_classes"><span class="node_classes_concrete">Block</span></li>
        <li class="node_classes"><span class="node_classes_concrete">If</span></li>
        <li class="node_classes"><span class="node_classes_concrete">Switch</span></li>
        <li class="node_classes"><span class="node_classes_concrete">While</span></li>
        <li class="node_classes"><span class="node_classes_concrete">For</span></li>
        <li class="node_classes"><span class="node_classes_concrete">Goto</span></li>
        <li class="node_classes"><span class="node_classes_concrete">Continue</span></li>
        <li class="node_classes"><span class="node_classes_concrete">Break</span></li>
        <li class="node_classes"><span class="node_classes_concrete">Return</span></li>
        <li class="node_classes"><span class="node_classes_concrete">ExpressionStatement</span></li>
      </ul></li>
      <li class="node_classes"><span class="node_classes_abstract">Label</span><ul>
        <li class="node_classes"><span class="node_classes_concrete">PlainLabel</span></li>
        <li class="node_classes"><span class="node_classes_concrete">Default</span></li>
        <li class="node_classes"><span class="node_classes_concrete">Case</span></li>
      </ul></li>
    </ul></li>
  </ul>
</td><td>
  <ul>
    <li class="node_classes"><span class="node_classes_abstract">Node</span><ul>
      <li class="node_classes"><span class="node_classes_abstract">Expression</span><ul>
        <li class="node_classes"><span class="node_classes_concrete">Comma</span></li>
        <li class="node_classes"><span class="node_classes_concrete">Conditional</span></li>
        <li class="node_classes"><span class="node_classes_concrete">Variable</span></li>
        <li class="node_classes"><span class="node_classes_abstract">UnaryExpression</span><ul>
          <li class="node_classes"><span class="node_classes_abstract">PostfixExpression</span><ul>
            <li class="node_classes"><span class="node_classes_concrete">Index</span></li>
            <li class="node_classes"><span class="node_classes_concrete">Call</span></li>
            <li class="node_classes"><span class="node_classes_concrete">Dot</span></li>
            <li class="node_classes"><span class="node_classes_concrete">Arrow</span></li>
            <li class="node_classes"><span class="node_classes_concrete">PostInc</span></li>
            <li class="node_classes"><span class="node_classes_concrete">PostDec</span></li>
          </ul></li>
          <li class="node_classes"><span class="node_classes_abstract">PrefixExpression</span><ul>
            <li class="node_classes"><span class="node_classes_concrete">Cast</span></li>
            <li class="node_classes"><span class="node_classes_concrete">Address</span></li>
            <li class="node_classes"><span class="node_classes_concrete">Dereference</span></li>
            <li class="node_classes"><span class="node_classes_concrete">Sizeof</span></li>
            <li class="node_classes"><span class="node_classes_concrete">Plus</span></li>
            <li class="node_classes"><span class="node_classes_concrete">Minus</span></li>
            <li class="node_classes"><span class="node_classes_concrete">PreInc</span></li>
            <li class="node_classes"><span class="node_classes_concrete">PreDec</span></li>
            <li class="node_classes"><span class="node_classes_concrete">BitNot</span></li>
            <li class="node_classes"><span class="node_classes_concrete">Not</span></li>
          </ul></li>
        </ul></li>
      </ul></li>
    </ul></li>
  </ul>
</td><td>
  <ul>
    <li class="node_classes"><span class="node_classes_abstract">Node</span><ul>
      <li class="node_classes"><span class="node_classes_abstract">Expression</span><ul>
        <li class="node_classes"><span class="node_classes_abstract">BinaryExpression</span><ul>
          <li class="node_classes"><span class="node_classes_concrete">Add</span></li>
          <li class="node_classes"><span class="node_classes_concrete">Subtract</span></li>
          <li class="node_classes"><span class="node_classes_concrete">Multiply</span></li>
          <li class="node_classes"><span class="node_classes_concrete">Divide</span></li>
          <li class="node_classes"><span class="node_classes_concrete">Mod</span></li>
          <li class="node_classes"><span class="node_classes_concrete">Equal</span></li>
          <li class="node_classes"><span class="node_classes_concrete">NotEqual</span></li>
          <li class="node_classes"><span class="node_classes_concrete">Less</span></li>
          <li class="node_classes"><span class="node_classes_concrete">More</span></li>
          <li class="node_classes"><span class="node_classes_concrete">LessOrEqual</span></li>
          <li class="node_classes"><span class="node_classes_concrete">MoreOrEqual</span></li>
          <li class="node_classes"><span class="node_classes_concrete">BitAnd</span></li>
          <li class="node_classes"><span class="node_classes_concrete">BitOr</span></li>
          <li class="node_classes"><span class="node_classes_concrete">BitXor</span></li>
          <li class="node_classes"><span class="node_classes_concrete">ShiftLeft</span></li>
          <li class="node_classes"><span class="node_classes_concrete">ShiftRight</span></li>
          <li class="node_classes"><span class="node_classes_concrete">And</span></li>
          <li class="node_classes"><span class="node_classes_concrete">Or</span></li>
        </ul></li>
      </ul></li>
    </ul></li>
  </ul>
</td><td>
  <ul>
    <li class="node_classes"><span class="node_classes_abstract">Node</span><ul>
      <li class="node_classes"><span class="node_classes_abstract">Expression</span><ul>
        <li class="node_classes"><span class="node_classes_abstract">AssignmentExpression</span><ul>
          <li class="node_classes"><span class="node_classes_concrete">Assign</span></li>
          <li class="node_classes"><span class="node_classes_concrete">MultiplyAssign</span></li>
          <li class="node_classes"><span class="node_classes_concrete">DivideAssign</span></li>
          <li class="node_classes"><span class="node_classes_concrete">ModAssign</span></li>
          <li class="node_classes"><span class="node_classes_concrete">AddAssign</span></li>
          <li class="node_classes"><span class="node_classes_concrete">SubtractAssign</span></li>
          <li class="node_classes"><span class="node_classes_concrete">ShiftLeftAssign</span></li>
          <li class="node_classes"><span class="node_classes_concrete">ShiftRightAssign</span></li>
          <li class="node_classes"><span class="node_classes_concrete">BitAndAssign</span></li>
          <li class="node_classes"><span class="node_classes_concrete">BitXorAssign</span></li>
          <li class="node_classes"><span class="node_classes_concrete">BitOrAssign</span></li>
        </ul></li>
        <li class="node_classes"><span class="node_classes_abstract">Literal</span><ul>
          <li class="node_classes"><span class="node_classes_concrete">StringLiteral</span></li>
          <li class="node_classes"><span class="node_classes_concrete">CharLiteral</span></li>
          <li class="node_classes"><span class="node_classes_concrete">CompoundLiteral</span></li>
          <li class="node_classes"><span class="node_classes_concrete">IntLiteral</span></li>
          <li class="node_classes"><span class="node_classes_concrete">FloatLiteral</span></li>
        </ul></li>
      </ul></li>
    </ul></li>
  </ul>
</td><td>
  <ul>
    <li class="node_classes"><span class="node_classes_abstract">Node</span><ul>
      <li class="node_classes"><span class="node_classes_abstract">Type</span><ul>
        <li class="node_classes"><span class="node_classes_abstract">IndirectType</span><ul>
          <li class="node_classes"><span class="node_classes_concrete">Pointer</span></li>
          <li class="node_classes"><span class="node_classes_concrete">Array</span></li>
          <li class="node_classes"><span class="node_classes_concrete">Function</span></li>
        </ul></li>
        <li class="node_classes"><span class="node_classes_abstract">DirectType</span><ul>
          <li class="node_classes"><span class="node_classes_concrete">Struct</span></li>
          <li class="node_classes"><span class="node_classes_concrete">Union</span></li>
          <li class="node_classes"><span class="node_classes_concrete">Enum</span></li>
          <li class="node_classes"><span class="node_classes_concrete">CustomType</span></li>
          <li class="node_classes"><span class="node_classes_abstract">PrimitiveType</span><ul>
            <li class="node_classes"><span class="node_classes_concrete">Void</span></li>
            <li class="node_classes"><span class="node_classes_concrete">Int</span></li>
            <li class="node_classes"><span class="node_classes_concrete">Float</span></li>
            <li class="node_classes"><span class="node_classes_concrete">Char</span></li>
            <li class="node_classes"><span class="node_classes_concrete">Bool</span></li>
            <li class="node_classes"><span class="node_classes_concrete">Complex</span></li>
            <li class="node_classes"><span class="node_classes_concrete">Imaginary</span></li>
          </ul></li>
        </ul></li>
      </ul></li>
      <li class="node_classes"><span class="node_classes_abstract">NodeList</span><ul>
        <li class="node_classes"><span class="node_classes_concrete">NodeArray</span></li>
        <li class="node_classes"><span class="node_classes_concrete">NodeChain</span></li>
      </ul></li>
    </ul></li>
  </ul>
</td></tr>

</table></div>

The bold ones are abstract.

The last 2 (the NodeLists) represent lists of nodes. Methodwise, they try to behave like normal ruby ::Arrays. Implementationwise, a NodeChain is a doubly linked list, whereas a NodeArray is an array. NodeChains may be more efficient when adding things at the beginning of a LARGE list.

Attributes

Each Node object has:

  • #parent – return the parent in the tree (a Node or nil).

  • #pos, #pos= – the position in the source file (a Node::Pos).

  • #to_s – return the code for the tree (a String).

  • #inspect – return a pretty string for inspection. Try it.

  • #match?(str), #=~(str) – return true iff str parses as a Node equal to this one.

  • #detach – remove this node from the tree (parent becomes nil) and return it.

  • #detached?, #attached? – return true if parent is nil or non-nil respectively.

  • #replace_with(node) – replace this node with node in the tree.

  • #swap_with(node) – exchange this node with node in their trees.

  • #insert_prev(*nodes), #insert_next(*nodes) – insert nodes before this node in the parent list. Parent must be a NodeList! Useful for adding statements before a node in a block, for example.

  • #Foo? – (where Foo is a module name) return self.is_a?(Foo).

<!–

Now the <tt>Foo?</tt> method above probably gave all the duck typing
purists heart attacks, so I should prepare my defence.  CAST pays
close attention to the classes of <tt>Node</tt>s.  That means if you
dress up a <tt>Thingy</tt> as a <tt>FunctionDef</tt> and smuggle it
into the tree, don't expect the pacemaker you're using this for to
function correctly.  Basic methods like <tt>Node#==</tt> check that
the classes match.

–>

The #Foo? method is a convienience for a common need. Example:

## make a tree
ast = C::Parser.new.parse(code_string)

## print all global variables
ast.entities.each do |node|
  node.Declaration? or next
  node.declarators.each do |decl|
    unless decl.type.Function?
      puts "#{decl.name}: #{decl.type}"
    end
  end
end

If you're a duck-typing purist, then sorry for the cardiac arrest you're now experiencing. CAST does pay attention to the class of Node objects for quite a few things. This is the cleanest way to distinguish, e.g., an Add from a Subtract (which both have the same methods but represent very different things). It just seems impractical (and unnecessary) to allow duck typing in this situation.

The #=~ method lets you do:

if declarator.type =~ 'const int *'
  puts "Ooh, a const int pointer!"
end

This is not the same as

declarator.type.to_s == 'const int *'

That'd require you to guess how to_s formats its strings (most notably, the whitespace).

Fields and children

Each concrete Node class has a member for each bit of important C stuff it pertains to. I know you peeked at the big list below, so you know the kind of thing I mean.

But these aren't defined as attrs as you normally do in Ruby – they're <strong>field</strong>s. If a node has a field foo, it means there's a setter #foo= and getter #foo. (A field foo? means the setter is #foo= and the getter is #foo?.) Some fields are even more special: <strong>child</strong> fields. These form the tree structure, and always have a Node or nil value.

Why divulge these bizarre internal secrets? Because these Node methods are defined in terms of fields and children:

  • #==, #eql? – Equality is checked recursively. That is, all fields (including children) must be equal.

  • #dup, #clone – Children are copied recursively (other fields and attrs as normal).

Then there's the tree-twiddling methods, which only ever yield/return/affect (non-nil) children.

  • #next, #prev – return the next/prev sibling.

  • #list_next, #list_prev – like #next/#prev, but also requires the parent to be NodeList. I'll be honest; I don't remember why I added these methods. They may well suddenly disappear.

  • #each, #reverse_each – Yield all (non-nil) children. Node includes Enumerable, so you get the free chocolates too.

  • #depth_first, #reverse_depth_first – Walk the tree in that order, yielding two args (event, node) at each node. event is :down on the way down, :up on the way up. If the block throws :prune, it won't descend any further.

  • #preorder, #reverse_preorder, #postorder, #reverse_postorder – Walk the tree depth first, yielding nodes in the given order. For the preorders, if the block throws :prune, it won't descend any further.

  • #node_after(child), #node_before(child) – return the node before/after child (same as child.next).

  • #remove_node(child) – remove child from this node (same as child.detach).

  • #replace_node(child, new_child) – replace child with yeah you guessed it (same as child.replace_with(newchild)).

If you're walking the tree looking for nodes to move around, don't forget that modifying the tree during traversal is a criminal offence.

And now, the episode you've been waiting for: THE FIELD LIST! (Cue music and dim lights.)

Notes about the table:

  • If no default is listed, it is false if the field name ends in a '?', nil otherwise.

  • nil is always allowed for a child field.

  • There are some conventions we follow religiously to help you:

    • Field names that end in '?' are always true-or-false.

    • NodeList-valued fields always default to an empty NodeArray or NodeChain, so you can tack things on there with &lt;&lt;, without worrying about needing to create the list first.

    • A field is Node-valued if and only if it is a child field.

    • The rows go yellow, green, yellow, green, … .

<table class=“node_desc”>

<thead><tr>
</tr></thead>

<thead><tr class="node_desc_header">
  <td align="center">Class</td>
  <td align="center">Field</td>
  <td align="center">Child?</td>
  <td align="center">Type or possible values</td>
  <td align="center">Default</td>
  <td align="center">Comments</td>
</tr></thead>

<tbody>
<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="1"><tt>TranslationUnit</tt></td>
  <td class="nd_field"><tt>entities</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>NodeList</tt></td>
  <td class="nd_default"><tt>NodeChain[]</tt></td>
  <td class="nd_comments" rowspan="1">
    He lives at the root of a parsed file.
  </td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="4"><tt>Declaration</tt></td>
  <td class="nd_field"><tt>storage</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>:typedef</tt>, <tt>:extern</tt>, <tt>:static</tt>, <tt>:auto</tt>, <tt>:register</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="4">
    There are also methods to query the storage more humanely:
    <ul>
      <li><tt>#typedef? </tt> -- true iff <tt>storage == :typedef </tt></li>
      <li><tt>#extern?  </tt> -- true iff <tt>storage == :extern  </tt></li>
      <li><tt>#static?  </tt> -- true iff <tt>storage == :static  </tt></li>
      <li><tt>#auto?    </tt> -- true iff <tt>storage == :auto    </tt></li>
      <li><tt>#register?</tt> -- true iff <tt>storage == :register</tt></li>
    </ul>
  </td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>type</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>DirectType</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>declarators</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>NodeList</tt></td>
  <td class="nd_default"><tt>NodeArray[]</tt></td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>inline?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="4"><tt>Declarator</tt></td>
  <td class="nd_field"><tt>indirect_type</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>IndirectType</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="4">
    What on earth is a "declarator", you ask?  Consider "<tt>int i,
    *ip;</tt>".  This is a <tt>Declaration</tt> with two
    <tt>Declarator</tt>s:

<pre>

Declaration
    type: Int
    declarators:
        - Declarator
            name: "i"
        - Declarator
            indirect_type: Pointer
            name: "ip"

</pre>

The <tt>indirect_type</tt> of the <tt>ip</tt>
<tt>Declarator</tt> is a <tt>Pointer</tt> to <tt>nil</tt>.
"'Pointer to nil' my foot -- I want the type of the stupid
variable!"  Here:
<ul>
  <li>
    <tt>#type</tt> -- return the type, the whole type, and
    nothing but the type.  This is a clone; modifying it won't
    modify the tree.
  </li>
</ul>
So calling <tt>#type</tt> on the <tt>ip</tt> <tt>Declarator</tt>
gives:

<pre>

Pointer
    type: Int

</pre>

  </td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>name</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>String</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>init</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>num_bits</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Integer</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="6"><tt>FunctionDef</tt></td>
  <td class="nd_field"><tt>storage</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>:extern</tt>, <tt>:static</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="6">
    Just like <tt>Declaration</tt>, there's also:
    <ul>
      <li><tt>#extern?</tt> -- return true iff <tt>storage == :extern</tt></li>
      <li><tt>#static?</tt> -- return true iff <tt>storage == :static</tt></li>
    </ul>
    There's also a pseudo-field:
    <ul>
      <li><tt>#prototype?</tt> -- same as !no_prototype?</li>
      <li><tt>#prototype=(val)</tt> -- same as no_prototype = !val</li>
    </ul>
    <tt>no_prototype?</tt> means that no prototype was given.  That means parameter types weren't given in the parens, but in the "old-style" declaration list.  Example:
    <table cellpadding="5" width="100%">
      <tr><td>

<pre> int main(argc, argv)

int argc;
char **argv;

{

return 0;

} </pre>

</td><td>

<pre> int main(int argc, char **argv) {

return 0;

} </pre>

  </td></tr><tr><td>
    <b>No prototype.</b>
  </td><td>
    <b>Prototype.</b>
  </td></tr>
</table>
Everyone tells you to use prototypes.  That's because no type
checking is done when calling a function declared without a
prototype.

</pre>

  </td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>inline?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>type</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Type</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>name</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>String</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>def</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Block</tt></td>
  <td class="nd_default"><tt>Block.new</tt></td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>no_prototype?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="3"><tt>Parameter</tt></td>
  <td class="nd_field"><tt>register?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="3">
    Used in <tt>Function</tt>s.
  </td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>type</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Type</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>name</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>String</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="2"><tt>Enumerator</tt></td>
  <td class="nd_field"><tt>name</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>String</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
    Used in <tt>Enum</tt>s.
  </td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>val</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="2"><tt>MemberInit</tt></td>
  <td class="nd_field"><tt>member</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>NodeList</tt> of <tt>Member</tt>-or-<tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
    Used in <tt>CompoundLiteral</tt>s.
  </td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>init</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="1"><tt>Member</tt></td>
  <td class="nd_field"><tt>name</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>String</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="1">
    Used in <tt>MemberInit</tt>s.
  </td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="2"><tt>Block</tt></td>
  <td class="nd_field"><tt>labels</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>NodeList</tt> of <tt>Label</tt></td>
  <td class="nd_default"><tt>NodeArray[]</tt></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>stmts</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>NodeList</tt> of <tt>Statement</tt></td>
  <td class="nd_default"><tt>NodeArray[]</tt></td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="4"><tt>If</tt></td>
  <td class="nd_field"><tt>labels</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>NodeList</tt> of <tt>Label</tt></td>
  <td class="nd_default"><tt>NodeArray[]</tt></td>
  <td class="nd_comments" rowspan="4">
  </td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>cond</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>then</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Statement</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>else</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Statement</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="3"><tt>Switch</tt></td>
  <td class="nd_field"><tt>labels</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>NodeList</tt> of <tt>Label</tt></td>
  <td class="nd_default"><tt>NodeArray[]</tt></td>
  <td class="nd_comments" rowspan="3">
  </td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>cond</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>stmt</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Statement</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="4"><tt>While</tt></td>
  <td class="nd_field"><tt>labels</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>NodeList</tt> of <tt>Label</tt></td>
  <td class="nd_default"><tt>NodeArray[]</tt></td>
  <td class="nd_comments" rowspan="4">
    <tt>do?</tt> means it's a do-while loop.
  </td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>do?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>cond</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>stmt</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Statement</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="5"><tt>For</tt></td>
  <td class="nd_field"><tt>labels</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>NodeList</tt> of <tt>Label</tt></td>
  <td class="nd_default"><tt>NodeArray[]</tt></td>
  <td class="nd_comments" rowspan="5">
  </td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>init</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt> or <tt>Declaration</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>cond</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>iter</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>stmt</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Statement</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="2"><tt>Goto</tt></td>
  <td class="nd_field"><tt>labels</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>NodeList</tt> of <tt>Label</tt></td>
  <td class="nd_default"><tt>NodeArray[]</tt></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>target</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>String</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="1"><tt>Continue</tt></td>
  <td class="nd_field"><tt>labels</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>NodeList</tt> of <tt>Label</tt></td>
  <td class="nd_default"><tt>NodeArray[]</tt></td>
  <td class="nd_comments" rowspan="1">
  </td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="1"><tt>Break</tt></td>
  <td class="nd_field"><tt>labels</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>NodeList</tt> of <tt>Label</tt></td>
  <td class="nd_default"><tt>NodeArray[]</tt></td>
  <td class="nd_comments" rowspan="1">
  </td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="2"><tt>Return</tt></td>
  <td class="nd_field"><tt>labels</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>NodeList</tt> of <tt>Label</tt></td>
  <td class="nd_default"><tt>NodeArray[]</tt></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>expr</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="2"><tt>ExpressionStatement</tt></td>
  <td class="nd_field"><tt>labels</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>NodeList</tt> of <tt>Label</tt></td>
  <td class="nd_default"><tt>NodeArray[]</tt></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>expr</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="1"><tt>PlainLabel</tt></td>
  <td class="nd_field"><tt>name</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>String</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="1">
  </td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="1"><tt>Default</tt></td>
  <td class="nd_field"></td>
  <td class="nd_child"></td>
  <td class="nd_values"></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="1">
  </td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="1"><tt>Case</tt></td>
  <td class="nd_field"><tt>expr</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="1">
  </td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="1"><tt>Comma</tt></td>
  <td class="nd_field"><tt>exprs</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>NodeList</tt> of <tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="1">
  </td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="3"><tt>Conditional</tt></td>
  <td class="nd_field"><tt>cond</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="3">
  </td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>then</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>else</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="1"><tt>Variable</tt></td>
  <td class="nd_field"><tt>name</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>String</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="1">
  </td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="2"><tt>Index</tt></td>
  <td class="nd_field"><tt>expr</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>index</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="2"><tt>Call</tt></td>
  <td class="nd_field"><tt>expr</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>args</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>NodeList</tt> of <tt>Expression</tt>-or-<tt>Type</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="2"><tt>Dot</tt></td>
  <td class="nd_field"><tt>expr</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>member</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>String</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="2"><tt>Arrow</tt></td>
  <td class="nd_field"><tt>expr</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>member</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>String</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="1"><tt>PostInc</tt></td>
  <td class="nd_field"><tt>expr</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="1">
  </td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="1"><tt>PostDec</tt></td>
  <td class="nd_field"><tt>expr</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="1">
  </td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="2"><tt>Cast</tt></td>
  <td class="nd_field"><tt>type</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Type</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>expr</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="1"><tt>Address</tt></td>
  <td class="nd_field"><tt>expr</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="1">
  </td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="1"><tt>Dereference</tt></td>
  <td class="nd_field"><tt>expr</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="1">
  </td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="1"><tt>Sizeof</tt></td>
  <td class="nd_field"><tt>expr</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Type</tt> or <tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="1">
  </td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="1"><tt>Positive</tt></td>
  <td class="nd_field"><tt>expr</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="1">
  </td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="1"><tt>Negative</tt></td>
  <td class="nd_field"><tt>expr</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="1">
  </td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="1"><tt>PreInc</tt></td>
  <td class="nd_field"><tt>expr</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="1">
  </td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="1"><tt>PreDec</tt></td>
  <td class="nd_field"><tt>expr</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="1">
  </td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="1"><tt>BitNot</tt></td>
  <td class="nd_field"><tt>expr</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="1">
  </td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="1"><tt>Not</tt></td>
  <td class="nd_field"><tt>expr</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="1">
  </td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="2"><tt>Add</tt></td>
  <td class="nd_field"><tt>expr1</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>expr2</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="2"><tt>Subtract</tt></td>
  <td class="nd_field"><tt>expr1</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>expr2</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="2"><tt>Multiply</tt></td>
  <td class="nd_field"><tt>expr1</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>expr2</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="2"><tt>Divide</tt></td>
  <td class="nd_field"><tt>expr1</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>expr2</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="2"><tt>Mod</tt></td>
  <td class="nd_field"><tt>expr1</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>expr2</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="2"><tt>Equal</tt></td>
  <td class="nd_field"><tt>expr1</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>expr2</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="2"><tt>NotEqual</tt></td>
  <td class="nd_field"><tt>expr1</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>expr2</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="2"><tt>Less</tt></td>
  <td class="nd_field"><tt>expr1</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>expr2</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="2"><tt>More</tt></td>
  <td class="nd_field"><tt>expr1</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>expr2</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="2"><tt>LessOrEqual</tt></td>
  <td class="nd_field"><tt>expr1</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>expr2</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="2"><tt>MoreOrEqual</tt></td>
  <td class="nd_field"><tt>expr1</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>expr2</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="2"><tt>BitAnd</tt></td>
  <td class="nd_field"><tt>expr1</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>expr2</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="2"><tt>BitOr</tt></td>
  <td class="nd_field"><tt>expr1</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>expr2</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="2"><tt>BitXor</tt></td>
  <td class="nd_field"><tt>expr1</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>expr2</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="2"><tt>ShiftLeft</tt></td>
  <td class="nd_field"><tt>expr1</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>expr2</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="2"><tt>ShiftRight</tt></td>
  <td class="nd_field"><tt>expr1</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>expr2</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="2"><tt>And</tt></td>
  <td class="nd_field"><tt>expr1</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>expr2</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="2"><tt>Or</tt></td>
  <td class="nd_field"><tt>expr1</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>expr2</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="2"><tt>Assign</tt></td>
  <td class="nd_field"><tt>lval</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>rval</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="2"><tt>MultiplyAssign</tt></td>
  <td class="nd_field"><tt>lval</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>rval</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="2"><tt>DivideAssign</tt></td>
  <td class="nd_field"><tt>lval</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>rval</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="2"><tt>ModAssign</tt></td>
  <td class="nd_field"><tt>lval</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>rval</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="2"><tt>AddAssign</tt></td>
  <td class="nd_field"><tt>lval</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>rval</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="2"><tt>SubtractAssign</tt></td>
  <td class="nd_field"><tt>lval</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>rval</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="2"><tt>ShiftLeftAssign</tt></td>
  <td class="nd_field"><tt>lval</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>rval</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="2"><tt>ShiftRightAssign</tt></td>
  <td class="nd_field"><tt>lval</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>rval</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="2"><tt>BitAndAssign</tt></td>
  <td class="nd_field"><tt>lval</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>rval</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="2"><tt>BitXorAssign</tt></td>
  <td class="nd_field"><tt>lval</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>rval</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="2"><tt>BitOrAssign</tt></td>
  <td class="nd_field"><tt>lval</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
  </td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>rval</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="1"><tt>StringLiteral</tt></td>
  <td class="nd_field"><tt>val</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>String</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="1">
    The <tt>String</tt> in <tt>val</tt> is the literal string entered.  <tt>"\n"</tt>
    isn't converted to a newline, for instance.
  </td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="1"><tt>CharLiteral</tt></td>
  <td class="nd_field"><tt>val</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>String</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="1">
    The <tt>String</tt> in <tt>val</tt> is the literal string entered.  <tt>'\n'</tt>
    isn't converted to a newline, for instance.
  </td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="2"><tt>CompoundLiteral</tt></td>
  <td class="nd_field"><tt>type</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Type</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
    <p>
      Here's an example.  <tt>(struct S){1, .x = 2, .y [3] .z =
      4}</tt> parses as:</p>

<pre> CompoundLiteral

type: Struct
    name: "S"
member_inits:
    - MemberInit
        init: IntLiteral
            val: 1
    - MemberInit
        member:
            - Member
                name: "x"
        init: IntLiteral
            val: 2
    - MemberInit
        member:
            - Member
                name: "y"
            - IntLiteral
                val: 3
            - Member
                name: "z"
        init: IntLiteral
            val: 4

</pre>

    "That's legal syntax!?"  Yep.  Look it up.
  </td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>member_inits</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>NodeList</tt> of <tt>MemberInit</tt></td>
  <td class="nd_default"><tt>NodeArray[]</tt></td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="2"><tt>IntLiteral</tt></td>
  <td class="nd_field"><tt>val</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>Integer</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="2">
    <p>Also:</p>
    <ul>
      <li><tt>#dec?</tt> -- return true iff <tt>format == :dec</tt></li>
      <li><tt>#hex?</tt> -- return true iff <tt>format == :hex</tt></li>
      <li><tt>#oct?</tt> -- return true iff <tt>format == :oct</tt></li>
    </ul>
  </td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>format</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>:dec</tt>, <tt>:hex</tt>, <tt>:oct</tt></td>
  <td class="nd_default"><tt>:dec</tt></td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="1"><tt>FloatLiteral</tt></td>
  <td class="nd_field"><tt>val</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>Float</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="1">
  </td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="4"><tt>Pointer</tt></td>
  <td class="nd_field"><tt>const?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="4">
  </td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>restrict?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>volatile?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>type</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Type</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="5"><tt>Array</tt></td>
  <td class="nd_field"><tt>const?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="5">
  </td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>restrict?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>volatile?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>type</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Type</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>length</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Expression</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="6"><tt>Function</tt></td>
  <td class="nd_field"><tt>const?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="6">
  </td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>restrict?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>volatile?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>type</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Type</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>params</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>NodeList</tt> of <tt>Parameter</tt></td>
  <td class="nd_default"><tt>NodeArray[]</tt></td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>var_args?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="5"><tt>Struct</tt></td>
  <td class="nd_field"><tt>const?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="5">
  </td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>restrict?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>volatile?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>name</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>String</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>members</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>NodeList</tt> of <tt>Member</tt></td>
  <td class="nd_default"><tt>NodeArray[]</tt></td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="5"><tt>Union</tt></td>
  <td class="nd_field"><tt>const?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="5">
  </td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>restrict?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>volatile?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>name</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>String</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>members</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>NodeList</tt> of <tt>Member</tt></td>
  <td class="nd_default"><tt>NodeArray[]</tt></td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="5"><tt>Enum</tt></td>
  <td class="nd_field"><tt>const?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="5">
  </td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>restrict?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>volatile?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>name</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>String</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>members</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>NodeList</tt> of <tt>Enumerator</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="4"><tt>CustomType</tt></td>
  <td class="nd_field"><tt>const?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="4">
    This is for <tt>typedef</tt>'d names.
  </td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>restrict?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>volatile?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>name</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>String</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="3"><tt>Void</tt></td>
  <td class="nd_field"><tt>const?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="3">
    <tt>const void</tt>!?  Yes, think about: <tt>const void *</tt>.
  </td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>restrict?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>volatile?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="5"><tt>Int</tt></td>
  <td class="nd_field"><tt>const?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="5">
        <tt>longness</tt> sounds silly, so here are some less silly
        methods:
    <ul>
      <li><tt>#short?</tt> -- return true iff <tt>longness == -1</tt></li>
      <li><tt>#plain?</tt> -- return true iff <tt>longness == 0</tt></li>
      <li><tt>#long?</tt> -- return true iff <tt>longness == 1</tt></li>
      <li><tt>#long_long?</tt> -- return true iff <tt>longness == 2</tt></li>
    </ul>
    Oh, and look, a pseudo-field:
    <ul>
      <li><tt>#signed?</tt> -- same as <tt>!unsigned?</tt></li>
      <li><tt>#signed=(val)</tt> -- same as <tt>unsigned = !val</tt></li>
    </ul>
  </td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>restrict?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>volatile?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>longness</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>-1</tt>, <tt>0</tt>, <tt>1</tt>, <tt>2</tt></td>
  <td class="nd_default"><tt>0</tt></td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>unsigned?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="4"><tt>Float</tt></td>
  <td class="nd_field"><tt>const?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="4">
    Less silly-sounding <tt>longness</tt> substitutes:
    <ul>
      <li><tt>#plain?</tt> -- return true iff <tt>longness == 0</tt></li>
      <li><tt>#double?</tt> -- return true iff <tt>longness == 1</tt></li>
      <li><tt>#long_double?</tt> -- return true iff <tt>longness == 2</tt></li>
    </ul>
  </td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>restrict?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>volatile?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>longness</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>0</tt>, <tt>1</tt>, <tt>2</tt></td>
  <td class="nd_default"><tt>0</tt></td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="4"><tt>Char</tt></td>
  <td class="nd_field"><tt>const?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="4">
    Also:
    <ul>
      <li><tt>#signed?</tt> -- return true iff <tt>signed == true</tt></li>
      <li><tt>#unsigned?</tt> -- return true iff <tt>signed == false</tt></li>
      <li><tt>#plain?</tt> -- return true iff <tt>signed == nil</tt></li>
    </ul>
    Yes, C99 says that <tt>char</tt>, <tt>signed char</tt>, and
    <tt>unsigned char</tt> are 3 distinct types (unlike with
    <tt>int</tt> -- go figure).  Like Martian chalk and Venusian
    cheese: completely different, but you can fit 'em each in one
    byte.  Mmm, Martian chalk...
  </td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>restrict?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>volatile?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>signed</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt>, <tt>nil</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="3"><tt>Bool</tt></td>
  <td class="nd_field"><tt>const?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="3">
    This is the rarely seen <tt>_Bool</tt> type.
  </td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>restrict?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>volatile?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
</tr>

<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="4"><tt>Complex</tt></td>
  <td class="nd_field"><tt>const?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="4">
    <p>This is the rarely seen <tt>_Complex</tt> type.</p>
    <ul>
      <li><tt>#plain?</tt> -- return true iff <tt>longness == 0</tt></li>
      <li><tt>#double?</tt> -- return true iff <tt>longness == 1</tt></li>
      <li><tt>#long_double?</tt> -- return true iff <tt>longness == 2</tt></li>
    </ul>
  </td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>restrict?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>volatile?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_field"><tt>longness</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>0</tt>, <tt>1</tt>, <tt>2</tt></td>
  <td class="nd_default"><tt>0</tt></td>
</tr>

<tr class="node_desc_oddrow">
  <td class="nd_class" rowspan="4"><tt>Imaginary</tt></td>
  <td class="nd_field"><tt>const?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
  <td class="nd_comments" rowspan="4">
    <p>This is the rarely seen <tt>_Imaginary</tt> type.</p>
    <ul>
      <li><tt>#plain?</tt> -- return true iff <tt>longness == 0</tt></li>
      <li><tt>#double?</tt> -- return true iff <tt>longness == 1</tt></li>
      <li><tt>#long_double?</tt> -- return true iff <tt>longness == 2</tt></li>
    </ul>
  </td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>restrict?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>volatile?</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>true</tt>, <tt>false</tt></td>
  <td class="nd_default"></td>
</tr>
<tr class="node_desc_oddrow">
  <td class="nd_field"><tt>longness</tt></td>
  <td class="nd_child"></td>
  <td class="nd_values"><tt>0</tt>, <tt>1</tt>, <tt>2</tt></td>
  <td class="nd_default"><tt>0</tt></td>
</tr>
<tr class="node_desc_evenrow">
  <td class="nd_class" rowspan="1"><tt>BlockExpression</tt></td>
  <td class="nd_field"><tt>block</tt></td>
  <td class="nd_child">Y</td>
  <td class="nd_values"><tt>Block</tt></td>
  <td class="nd_default"><tt>Block.new</tt></td>
  <td class="nd_comments" rowspan="1">
    Only if the <tt>block_expressions</tt> extension is enabled.
    See "Extensions" section below.
  </td>
</tr>

</tbody> </table>

Node Construction

Wanna make a Node? Take your pick:

  • #new(field1, field2, ...) – fields are in the order listed above.

  • #new(:field1 => val, :field2 => val, ...) – field order doesn't matter this way.

  • #new_at(pos, *args) – set the pos to that given, and pass args to #new.

They're for losers, though. What you really want to do is make Nodes by parsing C code. Each class – even the abstract classes like Statement – has a .parse method:

function_def = C::FunctionDef.parse <<EOS
  void frobnicate(int karma) {
    use_waffle_iron();
  }
stmt = C::Statement.parse('while (not_looking) paint_car();')

Need to tell it to treat WaffleIron as a type name? All those parse methods use C.default_parser:

C.default_parser.type_names << 'WaffleIron'
type = C::Type.parse('WaffleIron')

Alternatively, you could've given parse your own parser:

parser = C::Parser.new
parser.type_names << 'WaffleIron'
type = C::Type.parse('WaffleIron', parser)

In fact, there's also C.parse(str, parser=nil), which is an alias for C::TranslationUnit.parse(str, parser).

ast = C.parse(STDIN)

Yes, all that talk in the intro about doing parser = C::Parser.new; parser.parse(...) was actually all a charade to make you type more. I so own you.

Extensions

CAST has developed extensions! To the C99 grammar, I mean.

  • Types are allowed as function arguments. This lets you parse macros like va_arg().

  • Blocks in parentheses are allowed as expressions ((a gcc extension)). You need to call #enable_block_expressions on the parser first. They pop out as BlockExpression nodes.

    C.default_parser.enable_block_expressions
    node = C.parse 'char *brag(void) { return ({"I\'m tricky!";}); }'
    node.entities[0].def.stmts.last.expr.class  # => C::BlockExpression

Open Issues

  • Is it okay to bastardize the =~ operator like that?

  • Should binary operators have a list of expressions rather than just 2? That'd allow to_s to format the strings better in some cases and make it consistent with Comma.

  • At the moment CAST chokes on preprocessor #-lines. Ruby makes it trivial to filter these out before passing the string to Parser#parse, and this makes it obvious when you forget to run a file through the preprocessor (which you need to do to get type names at least once). Is this stupid? Ideally we should probably have a builtin preprocessor and use that.

Vote now

To Do

  • Stop embarrasing yourself and write the parser in C.

  • Make it -wd friendly.

  • Fix the “TODO” bits in c.y. These are for rarely used C constructs, like the declaration int arr[*];.

  • Add a comment node. Might make it useful for doc extraction. Anyone want this? Not all comments will be caught, though. Comments can appear between any two tokens, and I don't really want to add comment fields to every node. They'd probably just appear between toplevel entities (in TranslationUnit#entities) and between statements (in Block#stmts).

  • Make it rdoc-able.

If any of these affect you greatly, kick me to make it happen faster.

Contact

I'm not really sure what people are going to try to use this for. If there's some functionality you think would make a good addition, or think I've made a mess of this poor puppy, give me a yell.

You can spam me at george.ogata@gmail.com. It'd help if you prefixed the subject with “[cast] ” so I can easily distinguish CAST spam from fake Rolex spam.

License

Ruby License

Something went wrong with that request. Please try again.