cast 0.0.1 → 0.3.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.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/CHANGELOG +63 -0
- data/Gemfile +9 -0
- data/LICENSE +22 -0
- data/README.markdown +1924 -0
- data/Rakefile +29 -0
- data/cast.gemspec +18 -0
- data/ext/cast.c +6 -0
- data/ext/cast.h +141 -0
- data/ext/extconf.rb +2 -0
- data/ext/parser.c +287 -0
- data/ext/yylex.re +340 -0
- data/lib/cast.rb +11 -9
- data/lib/cast/c.y +904 -0
- data/lib/{c_nodes.rb → cast/c_nodes.rb} +188 -392
- data/lib/{to_debug.rb → cast/inspect.rb} +18 -20
- data/lib/cast/node.rb +741 -0
- data/lib/{node_list.rb → cast/node_list.rb} +175 -176
- data/lib/{parse.rb → cast/parse.rb} +86 -65
- data/lib/cast/preprocessor.rb +59 -0
- data/lib/cast/tempfile.rb +33 -0
- data/lib/{to_s.rb → cast/to_s.rb} +133 -80
- data/lib/cast/version.rb +11 -0
- data/test/c_nodes_test.rb +224 -0
- data/test/lexer_test.rb +335 -0
- data/test/{test_node_list.rb → node_list_test.rb} +401 -413
- data/test/{test_node.rb → node_test.rb} +186 -214
- data/test/parse_test.rb +2068 -0
- data/test/{test_parser.rb → parser_test.rb} +145 -58
- data/test/preprocessor_test.rb +85 -0
- data/test/render_test.rb +2116 -0
- data/test/test_helper.rb +198 -0
- metadata +83 -52
- data/README +0 -6
- data/doc/index.html +0 -2513
- data/install.rb +0 -14
- data/lib/c.tab.rb +0 -3433
- data/lib/c.y +0 -935
- data/lib/node.rb +0 -744
- data/test/common.rb +0 -174
- data/test/run.rb +0 -5
- data/test/test_c_nodes.rb +0 -160
- data/test/test_parse.rb +0 -2014
@@ -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,59 @@
|
|
1
|
+
require 'rbconfig'
|
2
|
+
require 'shellwords'
|
3
|
+
|
4
|
+
######################################################################
|
5
|
+
#
|
6
|
+
# A C preprocessor that wraps the command in Config::CONFIG['CPP'].
|
7
|
+
#
|
8
|
+
# Assumes a POSIX-style cpp command line interface, in particular, -I
|
9
|
+
# and -D options.
|
10
|
+
#
|
11
|
+
######################################################################
|
12
|
+
|
13
|
+
module C
|
14
|
+
class Preprocessor
|
15
|
+
class Error < StandardError
|
16
|
+
end
|
17
|
+
|
18
|
+
class << self
|
19
|
+
attr_accessor :command
|
20
|
+
end
|
21
|
+
self.command = (defined?(RbConfig) ? RbConfig : Config)::CONFIG['CPP']
|
22
|
+
|
23
|
+
attr_accessor :pwd, :include_path, :macros
|
24
|
+
|
25
|
+
def initialize(quiet: false)
|
26
|
+
@include_path = []
|
27
|
+
@macros = {}
|
28
|
+
@quiet = quiet
|
29
|
+
end
|
30
|
+
def preprocess(text)
|
31
|
+
filename = nil
|
32
|
+
Tempfile.open(['cast-preprocessor-input.', '.c'], File.expand_path(pwd || '.')) do |file|
|
33
|
+
filename = file.path
|
34
|
+
file.puts text
|
35
|
+
end
|
36
|
+
output = `#{full_command(filename)} #{'2> /dev/null' if @quiet}`
|
37
|
+
if $? == 0
|
38
|
+
return output
|
39
|
+
else
|
40
|
+
raise Error, output
|
41
|
+
end
|
42
|
+
end
|
43
|
+
def preprocess_file(file_name)
|
44
|
+
file_name = File.expand_path(file_name)
|
45
|
+
dir = File.dirname(file_name)
|
46
|
+
FileUtils.cd(dir) do
|
47
|
+
return preprocess(File.read(file_name))
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
private # -------------------------------------------------------
|
52
|
+
|
53
|
+
def full_command(filename)
|
54
|
+
include_args = include_path.map { |path| "-I#{path}" }
|
55
|
+
macro_args = macros.sort.map { |key, val| "-D#{key}" + (val ? "=#{val}" : '') }
|
56
|
+
[*Preprocessor.command.shellsplit, *include_args, *macro_args, filename].shelljoin
|
57
|
+
end
|
58
|
+
end
|
59
|
+
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
|
@@ -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 , '/' ],
|
@@ -301,55 +307,52 @@ module C
|
|
301
307
|
else
|
302
308
|
rvalstr = "#{rval}"
|
303
309
|
end
|
304
|
-
|
310
|
+
if lval.to_s_precedence < self.to_s_precedence
|
311
|
+
lvalstr = "(#{lval})"
|
312
|
+
else
|
313
|
+
lvalstr = "#{lval}"
|
314
|
+
end
|
315
|
+
"#{lvalstr} #{op}= #{rvalstr}"
|
305
316
|
end
|
306
317
|
end
|
307
|
-
|
318
|
+
# Other Expressions
|
308
319
|
class Sizeof
|
309
320
|
def to_s
|
310
|
-
|
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
|
321
|
+
"sizeof(#{expr})"
|
319
322
|
end
|
320
323
|
end
|
321
|
-
|
324
|
+
# DirectTypes
|
322
325
|
int_longnesses = ['short ', '', 'long ', 'long long ']
|
323
326
|
float_longnesses = ['float', 'double', 'long double']
|
324
|
-
[ [Struct,
|
327
|
+
[ [Struct, proc do
|
325
328
|
str = 'struct'
|
326
329
|
name and str << " #{name}"
|
327
330
|
members and str << " {\n" << indent(members.join("\n")) << "\n}"
|
328
331
|
str
|
329
332
|
end],
|
330
|
-
[Union,
|
333
|
+
[Union, proc do
|
331
334
|
str = 'union'
|
332
335
|
name and str << " #{name}"
|
333
336
|
members and str << " {\n" << indent(members.join("\n")) << "\n}"
|
334
337
|
str
|
335
338
|
end],
|
336
|
-
[Enum,
|
339
|
+
[Enum, proc do
|
337
340
|
str = 'enum'
|
338
341
|
name and str << " #{name}"
|
339
342
|
members and str << " {\n" << indent(members.join(",\n")) << "\n}"
|
340
343
|
str
|
341
344
|
end],
|
342
|
-
[CustomType,
|
343
|
-
[Void ,
|
344
|
-
[Int ,
|
345
|
+
[CustomType, proc{name.dup }],
|
346
|
+
[Void , proc{'void' }],
|
347
|
+
[Int , proc do
|
345
348
|
longness_str = int_longnesses[longness+1].dup
|
346
349
|
"#{unsigned? ? 'unsigned ' : ''}#{longness_str}int"
|
347
350
|
end],
|
348
|
-
[Float ,
|
349
|
-
[Char ,
|
350
|
-
[Bool ,
|
351
|
-
[Complex ,
|
352
|
-
[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]}"}]
|
353
356
|
].each do |c, x|
|
354
357
|
c.send(:define_method, :to_s) do |*args|
|
355
358
|
case args.length
|
@@ -389,7 +392,7 @@ module C
|
|
389
392
|
def to_s
|
390
393
|
strs = [:cond, :then, :else].map do |child|
|
391
394
|
val = send(child)
|
392
|
-
if val.to_s_precedence
|
395
|
+
if val.to_s_precedence <= self.to_s_precedence
|
393
396
|
"(#{val})"
|
394
397
|
else
|
395
398
|
"#{val}"
|
@@ -417,9 +420,9 @@ module C
|
|
417
420
|
end
|
418
421
|
end
|
419
422
|
|
420
|
-
|
423
|
+
## IndirectTypes
|
421
424
|
class Pointer
|
422
|
-
def to_s
|
425
|
+
def to_s(name=nil)
|
423
426
|
str = '*'
|
424
427
|
const? and str << 'const '
|
425
428
|
restrict? and str << 'restrict '
|
@@ -439,7 +442,7 @@ module C
|
|
439
442
|
end
|
440
443
|
end
|
441
444
|
class Array
|
442
|
-
def to_s
|
445
|
+
def to_s(name=nil)
|
443
446
|
str = "#{name}[#{length}]"
|
444
447
|
if type
|
445
448
|
type.to_s(str)
|
@@ -449,14 +452,18 @@ module C
|
|
449
452
|
end
|
450
453
|
end
|
451
454
|
class Function
|
452
|
-
def to_s
|
455
|
+
def to_s(name=nil, no_types=false)
|
453
456
|
str =
|
454
457
|
if params.nil?
|
455
458
|
paramstr = ''
|
456
459
|
elsif params.empty?
|
457
460
|
paramstr = 'void'
|
458
461
|
else
|
459
|
-
|
462
|
+
if no_types
|
463
|
+
paramstr = params.map{|p| p.name}.join(', ')
|
464
|
+
else
|
465
|
+
paramstr = params.join(', ')
|
466
|
+
end
|
460
467
|
end
|
461
468
|
var_args? and paramstr << ', ...'
|
462
469
|
str = "#{name}(#{paramstr})"
|
@@ -470,11 +477,15 @@ module C
|
|
470
477
|
class Parameter
|
471
478
|
def to_s
|
472
479
|
str = register? ? 'register ' : ''
|
473
|
-
|
480
|
+
if type
|
481
|
+
str << type.to_s(name)
|
482
|
+
else
|
483
|
+
str << name.to_s
|
484
|
+
end
|
474
485
|
end
|
475
486
|
end
|
476
487
|
|
477
|
-
|
488
|
+
## Literals
|
478
489
|
class StringLiteral
|
479
490
|
def to_s
|
480
491
|
"\"#{val}\""
|
@@ -490,7 +501,7 @@ module C
|
|
490
501
|
str = ''
|
491
502
|
type and
|
492
503
|
str << "(#{type}) "
|
493
|
-
str << "{\n" << indent(
|
504
|
+
str << "{\n" << indent(member_inits.join(",\n")) << "\n}"
|
494
505
|
end
|
495
506
|
end
|
496
507
|
class MemberInit
|
@@ -504,7 +515,7 @@ module C
|
|
504
515
|
".#{m}"
|
505
516
|
end
|
506
517
|
end
|
507
|
-
str <<
|
518
|
+
str << memberstr.join(' ') << ' = '
|
508
519
|
end
|
509
520
|
return str << init.to_s
|
510
521
|
end
|
@@ -516,12 +527,48 @@ module C
|
|
516
527
|
end
|
517
528
|
class IntLiteral
|
518
529
|
def to_s
|
519
|
-
|
530
|
+
case format
|
531
|
+
when :dec
|
532
|
+
"#{val.to_s}#{suffix}"
|
533
|
+
when :hex
|
534
|
+
"0x#{val.to_s(16)}#{suffix}"
|
535
|
+
when :oct
|
536
|
+
"0#{val.to_s(8)}#{suffix}"
|
537
|
+
else
|
538
|
+
raise "invalid C::IntLiteral format: #{format}"
|
539
|
+
end
|
520
540
|
end
|
521
541
|
end
|
522
542
|
class FloatLiteral
|
523
543
|
def to_s
|
524
|
-
|
544
|
+
case format
|
545
|
+
when :dec
|
546
|
+
if exponent
|
547
|
+
"#{val / 10**exponent}e#{exponent}#{suffix}"
|
548
|
+
else
|
549
|
+
"#{val}#{suffix}"
|
550
|
+
end
|
551
|
+
when :hex
|
552
|
+
"0x#{float_hex(val / 2**exponent)}p#{exponent || 0}#{suffix}"
|
553
|
+
else
|
554
|
+
raise "invalid C::FloatLiteral format: #{format}"
|
555
|
+
end
|
556
|
+
end
|
557
|
+
|
558
|
+
private
|
559
|
+
|
560
|
+
HEX_DIGITS = %w[0 1 2 3 4 5 6 7 8 9 a b c d e f]
|
561
|
+
|
562
|
+
def float_hex(value)
|
563
|
+
int, frac = value.divmod(1)
|
564
|
+
string = "#{int.to_s(16)}."
|
565
|
+
# 64-bit floats have 53 bits of significand ~ 14 hex digits.
|
566
|
+
14.times do
|
567
|
+
break if frac < 1e-17
|
568
|
+
int, frac = (frac * 16).divmod(1)
|
569
|
+
string << HEX_DIGITS[int]
|
570
|
+
end
|
571
|
+
string
|
525
572
|
end
|
526
573
|
end
|
527
574
|
class Variable
|
@@ -529,8 +576,14 @@ module C
|
|
529
576
|
name.dup
|
530
577
|
end
|
531
578
|
end
|
579
|
+
class BlockExpression
|
580
|
+
def to_s
|
581
|
+
# note that the grammar does not allow the block to have a label
|
582
|
+
"(#{block.to_s(:hanging)})"
|
583
|
+
end
|
584
|
+
end
|
532
585
|
|
533
|
-
|
586
|
+
# check we didn't miss any
|
534
587
|
CORE_C_NODE_CLASSES.each do |c|
|
535
588
|
c.method_defined? :to_s or
|
536
589
|
raise "#{c}#to_s not defined"
|