cast 0.1.0 → 0.2.0
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/.gitignore +8 -0
- data/CHANGELOG +50 -0
- data/Gemfile +2 -0
- data/LICENSE +22 -0
- data/README.markdown +1948 -0
- data/Rakefile +22 -0
- data/cast.gemspec +20 -0
- data/ext/cast.c +6 -0
- data/ext/extconf.rb +1 -1
- data/ext/parser.c +2 -2
- data/ext/yylex.c +2592 -4171
- data/ext/yylex.re +20 -26
- data/lib/cast.rb +11 -16
- data/lib/cast/c.tab.rb +2252 -2231
- data/lib/cast/c.y +185 -161
- data/lib/cast/c_nodes.rb +181 -391
- data/lib/cast/inspect.rb +8 -10
- data/lib/cast/node.rb +362 -365
- data/lib/cast/node_list.rb +156 -165
- data/lib/cast/parse.rb +86 -65
- data/lib/cast/preprocessor.rb +72 -0
- data/lib/cast/tempfile.rb +33 -0
- data/lib/cast/to_s.rb +83 -75
- data/lib/cast/version.rb +11 -0
- data/test/all.rb +5 -0
- data/test/{test_c_nodes.rb → c_nodes_test.rb} +91 -23
- data/test/lexer_test.rb +323 -0
- data/test/{test_node_list.rb → node_list_test.rb} +367 -396
- data/test/{test_node.rb → node_test.rb} +142 -160
- data/test/{test_parse.rb → parse_test.rb} +63 -17
- data/test/{test_parser.rb → parser_test.rb} +62 -22
- data/test/preprocessor_test.rb +87 -0
- data/test/render_test.rb +2086 -0
- data/test/{run.rb → test_helper.rb} +76 -88
- metadata +100 -54
- data/README +0 -6
- data/doc/index.html +0 -2505
- data/ext/cast_ext.c +0 -10
data/lib/cast/parse.rb
CHANGED
@@ -1,45 +1,43 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
### ##################################################################
|
9
|
-
###
|
1
|
+
######################################################################
|
2
|
+
#
|
3
|
+
# C.default_parser and the parse_* methods.
|
4
|
+
#
|
5
|
+
# Yeah, this could be so much faster.
|
6
|
+
#
|
7
|
+
######################################################################
|
10
8
|
|
11
9
|
module C
|
12
10
|
@@default_parser = Parser.new
|
13
11
|
def self.default_parser
|
14
12
|
@@default_parser
|
15
13
|
end
|
16
|
-
def self.default_parser=
|
14
|
+
def self.default_parser=(val)
|
17
15
|
@@default_parser = val
|
18
16
|
end
|
19
17
|
|
20
18
|
class Node
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
def match?
|
19
|
+
#
|
20
|
+
# Return true if `str' is parsed to something `==' to this Node.
|
21
|
+
# str is first converted to a String using #to_s, then given to
|
22
|
+
# self.class.parse (along with the optional `parser').
|
23
|
+
#
|
24
|
+
def match?(str, parser=nil)
|
27
25
|
node = self.class.parse(str.to_s, parser) rescue (return false)
|
28
26
|
self == node
|
29
27
|
end
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
def =~
|
34
|
-
match?
|
28
|
+
#
|
29
|
+
# Same as #match?.
|
30
|
+
#
|
31
|
+
def =~(*args)
|
32
|
+
match?(*args)
|
35
33
|
end
|
36
34
|
private
|
37
35
|
end
|
38
36
|
class NodeList
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
def match?
|
37
|
+
#
|
38
|
+
# As defined in Node.
|
39
|
+
#
|
40
|
+
def match?(arr, parser=nil)
|
43
41
|
arr = arr.to_a
|
44
42
|
return false if arr.length != self.length
|
45
43
|
each_with_index do |node, i|
|
@@ -49,19 +47,19 @@ module C
|
|
49
47
|
end
|
50
48
|
end
|
51
49
|
|
52
|
-
def self.parse
|
50
|
+
def self.parse(s, parser=nil)
|
53
51
|
TranslationUnit.parse(s, parser)
|
54
52
|
end
|
55
53
|
|
56
54
|
class TranslationUnit
|
57
|
-
def self.parse
|
55
|
+
def self.parse(s, parser=nil)
|
58
56
|
parser ||= C.default_parser
|
59
57
|
parser.parse(s)
|
60
58
|
end
|
61
59
|
end
|
62
60
|
|
63
61
|
class Declaration
|
64
|
-
def self.parse
|
62
|
+
def self.parse(s, parser=nil)
|
65
63
|
parser ||= C.default_parser
|
66
64
|
ents = parser.parse(s).entities
|
67
65
|
if ents.length == 1 && # int i; int j;
|
@@ -74,7 +72,7 @@ module C
|
|
74
72
|
end
|
75
73
|
|
76
74
|
class Parameter
|
77
|
-
def self.parse
|
75
|
+
def self.parse(s, parser=nil)
|
78
76
|
parser ||= C.default_parser
|
79
77
|
ents = parser.parse("void f(#{s}) {}").entities
|
80
78
|
if ents.length == 1 && # ) {} void (
|
@@ -94,20 +92,29 @@ module C
|
|
94
92
|
end
|
95
93
|
|
96
94
|
class Declarator
|
97
|
-
def self.parse
|
95
|
+
def self.parse(s, parser=nil)
|
98
96
|
parser ||= C.default_parser
|
99
|
-
|
100
|
-
if
|
101
|
-
|
102
|
-
|
97
|
+
# if there's a ':', declare in a struct so we can populate num_bits
|
98
|
+
if s =~ /:/
|
99
|
+
ents = parser.parse("struct {int #{s};};").entities
|
100
|
+
if ents.length == 1 && # i:1;}; struct {int i
|
101
|
+
ents[0].type.members.length == 1 && # i:1; int j
|
102
|
+
ents[0].type.members[0].declarators.length == 1 # i:1,j
|
103
|
+
return ents[0].type.members[0].declarators[0].detach
|
104
|
+
end
|
103
105
|
else
|
104
|
-
|
106
|
+
ents = parser.parse("int #{s};").entities
|
107
|
+
if ents.length == 1 && # f; int f;
|
108
|
+
ents[0].declarators.length == 1 # i,j
|
109
|
+
return ents[0].declarators[0].detach
|
110
|
+
end
|
105
111
|
end
|
112
|
+
raise ParseError, "invalid Declarator"
|
106
113
|
end
|
107
114
|
end
|
108
115
|
|
109
116
|
class FunctionDef
|
110
|
-
def self.parse
|
117
|
+
def self.parse(s, parser=nil)
|
111
118
|
parser ||= C.default_parser
|
112
119
|
ents = parser.parse(s).entities
|
113
120
|
if ents.length == 1 && # void f(); void g();
|
@@ -120,7 +127,7 @@ module C
|
|
120
127
|
end
|
121
128
|
|
122
129
|
class Enumerator
|
123
|
-
def self.parse
|
130
|
+
def self.parse(s, parser=nil)
|
124
131
|
parser ||= C.default_parser
|
125
132
|
ents = parser.parse("enum {#{s}};").entities
|
126
133
|
if ents.length == 1 && # } enum {
|
@@ -134,7 +141,7 @@ module C
|
|
134
141
|
end
|
135
142
|
|
136
143
|
class MemberInit
|
137
|
-
def self.parse
|
144
|
+
def self.parse(s, parser=nil)
|
138
145
|
parser ||= C.default_parser
|
139
146
|
ents = parser.parse("int f() {struct s x = {#{s}};}").entities
|
140
147
|
if ents.length == 1 && # } int f() {
|
@@ -149,16 +156,16 @@ module C
|
|
149
156
|
end
|
150
157
|
|
151
158
|
class Member
|
152
|
-
def self.parse
|
159
|
+
def self.parse(s, parser=nil)
|
153
160
|
parser ||= C.default_parser
|
154
|
-
ents = parser.parse("int f() {struct s x = {
|
155
|
-
if ents.length == 1 && # };} int f() {struct s x = {a
|
156
|
-
ents[0].def.stmts.length == 1 && # };
|
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
|
160
|
-
ents[0].def.stmts[0].declarators[0].init.member_inits[0].member
|
161
|
-
ents[0].def.stmts[0].declarators[0].init.member_inits[0].member
|
161
|
+
ents = parser.parse("int f() {struct s x = {.#{s} = 1};}").entities
|
162
|
+
if ents.length == 1 && # a = 1};} int f() {struct s x = {a
|
163
|
+
ents[0].def.stmts.length == 1 && # a = 1}; struct s y = {.a
|
164
|
+
#ents[0].def.stmts[0].length == 1 && # a = 1}, x = {.a
|
165
|
+
ents[0].def.stmts[0].declarators.length == 1 && # a = 1}, x = {.a
|
166
|
+
ents[0].def.stmts[0].declarators[0].init.member_inits.length == 1 && # x = 1, y
|
167
|
+
ents[0].def.stmts[0].declarators[0].init.member_inits[0].member && # 1
|
168
|
+
ents[0].def.stmts[0].declarators[0].init.member_inits[0].member.length == 1 # a .b
|
162
169
|
return ents[0].def.stmts[0].declarators[0].init.member_inits[0].member[0].detach
|
163
170
|
else
|
164
171
|
raise ParseError, "invalid Member"
|
@@ -167,12 +174,12 @@ module C
|
|
167
174
|
end
|
168
175
|
|
169
176
|
class Statement
|
170
|
-
def self.parse
|
177
|
+
def self.parse(s, parser=nil)
|
171
178
|
parser ||= C.default_parser
|
172
179
|
ents = parser.parse("void f() {#{s}}").entities
|
173
|
-
if ents.length == 1
|
180
|
+
if ents.length == 1 && # } void f() {
|
174
181
|
ents[0].def.stmts.length == 1 && # ;;
|
175
|
-
ents[0].def.stmts[0].is_a?(self)
|
182
|
+
ents[0].def.stmts[0].is_a?(self) # int i;
|
176
183
|
return ents[0].def.stmts[0].detach
|
177
184
|
else
|
178
185
|
raise ParseError, "invalid #{self}"
|
@@ -181,10 +188,10 @@ module C
|
|
181
188
|
end
|
182
189
|
|
183
190
|
class Label
|
184
|
-
def self.parse
|
191
|
+
def self.parse(s, parser=nil)
|
185
192
|
parser ||= C.default_parser
|
186
193
|
ents = parser.parse("void f() {switch (0) #{s};}").entities
|
187
|
-
if ents.length == 1
|
194
|
+
if ents.length == 1 && # } void f() {
|
188
195
|
ents[0].def.stmts.length == 1 && # ;
|
189
196
|
ents[0].def.stmts[0].stmt && #
|
190
197
|
ents[0].def.stmts[0].stmt.labels.length == 1 && # x
|
@@ -197,25 +204,39 @@ module C
|
|
197
204
|
end
|
198
205
|
|
199
206
|
class Expression
|
200
|
-
def self.parse
|
207
|
+
def self.parse(s, parser=nil)
|
201
208
|
parser ||= C.default_parser
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
209
|
+
if s =~ /\A(\s*(\/\*.*?\*\/)?)*\{/
|
210
|
+
# starts with a brace -- must be a CompoundLiteral. in this
|
211
|
+
# case, use a Declarator since only those can handle typeless
|
212
|
+
# CompoundLiterals.
|
213
|
+
ents = parser.parse("int i = #{s};").entities
|
214
|
+
if ents.length == 1 && # 1; int i = 1
|
215
|
+
ents[0].declarators.length == 1 && # 1, j = 2
|
216
|
+
ents[0].declarators[0].init.is_a?(self)
|
217
|
+
return ents[0].declarators[0].init.detach
|
218
|
+
else
|
219
|
+
raise ParseError, "invalid #{self}"
|
220
|
+
end
|
208
221
|
else
|
209
|
-
|
222
|
+
ents = parser.parse("void f() {#{s};}").entities
|
223
|
+
if ents.length == 1 && # } void f() {
|
224
|
+
ents[0].def.stmts.length == 1 && # ;
|
225
|
+
ents[0].def.stmts[0].is_a?(ExpressionStatement) && # int i
|
226
|
+
ents[0].def.stmts[0].expr.is_a?(self)
|
227
|
+
return ents[0].def.stmts[0].expr.detach
|
228
|
+
else
|
229
|
+
raise ParseError, "invalid #{self}"
|
230
|
+
end
|
210
231
|
end
|
211
232
|
end
|
212
233
|
end
|
213
234
|
|
214
235
|
class Type
|
215
|
-
def self.parse
|
236
|
+
def self.parse(s, parser=nil)
|
216
237
|
parser ||= C.default_parser
|
217
238
|
ents = parser.parse("void f() {(#{s})x;}").entities
|
218
|
-
if ents.length == 1
|
239
|
+
if ents.length == 1 && # 1);} void f() {(int
|
219
240
|
ents[0].def.stmts.length == 1 && # 1); (int
|
220
241
|
ents[0].def.stmts[0].expr.type.is_a?(self)
|
221
242
|
return ents[0].def.stmts[0].expr.type.detach
|
@@ -225,9 +246,9 @@ module C
|
|
225
246
|
end
|
226
247
|
end
|
227
248
|
|
228
|
-
|
249
|
+
# Make sure we didn't miss any
|
229
250
|
CORE_C_NODE_CLASSES.each do |c|
|
230
|
-
c.
|
231
|
-
raise "#{c}
|
251
|
+
c.respond_to? :parse or
|
252
|
+
raise "#{c}.parse not defined"
|
232
253
|
end
|
233
254
|
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'rbconfig'
|
2
|
+
|
3
|
+
######################################################################
|
4
|
+
#
|
5
|
+
# A C preprocessor that wraps the command in Config::CONFIG['CPP'].
|
6
|
+
#
|
7
|
+
# Assumes a POSIX-style cpp command line interface, in particular, -I
|
8
|
+
# and -D options.
|
9
|
+
#
|
10
|
+
######################################################################
|
11
|
+
|
12
|
+
module C
|
13
|
+
class Preprocessor
|
14
|
+
class Error < StandardError
|
15
|
+
end
|
16
|
+
|
17
|
+
class << self
|
18
|
+
attr_accessor :command
|
19
|
+
end
|
20
|
+
self.command = (defined?(RbConfig) ? RbConfig : Config)::CONFIG['CPP']
|
21
|
+
|
22
|
+
attr_accessor :pwd, :include_path, :macros
|
23
|
+
|
24
|
+
def initialize
|
25
|
+
@include_path = []
|
26
|
+
@macros = {}
|
27
|
+
end
|
28
|
+
def preprocess(text)
|
29
|
+
filename = nil
|
30
|
+
Tempfile.open(['cast-preprocessor-input.', '.c'], File.expand_path(pwd || '.')) do |file|
|
31
|
+
filename = file.path
|
32
|
+
file.puts text
|
33
|
+
end
|
34
|
+
output = `#{full_command(filename)} 2>&1`
|
35
|
+
if $? == 0
|
36
|
+
return output
|
37
|
+
else
|
38
|
+
raise Error, output
|
39
|
+
end
|
40
|
+
end
|
41
|
+
def preprocess_file(file_name)
|
42
|
+
file_name = File.expand_path(file_name)
|
43
|
+
dir = File.dirname(file_name)
|
44
|
+
FileUtils.cd(dir) do
|
45
|
+
return preprocess(File.read(file_name))
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private # -------------------------------------------------------
|
50
|
+
|
51
|
+
def shellquote(arg)
|
52
|
+
if arg !~ /[\"\'\\$&<>|\s]/
|
53
|
+
return arg
|
54
|
+
elsif arg !~ /\'/
|
55
|
+
return "'#{arg}'"
|
56
|
+
else
|
57
|
+
arg.gsub!(/([\"\\$&<>|])/, '\\\\\\1')
|
58
|
+
return "\"#{arg}\""
|
59
|
+
end
|
60
|
+
end
|
61
|
+
def full_command(filename)
|
62
|
+
include_args = include_path.map do |path|
|
63
|
+
"#{shellquote('-I'+path)}"
|
64
|
+
end.join(' ')
|
65
|
+
macro_args = macros.sort.map do |key, val|
|
66
|
+
shellquote("-D#{key}" + (val ? "=#{val}" : ''))
|
67
|
+
end.join(' ')
|
68
|
+
filename = shellquote(filename)
|
69
|
+
"#{Preprocessor.command} #{include_args} #{macro_args} #{filename}"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
######################################################################
|
2
|
+
#
|
3
|
+
# Alternative to the standard ruby tempfile library, which lets you
|
4
|
+
# specify a filename suffix.
|
5
|
+
#
|
6
|
+
######################################################################
|
7
|
+
|
8
|
+
require 'delegate'
|
9
|
+
require 'tmpdir'
|
10
|
+
require 'tempfile'
|
11
|
+
|
12
|
+
#
|
13
|
+
# Setting the extension of a temp file has only been possible since
|
14
|
+
# Ruby 1.8.7.
|
15
|
+
#
|
16
|
+
module C
|
17
|
+
if RUBY_VERSION >= '1.8.7'
|
18
|
+
Tempfile = ::Tempfile
|
19
|
+
else
|
20
|
+
class Tempfile < ::Tempfile
|
21
|
+
def initialize(basename, tmpdir=Dir::tmpdir)
|
22
|
+
if basename.is_a?(::Array)
|
23
|
+
basename, @suffix = *basename
|
24
|
+
end
|
25
|
+
super(basename, tmpdir)
|
26
|
+
end
|
27
|
+
|
28
|
+
def make_tmpname(basename, n)
|
29
|
+
sprintf('%s%d.%d%s', basename, $$, n, @suffix)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/cast/to_s.rb
CHANGED
@@ -1,26 +1,24 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
### ##################################################################
|
9
|
-
###
|
1
|
+
######################################################################
|
2
|
+
#
|
3
|
+
# The Node#to_s methods.
|
4
|
+
#
|
5
|
+
# Yeah, this could be so so *SO* much faster.
|
6
|
+
#
|
7
|
+
######################################################################
|
10
8
|
|
11
9
|
module C
|
12
|
-
|
13
|
-
|
10
|
+
# undef the #to_s methods so we can check that we didn't forget to
|
11
|
+
# define any
|
14
12
|
Node.send(:undef_method, :to_s)
|
15
13
|
|
16
14
|
INDENT = ' '
|
17
15
|
class Node
|
18
16
|
private
|
19
|
-
def indent
|
17
|
+
def indent(s, levels=1)
|
20
18
|
s.gsub(/^/, INDENT*levels)
|
21
19
|
end
|
22
|
-
def hang
|
23
|
-
if stmt.is_a?
|
20
|
+
def hang(stmt, cont=false)
|
21
|
+
if stmt.is_a?(Block) && stmt.labels.empty?
|
24
22
|
return " #{stmt.to_s(:hanging)}" << (cont ? ' ' : '')
|
25
23
|
else
|
26
24
|
return "\n#{stmt.to_s}" << (cont ? "\n" : '')
|
@@ -58,7 +56,7 @@ module C
|
|
58
56
|
static? and str << 'static '
|
59
57
|
inline? and str << 'inline '
|
60
58
|
if no_prototype?
|
61
|
-
str << "#{type.to_s(name)}\n"
|
59
|
+
str << "#{type.to_s(name, true)}\n"
|
62
60
|
type.params.each do |p|
|
63
61
|
str << indent("#{p.to_s};\n")
|
64
62
|
end
|
@@ -69,14 +67,17 @@ module C
|
|
69
67
|
end
|
70
68
|
end
|
71
69
|
|
72
|
-
|
70
|
+
# ------------------------------------------------------------------
|
71
|
+
# Statements
|
72
|
+
# ------------------------------------------------------------------
|
73
|
+
|
73
74
|
class Statement
|
74
|
-
def label
|
75
|
-
labels.map{|s| "#{s}
|
75
|
+
def label(str)
|
76
|
+
labels.map{|s| "#{s}\n"}.join + indent(str)
|
76
77
|
end
|
77
78
|
end
|
78
79
|
class Block
|
79
|
-
def to_s
|
80
|
+
def to_s(hanging=false)
|
80
81
|
str = stmts.map do |s|
|
81
82
|
if s.is_a? Statement
|
82
83
|
s.to_s
|
@@ -166,21 +167,24 @@ module C
|
|
166
167
|
|
167
168
|
class PlainLabel
|
168
169
|
def to_s
|
169
|
-
name
|
170
|
+
"#{name}:"
|
170
171
|
end
|
171
172
|
end
|
172
173
|
class Default
|
173
174
|
def to_s
|
174
|
-
'default'
|
175
|
+
'default:'
|
175
176
|
end
|
176
177
|
end
|
177
178
|
class Case
|
178
179
|
def to_s
|
179
|
-
"case #{expr}"
|
180
|
+
"case #{expr}:"
|
180
181
|
end
|
181
182
|
end
|
182
183
|
|
183
|
-
|
184
|
+
# ------------------------------------------------------------------
|
185
|
+
# Expressions
|
186
|
+
# ------------------------------------------------------------------
|
187
|
+
|
184
188
|
precedence_table = {}
|
185
189
|
[[Comma],
|
186
190
|
[Assign, MultiplyAssign, DivideAssign, ModAssign, AddAssign,
|
@@ -206,38 +210,40 @@ module C
|
|
206
210
|
klass.send(:define_method, :to_s_precedence){|| prec}
|
207
211
|
end
|
208
212
|
end
|
209
|
-
|
213
|
+
# check all Expression classes have a precedence
|
210
214
|
C::Expression.subclasses_recursive do |c|
|
211
215
|
next if !C::Node.subclasses_recursive.include? c
|
212
216
|
c.instance_methods.include? 'to_s_precedence' or
|
213
217
|
raise "#{c}#to_s_precedence not defined"
|
214
218
|
end
|
215
219
|
|
216
|
-
|
217
|
-
[ [Cast ,
|
218
|
-
[Address ,
|
219
|
-
[Dereference,
|
220
|
-
[Positive ,
|
221
|
-
[Negative ,
|
222
|
-
[PreInc ,
|
223
|
-
[PreDec ,
|
224
|
-
[BitNot ,
|
225
|
-
[Not ,
|
226
|
-
].each do |c, proc|
|
220
|
+
# PrefixExpressions
|
221
|
+
[ [Cast , proc{"(#{self.type})"}, false],
|
222
|
+
[Address , proc{"&" }, true ],
|
223
|
+
[Dereference, proc{"*" }, false],
|
224
|
+
[Positive , proc{"+" }, true ],
|
225
|
+
[Negative , proc{"-" }, true ],
|
226
|
+
[PreInc , proc{"++" }, false],
|
227
|
+
[PreDec , proc{"--" }, false],
|
228
|
+
[BitNot , proc{"~" }, false],
|
229
|
+
[Not , proc{"!" }, false]
|
230
|
+
].each do |c, proc, space_needed|
|
227
231
|
c.send(:define_method, :to_s) do | |
|
228
232
|
if expr.to_s_precedence < self.to_s_precedence
|
229
233
|
return "#{instance_eval(&proc)}(#{expr})"
|
234
|
+
elsif space_needed && expr.class == self.class
|
235
|
+
return "#{instance_eval(&proc)} #{expr}"
|
230
236
|
else
|
231
237
|
return "#{instance_eval(&proc)}#{expr}"
|
232
238
|
end
|
233
239
|
end
|
234
240
|
end
|
235
|
-
|
236
|
-
[ [Arrow ,
|
237
|
-
[Dot ,
|
238
|
-
[Index ,
|
239
|
-
[PostInc ,
|
240
|
-
[PostDec ,
|
241
|
+
# PostfixExpressions
|
242
|
+
[ [Arrow , proc{"->#{member}"}],
|
243
|
+
[Dot , proc{".#{member}" }],
|
244
|
+
[Index , proc{"[#{index}]" }],
|
245
|
+
[PostInc , proc{"++" }],
|
246
|
+
[PostDec , proc{"--" }]
|
241
247
|
].each do |c, proc|
|
242
248
|
c.send(:define_method, :to_s) do | |
|
243
249
|
if expr.to_s_precedence < self.to_s_precedence
|
@@ -247,7 +253,7 @@ module C
|
|
247
253
|
end
|
248
254
|
end
|
249
255
|
end
|
250
|
-
|
256
|
+
# BinaryExpressions
|
251
257
|
[ [Add , '+' ],
|
252
258
|
[Subtract , '-' ],
|
253
259
|
[Multiply , '*' ],
|
@@ -273,7 +279,7 @@ module C
|
|
273
279
|
else
|
274
280
|
str1 = "#{expr1}"
|
275
281
|
end
|
276
|
-
|
282
|
+
# all binary expressions are left associative
|
277
283
|
if expr2.to_s_precedence <= self.to_s_precedence
|
278
284
|
str2 = "(#{expr2})"
|
279
285
|
else
|
@@ -282,7 +288,7 @@ module C
|
|
282
288
|
"#{str1} #{op} #{str2}"
|
283
289
|
end
|
284
290
|
end
|
285
|
-
|
291
|
+
# AssignmentExpressions
|
286
292
|
[ [Assign , '' ],
|
287
293
|
[MultiplyAssign , '*' ],
|
288
294
|
[DivideAssign , '/' ],
|
@@ -309,52 +315,44 @@ module C
|
|
309
315
|
"#{lvalstr} #{op}= #{rvalstr}"
|
310
316
|
end
|
311
317
|
end
|
312
|
-
|
318
|
+
# Other Expressions
|
313
319
|
class Sizeof
|
314
320
|
def to_s
|
315
|
-
|
316
|
-
if expr.to_s_precedence < self.to_s_precedence
|
317
|
-
return "sizeof(#{expr})"
|
318
|
-
else
|
319
|
-
return "sizeof #{expr}"
|
320
|
-
end
|
321
|
-
else
|
322
|
-
return "sizeof(#{expr})"
|
323
|
-
end
|
321
|
+
"sizeof(#{expr})"
|
324
322
|
end
|
325
323
|
end
|
326
|
-
|
324
|
+
# DirectTypes
|
327
325
|
int_longnesses = ['short ', '', 'long ', 'long long ']
|
328
326
|
float_longnesses = ['float', 'double', 'long double']
|
329
|
-
[ [Struct,
|
327
|
+
[ [Struct, proc do
|
330
328
|
str = 'struct'
|
331
329
|
name and str << " #{name}"
|
332
330
|
members and str << " {\n" << indent(members.join("\n")) << "\n}"
|
333
331
|
str
|
334
332
|
end],
|
335
|
-
[Union,
|
333
|
+
[Union, proc do
|
336
334
|
str = 'union'
|
337
335
|
name and str << " #{name}"
|
338
336
|
members and str << " {\n" << indent(members.join("\n")) << "\n}"
|
339
337
|
str
|
340
338
|
end],
|
341
|
-
[Enum,
|
339
|
+
[Enum, proc do
|
342
340
|
str = 'enum'
|
343
341
|
name and str << " #{name}"
|
344
342
|
members and str << " {\n" << indent(members.join(",\n")) << "\n}"
|
345
343
|
str
|
346
344
|
end],
|
347
|
-
[CustomType,
|
348
|
-
[Void ,
|
349
|
-
[Int ,
|
345
|
+
[CustomType, proc{name.dup }],
|
346
|
+
[Void , proc{'void' }],
|
347
|
+
[Int , proc do
|
350
348
|
longness_str = int_longnesses[longness+1].dup
|
351
349
|
"#{unsigned? ? 'unsigned ' : ''}#{longness_str}int"
|
352
350
|
end],
|
353
|
-
[Float ,
|
354
|
-
[Char ,
|
355
|
-
[Bool ,
|
356
|
-
[Complex ,
|
357
|
-
[Imaginary ,
|
351
|
+
[Float , proc{float_longnesses[longness].dup}],
|
352
|
+
[Char , proc{"#{unsigned? ? 'unsigned ' : signed? ? 'signed ' : ''}char"}],
|
353
|
+
[Bool , proc{"_Bool" }],
|
354
|
+
[Complex , proc{"_Complex #{float_longnesses[longness]}"}],
|
355
|
+
[Imaginary , proc{"_Imaginary #{float_longnesses[longness]}"}]
|
358
356
|
].each do |c, x|
|
359
357
|
c.send(:define_method, :to_s) do |*args|
|
360
358
|
case args.length
|
@@ -394,7 +392,7 @@ module C
|
|
394
392
|
def to_s
|
395
393
|
strs = [:cond, :then, :else].map do |child|
|
396
394
|
val = send(child)
|
397
|
-
if val.to_s_precedence
|
395
|
+
if val.to_s_precedence <= self.to_s_precedence
|
398
396
|
"(#{val})"
|
399
397
|
else
|
400
398
|
"#{val}"
|
@@ -422,9 +420,9 @@ module C
|
|
422
420
|
end
|
423
421
|
end
|
424
422
|
|
425
|
-
|
423
|
+
## IndirectTypes
|
426
424
|
class Pointer
|
427
|
-
def to_s
|
425
|
+
def to_s(name=nil)
|
428
426
|
str = '*'
|
429
427
|
const? and str << 'const '
|
430
428
|
restrict? and str << 'restrict '
|
@@ -444,7 +442,7 @@ module C
|
|
444
442
|
end
|
445
443
|
end
|
446
444
|
class Array
|
447
|
-
def to_s
|
445
|
+
def to_s(name=nil)
|
448
446
|
str = "#{name}[#{length}]"
|
449
447
|
if type
|
450
448
|
type.to_s(str)
|
@@ -454,14 +452,18 @@ module C
|
|
454
452
|
end
|
455
453
|
end
|
456
454
|
class Function
|
457
|
-
def to_s
|
455
|
+
def to_s(name=nil, no_types=false)
|
458
456
|
str =
|
459
457
|
if params.nil?
|
460
458
|
paramstr = ''
|
461
459
|
elsif params.empty?
|
462
460
|
paramstr = 'void'
|
463
461
|
else
|
464
|
-
|
462
|
+
if no_types
|
463
|
+
paramstr = params.map{|p| p.name}.join(', ')
|
464
|
+
else
|
465
|
+
paramstr = params.join(', ')
|
466
|
+
end
|
465
467
|
end
|
466
468
|
var_args? and paramstr << ', ...'
|
467
469
|
str = "#{name}(#{paramstr})"
|
@@ -483,7 +485,7 @@ module C
|
|
483
485
|
end
|
484
486
|
end
|
485
487
|
|
486
|
-
|
488
|
+
## Literals
|
487
489
|
class StringLiteral
|
488
490
|
def to_s
|
489
491
|
"\"#{val}\""
|
@@ -513,7 +515,7 @@ module C
|
|
513
515
|
".#{m}"
|
514
516
|
end
|
515
517
|
end
|
516
|
-
str <<
|
518
|
+
str << memberstr.join(' ') << ' = '
|
517
519
|
end
|
518
520
|
return str << init.to_s
|
519
521
|
end
|
@@ -538,8 +540,14 @@ module C
|
|
538
540
|
name.dup
|
539
541
|
end
|
540
542
|
end
|
543
|
+
class BlockExpression
|
544
|
+
def to_s
|
545
|
+
# note that the grammar does not allow the block to have a label
|
546
|
+
"(#{block.to_s(:hanging)})"
|
547
|
+
end
|
548
|
+
end
|
541
549
|
|
542
|
-
|
550
|
+
# check we didn't miss any
|
543
551
|
CORE_C_NODE_CLASSES.each do |c|
|
544
552
|
c.method_defined? :to_s or
|
545
553
|
raise "#{c}#to_s not defined"
|