# CASTY Casty is a fork of CAST, a C parser and abstract syntax tree for Ruby. ## Example require 'casty' source = File.read('file.c') ast = C.parse(source) ast.entities.each do |declaration| declaration.declarator.each do |declarator| puts "#{declarator.name}: declarator.type" end end Or in irb: irb> ast = C.parse('int main(void) { return 0; }') => TranslationUnit entities: - FunctionDef type: Function type: Int params: [] name: "main" def: Block stmts: - Return expr: IntLiteral val: 0 irb> puts ast int main(void) { return 0; } => nil ## Nodes `C.parse` returns a tree of `Node` objects. Here's the class hierarchy:
\# 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 endThe `=~` 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 The big table down below lists the *fields* of each `Node`. A field is an attribute which: * is used in equality checks (`==` and `eql?`). * are copied recursively by `dup` and `clone`. Fields listed as *children* form the tree structure. They only have a `Node` or `nil` value, and are yielded/returned/affected by the traversal methods: * `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 know. * `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)`). Note: don't modify the tree during traversal! Other notes about the table: * Field names that end in '?' are always true-or-false. * If no default is listed: * it is false if the field name ends in a '?' * it is a `NodeArray` if it is a `NodeList`. * it is `nil` otherwise.
Class | Field | Type / values | Default | Comments | ||||
---|---|---|---|---|---|---|---|---|
TranslationUnit | entities * | NodeList | NodeChain[] | The root of a parsed file. | ||||
Declaration | storage | :typedef, :extern, :static, :auto, :register |
Also:
|
|||||
type * | DirectType | |||||||
declarators * | NodeList | NodeArray[] | ||||||
inline? | true, false | |||||||
Declarator | indirect_type * | IndirectType |
What's a "declarator?" Consider "int i, *ip;". This is
a Declaration with two Declarators:
Declaration type: Int declarators: - Declarator name: "i" - Declarator indirect_type: Pointer name: "ip"The indirect_type of the ip Declarator is a Pointer to nil. To get the complete type of the variable use:
Pointer type: Int |
|||||
name | String | |||||||
init * | Expression | |||||||
num_bits * | Integer | |||||||
FunctionDef | storage | :extern, :static |
Also:
|
|||||
inline? | true, false | |||||||
type * | Type | |||||||
name | String | |||||||
def * | Block | Block.new | ||||||
no_prototype? | true, false | |||||||
Parameter | register? | true, false | Used in Functions. | |||||
type * | Type | |||||||
name | String | |||||||
Enumerator | name | String | Used in Enums. | |||||
val * | Expression | |||||||
MemberInit | member * | NodeList of (Member or Expression) | Used in CompoundLiterals. | |||||
init * | Expression | |||||||
Member | name | String | Used in MemberInits. | |||||
Block | labels * | NodeList of Label | NodeArray[] | |||||
stmts * | NodeList of (Statement or Declaration or Comment) | NodeArray[] | ||||||
If | labels * | NodeList of Label | NodeArray[] | |||||
cond * | Expression | |||||||
then * | Statement | |||||||
else * | Statement | |||||||
Switch | labels * | NodeList of Label | NodeArray[] | |||||
cond * | Expression | |||||||
stmt * | Statement | |||||||
While | labels * | NodeList of Label | NodeArray[] | do? means it's a do-while loop. | ||||
do? | true, false | |||||||
cond * | Expression | |||||||
stmt * | Statement | |||||||
For | labels * | NodeList of Label | NodeArray[] | |||||
init * | Expression or Declaration | |||||||
cond * | Expression | |||||||
iter * | Expression | |||||||
stmt * | Statement | |||||||
Goto | labels * | NodeList of Label | NodeArray[] | |||||
target | String | |||||||
Continue | labels * | NodeList of Label | NodeArray[] | |||||
Break | labels * | NodeList of Label | NodeArray[] | |||||
Return | labels * | NodeList of Label | NodeArray[] | |||||
expr * | Expression | |||||||
ExpressionStatement | labels * | NodeList of Label | NodeArray[] | |||||
expr * | Expression | |||||||
PlainLabel | name | String | ||||||
Default | ||||||||
Case | expr * | Expression | ||||||
Comma | exprs * | NodeList of Expression | ||||||
Conditional | cond * | Expression | ||||||
then * | Expression | |||||||
else * | Expression | |||||||
Variable | name | String | ||||||
Index | expr * | Expression | ||||||
index * | Expression | |||||||
Call | expr * | Expression | ||||||
args * | NodeList of (Expression or Type) | |||||||
Dot | expr * | Expression | ||||||
member * | String | |||||||
Arrow | expr * | Expression | ||||||
member * | String | |||||||
PostInc | expr * | Expression | ||||||
PostDec | expr * | Expression | ||||||
Cast | type * | Type | ||||||
expr * | Expression | |||||||
Address | expr * | Expression | ||||||
Dereference | expr * | Expression | ||||||
Sizeof | expr * | Type or Expression | ||||||
Positive | expr * | Expression | ||||||
Negative | expr * | Expression | ||||||
PreInc | expr * | Expression | ||||||
PreDec | expr * | Expression | ||||||
BitNot | expr * | Expression | ||||||
Not | expr * | Expression | ||||||
Add | expr1 * | Expression | ||||||
expr2 * | Expression | |||||||
Subtract | expr1 * | Expression | ||||||
expr2 * | Expression | |||||||
Multiply | expr1 * | Expression | ||||||
expr2 * | Expression | |||||||
Divide | expr1 * | Expression | ||||||
expr2 * | Expression | |||||||
Mod | expr1 * | Expression | ||||||
expr2 * | Expression | |||||||
Equal | expr1 * | Expression | ||||||
expr2 * | Expression | |||||||
NotEqual | expr1 * | Expression | ||||||
expr2 * | Expression | |||||||
Less | expr1 * | Expression | ||||||
expr2 * | Expression | |||||||
More | expr1 * | Expression | ||||||
expr2 * | Expression | |||||||
LessOrEqual | expr1 * | Expression | ||||||
expr2 * | Expression | |||||||
MoreOrEqual | expr1 * | Expression | ||||||
expr2 * | Expression | |||||||
BitAnd | expr1 * | Expression | ||||||
expr2 * | Expression | |||||||
BitOr | expr1 * | Expression | ||||||
expr2 * | Expression | |||||||
BitXor | expr1 * | Expression | ||||||
expr2 * | Expression | |||||||
ShiftLeft | expr1 * | Expression | ||||||
expr2 * | Expression | |||||||
ShiftRight | expr1 * | Expression | ||||||
expr2 * | Expression | |||||||
And | expr1 * | Expression | ||||||
expr2 * | Expression | |||||||
Or | expr1 * | Expression | ||||||
expr2 * | Expression | |||||||
Assign | lval * | Expression | ||||||
rval * | Expression | |||||||
MultiplyAssign | lval * | Expression | ||||||
rval * | Expression | |||||||
DivideAssign | lval * | Expression | ||||||
rval * | Expression | |||||||
ModAssign | lval * | Expression | ||||||
rval * | Expression | |||||||
AddAssign | lval * | Expression | ||||||
rval * | Expression | |||||||
SubtractAssign | lval * | Expression | ||||||
rval * | Expression | |||||||
ShiftLeftAssign | lval * | Expression | ||||||
rval * | Expression | |||||||
ShiftRightAssign | lval * | Expression | ||||||
rval * | Expression | |||||||
BitAndAssign | lval * | Expression | ||||||
rval * | Expression | |||||||
BitXorAssign | lval * | Expression | ||||||
rval * | Expression | |||||||
BitOrAssign | lval * | Expression | ||||||
rval * | Expression | |||||||
StringLiteral | val | String | The String in val is the literal string entered. "\n" isn't converted to a newline, for instance. | |||||
CharLiteral | val | String | The String in val is the literal string entered. '\n' isn't converted to a newline, for instance. | |||||
CompoundLiteral | type * | Type |
Here's an example: (struct S){1, .x = 2, .y [3] .z = 4} parses as: 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 |
|||||
member_inits * | NodeList of MemberInit | NodeArray[] | ||||||
IntLiteral | val | Integer |
Also:
|
|||||
format | :dec, :hex, :oct | :dec | ||||||
FloatLiteral | val | Float | ||||||
Pointer | const? | true, false | ||||||
restrict? | true, false | |||||||
volatile? | true, false | |||||||
type * | Type | |||||||
Array | const? | true, false | ||||||
restrict? | true, false | |||||||
volatile? | true, false | |||||||
type * | Type | |||||||
length * | Expression | |||||||
Function | const? | true, false | ||||||
restrict? | true, false | |||||||
volatile? | true, false | |||||||
type * | Type | |||||||
params * | NodeList of Parameter | NodeArray[] | ||||||
var_args? | true, false | |||||||
Struct | const? | true, false | ||||||
restrict? | true, false | |||||||
volatile? | true, false | |||||||
name | String | |||||||
members * | NodeList of Member | NodeArray[] | ||||||
Union | const? | true, false | ||||||
restrict? | true, false | |||||||
volatile? | true, false | |||||||
name | String | |||||||
members * | NodeList of Member | NodeArray[] | ||||||
Enum | const? | true, false | ||||||
restrict? | true, false | |||||||
volatile? | true, false | |||||||
name | String | |||||||
members * | NodeList of Enumerator | |||||||
CustomType | const? | true, false | For typedef'd names. | |||||
restrict? | true, false | |||||||
volatile? | true, false | |||||||
name | String | |||||||
Void | const? | true, false | const is for things like const void *. | |||||
restrict? | true, false | |||||||
volatile? | true, false | |||||||
Int | const? | true, false |
Also:
|
|||||
restrict? | true, false | |||||||
volatile? | true, false | |||||||
longness | -1, 0, 1, 2 | 0 | ||||||
unsigned? | true, false | |||||||
Float | const? | true, false |
Also:
|
|||||
restrict? | true, false | |||||||
volatile? | true, false | |||||||
longness | 0, 1, 2 | 0 | ||||||
Char | const? | true, false |
Also:
|
|||||
restrict? | true, false | |||||||
volatile? | true, false | |||||||
signed | true, false, nil | |||||||
Bool | const? | true, false | This is the rarely seen _Bool type. | |||||
restrict? | true, false | |||||||
volatile? | true, false | |||||||
Complex | const? | true, false |
This is the rarely seen _Complex type.
|
|||||
restrict? | true, false | |||||||
volatile? | true, false | |||||||
longness | 0, 1, 2 | 0 | ||||||
Imaginary | const? | true, false |
This is the rarely seen _Imaginary type.
|
|||||
restrict? | true, false | |||||||
volatile? | true, false | |||||||
longness | 0, 1, 2 | 0 | ||||||
BlockExpression | block * | Block | Block.new | Only if the block_expressions extension is enabled. See "Extensions" section below. |