rexical 1.0.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rexical might be problematic. Click here for more details.

@@ -0,0 +1,73 @@
1
+ Rexical README
2
+ ===========
3
+
4
+ Rexical �� Ruby �Τ���Υ�����ʥ����ͥ졼���Ǥ���
5
+ lex �� Ruby �Ǥ��������ޤ���
6
+ Racc �ȤȤ�˻Ȥ��褦���߷פ���Ƥ��ޤ���
7
+
8
+
9
+ ɬ�״Ķ�
10
+ --------
11
+
12
+ * ruby 1.8 �ʹ�
13
+
14
+
15
+ ���󥹥ȡ���
16
+ ------------
17
+
18
+ �ѥå������Υȥåץǥ��쥯�ȥ�Ǽ��Τ褦�����Ϥ��Ƥ���������
19
+ ($ ���̾�桼����# �ϥ롼�ȤΥץ���ץȤǤ�)
20
+
21
+ $ ruby setup.rb config
22
+ $ ruby setup.rb setup
23
+ ($ su)
24
+ # ruby setup.rb install
25
+
26
+ ������̾�Υѥ��� Racc �����󥹥ȡ��뤵��ޤ�����ʬ�ι���
27
+ �ʥǥ��쥯�ȥ�˥��󥹥ȡ��뤷�����Ȥ��ϡ�setup.rb config ��
28
+ �Ƽ索�ץ�����Ĥ��Ƽ¹Ԥ��Ƥ������������ץ����Υꥹ�Ȥ�
29
+
30
+ $ ruby setup.rb --help
31
+
32
+ �Ǹ����ޤ���
33
+
34
+
35
+ �ƥ���
36
+ ------
37
+
38
+ sample/ �ʲ��ˤ����Ĥ� Rexical ��ʸˡ�ե�����Υ���ץ뤬�Ѱ�
39
+ ���Ƥ���ޤ����ʲ���¹Ԥ��Ƥ���������
40
+
41
+ $ rex sample1.rex --stub
42
+ $ ruby sample1.rex.rb sample1.c
43
+
44
+ $ rex sample2.rex --stub
45
+ $ ruby sample2.rex.rb sample2.bas
46
+
47
+ $ racc calc3.racc
48
+ $ rex calc3.rex
49
+ $ ruby calc3.tab.rb
50
+
51
+ Rexical �ξܤ���ʸˡ�� doc/ �ǥ��쥯�ȥ�ʲ��򸫤Ƥ���������
52
+ �ޤ�������� sample/ �ǥ��쥯�ȥ�ʲ��򸫤Ƥ���������
53
+
54
+
55
+ �饤����
56
+ ----------
57
+
58
+ �饤���󥹤� GNU Lesser General Public License (LGPL) version 2
59
+ �Ǥ����������桼�����񤤤���§�ե�����䡢Racc ������������������
60
+ Ruby ������ץȤϤ����оݳ��Ǥ��������ʥ饤���󥹤����ۤ��Ƥ���������
61
+
62
+
63
+ �Х��ʤ�
64
+ --------
65
+
66
+ Rexical ��ȤäƤ��ƥХ��餷�����ݤ����������顢�����Υ��ɥ쥹�ޤ�
67
+ �᡼��򤯤�������
68
+ ���ΤȤ��ϤǤ�������Х���Ƹ��Ǥ���ʸˡ�ե�������դ��Ƥ���������
69
+
70
+
71
+ ARIMA Yasuhiro
72
+ arima.yasuhiro@nifty.com
73
+ http://raa.ruby-lang.org/project/rex/
@@ -0,0 +1,52 @@
1
+ = Rexical
2
+
3
+ * http://github.com/tenderlove/rexical/tree/master
4
+
5
+ == DESCRIPTION
6
+
7
+ Rexical is a lexical scanner generator.
8
+ It is written in Ruby itself, and generates Ruby program.
9
+ It is designed for use with Racc.
10
+
11
+
12
+ == SYNOPSIS
13
+
14
+ Here is a sample lexical definition:
15
+
16
+ class Sample
17
+ macro
18
+ BLANK [\ \t]+
19
+ rule
20
+ BLANK # no action
21
+ \d+ { [:digit, text.to_i] }
22
+ \w+ { [:word, text] }
23
+ \n
24
+ . { [text, text] }
25
+ end
26
+
27
+ Here is the command line usage:
28
+
29
+ $ rex sample1.rex --stub
30
+ $ ruby sample1.rex.rb sample1.c
31
+
32
+ $ rex sample2.rex --stub
33
+ $ ruby sample2.rex.rb sample2.bas
34
+
35
+ $ racc calc3.racc
36
+ $ rex calc3.rex
37
+ $ ruby calc3.tab.rb
38
+
39
+ == REQUIREMENTS
40
+
41
+ * ruby version 1.8.x or later.
42
+
43
+ == INSTALL
44
+
45
+ * sudo gem install rexical
46
+
47
+ == LICENSE
48
+
49
+ Rexical is distributed under the terms of the GNU Lesser General
50
+ Public License version 2. Note that you do NOT need to follow
51
+ LGPL for your own parser (Rexical outputs). You can provide those
52
+ files under any licenses you want.
@@ -0,0 +1,28 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+
6
+ $LOAD_PATH << File.join(File.dirname(__FILE__), 'lib')
7
+ require 'rexical'
8
+
9
+ HOE = Hoe.new('rexical', Rexical::VERSION) do |p|
10
+ p.readme_file = 'README.rdoc'
11
+ p.history_file = 'CHANGELOG.rdoc'
12
+ p.developer('Aaron Patterson', 'aaronp@rubyforge.org')
13
+ p.rubyforge_name = 'ruby-rex'
14
+ p.extra_rdoc_files = FileList['*.rdoc']
15
+ end
16
+
17
+ namespace :gem do
18
+ namespace :spec do
19
+ task :dev do
20
+ File.open("#{HOE.name}.gemspec", 'w') do |f|
21
+ HOE.spec.version = "#{HOE.version}.#{Time.now.strftime("%Y%m%d%H%M%S")}"
22
+ f.write(HOE.spec.to_ruby)
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ # vim: syntax=Ruby
data/bin/rex ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # rex
4
+ #
5
+ # Copyright (c) 2005-2006 ARIMA Yasuhiro <arima.yasuhiro@nifty.com>
6
+ #
7
+ # This program is free software.
8
+ # You can distribute/modify this program under the terms of
9
+ # the GNU LGPL, Lesser General Public License version 2.1.
10
+ # For details of LGPL, see the file "COPYING".
11
+ #
12
+
13
+ ## ---------------------------------------------------------------------
14
+
15
+ require 'rubygems'
16
+ require 'rexical'
17
+
18
+ Rexical::Cmd.new.run
@@ -0,0 +1,3 @@
1
+ require 'rexical/generator'
2
+ require 'rexical/info'
3
+ require 'rexical/rexcmd'
@@ -0,0 +1,523 @@
1
+ #
2
+ # generator.rb
3
+ #
4
+ # Copyright (c) 2005-2006 ARIMA Yasuhiro <arima.yasuhiro@nifty.com>
5
+ #
6
+ # This program is free software.
7
+ # You can distribute/modify this program under the terms of
8
+ # the GNU Lesser General Public License version 2 or later.
9
+ #
10
+
11
+ require 'strscan'
12
+ module Rexical
13
+
14
+ ## ---------------------------------------------------------------------
15
+ class ParseError < StandardError ; end
16
+
17
+ ## ---------------------------------------------------------------------
18
+ class Generator
19
+
20
+ ## ---------------------------------------------------------------------
21
+ attr_accessor :grammar_file
22
+ attr_accessor :grammar_lines
23
+ attr_accessor :scanner_file
24
+ attr_accessor :module_name
25
+ attr_accessor :class_name
26
+ attr_accessor :lineno
27
+ attr_accessor :rules
28
+ attr_accessor :exclusive_states
29
+ attr_accessor :ignorecase
30
+ attr_accessor :independent
31
+ attr_accessor :debug
32
+
33
+ ## ---------------------------------------------------------------------
34
+ def initialize(opts)
35
+ @lineno = 0
36
+ @macro = {}
37
+ @rules = []
38
+ @exclusive_states = [nil]
39
+ @grammar_lines = nil
40
+ @scanner_header = ""
41
+ @scanner_footer = ""
42
+ @scanner_inner = ""
43
+ @opt = opts
44
+ end
45
+
46
+ ## ---------------------------------------------------------------------
47
+ def add_header( st )
48
+ @scanner_header += "#{st}\n"
49
+ end
50
+
51
+ ## ---------------------------------------------------------------------
52
+ def add_footer( st )
53
+ @scanner_footer += "#{st}\n"
54
+ end
55
+
56
+ ## ---------------------------------------------------------------------
57
+ def add_inner( st )
58
+ @scanner_inner += "#{st}\n"
59
+ end
60
+
61
+ ## ---------------------------------------------------------------------
62
+ def add_option( st )
63
+ opts = st.split
64
+ opts.each do |opt|
65
+ case opt
66
+ when /ignorecase/i
67
+ @opt['--ignorecase'] = true
68
+ when /stub/i
69
+ @opt['--stub'] = true
70
+ when /independent/i
71
+ @opt['--independent'] = true
72
+ end
73
+ end
74
+ end
75
+
76
+ ## ---------------------------------------------------------------------
77
+ def add_macro( st )
78
+ ss = StringScanner.new(st)
79
+ ss.scan(/\s+/)
80
+ key = ss.scan(/\S+/)
81
+ ss.scan(/\s+/)
82
+ st = ss.post_match
83
+ len = st.size
84
+ ndx = 0
85
+ while ndx <= len
86
+ c = st[ndx,1]
87
+ ndx += 1
88
+ case c
89
+ when '\\'
90
+ ndx += 1
91
+ next
92
+ when '#', ' '
93
+ ndx -= 1
94
+ break
95
+ end
96
+ end
97
+ expr = st[0,ndx]
98
+ key = '{' + key + '}'
99
+ @macro.each_pair do |k, e|
100
+ expr.gsub!(k) { |m| e }
101
+ end
102
+ @macro[key] = expr
103
+ rescue
104
+ raise ParseError, "parse error in add_macro:'#{st}'"
105
+ end
106
+
107
+ ## ---------------------------------------------------------------------
108
+ def add_rule( rule_state, rule_expr, rule_action=nil )
109
+ st = rule_expr.dup
110
+ @macro.each_pair do |k, e|
111
+ rule_expr.gsub!(k) { |m| e }
112
+ end
113
+ if rule_state.to_s[1,1] =~ /[A-Z]/
114
+ @exclusive_states << rule_state unless @exclusive_states.include?(rule_state)
115
+ exclusive_state = rule_state
116
+ start_state = nil
117
+ else
118
+ exclusive_state = nil
119
+ start_state = rule_state
120
+ end
121
+ rule = [exclusive_state, start_state, rule_expr, rule_action]
122
+ @rules << rule
123
+ rescue
124
+ raise ParseError, "parse error in add_rule:'#{st}'"
125
+ end
126
+
127
+ def read_grammar
128
+ @grammar_lines = StringScanner.new File.read(grammar_file)
129
+ end
130
+
131
+ def next_line
132
+ @lineno += 1
133
+ @grammar_lines.scan_until(/\n/).chomp
134
+ rescue
135
+ nil
136
+ end
137
+
138
+ def parse
139
+ state1 = :HEAD
140
+ state2 = nil
141
+ state3 = nil
142
+ lastmodes = []
143
+ while st = next_line
144
+ case state1
145
+ when :FOOT
146
+ add_footer st
147
+
148
+ when :HEAD
149
+ ss = StringScanner.new(st)
150
+ if ss.scan(/class/)
151
+ state1 = :CLASS
152
+ st = ss.post_match.strip
153
+ if st =~ /^(\S+)::(\S+)/
154
+ @module_name = $1
155
+ @class_name = $2
156
+ else
157
+ @module_name = nil
158
+ @class_name = st
159
+ end
160
+ else
161
+ add_header st
162
+ end
163
+
164
+ when :CLASS
165
+ s = st.strip
166
+ next if s.size == 0 or s[0,1] == '#'
167
+
168
+ ss = StringScanner.new(st)
169
+ if ss.scan(/option.*$/)
170
+ state2 = :OPTION
171
+ next
172
+ end
173
+ if ss.scan(/inner.*$/)
174
+ state2 = :INNER
175
+ next
176
+ end
177
+ if ss.scan(/macro.*$/)
178
+ state2 = :MACRO
179
+ next
180
+ end
181
+ if ss.scan(/rule.*$/)
182
+ state2 = :RULE
183
+ next
184
+ end
185
+ if ss.scan(/end.*$/)
186
+ state1 = :FOOT
187
+ next
188
+ end
189
+
190
+ case state2
191
+ when :OPTION
192
+ add_option st
193
+
194
+ when :INNER
195
+ add_inner st
196
+
197
+ when :MACRO
198
+ add_macro st
199
+
200
+ when :RULE
201
+ case state3
202
+ when nil
203
+ rule_state, rule_expr, rule_action = parse_rule(st)
204
+ if rule_action =~ /\s*\{/
205
+ lastmodes = parse_action(rule_action, lastmodes)
206
+ if lastmodes.empty?
207
+ add_rule rule_state, rule_expr, rule_action
208
+ else
209
+ state3 = :CONT
210
+ rule_action += "\n"
211
+ end
212
+ else
213
+ add_rule rule_state, rule_expr
214
+ end
215
+
216
+ when :CONT
217
+ rule_action += "#{st}\n"
218
+ lastmodes = parse_action(st, lastmodes)
219
+ if lastmodes.empty?
220
+ state3 = nil
221
+ add_rule rule_state, rule_expr, rule_action
222
+ else
223
+ end
224
+
225
+ end # case state3
226
+
227
+ end # case state2
228
+
229
+ end # case state1
230
+
231
+ end # while
232
+
233
+ end
234
+
235
+ ## ---------------------------------------------------------------------
236
+ def parse_rule(st)
237
+ st.strip!
238
+ return if st.size == 0 or st[0,1] == '#'
239
+ ss = StringScanner.new(st)
240
+ ss.scan(/\s+/)
241
+ rule_state = ss.scan(/\:\S+/)
242
+ ss.scan(/\s+/)
243
+ rule_expr = ss.scan(/\S+/)
244
+ ss.scan(/\s+/)
245
+ [rule_state, rule_expr, ss.post_match]
246
+ end
247
+
248
+ ## ---------------------------------------------------------------------
249
+ def parse_action(st, lastmodes=[])
250
+ modes = lastmodes
251
+ mode = lastmodes[-1]
252
+ ss = StringScanner.new(st)
253
+ until ss.eos?
254
+ c = ss.scan(/./)
255
+ case c
256
+ when '#'
257
+ if (mode == :brace) or (mode == nil)
258
+ #p [c, mode, modes]
259
+ return modes
260
+ end
261
+ when '{'
262
+ if (mode == :brace) or (mode == nil)
263
+ mode = :brace
264
+ modes.push mode
265
+ end
266
+ when '}'
267
+ if (mode == :brace)
268
+ modes.pop
269
+ mode = modes[0]
270
+ end
271
+ when "'"
272
+ if (mode == :brace)
273
+ mode = :quote
274
+ modes.push mode
275
+ elsif (mode == :quote)
276
+ modes.pop
277
+ mode = modes[0]
278
+ end
279
+ when '"'
280
+ if (mode == :brace)
281
+ mode = :doublequote
282
+ modes.push mode
283
+ elsif (mode == :doublequote)
284
+ modes.pop
285
+ mode = modes[0]
286
+ end
287
+ when '`'
288
+ if (mode == :brace)
289
+ mode = :backquote
290
+ modes.push mode
291
+ elsif (mode == :backquote)
292
+ modes.pop
293
+ mode = modes[0]
294
+ end
295
+ end
296
+ end
297
+ #p [c, mode, modes]
298
+ return modes
299
+ end
300
+
301
+ ## ---------------------------------------------------------------------
302
+
303
+ REX_HEADER = <<-REX_EOT
304
+ #--
305
+ # DO NOT MODIFY!!!!
306
+ # This file is automatically generated by rex %s
307
+ # from lexical definition file "%s".
308
+ #++
309
+
310
+ REX_EOT
311
+
312
+ REX_UTIL = <<-REX_EOT
313
+ require 'strscan'
314
+
315
+ class ScanError < StandardError ; end
316
+
317
+ attr_reader :lineno
318
+ attr_reader :filename
319
+
320
+ def scan_setup ; end
321
+
322
+ def action &block
323
+ yield
324
+ end
325
+
326
+ def scan_str( str )
327
+ scan_evaluate str
328
+ do_parse
329
+ end
330
+
331
+ def load_file( filename )
332
+ @filename = filename
333
+ open(filename, "r") do |f|
334
+ scan_evaluate f.read
335
+ end
336
+ end
337
+
338
+ def scan_file( filename )
339
+ load_file filename
340
+ do_parse
341
+ end
342
+
343
+ REX_EOT
344
+
345
+ REX_NEXTTOKEN_DEBUG = <<-REX_EOT
346
+ def next_token
347
+ p token = @rex_tokens.shift
348
+ token
349
+ end
350
+ REX_EOT
351
+
352
+ REX_NEXTTOKEN = <<-REX_EOT
353
+ def next_token
354
+ @rex_tokens.shift
355
+ end
356
+ REX_EOT
357
+
358
+ REX_STUB = <<-REX_EOT
359
+
360
+ if __FILE__ == $0
361
+ exit if ARGV.size != 1
362
+ filename = ARGV.shift
363
+ rex = %s.new
364
+ begin
365
+ rex.load_file filename
366
+ while token = rex.next_token
367
+ p token
368
+ end
369
+ rescue
370
+ $stderr.printf %s, rex.filename, rex.lineno, $!.message
371
+ end
372
+ end
373
+ REX_EOT
374
+
375
+ ## ---------------------------------------------------------------------
376
+
377
+
378
+ def scanner_io
379
+ unless scanner_file = @opt['--output-file']
380
+ scanner_file = grammar_file + ".rb"
381
+ end
382
+ f = File.open(scanner_file, 'w')
383
+ end
384
+ private :scanner_io
385
+
386
+ def write_scanner f = scanner_io
387
+ ## scan flag
388
+ flag = ""
389
+ flag += "i" if @opt['--ignorecase']
390
+ ## header
391
+ f.printf REX_HEADER, Rexical::VERSION, grammar_file
392
+
393
+ unless @opt['--independent']
394
+ f.printf "require 'racc/parser'\n"
395
+ end
396
+
397
+ @scanner_header.each_line do |s|
398
+ f.print s
399
+ end
400
+ if @module_name
401
+ f.puts "module #{@module_name}"
402
+ end
403
+ if @opt['--independent']
404
+ f.puts "class #{@class_name}"
405
+ else
406
+ f.puts "class #{@class_name} < Racc::Parser"
407
+ end
408
+
409
+ ## utility method
410
+ f.print REX_UTIL
411
+
412
+ if @opt['--debug']
413
+ f.print REX_NEXTTOKEN_DEBUG
414
+ else
415
+ f.print REX_NEXTTOKEN
416
+ end
417
+
418
+ ## scanner method
419
+
420
+ f.print <<-REX_EOT
421
+
422
+ def scan_evaluate( str )
423
+ scan_setup
424
+ @rex_tokens = []
425
+ @lineno = 1
426
+ ss = StringScanner.new(str)
427
+ state = nil
428
+ until ss.eos?
429
+ text = ss.peek(1)
430
+ @lineno += 1 if text == "\\n"
431
+ case state
432
+ REX_EOT
433
+
434
+ exclusive_states.each do |es|
435
+ f.printf <<-REX_EOT
436
+ when #{es ? es.to_s : "nil"}
437
+ case
438
+ REX_EOT
439
+ rules.each do |rule|
440
+ exclusive_state, start_state, rule_expr, rule_action = *rule
441
+ if es == exclusive_state
442
+
443
+ if rule_action
444
+ if start_state
445
+ f.print <<-REX_EOT
446
+ when (state == #{start_state}) and (text = ss.scan(/#{rule_expr}/#{flag}))
447
+ @rex_tokens.push action #{rule_action}
448
+
449
+ REX_EOT
450
+ else
451
+ f.print <<-REX_EOT
452
+ when (text = ss.scan(/#{rule_expr}/#{flag}))
453
+ @rex_tokens.push action #{rule_action}
454
+
455
+ REX_EOT
456
+ end
457
+ else
458
+ if start_state
459
+ f.print <<-REX_EOT
460
+ when (state == #{start_state}) and (text = ss.scan(/#{rule_expr}/#{flag}))
461
+ ;
462
+
463
+ REX_EOT
464
+ else
465
+ f.print <<-REX_EOT
466
+ when (text = ss.scan(/#{rule_expr}/#{flag}))
467
+ ;
468
+
469
+ REX_EOT
470
+ end
471
+ end
472
+
473
+ end
474
+ end
475
+ f.print <<-REX_EOT
476
+ else
477
+ text = ss.string[ss.pos .. -1]
478
+ raise ScanError, "can not match: '" + text + "'"
479
+ end # if
480
+
481
+ REX_EOT
482
+ end
483
+ f.print <<-REX_EOT
484
+ else
485
+ raise ScanError, "undefined state: '" + state.to_s + "'"
486
+ end # case state
487
+ end # until ss
488
+ end # def scan_evaluate
489
+
490
+ REX_EOT
491
+
492
+ ## inner method
493
+ @scanner_inner.each_line do |s|
494
+ f.print s
495
+ end
496
+ f.puts "end # class"
497
+ f.puts "end # module" if @module_name
498
+
499
+ ## footer
500
+ @scanner_footer.each_line do |s|
501
+ f.print s
502
+ end # case
503
+
504
+ ## stub main
505
+ f.printf REX_STUB, @class_name, '"%s:%d:%s\n"' if @opt['--stub']
506
+ f.close
507
+
508
+ end ## def
509
+ end ## class
510
+ end ## module
511
+
512
+
513
+ ## ---------------------------------------------------------------------
514
+ ## test
515
+
516
+ if __FILE__ == $0
517
+ rex = Rexical::Generator.new(nil)
518
+ rex.grammar_file = "sample.rex"
519
+ rex.read_grammar
520
+ rex.parse
521
+ rex.write_scanner
522
+ end
523
+