cast 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +6 -0
- data/doc/index.html +2513 -0
- data/install.rb +14 -0
- data/lib/c.tab.rb +3433 -0
- data/lib/c.y +935 -0
- data/lib/c_nodes.rb +1301 -0
- data/lib/cast.rb +9 -0
- data/lib/node.rb +744 -0
- data/lib/node_list.rb +842 -0
- data/lib/parse.rb +233 -0
- data/lib/to_debug.rb +59 -0
- data/lib/to_s.rb +538 -0
- data/test/common.rb +174 -0
- data/test/run.rb +5 -0
- data/test/test_c_nodes.rb +160 -0
- data/test/test_node.rb +1224 -0
- data/test/test_node_list.rb +2485 -0
- data/test/test_parse.rb +2014 -0
- data/test/test_parser.rb +2925 -0
- metadata +56 -0
data/lib/parse.rb
ADDED
@@ -0,0 +1,233 @@
|
|
1
|
+
###
|
2
|
+
### ##################################################################
|
3
|
+
###
|
4
|
+
### C.default_parser and the parse_* methods.
|
5
|
+
###
|
6
|
+
### Yeah, this could be so much faster.
|
7
|
+
###
|
8
|
+
### ##################################################################
|
9
|
+
###
|
10
|
+
|
11
|
+
module C
|
12
|
+
@@default_parser = Parser.new
|
13
|
+
def self.default_parser
|
14
|
+
@@default_parser
|
15
|
+
end
|
16
|
+
def self.default_parser= val
|
17
|
+
@@default_parser = val
|
18
|
+
end
|
19
|
+
|
20
|
+
class Node
|
21
|
+
###
|
22
|
+
### Return true if `str' is parsed to something `==' to this Node.
|
23
|
+
### str is first converted to a String using #to_s, then given to
|
24
|
+
### self.class.parse (along with the optional `parser').
|
25
|
+
###
|
26
|
+
def match? str, parser=nil
|
27
|
+
node = self.class.parse(str.to_s, parser) rescue (return false)
|
28
|
+
self == node
|
29
|
+
end
|
30
|
+
###
|
31
|
+
### Same as #match?.
|
32
|
+
###
|
33
|
+
def =~ *args
|
34
|
+
match? *args
|
35
|
+
end
|
36
|
+
private
|
37
|
+
end
|
38
|
+
class NodeList
|
39
|
+
###
|
40
|
+
### As defined in Node.
|
41
|
+
###
|
42
|
+
def match? arr, parser=nil
|
43
|
+
arr = arr.to_a
|
44
|
+
return false if arr.length != self.length
|
45
|
+
each_with_index do |node, i|
|
46
|
+
node.match?(arr[i], parser) or return false
|
47
|
+
end
|
48
|
+
return true
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.parse s, parser=nil
|
53
|
+
TranslationUnit.parse(s, parser)
|
54
|
+
end
|
55
|
+
|
56
|
+
class TranslationUnit
|
57
|
+
def self.parse s, parser=nil
|
58
|
+
parser ||= C.default_parser
|
59
|
+
parser.parse(s)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class Declaration
|
64
|
+
def self.parse s, parser=nil
|
65
|
+
parser ||= C.default_parser
|
66
|
+
ents = parser.parse(s).entities
|
67
|
+
if ents.length == 1 && # int i; int j;
|
68
|
+
ents[0].is_a?(Declaration) # void f() {}
|
69
|
+
return ents[0].detach
|
70
|
+
else
|
71
|
+
raise ParseError, "invalid Declaration"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class Parameter
|
77
|
+
def self.parse s, parser=nil
|
78
|
+
parser ||= C.default_parser
|
79
|
+
ents = parser.parse("void f(#{s}) {}").entities
|
80
|
+
if ents.length == 1 && # ) {} void (
|
81
|
+
ents[0].is_a?(FunctionDef) && # ); void(
|
82
|
+
ents[0].type.params && #
|
83
|
+
ents[0].type.params.length <= 1 # x,y
|
84
|
+
param = ents[0].type.params[0]
|
85
|
+
if param.nil?
|
86
|
+
return Parameter.new(Void.new)
|
87
|
+
else
|
88
|
+
return param.detach
|
89
|
+
end
|
90
|
+
else
|
91
|
+
raise ParseError, "invalid Parameter"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
class Declarator
|
97
|
+
def self.parse s, parser=nil
|
98
|
+
parser ||= C.default_parser
|
99
|
+
ents = parser.parse("int #{s};").entities
|
100
|
+
if ents.length == 1 && # f; int f;
|
101
|
+
ents[0].declarators.length == 1 # i,j
|
102
|
+
return ents[0].declarators[0].detach
|
103
|
+
else
|
104
|
+
raise ParseError, "invalid Declarator"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
class FunctionDef
|
110
|
+
def self.parse s, parser=nil
|
111
|
+
parser ||= C.default_parser
|
112
|
+
ents = parser.parse(s).entities
|
113
|
+
if ents.length == 1 && # void f(); void g();
|
114
|
+
ents[0].is_a?(FunctionDef) # int i;
|
115
|
+
return ents[0].detach
|
116
|
+
else
|
117
|
+
raise ParseError, "invalid FunctionDef"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
class Enumerator
|
123
|
+
def self.parse s, parser=nil
|
124
|
+
parser ||= C.default_parser
|
125
|
+
ents = parser.parse("enum {#{s}};").entities
|
126
|
+
if ents.length == 1 && # } enum {
|
127
|
+
ents[0].is_a?(Declaration) && # } f() {
|
128
|
+
ents[0].type.members.length == 1 # X, Y
|
129
|
+
return ents[0].type.members[0].detach
|
130
|
+
else
|
131
|
+
raise ParseError, "invalid Enumerator"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
class MemberInit
|
137
|
+
def self.parse s, parser=nil
|
138
|
+
parser ||= C.default_parser
|
139
|
+
ents = parser.parse("int f() {struct s x = {#{s}};}").entities
|
140
|
+
if ents.length == 1 && # } int f() {
|
141
|
+
ents[0].def.stmts.length == 1 && # }} f() {{
|
142
|
+
ents[0].def.stmts[0].declarators.length == 1 && # 1}, y
|
143
|
+
ents[0].def.stmts[0].declarators[0].init.member_inits.length == 1 # 1, 2
|
144
|
+
return ents[0].def.stmts[0].declarators[0].init.member_inits[0].detach
|
145
|
+
else
|
146
|
+
raise ParseError, "invalid MemberInit"
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
class Member
|
152
|
+
def self.parse s, parser=nil
|
153
|
+
parser ||= C.default_parser
|
154
|
+
ents = parser.parse("int f() {struct s x = {#{s} = 1;};}").entities
|
155
|
+
if ents.length == 1 && # };} int f() {struct s x = {a
|
156
|
+
ents[0].def.stmts.length == 1 && # }; x
|
157
|
+
#ents[0].def.stmts[0].length == 1 && # 1}, x = {.a
|
158
|
+
ents[0].def.stmts[0].declarators.length == 1 && # 1}, x = {.a
|
159
|
+
ents[0].def.stmts[0].declarators[0].init.member_inits.length == 1 && # x = 1, y
|
160
|
+
ents[0].def.stmts[0].declarators[0].init.member_inits[0].member.length == 1 && # .a .b
|
161
|
+
ents[0].def.stmts[0].declarators[0].init.member_inits[0].member[0].is_a?(C::Member) # [0]
|
162
|
+
return ents[0].def.stmts[0].declarators[0].init.member_inits[0].member[0].detach
|
163
|
+
else
|
164
|
+
raise ParseError, "invalid Member"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
class Statement
|
170
|
+
def self.parse s, parser=nil
|
171
|
+
parser ||= C.default_parser
|
172
|
+
ents = parser.parse("void f() {#{s}}").entities
|
173
|
+
if ents.length == 1 && # } void f() {
|
174
|
+
ents[0].def.stmts.length == 1 && # ;;
|
175
|
+
ents[0].def.stmts[0].is_a?(self) # int i;
|
176
|
+
return ents[0].def.stmts[0].detach
|
177
|
+
else
|
178
|
+
raise ParseError, "invalid #{self}"
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
class Label
|
184
|
+
def self.parse s, parser=nil
|
185
|
+
parser ||= C.default_parser
|
186
|
+
ents = parser.parse("void f() {switch (0) #{s};}").entities
|
187
|
+
if ents.length == 1 && # } void f() {
|
188
|
+
ents[0].def.stmts.length == 1 && # ;
|
189
|
+
ents[0].def.stmts[0].stmt && #
|
190
|
+
ents[0].def.stmts[0].stmt.labels.length == 1 && # x
|
191
|
+
ents[0].def.stmts[0].stmt.labels[0].is_a?(self)
|
192
|
+
return ents[0].def.stmts[0].stmt.labels[0].detach
|
193
|
+
else
|
194
|
+
raise ParseError, "invalid #{self}"
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
class Expression
|
200
|
+
def self.parse s, parser=nil
|
201
|
+
parser ||= C.default_parser
|
202
|
+
ents = parser.parse("void f() {#{s};}").entities
|
203
|
+
if ents.length == 1 && # } void f() {
|
204
|
+
ents[0].def.stmts.length == 1 && # ;
|
205
|
+
ents[0].def.stmts[0].is_a?(ExpressionStatement) && # int i
|
206
|
+
ents[0].def.stmts[0].expr.is_a?(self)
|
207
|
+
return ents[0].def.stmts[0].expr.detach
|
208
|
+
else
|
209
|
+
raise ParseError, "invalid #{self}"
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
class Type
|
215
|
+
def self.parse s, parser=nil
|
216
|
+
parser ||= C.default_parser
|
217
|
+
ents = parser.parse("void f() {(#{s})x;}").entities
|
218
|
+
if ents.length == 1 && # 1);} void f() {(int
|
219
|
+
ents[0].def.stmts.length == 1 && # 1); (int
|
220
|
+
ents[0].def.stmts[0].expr.type.is_a?(self)
|
221
|
+
return ents[0].def.stmts[0].expr.type.detach
|
222
|
+
else
|
223
|
+
raise ParseError, "invalid #{self}"
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
#### Make sure we didn't miss any
|
229
|
+
CORE_C_NODE_CLASSES.each do |c|
|
230
|
+
c.methods.include? 'parse' or
|
231
|
+
raise "#{c}#parse not defined"
|
232
|
+
end
|
233
|
+
end
|
data/lib/to_debug.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
###
|
2
|
+
### ##################################################################
|
3
|
+
###
|
4
|
+
### Node#to_debug.
|
5
|
+
###
|
6
|
+
### ##################################################################
|
7
|
+
###
|
8
|
+
|
9
|
+
module C
|
10
|
+
class Node
|
11
|
+
TO_DEBUG_TAB = ' '
|
12
|
+
def to_debug
|
13
|
+
return Node.to_debug1(self)
|
14
|
+
end
|
15
|
+
|
16
|
+
def Node.to_debug1 x, prefix='', indent=0, is_child=true
|
17
|
+
case x
|
18
|
+
when NodeList
|
19
|
+
if x.empty?
|
20
|
+
return "#{TO_DEBUG_TAB*indent}#{prefix}[]\n"
|
21
|
+
else
|
22
|
+
str = "#{TO_DEBUG_TAB*indent}#{prefix}\n"
|
23
|
+
x.each do |el|
|
24
|
+
str << to_debug1(el, "- ", indent+1)
|
25
|
+
end
|
26
|
+
return str
|
27
|
+
end
|
28
|
+
when Node
|
29
|
+
classname = x.class.name.gsub(/^C::/, '')
|
30
|
+
str = "#{TO_DEBUG_TAB*indent}#{prefix}#{classname}"
|
31
|
+
|
32
|
+
fields = x.fields
|
33
|
+
bools, others = fields.partition{|field| field.reader.to_s[-1] == ??}
|
34
|
+
bools.delete_if{|field| !x.send(field.reader)}
|
35
|
+
bools.map!{|field| field.init_key}
|
36
|
+
|
37
|
+
unless bools == []
|
38
|
+
str << " (#{bools.join(' ')})"
|
39
|
+
end
|
40
|
+
str << "\n"
|
41
|
+
|
42
|
+
others.each do |field|
|
43
|
+
val = x.send(field.reader)
|
44
|
+
next if val == field.make_default ||
|
45
|
+
## don't bother with non-child Nodes, since they may cause
|
46
|
+
## loops in the tree
|
47
|
+
(val.is_a?(Node) && !field.child?)
|
48
|
+
str << to_debug1(val, "#{field.reader}: ", indent+1, field.child?)
|
49
|
+
end
|
50
|
+
return str
|
51
|
+
when Symbol
|
52
|
+
return "#{TO_DEBUG_TAB*indent}#{prefix}#{x}\n"
|
53
|
+
else
|
54
|
+
return "#{TO_DEBUG_TAB*indent}#{prefix}#{x.inspect}\n"
|
55
|
+
end
|
56
|
+
return s.string
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/lib/to_s.rb
ADDED
@@ -0,0 +1,538 @@
|
|
1
|
+
###
|
2
|
+
### ##################################################################
|
3
|
+
###
|
4
|
+
### The Node#to_s methods.
|
5
|
+
###
|
6
|
+
### Yeah, this could be so so *SO* much faster.
|
7
|
+
###
|
8
|
+
### ##################################################################
|
9
|
+
###
|
10
|
+
|
11
|
+
module C
|
12
|
+
## undef the #to_s methods so we can check that we didn't forget to
|
13
|
+
## define any
|
14
|
+
Node.send(:undef_method, :to_s)
|
15
|
+
|
16
|
+
INDENT = ' '
|
17
|
+
class Node
|
18
|
+
private
|
19
|
+
def indent s, levels=1
|
20
|
+
s.gsub(/^/, INDENT*levels)
|
21
|
+
end
|
22
|
+
def hang stmt, cont=false
|
23
|
+
if stmt.is_a? Block
|
24
|
+
return " #{stmt.to_s(:hanging)}" << (cont ? ' ' : '')
|
25
|
+
else
|
26
|
+
return "\n#{stmt.to_s}" << (cont ? "\n" : '')
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class TranslationUnit
|
32
|
+
def to_s
|
33
|
+
entities.map{|n| n.to_s}.join("\n\n")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
class Declaration
|
37
|
+
def to_s
|
38
|
+
str = ''
|
39
|
+
inline? and str << "inline "
|
40
|
+
storage and str << "#{storage} "
|
41
|
+
if declarators.empty?
|
42
|
+
return str << "#{type};"
|
43
|
+
else
|
44
|
+
return str << "#{type} " << declarators.join(', ') << ';'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
class Declarator
|
49
|
+
def to_s
|
50
|
+
(indirect_type ? indirect_type.to_s(name) : name.dup) <<
|
51
|
+
(init ? " = #{init}" : '') <<
|
52
|
+
(num_bits ? " : #{num_bits}" : '')
|
53
|
+
end
|
54
|
+
end
|
55
|
+
class FunctionDef
|
56
|
+
def to_s
|
57
|
+
str = ''
|
58
|
+
static? and str << 'static '
|
59
|
+
inline? and str << 'inline '
|
60
|
+
if no_prototype?
|
61
|
+
str << "#{type.to_s(name)}\n"
|
62
|
+
type.params.each do |p|
|
63
|
+
str << indent("#{p.to_s};\n")
|
64
|
+
end
|
65
|
+
str << "#{self.def.to_s(:hanging)}"
|
66
|
+
else
|
67
|
+
str << "#{type.to_s(name)}#{hang(self.def)}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
### Statements
|
73
|
+
class Statement
|
74
|
+
def label str
|
75
|
+
labels.map{|s| "#{s}:\n"}.join + indent(str)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
class Block
|
79
|
+
def to_s hanging=false
|
80
|
+
str = stmts.map do |s|
|
81
|
+
if s.is_a? Statement
|
82
|
+
s.to_s
|
83
|
+
else
|
84
|
+
indent(s.to_s)
|
85
|
+
end
|
86
|
+
end.join("\n")
|
87
|
+
str << "\n" unless str == ''
|
88
|
+
str = "{\n" << str << "}"
|
89
|
+
if hanging
|
90
|
+
if labels.empty?
|
91
|
+
return str
|
92
|
+
else
|
93
|
+
return "\n" << label(str)
|
94
|
+
end
|
95
|
+
else
|
96
|
+
return label(str)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
class If
|
101
|
+
def to_s
|
102
|
+
str = "if (#{cond})"
|
103
|
+
if self.else.nil?
|
104
|
+
str << hang(self.then)
|
105
|
+
else
|
106
|
+
str << hang(self.then, :cont) << 'else' << hang(self.else)
|
107
|
+
end
|
108
|
+
return label(str)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
class Switch
|
112
|
+
def to_s
|
113
|
+
label("switch (#{cond})" << hang(stmt))
|
114
|
+
end
|
115
|
+
end
|
116
|
+
class While
|
117
|
+
def to_s
|
118
|
+
if do?
|
119
|
+
label('do' << hang(stmt, :cont) << "while (#{cond});")
|
120
|
+
else
|
121
|
+
label("while (#{cond})" << hang(stmt))
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
class For
|
126
|
+
def to_s
|
127
|
+
initstr =
|
128
|
+
case init
|
129
|
+
when nil
|
130
|
+
';'
|
131
|
+
when Declaration
|
132
|
+
"#{init}"
|
133
|
+
else
|
134
|
+
"#{init};"
|
135
|
+
end
|
136
|
+
condstr = cond ? " #{cond};" : ';'
|
137
|
+
iterstr = iter ? " #{iter}" : ''
|
138
|
+
label("for (#{initstr}#{condstr}#{iterstr})" << hang(stmt))
|
139
|
+
end
|
140
|
+
end
|
141
|
+
class Goto
|
142
|
+
def to_s
|
143
|
+
label("goto #{target};")
|
144
|
+
end
|
145
|
+
end
|
146
|
+
class Continue
|
147
|
+
def to_s
|
148
|
+
label("continue;")
|
149
|
+
end
|
150
|
+
end
|
151
|
+
class Break
|
152
|
+
def to_s
|
153
|
+
label("break;")
|
154
|
+
end
|
155
|
+
end
|
156
|
+
class Return
|
157
|
+
def to_s
|
158
|
+
label("return#{expr ? ' '+expr.to_s : ''};")
|
159
|
+
end
|
160
|
+
end
|
161
|
+
class ExpressionStatement
|
162
|
+
def to_s
|
163
|
+
label("#{expr};")
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
class PlainLabel
|
168
|
+
def to_s
|
169
|
+
name.to_s
|
170
|
+
end
|
171
|
+
end
|
172
|
+
class Default
|
173
|
+
def to_s
|
174
|
+
'default'
|
175
|
+
end
|
176
|
+
end
|
177
|
+
class Case
|
178
|
+
def to_s
|
179
|
+
"case #{expr}"
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
### Expressions
|
184
|
+
precedence_table = {}
|
185
|
+
[[Comma],
|
186
|
+
[Assign, MultiplyAssign, DivideAssign, ModAssign, AddAssign,
|
187
|
+
SubtractAssign, ShiftLeftAssign, ShiftRightAssign, BitAndAssign,
|
188
|
+
BitXorAssign, BitOrAssign],
|
189
|
+
[Conditional],
|
190
|
+
[Or],
|
191
|
+
[And],
|
192
|
+
[BitOr],
|
193
|
+
[BitXor],
|
194
|
+
[BitAnd],
|
195
|
+
[Equal, NotEqual],
|
196
|
+
[Less, More, LessOrEqual, MoreOrEqual],
|
197
|
+
[ShiftLeft, ShiftRight],
|
198
|
+
[Add, Subtract],
|
199
|
+
[Multiply, Divide, Mod],
|
200
|
+
[PreInc, PreDec, Sizeof, Cast, Address, Dereference, Positive, Negative,
|
201
|
+
BitNot, Not],
|
202
|
+
[Index, Call, Arrow, Dot, PostInc, PostDec],
|
203
|
+
[Literal, Variable]
|
204
|
+
].each_with_index do |klasses, prec|
|
205
|
+
klasses.each do |klass|
|
206
|
+
klass.send(:define_method, :to_s_precedence){|| prec}
|
207
|
+
end
|
208
|
+
end
|
209
|
+
## check all Expression classes have a precedence
|
210
|
+
C::Expression.subclasses_recursive do |c|
|
211
|
+
next if !C::Node.subclasses_recursive.include? c
|
212
|
+
c.instance_methods.include? 'to_s_precedence' or
|
213
|
+
raise "#{c}#to_s_precedence not defined"
|
214
|
+
end
|
215
|
+
|
216
|
+
## PrefixExpressions
|
217
|
+
[ [Cast , lambda{"(#{self.type})"}],
|
218
|
+
[Address , lambda{"&" }],
|
219
|
+
[Dereference, lambda{"*" }],
|
220
|
+
[Positive , lambda{"+" }],
|
221
|
+
[Negative , lambda{"-" }],
|
222
|
+
[PreInc , lambda{"++" }],
|
223
|
+
[PreDec , lambda{"--" }],
|
224
|
+
[BitNot , lambda{"~" }],
|
225
|
+
[Not , lambda{"!" }]
|
226
|
+
].each do |c, proc|
|
227
|
+
c.send(:define_method, :to_s) do | |
|
228
|
+
if expr.to_s_precedence < self.to_s_precedence
|
229
|
+
return "#{instance_eval(&proc)}(#{expr})"
|
230
|
+
else
|
231
|
+
return "#{instance_eval(&proc)}#{expr}"
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
## PostfixExpressions
|
236
|
+
[ [Arrow , lambda{"->#{member}"}],
|
237
|
+
[Dot , lambda{".#{member}" }],
|
238
|
+
[Index , lambda{"[#{index}]" }],
|
239
|
+
[PostInc , lambda{"++" }],
|
240
|
+
[PostDec , lambda{"--" }]
|
241
|
+
].each do |c, proc|
|
242
|
+
c.send(:define_method, :to_s) do | |
|
243
|
+
if expr.to_s_precedence < self.to_s_precedence
|
244
|
+
return "(#{expr})#{instance_eval(&proc)}"
|
245
|
+
else
|
246
|
+
return "#{expr}#{instance_eval(&proc)}"
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
## BinaryExpressions
|
251
|
+
[ [Add , '+' ],
|
252
|
+
[Subtract , '-' ],
|
253
|
+
[Multiply , '*' ],
|
254
|
+
[Divide , '/' ],
|
255
|
+
[Mod , '%' ],
|
256
|
+
[Equal , '=='],
|
257
|
+
[NotEqual , '!='],
|
258
|
+
[Less , '<' ],
|
259
|
+
[More , '>' ],
|
260
|
+
[LessOrEqual, '<='],
|
261
|
+
[MoreOrEqual, '>='],
|
262
|
+
[BitAnd , '&' ],
|
263
|
+
[BitOr , '|' ],
|
264
|
+
[BitXor , '^' ],
|
265
|
+
[ShiftLeft , '<<'],
|
266
|
+
[ShiftRight , '>>'],
|
267
|
+
[And , '&&'],
|
268
|
+
[Or , '||'],
|
269
|
+
].each do |c, op|
|
270
|
+
c.send(:define_method, :to_s) do | |
|
271
|
+
if expr1.to_s_precedence < self.to_s_precedence
|
272
|
+
str1 = "(#{expr1})"
|
273
|
+
else
|
274
|
+
str1 = "#{expr1}"
|
275
|
+
end
|
276
|
+
## all binary expressions are left associative
|
277
|
+
if expr2.to_s_precedence <= self.to_s_precedence
|
278
|
+
str2 = "(#{expr2})"
|
279
|
+
else
|
280
|
+
str2 = "#{expr2}"
|
281
|
+
end
|
282
|
+
"#{str1} #{op} #{str2}"
|
283
|
+
end
|
284
|
+
end
|
285
|
+
## AssignmentExpressions
|
286
|
+
[ [Assign , '' ],
|
287
|
+
[MultiplyAssign , '*' ],
|
288
|
+
[DivideAssign , '/' ],
|
289
|
+
[ModAssign , '%' ],
|
290
|
+
[AddAssign , '+' ],
|
291
|
+
[SubtractAssign , '-' ],
|
292
|
+
[ShiftLeftAssign , '<<'],
|
293
|
+
[ShiftRightAssign, '>>'],
|
294
|
+
[BitAndAssign , '&' ],
|
295
|
+
[BitXorAssign , '^' ],
|
296
|
+
[BitOrAssign , '|' ]
|
297
|
+
].each do |c, op|
|
298
|
+
c.send(:define_method, :to_s) do | |
|
299
|
+
if rval.to_s_precedence < self.to_s_precedence
|
300
|
+
rvalstr = "(#{rval})"
|
301
|
+
else
|
302
|
+
rvalstr = "#{rval}"
|
303
|
+
end
|
304
|
+
"#{lval} #{op}= #{rvalstr}"
|
305
|
+
end
|
306
|
+
end
|
307
|
+
## Other Expressions
|
308
|
+
class Sizeof
|
309
|
+
def to_s
|
310
|
+
if expr.is_a? Expression
|
311
|
+
if expr.to_s_precedence < self.to_s_precedence
|
312
|
+
return "sizeof(#{expr})"
|
313
|
+
else
|
314
|
+
return "sizeof #{expr}"
|
315
|
+
end
|
316
|
+
else
|
317
|
+
return "sizeof(#{expr})"
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
## DirectTypes
|
322
|
+
int_longnesses = ['short ', '', 'long ', 'long long ']
|
323
|
+
float_longnesses = ['float', 'double', 'long double']
|
324
|
+
[ [Struct, lambda do
|
325
|
+
str = 'struct'
|
326
|
+
name and str << " #{name}"
|
327
|
+
members and str << " {\n" << indent(members.join("\n")) << "\n}"
|
328
|
+
str
|
329
|
+
end],
|
330
|
+
[Union, lambda do
|
331
|
+
str = 'union'
|
332
|
+
name and str << " #{name}"
|
333
|
+
members and str << " {\n" << indent(members.join("\n")) << "\n}"
|
334
|
+
str
|
335
|
+
end],
|
336
|
+
[Enum, lambda do
|
337
|
+
str = 'enum'
|
338
|
+
name and str << " #{name}"
|
339
|
+
members and str << " {\n" << indent(members.join(",\n")) << "\n}"
|
340
|
+
str
|
341
|
+
end],
|
342
|
+
[CustomType, lambda{name.dup }],
|
343
|
+
[Void , lambda{'void' }],
|
344
|
+
[Int , lambda do
|
345
|
+
longness_str = int_longnesses[longness+1].dup
|
346
|
+
"#{unsigned? ? 'unsigned ' : ''}#{longness_str}int"
|
347
|
+
end],
|
348
|
+
[Float , lambda{float_longnesses[longness].dup}],
|
349
|
+
[Char , lambda{"#{unsigned? ? 'unsigned ' : ''}char"}],
|
350
|
+
[Bool , lambda{'_Bool' }],
|
351
|
+
[Complex , lambda{'_Complex' }],
|
352
|
+
[Imaginary , lambda{'_Imaginary'}]
|
353
|
+
].each do |c, x|
|
354
|
+
c.send(:define_method, :to_s) do |*args|
|
355
|
+
case args.length
|
356
|
+
when 0
|
357
|
+
namestr = nil
|
358
|
+
when 1
|
359
|
+
namestr = args[0]
|
360
|
+
namestr = nil if namestr == ''
|
361
|
+
else
|
362
|
+
raise ArgumentError, "wrong number of args (#{args.length} for 1)"
|
363
|
+
end
|
364
|
+
str = ''
|
365
|
+
const? and str << 'const '
|
366
|
+
restrict? and str << 'restrict '
|
367
|
+
volatile? and str << 'volatile '
|
368
|
+
str << instance_eval(&x) << (namestr ? " #{namestr}" : '')
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
class Enumerator
|
373
|
+
def to_s
|
374
|
+
if val
|
375
|
+
"#{name} = #{val}"
|
376
|
+
else
|
377
|
+
"#{name}"
|
378
|
+
end
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
class Comma
|
383
|
+
def to_s
|
384
|
+
exprs.join(', ')
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
class Conditional
|
389
|
+
def to_s
|
390
|
+
strs = [:cond, :then, :else].map do |child|
|
391
|
+
val = send(child)
|
392
|
+
if val.to_s_precedence < self.to_s_precedence
|
393
|
+
"(#{val})"
|
394
|
+
else
|
395
|
+
"#{val}"
|
396
|
+
end
|
397
|
+
end
|
398
|
+
"#{strs[0]} ? #{strs[1]} : #{strs[2]}"
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
402
|
+
class Call
|
403
|
+
def to_s
|
404
|
+
argstrs = args.map do |arg|
|
405
|
+
if arg.is_a? Comma
|
406
|
+
"(#{arg})"
|
407
|
+
else
|
408
|
+
"#{arg}"
|
409
|
+
end
|
410
|
+
end
|
411
|
+
if expr.to_s_precedence < self.to_s_precedence
|
412
|
+
exprstr = "(#{expr})"
|
413
|
+
else
|
414
|
+
exprstr = "#{expr}"
|
415
|
+
end
|
416
|
+
"#{exprstr}(#{argstrs.join(', ')})"
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
### IndirectTypes
|
421
|
+
class Pointer
|
422
|
+
def to_s name=nil
|
423
|
+
str = '*'
|
424
|
+
const? and str << 'const '
|
425
|
+
restrict? and str << 'restrict '
|
426
|
+
volatile? and str << 'volatile '
|
427
|
+
str =
|
428
|
+
case type
|
429
|
+
when Function, Array
|
430
|
+
"(#{str}#{name})"
|
431
|
+
else
|
432
|
+
"#{str}#{name}"
|
433
|
+
end
|
434
|
+
if type
|
435
|
+
type.to_s(str)
|
436
|
+
else
|
437
|
+
str
|
438
|
+
end
|
439
|
+
end
|
440
|
+
end
|
441
|
+
class Array
|
442
|
+
def to_s name=nil
|
443
|
+
str = "#{name}[#{length}]"
|
444
|
+
if type
|
445
|
+
type.to_s(str)
|
446
|
+
else
|
447
|
+
str
|
448
|
+
end
|
449
|
+
end
|
450
|
+
end
|
451
|
+
class Function
|
452
|
+
def to_s name=nil
|
453
|
+
str =
|
454
|
+
if params.nil?
|
455
|
+
paramstr = ''
|
456
|
+
elsif params.empty?
|
457
|
+
paramstr = 'void'
|
458
|
+
else
|
459
|
+
paramstr = params.join(', ')
|
460
|
+
end
|
461
|
+
var_args? and paramstr << ', ...'
|
462
|
+
str = "#{name}(#{paramstr})"
|
463
|
+
if type
|
464
|
+
type.to_s(str)
|
465
|
+
else
|
466
|
+
str
|
467
|
+
end
|
468
|
+
end
|
469
|
+
end
|
470
|
+
class Parameter
|
471
|
+
def to_s
|
472
|
+
str = register? ? 'register ' : ''
|
473
|
+
str << type.to_s(name)
|
474
|
+
end
|
475
|
+
end
|
476
|
+
|
477
|
+
### Literals
|
478
|
+
class StringLiteral
|
479
|
+
def to_s
|
480
|
+
"\"#{val}\""
|
481
|
+
end
|
482
|
+
end
|
483
|
+
class CharLiteral
|
484
|
+
def to_s
|
485
|
+
"'#{val}'"
|
486
|
+
end
|
487
|
+
end
|
488
|
+
class CompoundLiteral
|
489
|
+
def to_s
|
490
|
+
str = ''
|
491
|
+
type and
|
492
|
+
str << "(#{type}) "
|
493
|
+
str << "{\n" << indent(inits.join(",\n")) << "\n}"
|
494
|
+
end
|
495
|
+
end
|
496
|
+
class MemberInit
|
497
|
+
def to_s
|
498
|
+
str = ''
|
499
|
+
if member
|
500
|
+
memberstr = member.map do |m|
|
501
|
+
if m.is_a? Expression
|
502
|
+
"[#{m}]"
|
503
|
+
else
|
504
|
+
".#{m}"
|
505
|
+
end
|
506
|
+
end
|
507
|
+
str << member.join(' ') << ' = '
|
508
|
+
end
|
509
|
+
return str << init.to_s
|
510
|
+
end
|
511
|
+
end
|
512
|
+
class Member
|
513
|
+
def to_s
|
514
|
+
name.dup
|
515
|
+
end
|
516
|
+
end
|
517
|
+
class IntLiteral
|
518
|
+
def to_s
|
519
|
+
val.to_s
|
520
|
+
end
|
521
|
+
end
|
522
|
+
class FloatLiteral
|
523
|
+
def to_s
|
524
|
+
val.to_s
|
525
|
+
end
|
526
|
+
end
|
527
|
+
class Variable
|
528
|
+
def to_s
|
529
|
+
name.dup
|
530
|
+
end
|
531
|
+
end
|
532
|
+
|
533
|
+
## check we didn't miss any
|
534
|
+
CORE_C_NODE_CLASSES.each do |c|
|
535
|
+
c.method_defined? :to_s or
|
536
|
+
raise "#{c}#to_s not defined"
|
537
|
+
end
|
538
|
+
end
|