rsec 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
data/bench/bench.rb ADDED
@@ -0,0 +1,60 @@
1
+ # Compare performance between rsec and treetop
2
+ # NOTE simple parser doesn't require much backtracking, so treetop's caching is sure to fail.
3
+ # Next step is to compare really complex parsers.
4
+
5
+ # string to be parsed
6
+ s = '(3+24/5)/10-3*4+((82321+12-3)-3*4+(82321+12-3))/5'
7
+
8
+ # rsec
9
+ $:.unshift "#{File.dirname(__FILE__)}/../lib"
10
+ $:.unshift "#{File.dirname(__FILE__)}/../ext"
11
+ require "#{File.dirname(__FILE__)}/../examples/arithmetic"
12
+
13
+ # treetop
14
+ require "treetop"
15
+ require "#{File.dirname(__FILE__)}/little.rb"
16
+
17
+ require "benchmark"
18
+
19
+ def measure &proc
20
+ puts proc[]
21
+ 200.times &proc
22
+ puts((Benchmark.measure{
23
+ 1000.times &proc
24
+ }), '')
25
+ end
26
+
27
+ # ------------------------------------------------------------------------------
28
+
29
+ puts ''
30
+ puts Benchmark::CAPTION
31
+ puts ''
32
+
33
+ print 'rsec result:', "\t"
34
+ p = arithmetic()
35
+ measure{ p.parse! s }
36
+
37
+ print 'treetop result:', "\t"
38
+ t = ArithmeticParser.new
39
+ measure{ t.parse(s).value }
40
+
41
+ puts 'treetop without calculation'
42
+ t = ArithmeticParser.new
43
+ measure{ t.parse s }
44
+
45
+ PARSEC_ARITH_SO = "#{File.dirname(__FILE__)}/parsec/Arithmetic.so"
46
+ if File.exist?(PARSEC_ARITH_SO)
47
+ require 'dl/import'
48
+ require 'dl/types'
49
+ module Arithmetic
50
+ extend DL::Importer
51
+ dlload PARSEC_ARITH_SO
52
+ extern "long calculate(char *)", :stdcall
53
+ extern "long donothing(char *)", :stdcall
54
+ end
55
+ print 'Haskell Parsec result:', "\t"
56
+ measure{ Arithmetic.calculate s }
57
+ else
58
+ puts 'Haskell Parsec benchmark requires ghc installation. cd bench/parsec and run make.sh(unix) or make.bat(windows)'
59
+ end
60
+
data/bench/little.rb ADDED
@@ -0,0 +1,328 @@
1
+ # Autogenerated from a Treetop grammar. Edits may be lost.
2
+
3
+
4
+ module Arithmetic
5
+ include Treetop::Runtime
6
+
7
+ def root
8
+ @root || :expr
9
+ end
10
+
11
+ module Expr0
12
+ def op
13
+ elements[0]
14
+ end
15
+
16
+ def right
17
+ elements[1]
18
+ end
19
+ end
20
+
21
+ module Expr1
22
+ def left
23
+ elements[0]
24
+ end
25
+
26
+ def right_opt
27
+ elements[1]
28
+ end
29
+ end
30
+
31
+ module Expr2
32
+ def value
33
+ right_opt.elements.inject(left.value) {|acc, plus_and_right|
34
+ acc.send \
35
+ plus_and_right.op.text_value,
36
+ plus_and_right.right.value
37
+ }
38
+ end
39
+ end
40
+
41
+ def _nt_expr
42
+ start_index = index
43
+ if node_cache[:expr].has_key?(index)
44
+ cached = node_cache[:expr][index]
45
+ if cached
46
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
47
+ @index = cached.interval.end
48
+ end
49
+ return cached
50
+ end
51
+
52
+ i0, s0 = index, []
53
+ r1 = _nt_term
54
+ s0 << r1
55
+ if r1
56
+ s2, i2 = [], index
57
+ loop do
58
+ i3, s3 = index, []
59
+ if has_terminal?('\G[\\+\\-]', true, index)
60
+ r4 = true
61
+ @index += 1
62
+ else
63
+ r4 = nil
64
+ end
65
+ s3 << r4
66
+ if r4
67
+ r5 = _nt_term
68
+ s3 << r5
69
+ end
70
+ if s3.last
71
+ r3 = instantiate_node(SyntaxNode,input, i3...index, s3)
72
+ r3.extend(Expr0)
73
+ else
74
+ @index = i3
75
+ r3 = nil
76
+ end
77
+ if r3
78
+ s2 << r3
79
+ else
80
+ break
81
+ end
82
+ end
83
+ r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
84
+ s0 << r2
85
+ end
86
+ if s0.last
87
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
88
+ r0.extend(Expr1)
89
+ r0.extend(Expr2)
90
+ else
91
+ @index = i0
92
+ r0 = nil
93
+ end
94
+
95
+ node_cache[:expr][start_index] = r0
96
+
97
+ r0
98
+ end
99
+
100
+ module Term0
101
+ def op
102
+ elements[0]
103
+ end
104
+
105
+ def right
106
+ elements[1]
107
+ end
108
+ end
109
+
110
+ module Term1
111
+ def left
112
+ elements[0]
113
+ end
114
+
115
+ def right_opt
116
+ elements[1]
117
+ end
118
+ end
119
+
120
+ module Term2
121
+ def value
122
+ right_opt.elements.inject(left.value) {|acc, mul_and_right|
123
+ acc.send \
124
+ mul_and_right.op.text_value,
125
+ mul_and_right.right.value
126
+ }
127
+ end
128
+ end
129
+
130
+ def _nt_term
131
+ start_index = index
132
+ if node_cache[:term].has_key?(index)
133
+ cached = node_cache[:term][index]
134
+ if cached
135
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
136
+ @index = cached.interval.end
137
+ end
138
+ return cached
139
+ end
140
+
141
+ i0, s0 = index, []
142
+ r1 = _nt_factor
143
+ s0 << r1
144
+ if r1
145
+ s2, i2 = [], index
146
+ loop do
147
+ i3, s3 = index, []
148
+ if has_terminal?('\G[\\*\\/]', true, index)
149
+ r4 = true
150
+ @index += 1
151
+ else
152
+ r4 = nil
153
+ end
154
+ s3 << r4
155
+ if r4
156
+ r5 = _nt_factor
157
+ s3 << r5
158
+ end
159
+ if s3.last
160
+ r3 = instantiate_node(SyntaxNode,input, i3...index, s3)
161
+ r3.extend(Term0)
162
+ else
163
+ @index = i3
164
+ r3 = nil
165
+ end
166
+ if r3
167
+ s2 << r3
168
+ else
169
+ break
170
+ end
171
+ end
172
+ r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
173
+ s0 << r2
174
+ end
175
+ if s0.last
176
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
177
+ r0.extend(Term1)
178
+ r0.extend(Term2)
179
+ else
180
+ @index = i0
181
+ r0 = nil
182
+ end
183
+
184
+ node_cache[:term][start_index] = r0
185
+
186
+ r0
187
+ end
188
+
189
+ module Factor0
190
+ def expr
191
+ elements[1]
192
+ end
193
+
194
+ end
195
+
196
+ module Factor1
197
+ def value
198
+ expr.value
199
+ end
200
+ end
201
+
202
+ def _nt_factor
203
+ start_index = index
204
+ if node_cache[:factor].has_key?(index)
205
+ cached = node_cache[:factor][index]
206
+ if cached
207
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
208
+ @index = cached.interval.end
209
+ end
210
+ return cached
211
+ end
212
+
213
+ i0 = index
214
+ i1, s1 = index, []
215
+ if has_terminal?('(', false, index)
216
+ r2 = instantiate_node(SyntaxNode,input, index...(index + 1))
217
+ @index += 1
218
+ else
219
+ terminal_parse_failure('(')
220
+ r2 = nil
221
+ end
222
+ s1 << r2
223
+ if r2
224
+ r3 = _nt_expr
225
+ s1 << r3
226
+ if r3
227
+ if has_terminal?(')', false, index)
228
+ r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
229
+ @index += 1
230
+ else
231
+ terminal_parse_failure(')')
232
+ r4 = nil
233
+ end
234
+ s1 << r4
235
+ end
236
+ end
237
+ if s1.last
238
+ r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
239
+ r1.extend(Factor0)
240
+ r1.extend(Factor1)
241
+ else
242
+ @index = i1
243
+ r1 = nil
244
+ end
245
+ if r1
246
+ r0 = r1
247
+ else
248
+ r5 = _nt_number
249
+ if r5
250
+ r0 = r5
251
+ else
252
+ @index = i0
253
+ r0 = nil
254
+ end
255
+ end
256
+
257
+ node_cache[:factor][start_index] = r0
258
+
259
+ r0
260
+ end
261
+
262
+ module Number0
263
+ end
264
+
265
+ module Number1
266
+ def value
267
+ text_value.to_f
268
+ end
269
+ end
270
+
271
+ def _nt_number
272
+ start_index = index
273
+ if node_cache[:number].has_key?(index)
274
+ cached = node_cache[:number][index]
275
+ if cached
276
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
277
+ @index = cached.interval.end
278
+ end
279
+ return cached
280
+ end
281
+
282
+ i0, s0 = index, []
283
+ if has_terminal?('\G[1-9]', true, index)
284
+ r1 = true
285
+ @index += 1
286
+ else
287
+ r1 = nil
288
+ end
289
+ s0 << r1
290
+ if r1
291
+ s2, i2 = [], index
292
+ loop do
293
+ if has_terminal?('\G[0-9]', true, index)
294
+ r3 = true
295
+ @index += 1
296
+ else
297
+ r3 = nil
298
+ end
299
+ if r3
300
+ s2 << r3
301
+ else
302
+ break
303
+ end
304
+ end
305
+ r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
306
+ s0 << r2
307
+ end
308
+ if s0.last
309
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
310
+ r0.extend(Number0)
311
+ r0.extend(Number1)
312
+ else
313
+ @index = i0
314
+ r0 = nil
315
+ end
316
+
317
+ node_cache[:number][start_index] = r0
318
+
319
+ r0
320
+ end
321
+
322
+ end
323
+
324
+ class ArithmeticParser < Treetop::Runtime::CompiledParser
325
+ include Arithmetic
326
+ end
327
+
328
+
data/bench/profile.rb ADDED
@@ -0,0 +1,14 @@
1
+ # string to be parsed
2
+ s = '(3+24/5)/10-3*4+((82321+12-3)-3*4+(82321+12-3))/5'
3
+
4
+ # rsec
5
+ $:.unshift "#{File.dirname(__FILE__)}/../lib"
6
+ $:.unshift "#{File.dirname(__FILE__)}/../ext"
7
+ require "#{File.dirname(__FILE__)}/../examples/arithmetic"
8
+
9
+ p = arithmetic
10
+
11
+ require "profile"
12
+ 1000.times{
13
+ p.parse s
14
+ }
@@ -0,0 +1,28 @@
1
+ # arithmetic parser
2
+
3
+ require "rsec"
4
+
5
+ include Rsec::Helpers
6
+
7
+ def arithmetic
8
+ calculate = proc do |(p, *ps)|
9
+ ps.each_slice(2).inject(p) do |left, (op, right)|
10
+ left.send op, right
11
+ end
12
+ end
13
+
14
+ num = prim(:double).fail 'number'
15
+ paren = '('.r >> lazy{expr} << ')'
16
+ factor = num | paren
17
+ term = factor.join(one_of_('*/%').fail 'operator').map &calculate
18
+ expr = term.join(one_of_('+-').fail 'operator').map &calculate
19
+ expr.eof
20
+ end
21
+
22
+ if __FILE__ == $PROGRAM_NAME
23
+ print '1+ 2*4 = '
24
+ p arithmetic.parse! '1+ 2*4' #=> 9
25
+ print '1+ 2*/4 = '
26
+ p arithmetic.parse! '1+ 2*/4' #=> syntax error
27
+ end
28
+
data/examples/bnf.rb ADDED
@@ -0,0 +1,31 @@
1
+ # BNF grammar parser
2
+ # http://en.wikipedia.org/wiki/Backus-Naur_form
3
+
4
+ require "rsec"
5
+
6
+ include Rsec::Helpers
7
+
8
+ def bnf
9
+ nbsp = /[\ \t]*/.r
10
+ spacee = /\s*/.r # include \n
11
+ literal = /".*?"|'.*?'/.r
12
+ rule_name = /\<.*?\>/
13
+ term = literal | rule_name
14
+ list = term.join(nbsp).even
15
+ expr = list.join seq(nbsp, '|', nbsp)[1]
16
+ rule = seq_ rule_name, '::=', expr
17
+ spacee.join(rule).eof
18
+ end
19
+
20
+ require "pp"
21
+ pp bnf.parse! DATA.read
22
+
23
+ __END__
24
+ <syntax> ::= <rule> | <rule> <syntax>
25
+ <rule> ::= <opt-whitespace> "<" <rule-name> ">" <opt-whitespace> "::=" <opt-whitespace> <expression> <line-end>
26
+ <opt-whitespace> ::= " " <opt-whitespace> | ""
27
+ <expression> ::= <list> | <list> "|" <expression>
28
+ <line-end> ::= <opt-whitespace> <EOL> | <line-end> <line-end>
29
+ <list> ::= <term> | <term> <opt-whitespace> <list>
30
+ <term> ::= <literal> | "<" <rule-name> ">"
31
+ <literal> ::= '"' <text> '"' | "'" <text> "'"