grammar 0.8 → 0.8.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.
@@ -6,25 +6,45 @@ require 'rubygems'
6
6
 
7
7
  class JSON_Generator
8
8
  attr_accessor(:array, :object)
9
+ def convert(obj)
10
+ obj.inspect.gsub(/=>/, ':').gsub(/\bnil\b/, 'null')
11
+ end
9
12
  def initialize
10
13
  @string1 = '1'
14
+ @string1s = @string1.inspect
11
15
  @string2 = '2'
16
+ @string2s = @string2.inspect
12
17
  @array1 = ['abc : 123', {}, false]
13
- @array2 = [1.234e-5, {@string2 => nil}, '']
18
+ @array2 = [1.234e-5, {@string2 => nil}, ""]
14
19
  @object1 = {@string1 => '\\\n\t', @string2 => true}
15
20
  @object2 = {@string2 => -789, @string2 => []}
21
+ @array1s = @array1.map { |obj| convert(obj) }
22
+ @array2s = @array2.map { |obj| convert(obj) }
23
+ @object1s = @object1.map { |k,v| "#{convert(k)}:#{convert(v)}" }
24
+ @object2s = @object2.map { |k,v| "#{convert(k)}:#{convert(v)}" }
16
25
  end
17
26
  def grow
18
27
  @array1,
19
28
  @array2,
20
- @object1,
21
- @object2 =
29
+ @object2,
30
+ @object1 =
22
31
  @array1.reverse << @object2,
23
32
  @array2.reverse.concat(@array1),
24
- @object1.merge({@string1 => @array2}),
25
- @object2.merge(@object1)
33
+ @object2.merge(@object1),
34
+ @object1.merge!({@string1 => @array2})
35
+ @array1s,
36
+ @array2s,
37
+ @object2s,
38
+ @object1s =
39
+ @array1s.reverse << "{#{@object2s.join(', ')}}",
40
+ @array2s.reverse.concat(@array1s),
41
+ @object2s.concat(@object1s),
42
+ @object1s << "#{@string1s}:[#{@array2s.join(', ')}]"
26
43
  @array2
27
44
  end
45
+ def to_s
46
+ "[#{@array2s.join(', ')}]"
47
+ end
28
48
  end
29
49
 
30
50
  def filesize(filename)
@@ -52,9 +72,6 @@ def benchmark(label='', filename=nil)
52
72
  load_path = $LOAD_PATH.clone
53
73
  loaded_features = $LOADED_FEATURES.clone
54
74
  !ARGV[0] or Regexp.new(ARGV[0])=~label or return
55
- make = yield
56
- limit = (ARGV[1]||1).to_f
57
- max_tries = 4
58
75
  unless label.empty?
59
76
  STDERR.print(label)
60
77
  if filename
@@ -63,6 +80,9 @@ def benchmark(label='', filename=nil)
63
80
  STDERR.print(" -")
64
81
  end
65
82
  end
83
+ run = yield
84
+ limit = (ARGV[1]||1).to_f
85
+ max_tries = 4
66
86
  bandwidth = nil
67
87
  generator = JSON_Generator.new
68
88
  tree0 = nil
@@ -70,39 +90,38 @@ def benchmark(label='', filename=nil)
70
90
  tree = nil
71
91
  tries = 0
72
92
  done = false
93
+ t0 = nil
94
+ n = 1
73
95
  begin
74
96
  GC.start
75
- tms = Benchmark.measure {
76
- if tries>0
77
- tries += 1
78
- else
97
+ if tries>0
98
+ tries += 1
99
+ elsif t0 && t0>limit
100
+ n *= 2
101
+ else
102
+ tms = Benchmark.measure {
79
103
  tree0 = generator.grow
80
- end
81
- s = tree0.inspect
82
- s.gsub!(/=>/, ':')
83
- s.gsub!(/nil/, 'null')
84
- }
85
- if !make
86
- return if tms.utime+tms.stime>limit
87
- next
104
+ s = generator.to_s
105
+ }
106
+ t0 = tms.utime+tms.stime
88
107
  end
89
108
  #puts s
90
- run = make[s]
91
109
  GC.start
92
110
  GC.start
93
- tms = Benchmark.measure { tree = run[] }
111
+ tms = Benchmark.measure { n.times { tree = run[s] } }
94
112
  GC.start
95
- raise("#{tree.inspect}!=#{tree0.inspect}") if tree!=tree0
113
+ raise("#{tree.inspect}!=#{tree0.inspect}") if tree && tree!=tree0
96
114
  tree = nil
97
115
  t = tms.utime+tms.stime
98
- bandwidth = s.length/t
99
- s = nil
100
- GC.start
116
+ bandwidth = (n*s.length)/t
101
117
  if tries.zero?
102
118
  if t>limit
103
119
  tries = 1
120
+ GC.start
104
121
  else
105
- next #if t<(limit/3)
122
+ s = nil unless t0>limit
123
+ GC.start
124
+ next
106
125
  end
107
126
  end
108
127
  if bandwidth>=1e9
@@ -122,11 +141,11 @@ def benchmark(label='', filename=nil)
122
141
  end until tries>=max_tries
123
142
  STDERR.print("\n")
124
143
  return bandwidth
125
- rescue => error
126
- p error
144
+ rescue ScriptError,StandardError => error
145
+ puts(" #{error}")
127
146
  ensure
128
- #Gem.clear_paths
129
- #Gem.loaded_specs.clear
147
+ begin;Gem.clear_paths;rescue Exception;end
148
+ begin;Gem.loaded_specs.clear;rescue Exception;end
130
149
  self.class.constants.each { |constant|
131
150
  next if constants[constant]
132
151
  #puts("removing #{constant}")
@@ -142,32 +161,47 @@ require 'stringio'
142
161
  json_pure = '/var/lib/gems/1.8/gems/json-1.1.2/lib/json/pure/parser.rb'
143
162
  json_ext = '/var/lib/gems/1.8/gems/json-1.1.2/ext/json/ext/parser/parser.rl'
144
163
 
145
- benchmark('') {}
164
+ benchmark('String#index') {
165
+ lambda { |s|
166
+ s.index(?\0)
167
+ nil
168
+ }
169
+ }
170
+
171
+ benchmark('String#each_byte') {
172
+ lambda { |s|
173
+ s.each_byte{}
174
+ nil
175
+ }
176
+ }
146
177
 
147
- benchmark('json/ext', json_ext) {
178
+ benchmark('StringIO#getc') {
179
+ lambda { |s|
180
+ i = StringIO.new(s)
181
+ while i.getc;end
182
+ nil
183
+ }
184
+ }
185
+
186
+ benchmark('Ragel/C(json/ext)', json_ext) {
148
187
  gem 'json'
149
188
  require 'json/ext'
150
189
  lambda { |s|
151
- JSON::Ext::Parser.new(s).method(:parse)
190
+ JSON::Ext::Parser.new(s).parse
152
191
  }
153
192
  }
154
193
 
155
194
  benchmark('Grammar/Ruby2CExt', 'json.grammar.rb') {
156
195
  $LOAD_PATH << '../lib'
157
- require '../lib/grammar'
196
+ require 'grammar'
158
197
  grammar = Grammar.new.instance_eval(IO.read('json.grammar.rb'))
159
198
  Kernel.module_eval { alias_method(:_warn, :warn) }
160
199
  Kernel.module_eval { def warn(*);end }
161
200
  require 'grammar/ruby2cext'
162
201
  Kernel.module_eval { alias_method(:warn, :_warn) }
163
- grammar_ruby2cext = Grammar::Ruby2CExt.compile(grammar)
202
+ grammar_ruby2cext = Grammar::Ruby2CExt.compile(grammar, :getc)
164
203
  lambda { |s|
165
- i = StringIO.new(s).method(:getc)
166
- out = []
167
- lambda {
168
- grammar_ruby2cext[out, i]
169
- out[0]
170
- }
204
+ grammar_ruby2cext[out=[], StringIO.new(s)] && out[0]
171
205
  }
172
206
  }
173
207
 
@@ -175,10 +209,7 @@ benchmark('hand/RE', 'json.re.rb') {
175
209
  load 'json.re.rb'
176
210
  re = JSON.new
177
211
  lambda { |s|
178
- i = StringScanner.new(s)
179
- lambda {
180
- re.parse(i)
181
- }
212
+ re.parse(StringScanner.new(s))
182
213
  }
183
214
  }
184
215
 
@@ -186,26 +217,19 @@ benchmark('hand/LL1', 'json.ll1.rb') {
186
217
  load 'json.ll1.rb'
187
218
  ll1 = JSON.new
188
219
  lambda { |s|
189
- i = StringIO.new(s)
190
- lambda {
191
- ll1.parse(i)
192
- }
220
+ ll1.parse(StringIO.new(s))
193
221
  }
194
222
  }
195
223
 
196
224
  benchmark('Grammar/Ruby', 'json.grammar.rb') {
197
225
  $LOAD_PATH << '../lib'
198
- require '../lib/grammar'
226
+ require 'grammar'
199
227
  grammar = Grammar.new.instance_eval(IO.read('json.grammar.rb'))
200
228
  require 'grammar/ruby'
201
- grammar_ruby = Grammar::Ruby.compile(grammar)
229
+ grammar_ruby = Grammar::Ruby.compile(grammar, :getc)
202
230
  lambda { |s|
203
- i = StringIO.new(s).method(:getc)
204
- out = []
205
- lambda {
206
- grammar_ruby[out, i]
207
- out[0]
208
- }
231
+ grammar_ruby[out=[], StringIO.new(s)] && out[0]
232
+ out[0]
209
233
  }
210
234
  }
211
235
 
@@ -222,10 +246,7 @@ benchmark('RACC/ext', 'json.y') {
222
246
  }
223
247
  racc = JSON.new
224
248
  lambda { |s|
225
- i = StringScanner.new(s)
226
- lambda {
227
- racc.parse(i)
228
- }
249
+ racc.parse(StringScanner.new(s))
229
250
  }
230
251
  }
231
252
 
@@ -233,7 +254,7 @@ benchmark('json/pure', json_pure) {
233
254
  gem 'json'
234
255
  require 'json/pure'
235
256
  lambda { |s|
236
- JSON::Pure::Parser.new(s).method(:parse)
257
+ JSON::Pure::Parser.new(s).parse
237
258
  }
238
259
  }
239
260
 
@@ -242,19 +263,14 @@ benchmark('Grammar/RubyCall', 'json.grammar.rb') {
242
263
  require '../lib/grammar'
243
264
  grammar = Grammar.new.instance_eval(IO.read('json.grammar.rb'))
244
265
  require 'grammar/rubycall'
245
- grammar_ruby = Grammar::RubyCall.compile(grammar)
266
+ grammar_ruby = Grammar::RubyCall.compile(grammar, :getc)
246
267
  lambda { |s|
247
- i = StringIO.new(s).method(:getc)
248
- out = []
249
- lambda {
250
- grammar_ruby[out, i]
251
- out[0]
252
- }
268
+ grammar_ruby[out=[], StringIO.new(s)] && out[0]
253
269
  }
254
270
  }
255
271
 
256
272
  benchmark('Grammar/0.5', 'json.grammar0_5.rb') {
257
- gem 'grammar'
273
+ gem 'grammar', '0.5'
258
274
  require 'grammar'
259
275
  require 'duck'
260
276
  require 'json.grammar0_5'
@@ -262,11 +278,7 @@ benchmark('Grammar/0.5', 'json.grammar0_5.rb') {
262
278
  require 'cursor/io'
263
279
  grammar0_5 = JSON.new
264
280
  lambda { |s|
265
- i = Cursor::IO.new(StringIO.new(s))
266
- lambda {
267
- grammar0_5.scan(i, out=[])
268
- out[0]
269
- }
281
+ grammar0_5.scan(Cursor::IO.new(StringIO.new(s)), out=[]) && out[0]
270
282
  }
271
283
  }
272
284
 
@@ -283,10 +295,7 @@ benchmark('RACC/ruby', 'json.y') {
283
295
  }
284
296
  racc = JSON.new
285
297
  lambda { |s|
286
- i = StringScanner.new(s)
287
- lambda {
288
- racc.parse(i)
289
- }
298
+ racc.parse(StringScanner.new(s))
290
299
  }
291
300
  }
292
301
 
@@ -296,9 +305,7 @@ benchmark('Treetop', 'json.treetop') {
296
305
  Treetop.load('json.treetop')
297
306
  treetop = JSONParser.new
298
307
  lambda { |s|
299
- lambda {
300
- treetop.parse(s).obj
301
- }
308
+ treetop.parse(s).obj
302
309
  }
303
310
  }
304
311
 
@@ -307,9 +314,7 @@ benchmark('GhostWheel', 'json.ghostwheel') {
307
314
  require 'ghost_wheel'
308
315
  ghostwheel = GhostWheel.build_parser(IO.read("json.ghostwheel"))
309
316
  lambda { |s|
310
- lambda {
311
- ghostwheel.parse(s)
312
- }
317
+ ghostwheel.parse(s)
313
318
  }
314
319
  }
315
320
 
@@ -320,12 +325,7 @@ benchmark('Grammar/Ruby0', 'json.grammar.rb') {
320
325
  require 'grammar/ruby0'
321
326
  grammar_ruby0 = Grammar::Ruby0.compile(grammar)
322
327
  lambda { |s|
323
- i = StringIO.new(s).method(:getc)
324
- out = []
325
- lambda {
326
- grammar_ruby0[out, i]
327
- out[0]
328
- }
328
+ grammar_ruby0[out=[], StringIO.new(s).method(:getc)] && out[0]
329
329
  }
330
330
  }
331
331
 
@@ -337,18 +337,8 @@ benchmark('Peggy', 'json.peggy.rb') {
337
337
  peggy = JSON.new
338
338
  lambda { |s|
339
339
  peggy.source_text = s
340
- lambda {
341
- peggy.parse?(:value)
342
- peggy.to_ruby
343
- }
344
- }
345
- }
346
-
347
- benchmark('json/ext', json_ext) {
348
- gem 'json'
349
- require 'json/ext'
350
- lambda { |s|
351
- JSON::Ext::Parser.new(s).method(:parse)
340
+ peggy.parse?(:value)
341
+ peggy.to_ruby
352
342
  }
353
343
  }
354
344
 
@@ -0,0 +1,268 @@
1
+ #
2
+ # DO NOT MODIFY!!!!
3
+ # This file is automatically generated by racc 1.4.5
4
+ # from racc grammer file "json.y".
5
+ #
6
+
7
+ require 'racc/parser'
8
+
9
+
10
+ class JSON < Racc::Parser
11
+
12
+ module_eval <<'..end json.y modeval..idf8edf52a5d', 'json.y', 26
13
+
14
+ def parse(input)
15
+ @input = input
16
+ yyparse self, :scan
17
+ end
18
+
19
+ private
20
+
21
+ def scan
22
+ input = @input
23
+ while true
24
+ if input.scan(/\s+/)
25
+ elsif input.scan(/"/)
26
+ s = ""
27
+ while true
28
+ if text=input.scan(/[^\\"]+/)
29
+ s.concat(text)
30
+ elsif input.scan(/\\/)
31
+ case (ch=input.getch[0])
32
+ when ?b ; s << ?\b
33
+ when ?f ; s << ?\f
34
+ when ?n ; s << ?\n
35
+ when ?r ; s << ?\r
36
+ when ?t ; s << ?\t
37
+ when ?u
38
+ text = input.scan(/[0-9a-fA-F]{4}/) or raise("expected hex*4")
39
+ s << text.to_i(16)
40
+ else
41
+ s << ch
42
+ end
43
+ else
44
+ break
45
+ end
46
+ end
47
+ input.scan(/"/) or raise("expected quote")
48
+ yield :STRING, s
49
+ elsif text=input.scan(/-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?\s*/)
50
+ yield :NUMBER, eval(text)
51
+ elsif text=input.scan(/true/)
52
+ yield :BOOLEAN, true
53
+ elsif text=input.scan(/false/)
54
+ yield :BOOLEAN, false
55
+ elsif text=input.scan(/null/)
56
+ yield :BOOLEAN, nil
57
+ elsif text=input.scan(/./)
58
+ yield text, text
59
+ else
60
+ break
61
+ end
62
+ end
63
+ yield false, '$'
64
+ end
65
+
66
+ ..end json.y modeval..idf8edf52a5d
67
+
68
+ ##### racc 1.4.5 generates ###
69
+
70
+ racc_reduce_table = [
71
+ 0, 0, :racc_error,
72
+ 1, 12, :_reduce_none,
73
+ 1, 12, :_reduce_none,
74
+ 1, 12, :_reduce_none,
75
+ 1, 12, :_reduce_none,
76
+ 1, 12, :_reduce_none,
77
+ 3, 13, :_reduce_6,
78
+ 2, 13, :_reduce_7,
79
+ 3, 15, :_reduce_8,
80
+ 5, 15, :_reduce_9,
81
+ 3, 14, :_reduce_10,
82
+ 2, 14, :_reduce_11,
83
+ 1, 16, :_reduce_12,
84
+ 3, 16, :_reduce_13 ]
85
+
86
+ racc_reduce_n = 14
87
+
88
+ racc_shift_n = 27
89
+
90
+ racc_action_table = [
91
+ 3, 4, 6, 7, 18, 23, 19, 8, 15, 3,
92
+ 4, 6, 7, 20, 16, 21, 8, 3, 4, 6,
93
+ 7, 9, 25, 17, 8, 3, 4, 6, 7, nil,
94
+ nil, nil, 8, 3, 4, 6, 7, 10, nil, nil,
95
+ 8, 12 ]
96
+
97
+ racc_action_check = [
98
+ 8, 8, 8, 8, 11, 19, 11, 8, 8, 17,
99
+ 17, 17, 17, 14, 9, 14, 17, 20, 20, 20,
100
+ 20, 1, 23, 10, 20, 0, 0, 0, 0, nil,
101
+ nil, nil, 0, 25, 25, 25, 25, 7, nil, nil,
102
+ 25, 7 ]
103
+
104
+ racc_action_pointer = [
105
+ 23, 21, nil, nil, nil, nil, nil, 35, -2, 14,
106
+ 16, -2, nil, nil, 5, nil, nil, 7, nil, 3,
107
+ 15, nil, nil, 15, nil, 31, nil ]
108
+
109
+ racc_action_default = [
110
+ -14, -14, -2, -1, -4, -3, -5, -14, -14, -14,
111
+ -14, -14, -7, -12, -14, -11, 27, -14, -6, -14,
112
+ -14, -10, -8, -14, -13, -14, -9 ]
113
+
114
+ racc_goto_table = [
115
+ 1, 11, 14, nil, nil, nil, nil, nil, 13, nil,
116
+ nil, nil, nil, nil, nil, nil, nil, 22, nil, nil,
117
+ 24, nil, nil, nil, nil, 26 ]
118
+
119
+ racc_goto_check = [
120
+ 1, 4, 5, nil, nil, nil, nil, nil, 1, nil,
121
+ nil, nil, nil, nil, nil, nil, nil, 1, nil, nil,
122
+ 1, nil, nil, nil, nil, 1 ]
123
+
124
+ racc_goto_pointer = [
125
+ nil, 0, nil, nil, -6, -6 ]
126
+
127
+ racc_goto_default = [
128
+ nil, nil, 2, 5, nil, nil ]
129
+
130
+ racc_token_table = {
131
+ false => 0,
132
+ Object.new => 1,
133
+ :STRING => 2,
134
+ :BOOLEAN => 3,
135
+ :NUMBER => 4,
136
+ "{" => 5,
137
+ "}" => 6,
138
+ ":" => 7,
139
+ "," => 8,
140
+ "[" => 9,
141
+ "]" => 10 }
142
+
143
+ racc_use_result_var = false
144
+
145
+ racc_nt_base = 11
146
+
147
+ Racc_arg = [
148
+ racc_action_table,
149
+ racc_action_check,
150
+ racc_action_default,
151
+ racc_action_pointer,
152
+ racc_goto_table,
153
+ racc_goto_check,
154
+ racc_goto_default,
155
+ racc_goto_pointer,
156
+ racc_nt_base,
157
+ racc_reduce_table,
158
+ racc_token_table,
159
+ racc_shift_n,
160
+ racc_reduce_n,
161
+ racc_use_result_var ]
162
+
163
+ Racc_token_to_s_table = [
164
+ '$end',
165
+ 'error',
166
+ 'STRING',
167
+ 'BOOLEAN',
168
+ 'NUMBER',
169
+ '"{"',
170
+ '"}"',
171
+ '":"',
172
+ '","',
173
+ '"["',
174
+ '"]"',
175
+ '$start',
176
+ 'value',
177
+ 'object',
178
+ 'array',
179
+ 'members',
180
+ 'elements']
181
+
182
+ Racc_debug_parser = false
183
+
184
+ ##### racc system variables end #####
185
+
186
+ # reduce 0 omitted
187
+
188
+ # reduce 1 omitted
189
+
190
+ # reduce 2 omitted
191
+
192
+ # reduce 3 omitted
193
+
194
+ # reduce 4 omitted
195
+
196
+ # reduce 5 omitted
197
+
198
+ module_eval <<'.,.,', 'json.y', 10
199
+ def _reduce_6( val, _values)
200
+ val[1]
201
+ end
202
+ .,.,
203
+
204
+ module_eval <<'.,.,', 'json.y', 11
205
+ def _reduce_7( val, _values)
206
+ {}
207
+ end
208
+ .,.,
209
+
210
+ module_eval <<'.,.,', 'json.y', 13
211
+ def _reduce_8( val, _values)
212
+ {val[0] => val[2]}
213
+ end
214
+ .,.,
215
+
216
+ module_eval <<'.,.,', 'json.y', 14
217
+ def _reduce_9( val, _values)
218
+ val[0][val[2]] = val[4]; val[0]
219
+ end
220
+ .,.,
221
+
222
+ module_eval <<'.,.,', 'json.y', 16
223
+ def _reduce_10( val, _values)
224
+ val[1]
225
+ end
226
+ .,.,
227
+
228
+ module_eval <<'.,.,', 'json.y', 17
229
+ def _reduce_11( val, _values)
230
+ []
231
+ end
232
+ .,.,
233
+
234
+ module_eval <<'.,.,', 'json.y', 19
235
+ def _reduce_12( val, _values)
236
+ val
237
+ end
238
+ .,.,
239
+
240
+ module_eval <<'.,.,', 'json.y', 20
241
+ def _reduce_13( val, _values)
242
+ val[0] << val[2]
243
+ end
244
+ .,.,
245
+
246
+ def _reduce_none( val, _values)
247
+ val[0]
248
+ end
249
+
250
+ end # class JSON
251
+
252
+
253
+ if $0 == __FILE__
254
+ src = <<EOS
255
+ {
256
+ "name" : null,
257
+ "id" : 12.3
258
+ }
259
+ EOS
260
+ require 'strscan'
261
+ puts 'Parsing (String):'
262
+ print src
263
+ puts
264
+ puts 'Result (Ruby Object):'
265
+ p JSON_RACC.new.parse(StringScanner.new(src))
266
+ end
267
+
268
+
@@ -6,8 +6,8 @@ class Ruby
6
6
  # compile a grammar to a parser. The parser can be called with
7
7
  # an input (#[] to get next element) and an output (#<< appends
8
8
  # to it).
9
- def self.compile(gram)
10
- code = new.dump(gram)
9
+ def self.compile(gram, input_method=:[])
10
+ code = new(input_method).dump(gram)
11
11
  #p(code)
12
12
  #code.lined
13
13
  eval(code.to_s).new
@@ -71,15 +71,19 @@ class Ruby
71
71
  @output << item
72
72
  end
73
73
 
74
- def initialize
74
+ def initialize(input_method=:[])
75
75
  @followed = 0
76
76
  @consumed = 0
77
77
  @output0 = Code::Primary.new("o")
78
78
  @output = @output0
79
+ @output_init = nil
79
80
  @input0 = Code::Primary.new("i")
80
81
  @input = @input0
82
+ @input_method = input_method
81
83
  @lookahead0 = Code::Primary.new("la")
82
84
  @lookahead = @lookahead0
85
+ @lookahead_get = Code::Self.at(Code[0])
86
+ @lookahead_set = Code::Self[Code[0]]
83
87
  @fail0 = Code::Primary.new("f")
84
88
  @fail = @fail0
85
89
  @failure_hard = lambda { |i, la, *expected|
@@ -99,7 +103,7 @@ class Ruby
99
103
  }
100
104
  @method_definitions = []
101
105
  @methods = {}
102
- @consume = generate_consume
106
+ @consume = true
103
107
  @void = nil
104
108
  @scope = nil
105
109
  end
@@ -110,14 +114,6 @@ class Ruby
110
114
  @assignments << var._assign(code)
111
115
  end
112
116
 
113
- def generate_consume
114
- @consume = Code::SharedSteps.new(
115
- (@output ? [@output << @lookahead] : []) <<
116
- @lookahead._assign(@input[]) <<
117
- Code::True
118
- )
119
- end
120
-
121
117
  class CodeProxy
122
118
  include Enumerable
123
119
  def initialize(code)
@@ -167,24 +163,25 @@ class Ruby
167
163
  @scope = "call"
168
164
  top = gram[self]
169
165
  @scope = scope
170
- CodeProxy.new(Code[Class].new { ||
166
+ CodeProxy.new(Code[Class].new(Code[Array]) { ||
171
167
  steps = []
172
168
  @assignments.each { |assignment|
173
169
  steps << assignment
174
170
  }
171
+ steps << Code::Implicit.super(Code[1])
175
172
  steps = [Code::Steps.new(steps)._def(:initialize)] unless
176
173
  steps.empty?
177
174
  @method_definitions.each { |definition|
178
175
  steps << definition
179
176
  }
180
- steps << top._ensure(
177
+ steps << top._and {
181
178
  Code::Self.block_given?._and{
182
179
  Code::Implicit.yield(@lookahead)
183
- }
184
- )._def(:call,
180
+ }._step(Code::True)
181
+ }._def(:call,
185
182
  @output,
186
183
  @input,
187
- @lookahead._assign(@input[]),
184
+ @lookahead._assign(@input.method_missing(@input_method)),
188
185
  @fail._assign(Code::Self.lambda { |i, la, *exp|
189
186
  exp = exp[0]
190
187
  Code::Implicit.raise(
@@ -213,9 +210,23 @@ class Ruby
213
210
  end
214
211
  end
215
212
  def consume(matching, expected=nil)
216
- matching._and{@consume||Code::True}._or{failure(expected)}
213
+ if @consume
214
+ matching = matching._and {
215
+ consume = @lookahead._assign(
216
+ @input.method_missing(@input_method)
217
+ )
218
+ if @output
219
+ consume = ((@output_init ? @output._assign(@output_init) :
220
+ @output) << @lookahead).
221
+ _step(consume)
222
+ end
223
+ consume._step(Code::True)
224
+ }
225
+ end
226
+ matching._or{failure(expected)}
217
227
  ensure
218
228
  if @consume
229
+ @output_init = nil
219
230
  @failure = @failure_hard
220
231
  @consumed += 1
221
232
  end
@@ -261,14 +272,33 @@ class Ruby
261
272
  def alternation(gram1) # :yield: engine
262
273
  failure = @failure
263
274
  @failure = nil
264
- begin
265
- gram1[self]
266
- ensure
267
- failure1 = @failure
268
- end._or{
269
- @failure = failure
270
- yield(self)
271
- }
275
+ if output_init = @output_init
276
+ begin
277
+ gram1[self]._and {
278
+ @output_init ? @output._assign(@output_init) : Code::True
279
+ }
280
+ ensure
281
+ failure1 = @failure
282
+ output_init1 = @output_init
283
+ end._or{
284
+ @failure = failure
285
+ @output_init = output_init
286
+ code = yield(self)
287
+ if !output_init1 and @output_init
288
+ code = @output._assign(@output_init)._step(code)
289
+ end
290
+ code
291
+ }
292
+ else
293
+ begin
294
+ gram1[self]
295
+ ensure
296
+ failure1 = @failure
297
+ end._or{
298
+ @failure = failure
299
+ yield(self)
300
+ }
301
+ end
272
302
  ensure
273
303
  @failure = failure1 if failure1
274
304
  end
@@ -382,10 +412,12 @@ class Ruby
382
412
  @fail = @fail0
383
413
  @failure = nil
384
414
  @expected = []
385
- generate_consume
415
+ @consume = true
386
416
  code = inner ? recurse(inner, true, &outer) : outer[self]
387
417
  @method_definitions[i] =
388
- code._ensure(Code::Implicit.yield(@lookahead))._def(
418
+ code._and {
419
+ @lookahead_set._assign(@lookahead)._step(Code::True)
420
+ }._def(
389
421
  name,
390
422
  @output,
391
423
  @input,
@@ -412,9 +444,8 @@ class Ruby
412
444
  }.new
413
445
  ))
414
446
  call = Code::Self.method_missing(name, output, @input,
415
- @lookahead, @fail) {
416
- |la|
417
- @lookahead._assign(la)
447
+ @lookahead, @fail)._and {
448
+ @lookahead._assign(@lookahead_get)._step(Code::True)
418
449
  }
419
450
  if expected.empty?
420
451
  Code::Always.new(call)
@@ -496,17 +527,24 @@ class Ruby
496
527
  Code::Local.new { |buf|
497
528
  begin
498
529
  @output = buf
499
- @consume = generate_consume
500
- @output._assign(self[buf0,true])._step(
530
+ @consume = true
531
+ output_init = self[buf0,true]
532
+ if @failure
533
+ @output._assign(output_init)._step(gram[self])
534
+ else
535
+ @output_init = output_init
501
536
  gram[self]
502
- )
537
+ end
503
538
  ensure
504
539
  @followed -= 1 if block_given?
505
540
  @output = output
506
541
  @consume = consume
507
542
  end._and {
508
543
  !block_given? ? Code::True :
509
- Code::Always.new(block.arity==1 ? yield(buf) : yield(buf, self))
544
+ (@output_init ? (@output._assign(@output_init)) : Code::True).
545
+ _step(Code::Always.new(
546
+ block.arity==1 ? yield(buf) : yield(buf, self)
547
+ ))
510
548
  }
511
549
  }
512
550
  end
@@ -518,7 +556,7 @@ class Ruby
518
556
  @followed += 1 if block_given?
519
557
  begin
520
558
  @output = nil
521
- @consume = generate_consume
559
+ @consume = true
522
560
  gram[self]
523
561
  ensure
524
562
  @followed -= 1 if block_given?
@@ -547,7 +585,7 @@ class Ruby
547
585
  buf.slice!(Code[0], buf.size),
548
586
  begin
549
587
  @output = buf
550
- @consume = generate_consume
588
+ @consume = true
551
589
  @expected = []
552
590
  tokenizer[self]
553
591
  ensure
@@ -561,7 +599,7 @@ class Ruby
561
599
  begin
562
600
  @input = input1
563
601
  @lookahead = lookahead1
564
- @consume = generate_consume
602
+ @consume = true
565
603
  @expected = []
566
604
  parser[self]
567
605
  ensure
@@ -1,13 +1,14 @@
1
1
 
2
2
  require 'grammar/ruby'
3
3
  require 'rubygems'
4
+ gem 'ruby2cext'
4
5
  require 'ruby2cext/eval2c'
5
6
 
6
7
  class Grammar
7
8
  class Ruby2CExt < Ruby
8
9
 
9
- def self.compile(gram)
10
- code = new.dump(gram)
10
+ def self.compile(gram, input_method=:[])
11
+ code = new(input_method).dump(gram)
11
12
  #p(code)
12
13
  #code.lined
13
14
  Ruby2CExtension::Eval2C.new.compile_to_proc(code.to_s).call.new
@@ -0,0 +1,319 @@
1
+
2
+ require 'grammar/ruby'
3
+ require 'rubygems'
4
+ gem 'ruby2cext'
5
+ require 'ruby2cext/compiler'
6
+ require 'digest/sha1'
7
+
8
+ class Grammar
9
+ class Ruby2CExt < Ruby
10
+
11
+ def self.compile(gram, input_method=:[])
12
+ code = new(input_method).dump(gram)
13
+ ruby_code = code.to_s
14
+ #puts(code)
15
+ path = File.join(File.expand_path(
16
+ ENV["HOME"] || ENV["USERPROFILE"] || ENV["HOMEPATH"] || "."),
17
+ ".ruby2cext")
18
+ prefix = 'grammar'
19
+ name = "#{prefix}_#{Digest::SHA1.hexdigest(ruby_code)}"
20
+ gvar_name = "$__#{name}__"
21
+ compiler = Ruby2CExtension::Compiler.new(name)
22
+ compiler.add_plugins({:optimizations => :all})
23
+ compiler.add_rb_file("#{gvar_name} = #{ruby_code}", name)
24
+ c_code = compiler.to_c_code
25
+
26
+ ws = /(?:\s|\/\*.*?\*\/)/m
27
+ sym2name = []
28
+ c_code.scan(
29
+ /^\s*sym\s*\[\s*(\d+)\s*\]\s*\=\s*rb_intern\s*\(\s*\"([^\"]*)\"\s*\)/
30
+ ) { |i,ruby|
31
+ sym2name[i.to_i] = ruby;
32
+ }
33
+
34
+ #c_code.gsub!(/\b
35
+ # switch\s*\(TYPE\s*\(argv\[0\]\)\)\s*\{\s*
36
+ # case\s+T_FIXNUM:\s*
37
+ # (res\s*=.*)\s*
38
+ # break;\s*
39
+ # default:\s*
40
+ # res\s*=.*\s*
41
+ # \}
42
+ #/x, '\1')
43
+
44
+ #c_code.gsub!(/\b
45
+ # if\s*\(\!RTEST\s*\(Qtrue\)\)\s*
46
+ # break;
47
+ #/x, ';')
48
+ #c_code.gsub!(/^\b(VALUE )?while_res = Qnil;/, ';')
49
+ #c_code.gsub!(/\bres = while_res;/, ';')
50
+
51
+ ##n = 0
52
+ ##c_code.scan(/VALUE argv\[(\d+)\]/) { |i|
53
+ ## i = i[0].to_i
54
+ ## n = i if i>n
55
+ ##}
56
+ ##c_code.gsub!(/^\s*VALUE argv\[\d+\]\;\n/, '')
57
+ ##c_code.gsub!(/\bVALUE (recv\s*\=)/, '\1')
58
+ ##c_code.gsub!(/^(\s*)(VALUE res;\n)/,
59
+ ## "\\1\\2\\1VALUE recv;\nVALUE argv[#{n}];\n")
60
+ ruby2c = Hash.new { |h,k|
61
+ lambda { |header, assign, call, footer, *argv|
62
+ call.gsub!(/\brecv\b/, 'self')
63
+ "#{header}#{assign}#{call}#{footer}"
64
+ }
65
+ }
66
+ ruby2c['at'] = lambda { |header, assign, call, footer, *argv|
67
+ "res = RARRAY(self)->ptr[NUM2LONG(#{argv[0]})];"
68
+ }
69
+ ruby2c['[]='] = lambda { |header, assign, call, footer, *argv|
70
+ "res = RARRAY(self)->ptr[NUM2LONG(#{argv[0]})] = #{argv[1]};"
71
+ }
72
+ c_code.scan(
73
+ /^\s*rb_define_method\s*\(s_class\,\s*\"([^\"]*)\"\,\s*(\w+)\,\s*\-1\)/
74
+ ) { |ruby,c|
75
+ ruby2c[ruby] = lambda { |header, assign, call, footer, *argv|
76
+ "#{header}#{assign}res = #{c}(argc, argv, self);#{footer}"
77
+ }
78
+ }
79
+ c_code.gsub!(/
80
+ (\{\s*)
81
+ VALUE\s+recv\s*\=\s*self\s*\;\s*
82
+ (
83
+ const\s+int\s+argc\s*\=\s*\d+\s*\;\s*
84
+ VALUE\s+argv\s*\[\s*\d+\s*\]\s*\;\s*
85
+ (?:(?>\/\*.*?\*\/)\s*argv\s*\[\s*\d+\s*\]\s*\=\s*(?>[^\;]+\;)\s*)*
86
+ )
87
+ (
88
+ (?:res\s*\=\s*)?rb_funcall2\s*\(\s*
89
+ recv\s*\,\s*
90
+ sym\s*\[\s*(\d+)\s*\]\s*(?>\/\*.*?\*\/)\s*\,\s*
91
+ argc\s*\,\s*
92
+ argv\s*\)\s*\;
93
+ (?:\s*res\s*=\s*argv\s*\[\s*argc\s*\-\s*1\s*\]\s*\;)?
94
+ )
95
+ (\s*\})
96
+ /xm) { |match|
97
+ header = $1
98
+ recv = $2
99
+ assign = $2
100
+ call = $3
101
+ symnum = $4.to_i
102
+ footer = $5
103
+ ruby = sym2name[symnum]
104
+ c = ruby2c[ruby]
105
+ argv = []
106
+ assign.scan(/argv#{ws}*\[#{ws}*(\d+)#{ws}*\]#{ws}*\=#{ws}*([^\;]+)/) {
107
+ |i,arg|
108
+ argv[i.to_i] = arg
109
+ }
110
+ c[header, assign, call, footer, *argv]
111
+ }
112
+
113
+ c_code.gsub!(/(?=\bstatic\s+BUILTINOPT_FP\s+builtinopt_method_lookup)/) {
114
+ %q{
115
+ #include <stdarg.h>
116
+ typedef struct {
117
+ BUILTINOPT_FP fp;
118
+ void* data;
119
+ } ruby_method;
120
+ static VALUE normal_call0(VALUE recv, ruby_method* m) {
121
+ return rb_funcall3(recv, (ID)(m->data), 0, 0);
122
+ }
123
+ static VALUE remember_call0(VALUE recv, ruby_method* m) {
124
+ VALUE klass = CLASS_OF(recv);
125
+ NODE* body;
126
+ while (!st_lookup(RCLASS(klass)->m_tbl, (ID)(m->data),
127
+ (st_data_t *)&body))
128
+ {
129
+ klass = RCLASS(klass)->super;
130
+ if (!klass) {
131
+ m->fp = &normal_call0;
132
+ return rb_funcall3(recv, (ID)(m->data), 0, 0);
133
+ }
134
+ }
135
+ body = body->nd_body;
136
+ if (nd_type(body)==NODE_FBODY) body = body->nd_head;
137
+ if (nd_type(body)==NODE_CFUNC && body->nd_argc==0) {
138
+ m->fp = body->nd_cfnc;
139
+ return (*(m->fp))(recv, m);
140
+ } else {
141
+ m->fp = &normal_call0;
142
+ return rb_funcall3(recv, (ID)(m->data), 0, 0);
143
+ }
144
+ }
145
+ static ruby_method next_input;
146
+ }
147
+ }
148
+
149
+ input_sym_num = nil
150
+ c_code.gsub!(/\b
151
+ rb_funcall3\s*\(\s*
152
+ lvar\s*\[\s*1\s*\]\s*,\s*
153
+ sym\s*\[\s*(\d+)\s*\]\s*(?>\/\*.*?\*\/)\s*,\s*
154
+ 0\s*,\s*
155
+ 0\s*\)
156
+ /xm) { |match|
157
+ input_sym_num = $1.to_i unless input_sym_num
158
+ (input_sym_num!=$1.to_i) ? match :
159
+ "(*next_input.fp)(lvar[1], &next_input)"
160
+ }
161
+ if input_sym_num
162
+ #c_code.gsub!(/(\bVALUE\s+lvar\s*\[\s*\d+\s*\]\s*\;)(\s*)/) {
163
+ # "#{$1}#{$2}ruby_method next_input;#{$2}"
164
+ #}
165
+ c_code.gsub!(/\bif\s*\(\s*meth_argc\s*>\s*2\s*\)/) { |match|
166
+ #c_code.gsub!(/\blvar\s*\[\s*1\s*\]\s*\=/) { |match|
167
+ "next_input.fp = &remember_call0; " +
168
+ "next_input.data = (void*)sym[#{input_sym_num}]; " +
169
+ match
170
+ }
171
+ end
172
+
173
+ builtinopt_method = {}
174
+ c_code.scan(/
175
+ \bbuiltinopt_method_tbl\s*\[\s*(\d+)\s*\]\s*\=\s*
176
+ builtinopt_method_lookup\s*\(\s*
177
+ (\w+)\s*\,\s*
178
+ (\w+)\s*\,\s*
179
+ sym\s*\[\s*(\d+)\s*\]\s*(?>\/\*.*?\*\/)\s*\,\s*
180
+ (-?\d+)\s*\)\s*\;
181
+ /xm) { |i,klass,origin,sym,arity|
182
+ builtinopt_method[[klass,sym2name[sym.to_i]]] = [i.to_i,arity.to_i]
183
+ }
184
+
185
+ #begin
186
+ # lvars = []
187
+ # done = true
188
+ # c_code.gsub!(/
189
+ # \blvar\s*\[\s*(\d+)\s*\]\s*\=\s*(\S\w*)
190
+ # |
191
+ # \{\s*
192
+ # VALUE\s+recv\s*\=\s*
193
+ # ((?:\(\s*)?lvar\s*\[\s*(\d+)\s*\]
194
+ # (?:\s*\=\s*(\S\w*)[^;]*?\))?)\s*\;\s*
195
+ # VALUE\s+argv\s*\[\s*1\s*\]\s*\;\s*
196
+ # (?>\/\*.*?\*\/)\s*
197
+ # (
198
+ # (?>\/\*.*?\*\/)\s*
199
+ # \{[^}]*\}\s*
200
+ # )?
201
+ # argv\s*\[\s*0\s*\]\s*\=\s*([^;]*?)\s*\;\s*
202
+ # res\s*\=\s*builtinopt(\w+)__1\s*\(\s*
203
+ # recv\s*\,\s*
204
+ # argv\s*
205
+ # \)\s*\;\s*
206
+ # \}
207
+ # /xm) { |match|
208
+ # if $1
209
+ # lvars[$1.to_i] = $2
210
+ # match
211
+ # else
212
+ # recv = $4.to_i
213
+ # lvars[recv] = $5 if $5
214
+ # klass = case lvars[recv]
215
+ # when "rb_ary_new"
216
+ # "rb_cArray"
217
+ # when "rb_str_new3"
218
+ # "rb_cString"
219
+ # else
220
+ # nil
221
+ # end
222
+ # recv = $3
223
+ # arg0 = $6||""
224
+ # arg = $7
225
+ # meth = case $8
226
+ # when "op_lshift"
227
+ # "<<"
228
+ # when /meth_(.*)/
229
+ # $1
230
+ # end
231
+ # builtin,arity = builtinopt_method[[klass, meth]]
232
+ # if builtin && arity==-1
233
+ # done = false
234
+ # arg0 +
235
+ # "{ " \
236
+ # "VALUE argv[1]; " \
237
+ # "argv[0] = #{arg}; " \
238
+ # "res = (*(builtinopt_method_tbl[#{builtin}]))(1, #{recv}, argv);" \
239
+ # "}"
240
+ # elsif builtin && arity==1
241
+ # done = false
242
+ # arg0 +
243
+ # "res = (*(builtinopt_method_tbl[#{builtin}]))(#{recv}, #{arg});"
244
+ # else
245
+ # match
246
+ # end
247
+ # end
248
+ # }
249
+ #end until done
250
+ #c_code.gsub!(/
251
+ # (\blvar\s*\[\s*(\d+)\s*\]\s*\=\s*)(
252
+ # builtinopt(\w+)__0\s*\(\s*
253
+ # lvar\s*\[\s*(\d+)\s*\]\s*
254
+ # \)
255
+ # |
256
+ # \S\w*
257
+ # )
258
+ #/xm) { |match|
259
+ # if !$4
260
+ # lvars[$2.to_i] = $3
261
+ # match
262
+ # else
263
+ # recv = $5.to_i
264
+ # klass = case lvars[recv]
265
+ # when "rb_ary_new"
266
+ # "rb_cArray"
267
+ # when "rb_str_new3"
268
+ # "rb_cString"
269
+ # else
270
+ # nil
271
+ # end
272
+ # header = $1
273
+ # recv = "lvar[#{recv}]"
274
+ # meth = case $4
275
+ # when "op_lshift"
276
+ # "<<"
277
+ # when /meth_(.*)/
278
+ # $1
279
+ # end
280
+ # builtin,arity = builtinopt_method[[klass, meth]]
281
+ # if builtin && arity==-1
282
+ # done = false
283
+ # header +
284
+ # "(*(builtinopt_method_tbl[#{builtin}]))(0, #{recv}, 0)"
285
+ # elsif builtin && arity==0
286
+ # done = false
287
+ # header +
288
+ # "(*(builtinopt_method_tbl[#{builtin}]))(#{recv})"
289
+ # else
290
+ # match
291
+ # end
292
+ # end
293
+ #}
294
+
295
+ c_filename = File.join(path, "#{name}.c")
296
+ File.open(c_filename, "w") { |f| f.puts(c_code) }
297
+ #system("indent -fc1 -st #{c_filename}")
298
+ #p ::Config::CONFIG
299
+
300
+ dl_filename = File.join(path,
301
+ "#{name}.#{Ruby2CExtension::Compiler::DLEXT}")
302
+ cflags = ::Config::CONFIG['CFLAGS']
303
+ #::Config::CONFIG['CFLAGS'] = cflags.gsub(/-g /,'') + ' -O3'
304
+ begin
305
+ Ruby2CExtension::Compiler.compile_c_file_to_dllib(c_filename)
306
+ ensure
307
+ ::Config::CONFIG['CFLAGS'] = cflags
308
+ end == dl_filename or
309
+ raise(Ruby2CExtension::Ruby2CExtError::Bug,
310
+ "unexpected return value from compile_c_file_to_dllib")
311
+
312
+ require(dl_filename)
313
+ eval(gvar_name).new
314
+ end
315
+
316
+ end
317
+ end
318
+
319
+
@@ -5,8 +5,8 @@ require 'rubygems'
5
5
  class Grammar
6
6
  class RubyCall < Ruby
7
7
 
8
- def self.compile(gram)
9
- code = new.dump(gram)
8
+ def self.compile(gram, input_method=:[])
9
+ code = new(input_method).dump(gram)
10
10
  #p(code)
11
11
  #code.lined
12
12
  eval(code.to_s).new
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
3
3
  specification_version: 1
4
4
  name: grammar
5
5
  version: !ruby/object:Gem::Version
6
- version: "0.8"
7
- date: 2008-09-05 00:00:00 -05:00
6
+ version: 0.8.1
7
+ date: 2008-09-17 00:00:00 -05:00
8
8
  summary: BNF-like grammar specified directly in ruby
9
9
  require_paths:
10
10
  - lib
@@ -34,6 +34,7 @@ files:
34
34
  - lib/grammar/ruby0.rb
35
35
  - lib/grammar/ruby.rb
36
36
  - lib/grammar/rubycall.rb
37
+ - lib/grammar/ruby2cext_hack.rb
37
38
  - lib/grammar/ruby/code.rb
38
39
  - test/molecules.rb
39
40
  - test/atoms.rb
@@ -46,6 +47,7 @@ files:
46
47
  - test/test_demo.rb
47
48
  - test/basic.rb
48
49
  - benchmark/json.benchmark.rb
50
+ - benchmark/json.racc.rb
49
51
  - benchmark/json.grammar.rb
50
52
  - benchmark/json.grammar0_5.rb
51
53
  - benchmark/json.ll1.rb