metal 0.0.1

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.
@@ -0,0 +1,13 @@
1
+ Copyright 2008 Furuhashi Sadayuki
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
@@ -0,0 +1,20 @@
1
+ License.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ bin/metal
6
+ bin/metal-run
7
+ config/hoe.rb
8
+ config/requirements.rb
9
+ lib/metal.rb
10
+ lib/metal/boot.metal
11
+ lib/metal/boot.rb
12
+ lib/metal/generator.rb
13
+ lib/metal/runtime.rb
14
+ lib/metal/version.rb
15
+ script/console
16
+ script/destroy
17
+ script/generate
18
+ setup.rb
19
+ tasks/deployment.rake
20
+ tasks/environment.rake
@@ -0,0 +1,29 @@
1
+ Metal
2
+ -----
3
+ Object-oriented parser generator based on Parser Expression Grammar (PEG)
4
+
5
+ *Usage:
6
+
7
+ TODO
8
+
9
+
10
+ *INSTALL:
11
+
12
+ $ gem install metal
13
+
14
+
15
+ == LICENSE:
16
+ Copyright (C) 2008 FURUHASHI Sadayuki
17
+
18
+ Licensed under the Apache License, Version 2.0 (the "License");
19
+ you may not use this file except in compliance with the License.
20
+ You may obtain a copy of the License at
21
+
22
+ http://www.apache.org/licenses/LICENSE-2.0
23
+
24
+ Unless required by applicable law or agreed to in writing, software
25
+ distributed under the License is distributed on an "AS IS" BASIS,
26
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
27
+ See the License for the specific language governing permissions and
28
+ limitations under the License.
29
+
@@ -0,0 +1,4 @@
1
+ require 'config/requirements'
2
+ require 'config/hoe' # setup Hoe + all gem configuration
3
+
4
+ Dir['tasks/**/*.rake'].each { |rake| load rake }
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optparse'
3
+
4
+ opts = {
5
+ :output => '-',
6
+ }
7
+
8
+ op = OptionParser.new
9
+
10
+ op.on('-o OUTPUT', 'output file name') {|v|
11
+ opts[:output] = v
12
+ }
13
+ op.banner = "#{op.banner} <source.metal>"
14
+ op.parse!(ARGV)
15
+
16
+ if ARGV.length != 1
17
+ puts op.to_s
18
+ exit 1
19
+ end
20
+ src = ARGV[0]
21
+
22
+ require 'metal'
23
+ unless defined? MetalParser
24
+ require 'metal/boot'
25
+ end
26
+
27
+ parser = MetalParser.new
28
+ result = parser.parse File.read(src)
29
+ code = result.generate(:ruby)
30
+
31
+ if opts[:output] == '-'
32
+ $stdout.write code
33
+ else
34
+ File.open(opts[:output], 'wb') {|f|
35
+ f.write code
36
+ }
37
+ end
38
+
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ if ARGV.length != 2
4
+ puts "Usage: #{File.basename($0)} <source.rb> <target>"
5
+ exit 1
6
+ end
7
+ src = ARGV[0]
8
+ target = ARGV[1]
9
+
10
+ require 'rubygems'
11
+ require 'metal'
12
+
13
+ before = Object.constants
14
+ load src
15
+ after = Object.constants
16
+
17
+
18
+ parsers = (after - before) \
19
+ .map {|c| Object.const_get(c) } \
20
+ .select {|c| c.is_a?(Class) } \
21
+ .select {|c| c.public_instance_methods.include?('rule_main') } \
22
+ .sort_by {|c| c.ancestors.length } \
23
+ .reverse
24
+
25
+ if parsers.empty?
26
+ puts "Can't find parser in #{src}."
27
+ exit 1
28
+ end
29
+
30
+ first = parsers.first
31
+ $stderr.puts "Using #{first}"
32
+
33
+ if target == '-'
34
+ $stderr.puts "Using standard input as input."
35
+ input = $stdin
36
+ elsif File.file?(target)
37
+ $stderr.puts "Using #{target} file as input."
38
+ input = File.open(target)
39
+ else
40
+ $stderr.puts "Using '#{target}' as input."
41
+ input = target
42
+ end
43
+
44
+ result = first.new.parse(input)
45
+
46
+ if result.is_a?(String)
47
+ puts result
48
+ else
49
+ require 'pp'
50
+ pp result
51
+ end
52
+
@@ -0,0 +1,73 @@
1
+ require 'metal/version'
2
+
3
+ AUTHOR = 'FURUHASHI Sadayuki' # can also be an array of Authors
4
+ EMAIL = "fr _at_ syuki.skr.jp"
5
+ DESCRIPTION = "An object-oriented parser generator based on Parser Expression Grammar"
6
+ GEM_NAME = 'metal' # what ppl will type to install your gem
7
+ RUBYFORGE_PROJECT = 'metal' # The unix name for your project
8
+ HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
9
+ DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
10
+ EXTRA_DEPENDENCIES = [
11
+ # ['activesupport', '>= 1.3.1']
12
+ ] # An array of rubygem dependencies [name, version]
13
+
14
+ @config_file = "~/.rubyforge/user-config.yml"
15
+ @config = nil
16
+ RUBYFORGE_USERNAME = "unknown"
17
+ def rubyforge_username
18
+ unless @config
19
+ begin
20
+ @config = YAML.load(File.read(File.expand_path(@config_file)))
21
+ rescue
22
+ puts <<-EOS
23
+ ERROR: No rubyforge config file found: #{@config_file}
24
+ Run 'rubyforge setup' to prepare your env for access to Rubyforge
25
+ - See http://newgem.rubyforge.org/rubyforge.html for more details
26
+ EOS
27
+ exit
28
+ end
29
+ end
30
+ RUBYFORGE_USERNAME.replace @config["username"]
31
+ end
32
+
33
+
34
+ REV = nil
35
+ # UNCOMMENT IF REQUIRED:
36
+ # REV = YAML.load(`svn info`)['Revision']
37
+ VERS = Metal::VERSION::STRING + (REV ? ".#{REV}" : "")
38
+ RDOC_OPTS = ['--quiet', '--title', 'metal documentation',
39
+ "--opname", "index.html",
40
+ "--line-numbers",
41
+ "--main", "README",
42
+ "--inline-source"]
43
+
44
+ class Hoe
45
+ def extra_deps
46
+ @extra_deps.reject! { |x| Array(x).first == 'hoe' }
47
+ @extra_deps
48
+ end
49
+ end
50
+
51
+ # Generate all the Rake tasks
52
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
53
+ $hoe = Hoe.new(GEM_NAME, VERS) do |p|
54
+ p.developer(AUTHOR, EMAIL)
55
+ p.description = DESCRIPTION
56
+ p.summary = DESCRIPTION
57
+ p.url = HOMEPATH
58
+ p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
59
+ p.test_globs = ["test/**/test_*.rb"]
60
+ p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean.
61
+
62
+ # == Optional
63
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
64
+ #p.extra_deps = EXTRA_DEPENDENCIES
65
+
66
+ #p.spec_extras = {} # A hash of extra values to set in the gemspec.
67
+ end
68
+
69
+ CHANGES = $hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
70
+ PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
71
+ $hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
72
+ $hoe.rsync_args = '-av --delete --ignore-errors'
73
+ $hoe.spec.post_install_message = File.open(File.dirname(__FILE__) + "/../PostInstall.txt").read rescue ""
@@ -0,0 +1,15 @@
1
+ require 'fileutils'
2
+ include FileUtils
3
+
4
+ require 'rubygems'
5
+ %w[rake hoe newgem rubigen].each do |req_gem|
6
+ begin
7
+ require req_gem
8
+ rescue LoadError
9
+ puts "This Rakefile requires the '#{req_gem}' RubyGem."
10
+ puts "Installation: gem install #{req_gem} -y"
11
+ exit
12
+ end
13
+ end
14
+
15
+ $:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))
@@ -0,0 +1,7 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ module Metal
5
+ end
6
+
7
+ require 'metal/runtime'
@@ -0,0 +1,153 @@
1
+ @{#
2
+ # Metal Bootstrap Parser
3
+ #
4
+ # Copyright (C) 2008 FURUHASHI Sadayuki
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+ require 'metal/generator'
19
+ @}
20
+
21
+
22
+ MetalParser {
23
+ @include Metal::Generator
24
+
25
+ -main
26
+ meta:m end {* m *}
27
+
28
+ -meta
29
+ (grammar / meta_command)*:xs s {* Meta.new(xs) *}
30
+
31
+ -meta_command
32
+ s precode
33
+
34
+ -grammar
35
+ s interface_attr:i grammar_name:n s extend_attr?:e s '{' grammar_body:b '}'
36
+ {* Grammar.new(n, b, e, i) *}
37
+
38
+ -interface_attr
39
+ 'module' fs {* true *}
40
+ / 'class' fs {* false *}
41
+ / {* false *}
42
+
43
+ -extend_attr
44
+ '<' s grammar_name
45
+
46
+ -grammar_body
47
+ s (rule / grammar_command)*
48
+
49
+ -grammar_command
50
+ precode
51
+ / mixin
52
+
53
+ -precode
54
+ '@{' (!'@' . / '@' !'}' {*'@'*})+:s '@}' s {* Precode.new(s.join) *}
55
+
56
+ -mixin
57
+ '@include' fs scoped_grammar_name:n s {* Mixin.new(n) *}
58
+
59
+ -scoped_grammar_name
60
+ ('::'?:s grammar_name:n {*"#{s}#{n}"*})+:xs {* xs.join *}
61
+
62
+ -rule
63
+ '-' s rule_name:n rule_args:a fs or_set:r s
64
+ {* Rule.new(n, r, a) *}
65
+
66
+ -rule_args
67
+ (s ':' var_name)*
68
+
69
+ -or_set
70
+ and_set:x s (s '/' and_set)*:xs
71
+ {* OrSet.new([x] + xs) *}
72
+
73
+ -and_set
74
+ s (expr:x (fs expr)*:xs {*[x]+xs*})?:xs
75
+ {* AndSet.new(xs || []) *}
76
+
77
+ -expr
78
+ pred:p iter(p)?:p var?:v {* Expression.new(p, v) *}
79
+
80
+ -pred
81
+ '!' pred:p {* PredNot.new(p) *}
82
+ / '&' literal:f {* PredLookahead.new(f) *}
83
+ / literal
84
+
85
+ -iter :x
86
+ '*' {* IterMany.new(x) *}
87
+ / '+' {* IterMany1.new(x) *}
88
+ / '?' {* IterMay.new(x) *}
89
+ / {* x *}
90
+
91
+ -literal
92
+ apply_rule
93
+ / action
94
+ / where
95
+ / q_string:s {* LiteralQuotedToken.new(s) *}
96
+ / dq_string:s {* LiteralToken.new(s) *}
97
+ / charclass:s {* LiteralCharset.new(s) *}
98
+ / '.' {* LiteralAny.new *}
99
+ / other_call
100
+ / '(' s or_set:r s ')' {* r *}
101
+
102
+ -var
103
+ ':' var_name:n {* n *}
104
+
105
+ -apply_rule
106
+ rule_name:r apply_args?:a {*
107
+ if r == "super"
108
+ Super.new(a)
109
+ else
110
+ Apply.new(r, a || [])
111
+ end *}
112
+
113
+ -other_call
114
+ grammar_name:g '.' rule_name:r apply_args?:a {* Other.new(g, r, a || []) *}
115
+
116
+ -apply_args
117
+ '(' (s var_name:x (',' s var_name)*:xs {*[x] + xs*})?:a ')' {* a || [] *}
118
+
119
+ -action
120
+ '{*' (!'*' . / '*' !'}' {*'*'*})+:s '*}' {* Action.new(s.join) *}
121
+
122
+ -where
123
+ '?{*' (!'*' . / '*' !'}' {*'*'*})+:s '*}' {* Where.new(s.join) *}
124
+
125
+ -rule_name
126
+ [a-z_]:x [a-zA-Z_0-9]*:xs {* ([x] + xs).join *}
127
+
128
+ -var_name
129
+ [a-z_]:x [a-zA-Z_0-9]*:xs {* ([x] + xs).join *}
130
+
131
+ -grammar_name
132
+ [A-Z]:x [a-zA-Z_0-9]*:xs {* ([x] + xs).join *}
133
+
134
+ -dq_string
135
+ '"' (!'"' . / '\"')+:s '"' {* s.join *}
136
+
137
+ -q_string
138
+ "'" (!"'" . / "\\'")+:s "'" {* s.join *}
139
+
140
+ -charclass
141
+ '[' (!']' . / '\]')+:s ']' {* s.join *}
142
+
143
+ -s
144
+ (comment / [ \t\r\n])*
145
+
146
+ -fs
147
+ (comment / [ \t\r\n])+
148
+
149
+ -comment
150
+ '#' (!"\n" .)* "\n"
151
+ }
152
+
153
+
@@ -0,0 +1,351 @@
1
+ #
2
+ # Metal Bootstrap Parser
3
+ #
4
+ # Copyright (C) 2008 FURUHASHI Sadayuki
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+ require 'metal/generator'
19
+
20
+ class MetalParser < Metal::ParserBase
21
+ include Metal::Generator
22
+ def rule_main()
23
+ m = apply(:meta)
24
+ apply(:end)
25
+ m
26
+ end
27
+ def rule_meta()
28
+ xs = act_many(lambda{act_or([lambda{apply(:grammar)
29
+ },
30
+ lambda{apply(:meta_command)
31
+ },
32
+ ])
33
+ })
34
+ apply(:s)
35
+ Meta.new(xs)
36
+ end
37
+ def rule_meta_command()
38
+ apply(:s)
39
+ apply(:precode)
40
+ end
41
+ def rule_grammar()
42
+ apply(:s)
43
+ i = apply(:interface_attr)
44
+ n = apply(:grammar_name)
45
+ apply(:s)
46
+ e = act_may(lambda{apply(:extend_attr)})
47
+ apply(:s)
48
+ act_token('{')
49
+ b = apply(:grammar_body)
50
+ act_token('}')
51
+ Grammar.new(n, b, e, i)
52
+ end
53
+ def rule_interface_attr()
54
+ act_or([lambda{act_token('module')
55
+ apply(:fs)
56
+ true
57
+ },
58
+ lambda{act_token('class')
59
+ apply(:fs)
60
+ false
61
+ },
62
+ lambda{ false
63
+ },
64
+ ])
65
+ end
66
+ def rule_extend_attr()
67
+ act_token('<')
68
+ apply(:s)
69
+ apply(:grammar_name)
70
+ end
71
+ def rule_grammar_body()
72
+ apply(:s)
73
+ act_many(lambda{act_or([lambda{apply(:rule)
74
+ },
75
+ lambda{apply(:grammar_command)
76
+ },
77
+ ])
78
+ })
79
+ end
80
+ def rule_grammar_command()
81
+ act_or([lambda{apply(:precode)
82
+ },
83
+ lambda{apply(:mixin)
84
+ },
85
+ ])
86
+ end
87
+ def rule_precode()
88
+ act_token('@{')
89
+ s = act_many1(lambda{act_or([lambda{act_not(lambda{act_token('@')})
90
+ rule_anything
91
+ },
92
+ lambda{act_token('@')
93
+ act_not(lambda{act_token('}')})
94
+ '@'
95
+ },
96
+ ])
97
+ })
98
+ act_token('@}')
99
+ apply(:s)
100
+ Precode.new(s.join)
101
+ end
102
+ def rule_mixin()
103
+ act_token('@include')
104
+ apply(:fs)
105
+ n = apply(:scoped_grammar_name)
106
+ apply(:s)
107
+ Mixin.new(n)
108
+ end
109
+ def rule_scoped_grammar_name()
110
+ xs = act_many1(lambda{s = act_may(lambda{act_token('::')})
111
+ n = apply(:grammar_name)
112
+ "#{s}#{n}"
113
+ })
114
+ xs.join
115
+ end
116
+ def rule_rule()
117
+ act_token('-')
118
+ apply(:s)
119
+ n = apply(:rule_name)
120
+ a = apply(:rule_args)
121
+ apply(:fs)
122
+ r = apply(:or_set)
123
+ apply(:s)
124
+ Rule.new(n, r, a)
125
+ end
126
+ def rule_rule_args()
127
+ act_many(lambda{apply(:s)
128
+ act_token(':')
129
+ apply(:var_name)
130
+ })
131
+ end
132
+ def rule_or_set()
133
+ x = apply(:and_set)
134
+ apply(:s)
135
+ xs = act_many(lambda{apply(:s)
136
+ act_token('/')
137
+ apply(:and_set)
138
+ })
139
+ OrSet.new([x] + xs)
140
+ end
141
+ def rule_and_set()
142
+ apply(:s)
143
+ xs = act_may(lambda{x = apply(:expr)
144
+ xs = act_many(lambda{apply(:fs)
145
+ apply(:expr)
146
+ })
147
+ [x]+xs
148
+ })
149
+ AndSet.new(xs || [])
150
+ end
151
+ def rule_expr()
152
+ p = apply(:pred)
153
+ p = act_may(lambda{apply(:iter,p)})
154
+ v = act_may(lambda{apply(:var)})
155
+ Expression.new(p, v)
156
+ end
157
+ def rule_pred()
158
+ act_or([lambda{act_token('!')
159
+ p = apply(:pred)
160
+ PredNot.new(p)
161
+ },
162
+ lambda{act_token('&')
163
+ f = apply(:literal)
164
+ PredLookahead.new(f)
165
+ },
166
+ lambda{apply(:literal)
167
+ },
168
+ ])
169
+ end
170
+ def rule_iter(x)
171
+ act_or([lambda{act_token('*')
172
+ IterMany.new(x)
173
+ },
174
+ lambda{act_token('+')
175
+ IterMany1.new(x)
176
+ },
177
+ lambda{act_token('?')
178
+ IterMay.new(x)
179
+ },
180
+ lambda{ x
181
+ },
182
+ ])
183
+ end
184
+ def rule_literal()
185
+ act_or([lambda{apply(:apply_rule)
186
+ },
187
+ lambda{apply(:action)
188
+ },
189
+ lambda{apply(:where)
190
+ },
191
+ lambda{s = apply(:q_string)
192
+ LiteralQuotedToken.new(s)
193
+ },
194
+ lambda{s = apply(:dq_string)
195
+ LiteralToken.new(s)
196
+ },
197
+ lambda{s = apply(:charclass)
198
+ LiteralCharset.new(s)
199
+ },
200
+ lambda{act_token('.')
201
+ LiteralAny.new
202
+ },
203
+ lambda{apply(:other_call)
204
+ },
205
+ lambda{act_token('(')
206
+ apply(:s)
207
+ r = apply(:or_set)
208
+ apply(:s)
209
+ act_token(')')
210
+ r
211
+ },
212
+ ])
213
+ end
214
+ def rule_var()
215
+ act_token(':')
216
+ n = apply(:var_name)
217
+ n
218
+ end
219
+ def rule_apply_rule()
220
+ r = apply(:rule_name)
221
+ a = act_may(lambda{apply(:apply_args)})
222
+
223
+ if r == "super"
224
+ Super.new(a)
225
+ else
226
+ Apply.new(r, a || [])
227
+ end
228
+ end
229
+ def rule_other_call()
230
+ g = apply(:grammar_name)
231
+ act_token('.')
232
+ r = apply(:rule_name)
233
+ a = act_may(lambda{apply(:apply_args)})
234
+ Other.new(g, r, a || [])
235
+ end
236
+ def rule_apply_args()
237
+ act_token('(')
238
+ a = act_may(lambda{apply(:s)
239
+ x = apply(:var_name)
240
+ xs = act_many(lambda{act_token(',')
241
+ apply(:s)
242
+ apply(:var_name)
243
+ })
244
+ [x] + xs
245
+ })
246
+ act_token(')')
247
+ a || []
248
+ end
249
+ def rule_action()
250
+ act_token('{*')
251
+ s = act_many1(lambda{act_or([lambda{act_not(lambda{act_token('*')})
252
+ rule_anything
253
+ },
254
+ lambda{act_token('*')
255
+ act_not(lambda{act_token('}')})
256
+ ''
257
+ },
258
+ ])
259
+ })
260
+ act_token('*}')
261
+ Action.new(s.join)
262
+ end
263
+ def rule_where()
264
+ act_token('?{*')
265
+ s = act_many1(lambda{act_or([lambda{act_not(lambda{act_token('*')})
266
+ rule_anything
267
+ },
268
+ lambda{act_token('*')
269
+ act_not(lambda{act_token('}')})
270
+ ''
271
+ },
272
+ ])
273
+ })
274
+ act_token('*}')
275
+ Where.new(s.join)
276
+ end
277
+ def rule_rule_name()
278
+ x = rule_charset(%[a-z_])
279
+ xs = act_many(lambda{rule_charset(%[a-zA-Z_0-9])})
280
+ ([x] + xs).join
281
+ end
282
+ def rule_var_name()
283
+ x = rule_charset(%[a-z_])
284
+ xs = act_many(lambda{rule_charset(%[a-zA-Z_0-9])})
285
+ ([x] + xs).join
286
+ end
287
+ def rule_grammar_name()
288
+ x = rule_charset(%[A-Z])
289
+ xs = act_many(lambda{rule_charset(%[a-zA-Z_0-9])})
290
+ ([x] + xs).join
291
+ end
292
+ def rule_dq_string()
293
+ act_token('"')
294
+ s = act_many1(lambda{act_or([lambda{act_not(lambda{act_token('"')})
295
+ rule_anything
296
+ },
297
+ lambda{act_token('\"')
298
+ },
299
+ ])
300
+ })
301
+ act_token('"')
302
+ s.join
303
+ end
304
+ def rule_q_string()
305
+ act_token("'")
306
+ s = act_many1(lambda{act_or([lambda{act_not(lambda{act_token("'")})
307
+ rule_anything
308
+ },
309
+ lambda{act_token("\\'")
310
+ },
311
+ ])
312
+ })
313
+ act_token("'")
314
+ s.join
315
+ end
316
+ def rule_charclass()
317
+ act_token('[')
318
+ s = act_many1(lambda{act_or([lambda{act_not(lambda{act_token(']')})
319
+ rule_anything
320
+ },
321
+ lambda{act_token('\]')
322
+ },
323
+ ])
324
+ })
325
+ act_token(']')
326
+ s.join
327
+ end
328
+ def rule_s()
329
+ act_many(lambda{act_or([lambda{apply(:comment)
330
+ },
331
+ lambda{rule_charset(%[ \t\r\n])
332
+ },
333
+ ])
334
+ })
335
+ end
336
+ def rule_fs()
337
+ act_many1(lambda{act_or([lambda{apply(:comment)
338
+ },
339
+ lambda{rule_charset(%[ \t\r\n])
340
+ },
341
+ ])
342
+ })
343
+ end
344
+ def rule_comment()
345
+ act_token('#')
346
+ act_many(lambda{act_not(lambda{act_token("\n")})
347
+ rule_anything
348
+ })
349
+ act_token("\n")
350
+ end
351
+ end