aaronp-frex 1.0.0

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