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.
@@ -1,45 +1,43 @@
1
- ###
2
- ### ##################################################################
3
- ###
4
- ### C.default_parser and the parse_* methods.
5
- ###
6
- ### Yeah, this could be so much faster.
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= val
14
+ def self.default_parser=(val)
17
15
  @@default_parser = val
18
16
  end
19
17
 
20
18
  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
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
- ### Same as #match?.
32
- ###
33
- def =~ *args
34
- match? *args
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
- ### As defined in Node.
41
- ###
42
- def match? arr, parser=nil
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 s, parser=nil
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 s, parser=nil
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 s, parser=nil
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 s, parser=nil
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 s, parser=nil
95
+ def self.parse(s, parser=nil)
98
96
  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
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
- raise ParseError, "invalid Declarator"
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 s, parser=nil
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 s, parser=nil
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 s, parser=nil
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 s, parser=nil
159
+ def self.parse(s, parser=nil)
153
160
  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]
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 s, parser=nil
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 && # } void f() {
180
+ if ents.length == 1 && # } void f() {
174
181
  ents[0].def.stmts.length == 1 && # ;;
175
- ents[0].def.stmts[0].is_a?(self) # int i;
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 s, parser=nil
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 && # } void f() {
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 s, parser=nil
207
+ def self.parse(s, parser=nil)
201
208
  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
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
- raise ParseError, "invalid #{self}"
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 s, parser=nil
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 && # 1);} void f() {(int
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
- #### Make sure we didn't miss any
249
+ # Make sure we didn't miss any
229
250
  CORE_C_NODE_CLASSES.each do |c|
230
- c.methods.include? 'parse' or
231
- raise "#{c}#parse not defined"
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
- ### The Node#to_s methods.
5
- ###
6
- ### Yeah, this could be so so *SO* much faster.
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
- ## undef the #to_s methods so we can check that we didn't forget to
13
- ## define any
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 s, levels=1
17
+ def indent(s, levels=1)
20
18
  s.gsub(/^/, INDENT*levels)
21
19
  end
22
- def hang stmt, cont=false
23
- if stmt.is_a? Block
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
- ### Statements
70
+ # ------------------------------------------------------------------
71
+ # Statements
72
+ # ------------------------------------------------------------------
73
+
73
74
  class Statement
74
- def label str
75
- labels.map{|s| "#{s}:\n"}.join + indent(str)
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 hanging=false
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.to_s
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
- ### Expressions
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
- ## check all Expression classes have a precedence
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
- ## 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|
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
- ## PostfixExpressions
236
- [ [Arrow , lambda{"->#{member}"}],
237
- [Dot , lambda{".#{member}" }],
238
- [Index , lambda{"[#{index}]" }],
239
- [PostInc , lambda{"++" }],
240
- [PostDec , lambda{"--" }]
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
- ## BinaryExpressions
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
- ## all binary expressions are left associative
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
- ## AssignmentExpressions
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
- "#{lval} #{op}= #{rvalstr}"
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
- ## Other Expressions
318
+ # Other Expressions
308
319
  class Sizeof
309
320
  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
321
+ "sizeof(#{expr})"
319
322
  end
320
323
  end
321
- ## DirectTypes
324
+ # DirectTypes
322
325
  int_longnesses = ['short ', '', 'long ', 'long long ']
323
326
  float_longnesses = ['float', 'double', 'long double']
324
- [ [Struct, lambda do
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, lambda do
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, lambda do
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, lambda{name.dup }],
343
- [Void , lambda{'void' }],
344
- [Int , lambda do
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 , lambda{float_longnesses[longness].dup}],
349
- [Char , lambda{"#{unsigned? ? 'unsigned ' : ''}char"}],
350
- [Bool , lambda{'_Bool' }],
351
- [Complex , lambda{'_Complex' }],
352
- [Imaginary , lambda{'_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 < self.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
- ### IndirectTypes
423
+ ## IndirectTypes
421
424
  class Pointer
422
- def to_s name=nil
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 name=nil
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 name=nil
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
- paramstr = params.join(', ')
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
- str << type.to_s(name)
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
- ### Literals
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(inits.join(",\n")) << "\n}"
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 << member.join(' ') << ' = '
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
- val.to_s
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
- val.to_s
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
- ## check we didn't miss any
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"