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,12 @@
1
+ module A
2
+ module B
3
+ class C < SomethingElse
4
+
5
+ macro
6
+ w [\s\r\n\f]*
7
+
8
+ # [:state] pattern [actions]
9
+
10
+ {w}~={w} { [:INCLUDES, text] }
11
+
12
+ end
@@ -0,0 +1,152 @@
1
+ #!C:/Program Files/ruby-1.8/bin/ruby
2
+ #
3
+ # rex
4
+ #
5
+ # Copyright (c) 2005 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
+ REX_OPTIONS = <<-EOT
16
+
17
+ o -o --output-file <outfile> file name of output [<filename>.rb]
18
+ o -s --stub - append stub code for debug
19
+ o -i --ignorecase - ignore char case
20
+ o -C --check-only - syntax check only
21
+ o - --independent - independent mode
22
+ o -d --debug - print debug information
23
+ o -h --help - print this message and quit
24
+ o - --version - print version and quit
25
+ o - --copyright - print copyright and quit
26
+
27
+ EOT
28
+
29
+ ## ---------------------------------------------------------------------
30
+
31
+ require 'getoptlong'
32
+ require 'rex/generator'
33
+ require 'rex/info'
34
+
35
+ ## ---------------------------------------------------------------------
36
+
37
+ =begin
38
+ class Rex
39
+ def initialize
40
+ end
41
+ end
42
+ =end
43
+
44
+ def main
45
+ $cmd = File.basename($0, ".rb")
46
+ opt = get_options
47
+ filename = ARGV[0]
48
+
49
+ rex = Rex::Generator.new(opt)
50
+ begin
51
+ rex.grammar_file = filename
52
+ rex.read_grammar
53
+ rex.parse
54
+ if opt['--check-only']
55
+ $stderr.puts "syntax ok"
56
+ return 0
57
+ end
58
+ rex.write_scanner
59
+
60
+ rescue Rex::ParseError, Errno::ENOENT
61
+ msg = $!.to_s
62
+ unless /\A\d/ === msg
63
+ msg[0,0] = ' '
64
+ end
65
+ $stderr.puts "#{$cmd}:#{rex.grammar_file}:#{rex.lineno}:#{msg}"
66
+ return 1
67
+
68
+ end
69
+ return 0
70
+ end
71
+
72
+ ## ---------------------------------------------------------------------
73
+ def get_options
74
+ tmp = REX_OPTIONS.collect do |line|
75
+ next if /\A\s*\z/ === line
76
+ disp, sopt, lopt, takearg, doc = line.strip.split(/\s+/, 5)
77
+ a = []
78
+ a.push lopt unless lopt == '-'
79
+ a.push sopt unless sopt == '-'
80
+ a.push takearg == '-' ?
81
+ GetoptLong::NO_ARGUMENT : GetoptLong::REQUIRED_ARGUMENT
82
+ a
83
+ end
84
+ getopt = GetoptLong.new(*tmp.compact)
85
+ getopt.quiet = true
86
+
87
+ opt = {}
88
+ begin
89
+ getopt.each do |name, arg|
90
+ raise GetoptLong::InvalidOption,
91
+ "#{$cmd}: #{name} given twice" if opt.key? name
92
+ opt[name] = arg.empty? ? true : arg
93
+ end
94
+ rescue GetoptLong::AmbigousOption, GetoptLong::InvalidOption,
95
+ GetoptLong::MissingArgument, GetoptLong::NeedlessArgument
96
+ usage 1, $!.message
97
+ end
98
+
99
+ usage if opt['--help']
100
+
101
+ if opt['--version']
102
+ puts "#{$cmd} version #{Rex::Version}"
103
+ exit 0
104
+ end
105
+ if opt['--copyright']
106
+ puts "#{$cmd} version #{Rex::Version}"
107
+ puts "#{Rex::Copyright} <#{Rex::Mailto}>"
108
+ exit 0
109
+ end
110
+
111
+ usage(1, 'no grammar file given') if ARGV.empty?
112
+ usage(1, 'too many grammar files given') if ARGV.size > 1
113
+
114
+ opt
115
+ end
116
+
117
+ ## ---------------------------------------------------------------------
118
+
119
+ def usage(status=0, msg=nil )
120
+ f = (status == 0 ? $stdout : $stderr)
121
+ f.puts "#{$cmd}: #{msg}" if msg
122
+ f.print <<-EOT
123
+ Usage: #{$cmd} [options] <grammar file>
124
+ Options:
125
+ EOT
126
+
127
+ REX_OPTIONS.each do |line|
128
+ next if line.strip.empty?
129
+ if /\A\s*\z/ === line
130
+ f.puts
131
+ next
132
+ end
133
+
134
+ disp, sopt, lopt, takearg, doc = line.strip.split(/\s+/, 5)
135
+ if disp == 'o'
136
+ sopt = nil if sopt == '-'
137
+ lopt = nil if lopt == '-'
138
+ opt = [sopt, lopt].compact.join(',')
139
+
140
+ takearg = nil if takearg == '-'
141
+ opt = [opt, takearg].compact.join(' ')
142
+
143
+ f.printf "%-27s %s\n", opt, doc
144
+ end
145
+ end
146
+
147
+ exit status
148
+ end
149
+
150
+ ## ---------------------------------------------------------------------
151
+
152
+ main
@@ -0,0 +1,143 @@
1
+ #!/usr/local/bin/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
+ REX_OPTIONS = <<-EOT
16
+
17
+ o -o --output-file <outfile> file name of output [<filename>.rb]
18
+ o -s --stub - append stub code for debug
19
+ o -i --ignorecase - ignore char case
20
+ o -C --check-only - syntax check only
21
+ o - --independent - independent mode
22
+ o -d --debug - print debug information
23
+ o -h --help - print this message and quit
24
+ o - --version - print version and quit
25
+ o - --copyright - print copyright and quit
26
+
27
+ EOT
28
+
29
+ ## ---------------------------------------------------------------------
30
+
31
+ require 'getoptlong'
32
+ require 'rex/generator'
33
+ require 'rex/info'
34
+
35
+ ## ---------------------------------------------------------------------
36
+
37
+ class RexRunner
38
+ def run
39
+ @status = 1
40
+ usage 'no grammar file given' if ARGV.empty?
41
+ usage 'too many grammar files given' if ARGV.size > 1
42
+ filename = ARGV[0]
43
+
44
+ rex = Rex::Generator.new(@opt)
45
+ begin
46
+ rex.grammar_file = filename
47
+ rex.read_grammar
48
+ rex.parse
49
+ if @opt['--check-only']
50
+ $stderr.puts "syntax ok"
51
+ return 0
52
+ end
53
+ rex.write_scanner
54
+ @status = 0
55
+
56
+ rescue Rex::ParseError, Errno::ENOENT
57
+ msg = $!.to_s
58
+ unless /\A\d/ === msg
59
+ msg[0,0] = ' '
60
+ end
61
+ $stderr.puts "#{@cmd}:#{rex.grammar_file}:#{rex.lineno}:#{msg}"
62
+
63
+ ensure
64
+ exit @status
65
+
66
+ end
67
+ end
68
+
69
+ def initialize
70
+ @status = 2
71
+ @cmd = File.basename($0, ".rb")
72
+ tmp = REX_OPTIONS.collect do |line|
73
+ next if /\A\s*\z/ === line
74
+ disp, sopt, lopt, takearg, doc = line.strip.split(/\s+/, 5)
75
+ a = []
76
+ a.push lopt unless lopt == '-'
77
+ a.push sopt unless sopt == '-'
78
+ a.push takearg == '-' ?
79
+ GetoptLong::NO_ARGUMENT : GetoptLong::REQUIRED_ARGUMENT
80
+ a
81
+ end
82
+ getopt = GetoptLong.new(*tmp.compact)
83
+ getopt.quiet = true
84
+
85
+ @opt = {}
86
+ begin
87
+ getopt.each do |name, arg|
88
+ raise GetoptLong::InvalidOption,
89
+ "#{@cmd}: #{name} given twice" if @opt.key? name
90
+ @opt[name] = arg.empty? ? true : arg
91
+ end
92
+ rescue GetoptLong::AmbigousOption, GetoptLong::InvalidOption,
93
+ GetoptLong::MissingArgument, GetoptLong::NeedlessArgument
94
+ usage $!.message
95
+ end
96
+
97
+ usage if @opt['--help']
98
+
99
+ if @opt['--version']
100
+ puts "#{@cmd} version #{Rex::Version}"
101
+ exit 0
102
+ end
103
+ if @opt['--copyright']
104
+ puts "#{@cmd} version #{Rex::Version}"
105
+ puts "#{Rex::Copyright} <#{Rex::Mailto}>"
106
+ exit 0
107
+ end
108
+ end
109
+
110
+ def usage( msg=nil )
111
+ f = $stderr
112
+ f.puts "#{@cmd}: #{msg}" if msg
113
+ f.print <<-EOT
114
+ Usage: #{@cmd} [options] <grammar file>
115
+ Options:
116
+ EOT
117
+
118
+ REX_OPTIONS.each do |line|
119
+ next if line.strip.empty?
120
+ if /\A\s*\z/ === line
121
+ f.puts
122
+ next
123
+ end
124
+
125
+ disp, sopt, lopt, takearg, doc = line.strip.split(/\s+/, 5)
126
+ if disp == 'o'
127
+ sopt = nil if sopt == '-'
128
+ lopt = nil if lopt == '-'
129
+ opt = [sopt, lopt].compact.join(',')
130
+
131
+ takearg = nil if takearg == '-'
132
+ opt = [opt, takearg].compact.join(' ')
133
+
134
+ f.printf "%-27s %s\n", opt, doc
135
+ end
136
+ end
137
+
138
+ exit @status
139
+ end
140
+ end
141
+
142
+ RexRunner.new.run
143
+
@@ -0,0 +1,184 @@
1
+ require 'test/unit'
2
+ require 'tempfile'
3
+ require 'rexical'
4
+ require 'stringio'
5
+
6
+ class TestGenerator < Test::Unit::TestCase
7
+ def test_header_is_written_after_module
8
+ rex = Rexical::Generator.new(
9
+ "--independent" => true
10
+ )
11
+ rex.grammar_file = File.join File.dirname(__FILE__), 'assets', 'test.rex'
12
+ rex.read_grammar
13
+ rex.parse
14
+
15
+ output = StringIO.new
16
+ rex.write_scanner output
17
+
18
+ comments = []
19
+ output.string.split(/[\n]/).each do |line|
20
+ comments << line.chomp if line =~ /^#/
21
+ end
22
+
23
+ assert_match 'DO NOT MODIFY', comments.join
24
+ assert_equal '#--', comments.first
25
+ assert_equal '#++', comments.last
26
+ end
27
+
28
+ def test_read_non_existent_file
29
+ rex = Rexical::Generator.new(nil)
30
+ rex.grammar_file = 'non_existent_file'
31
+ assert_raises Errno::ENOENT do
32
+ rex.read_grammar
33
+ end
34
+ end
35
+
36
+ def test_scanner_inherits
37
+ rex = Rexical::Generator.new(
38
+ "--independent" => true
39
+ )
40
+ rex.grammar_lines = StringScanner.new %q{
41
+ class Calculator < Bar
42
+ rule
43
+ \d+ { [:NUMBER, text.to_i] }
44
+ \s+ { [:S, text] }
45
+ end
46
+ }
47
+
48
+ rex.parse
49
+
50
+ output = StringIO.new
51
+ rex.write_scanner output
52
+ assert_match 'Calculator < Bar', output.string
53
+ end
54
+
55
+ def test_scanner_inherits_many_levels
56
+ rex = Rexical::Generator.new(
57
+ "--independent" => true
58
+ )
59
+ rex.grammar_lines = StringScanner.new %q{
60
+ class Calculator < Foo::Bar
61
+ rule
62
+ \d+ { [:NUMBER, text.to_i] }
63
+ \s+ { [:S, text] }
64
+ end
65
+ }
66
+
67
+ rex.parse
68
+
69
+ output = StringIO.new
70
+ rex.write_scanner output
71
+ assert_match 'Calculator < Foo::Bar', output.string
72
+ end
73
+
74
+ def test_simple_scanner
75
+ rex = Rexical::Generator.new(
76
+ "--independent" => true
77
+ )
78
+ rex.grammar_lines = StringScanner.new %q{
79
+ class Calculator
80
+ rule
81
+ \d+ { [:NUMBER, text.to_i] }
82
+ \s+ { [:S, text] }
83
+ end
84
+ }
85
+
86
+ rex.parse
87
+
88
+ output = StringIO.new
89
+ rex.write_scanner output
90
+
91
+ m = Module.new
92
+ m.module_eval output.string
93
+ calc = m::Calculator.new
94
+ calc.scan_evaluate('1 2 10')
95
+
96
+ assert_tokens [[:NUMBER, 1],
97
+ [:S, ' '],
98
+ [:NUMBER, 2],
99
+ [:S, ' '],
100
+ [:NUMBER, 10]], calc
101
+ end
102
+
103
+ def test_simple_scanner_with_macros
104
+ rex = Rexical::Generator.new(
105
+ "--independent" => true
106
+ )
107
+ rex.grammar_lines = StringScanner.new %q{
108
+ class Calculator
109
+ macro
110
+ digit \d+
111
+ rule
112
+ {digit} { [:NUMBER, text.to_i] }
113
+ \s+ { [:S, text] }
114
+ end
115
+ }
116
+
117
+ rex.parse
118
+
119
+ output = StringIO.new
120
+ rex.write_scanner output
121
+
122
+ m = Module.new
123
+ m.module_eval output.string
124
+ calc = m::Calculator.new
125
+ calc.scan_evaluate('1 2 10')
126
+
127
+ assert_tokens [[:NUMBER, 1],
128
+ [:S, ' '],
129
+ [:NUMBER, 2],
130
+ [:S, ' '],
131
+ [:NUMBER, 10]], calc
132
+ end
133
+
134
+ def test_nested_macros
135
+ rex = Rexical::Generator.new(
136
+ "--independent" => true
137
+ )
138
+ rex.grammar_lines = StringScanner.new %q{
139
+ class Calculator
140
+ macro
141
+ nonascii [^\0-\177]
142
+ string "{nonascii}*"
143
+ rule
144
+ {string} { [:STRING, text] }
145
+ end
146
+ }
147
+
148
+ rex.parse
149
+
150
+ output = StringIO.new
151
+ rex.write_scanner output
152
+ assert_match '"[^\0-\177]*"', output.string
153
+ end
154
+
155
+ def test_more_nested_macros
156
+ rex = Rexical::Generator.new(
157
+ "--independent" => true
158
+ )
159
+ rex.grammar_lines = StringScanner.new %q{
160
+ class Calculator
161
+ macro
162
+ nonascii [^\0-\177]
163
+ sing {nonascii}*
164
+ string "{sing}"
165
+ rule
166
+ {string} { [:STRING, text] }
167
+ end
168
+ }
169
+
170
+ rex.parse
171
+
172
+ output = StringIO.new
173
+ rex.write_scanner output
174
+ assert_match '"[^\0-\177]*"', output.string
175
+ end
176
+
177
+ def assert_tokens expected, scanner
178
+ tokens = []
179
+ while token = scanner.next_token
180
+ tokens << token
181
+ end
182
+ assert_equal expected, tokens
183
+ end
184
+ end