tenderlove-frex 1.0.1.20090313144615
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.rdoc +7 -0
- data/DOCUMENTATION.en.rdoc +215 -0
- data/DOCUMENTATION.ja.rdoc +205 -0
- data/Manifest.txt +38 -0
- data/README.ja +73 -0
- data/README.rdoc +39 -0
- data/Rakefile +27 -0
- data/bin/frex +18 -0
- data/frex.gemspec +37 -0
- data/lib/frex.rb +3 -0
- data/lib/frex/generator.rb +526 -0
- data/lib/frex/info.rb +16 -0
- data/lib/frex/rexcmd.rb +136 -0
- data/sample/a.cmd +1 -0
- data/sample/b.cmd +1 -0
- data/sample/c.cmd +4 -0
- data/sample/calc3.racc +47 -0
- data/sample/calc3.rex +15 -0
- data/sample/calc3.rex.rb +94 -0
- data/sample/calc3.tab.rb +188 -0
- data/sample/error1.rex +15 -0
- data/sample/error2.rex +15 -0
- data/sample/sample.html +32 -0
- data/sample/sample.rex +15 -0
- data/sample/sample.rex.rb +100 -0
- data/sample/sample.xhtml +32 -0
- data/sample/sample1.c +9 -0
- data/sample/sample1.rex +43 -0
- data/sample/sample2.bas +4 -0
- data/sample/sample2.rex +33 -0
- data/sample/simple.html +7 -0
- data/sample/simple.xhtml +10 -0
- data/sample/xhtmlparser.racc +66 -0
- data/sample/xhtmlparser.rex +72 -0
- data/test/assets/test.rex +12 -0
- data/test/rex-20060125.rb +152 -0
- data/test/rex-20060511.rb +143 -0
- data/test/test_generator.rb +27 -0
- metadata +105 -0
data/README.ja
ADDED
@@ -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/
|
data/README.rdoc
ADDED
@@ -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.
|
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'hoe'
|
5
|
+
|
6
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__), 'lib')
|
7
|
+
require 'frex'
|
8
|
+
|
9
|
+
HOE = Hoe.new('frex', Frex::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.extra_rdoc_files = FileList['*.rdoc']
|
14
|
+
end
|
15
|
+
|
16
|
+
namespace :gem do
|
17
|
+
namespace :spec do
|
18
|
+
task :dev do
|
19
|
+
File.open("#{HOE.name}.gemspec", 'w') do |f|
|
20
|
+
HOE.spec.version = "#{HOE.version}.#{Time.now.strftime("%Y%m%d%H%M%S")}"
|
21
|
+
f.write(HOE.spec.to_ruby)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# vim: syntax=Ruby
|
data/bin/frex
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 'frex'
|
17
|
+
|
18
|
+
Frex::Cmd.new.run
|
data/frex.gemspec
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{frex}
|
5
|
+
s.version = "1.0.1.20090313144615"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Aaron Patterson"]
|
9
|
+
s.date = %q{2009-03-13}
|
10
|
+
s.default_executable = %q{frex}
|
11
|
+
s.description = %q{Frex is a fork of Rex. Rex is a lexical scanner generator. It is written in Ruby itself, and generates Ruby program. It is designed for use with Racc.}
|
12
|
+
s.email = ["aaronp@rubyforge.org"]
|
13
|
+
s.executables = ["frex"]
|
14
|
+
s.extra_rdoc_files = ["Manifest.txt", "CHANGELOG.rdoc", "DOCUMENTATION.en.rdoc", "DOCUMENTATION.ja.rdoc", "README.rdoc"]
|
15
|
+
s.files = ["CHANGELOG.rdoc", "DOCUMENTATION.en.rdoc", "DOCUMENTATION.ja.rdoc", "Manifest.txt", "README.ja", "README.rdoc", "Rakefile", "bin/frex", "frex.gemspec", "lib/frex.rb", "lib/frex/generator.rb", "lib/frex/info.rb", "lib/frex/rexcmd.rb", "sample/a.cmd", "sample/b.cmd", "sample/c.cmd", "sample/calc3.racc", "sample/calc3.rex", "sample/calc3.rex.rb", "sample/calc3.tab.rb", "sample/error1.rex", "sample/error2.rex", "sample/sample.html", "sample/sample.rex", "sample/sample.rex.rb", "sample/sample.xhtml", "sample/sample1.c", "sample/sample1.rex", "sample/sample2.bas", "sample/sample2.rex", "sample/simple.html", "sample/simple.xhtml", "sample/xhtmlparser.racc", "sample/xhtmlparser.rex", "test/assets/test.rex", "test/rex-20060125.rb", "test/rex-20060511.rb", "test/test_generator.rb"]
|
16
|
+
s.has_rdoc = true
|
17
|
+
s.homepage = %q{http://github.com/aaronp/frex/tree/master}
|
18
|
+
s.rdoc_options = ["--main", "README.rdoc"]
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
s.rubyforge_project = %q{frex}
|
21
|
+
s.rubygems_version = %q{1.3.1}
|
22
|
+
s.summary = %q{Frex is a fork of Rex}
|
23
|
+
s.test_files = ["test/test_generator.rb"]
|
24
|
+
|
25
|
+
if s.respond_to? :specification_version then
|
26
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
27
|
+
s.specification_version = 2
|
28
|
+
|
29
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
30
|
+
s.add_development_dependency(%q<hoe>, [">= 1.9.0"])
|
31
|
+
else
|
32
|
+
s.add_dependency(%q<hoe>, [">= 1.9.0"])
|
33
|
+
end
|
34
|
+
else
|
35
|
+
s.add_dependency(%q<hoe>, [">= 1.9.0"])
|
36
|
+
end
|
37
|
+
end
|
data/lib/frex.rb
ADDED
@@ -0,0 +1,526 @@
|
|
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 FrexError < 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 Frex::FrexError, "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, Frex::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
|
+
f.close
|
510
|
+
|
511
|
+
end ## def
|
512
|
+
end ## class
|
513
|
+
end ## module
|
514
|
+
|
515
|
+
|
516
|
+
## ---------------------------------------------------------------------
|
517
|
+
## test
|
518
|
+
|
519
|
+
if __FILE__ == $0
|
520
|
+
rex = Frex::Generator.new(nil)
|
521
|
+
rex.grammar_file = "sample.rex"
|
522
|
+
rex.read_grammar
|
523
|
+
rex.parse
|
524
|
+
rex.write_scanner
|
525
|
+
end
|
526
|
+
|