grammar 0.8 → 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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