ed-precompiled_racc 1.8.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.
- checksums.yaml +7 -0
- data/BSDL +22 -0
- data/COPYING +56 -0
- data/ChangeLog +846 -0
- data/README.ja.rdoc +58 -0
- data/README.rdoc +60 -0
- data/TODO +5 -0
- data/bin/racc +320 -0
- data/doc/en/grammar.en.rdoc +218 -0
- data/doc/en/grammar2.en.rdoc +219 -0
- data/doc/ja/command.ja.html +99 -0
- data/doc/ja/debug.ja.rdoc +36 -0
- data/doc/ja/grammar.ja.rdoc +348 -0
- data/doc/ja/index.ja.html +10 -0
- data/doc/ja/parser.ja.rdoc +125 -0
- data/doc/ja/usage.ja.html +414 -0
- data/ext/racc/cparse/cparse.c +840 -0
- data/ext/racc/cparse/extconf.rb +8 -0
- data/lib/racc/compat.rb +33 -0
- data/lib/racc/debugflags.rb +60 -0
- data/lib/racc/exception.rb +16 -0
- data/lib/racc/grammar.rb +1191 -0
- data/lib/racc/grammarfileparser.rb +667 -0
- data/lib/racc/info.rb +18 -0
- data/lib/racc/iset.rb +92 -0
- data/lib/racc/logfilegenerator.rb +212 -0
- data/lib/racc/parser-text.rb +496 -0
- data/lib/racc/parser.rb +650 -0
- data/lib/racc/parserfilegenerator.rb +473 -0
- data/lib/racc/sourcetext.rb +35 -0
- data/lib/racc/state.rb +976 -0
- data/lib/racc/statetransitiontable.rb +311 -0
- data/lib/racc/static.rb +5 -0
- data/lib/racc.rb +6 -0
- metadata +92 -0
@@ -0,0 +1,667 @@
|
|
1
|
+
#--
|
2
|
+
#
|
3
|
+
#
|
4
|
+
#
|
5
|
+
# Copyright (c) 1999-2006 Minero Aoki
|
6
|
+
#
|
7
|
+
# This program is free software.
|
8
|
+
# You can distribute/modify this program under the same terms of ruby.
|
9
|
+
# see the file "COPYING".
|
10
|
+
#
|
11
|
+
#++
|
12
|
+
|
13
|
+
require_relative '../racc'
|
14
|
+
require_relative 'compat'
|
15
|
+
require_relative 'grammar'
|
16
|
+
require_relative 'parserfilegenerator'
|
17
|
+
require_relative 'sourcetext'
|
18
|
+
require 'stringio'
|
19
|
+
|
20
|
+
module Racc
|
21
|
+
|
22
|
+
grammar = Grammar.define {
|
23
|
+
g = self
|
24
|
+
|
25
|
+
g.class = seq(:CLASS, :cname, many(:param), :RULE, :rules, option(:END))
|
26
|
+
|
27
|
+
g.cname = seq(:rubyconst) {|name|
|
28
|
+
@result.params.classname = name
|
29
|
+
}\
|
30
|
+
| seq(:rubyconst, "<", :rubyconst) {|c, _, s|
|
31
|
+
@result.params.classname = c
|
32
|
+
@result.params.superclass = s
|
33
|
+
}
|
34
|
+
|
35
|
+
g.rubyconst = separated_by1(:colon2, :SYMBOL) {|syms|
|
36
|
+
syms.map {|s| s.to_s }.join('::')
|
37
|
+
}
|
38
|
+
|
39
|
+
g.colon2 = seq(':', ':')
|
40
|
+
|
41
|
+
g.param = seq(:CONV, many1(:convdef), :END) {|*|
|
42
|
+
#@grammar.end_convert_block # FIXME
|
43
|
+
}\
|
44
|
+
| seq(:PRECHIGH, many1(:precdef), :PRECLOW) {|*|
|
45
|
+
@grammar.end_precedence_declaration true
|
46
|
+
}\
|
47
|
+
| seq(:PRECLOW, many1(:precdef), :PRECHIGH) {|*|
|
48
|
+
@grammar.end_precedence_declaration false
|
49
|
+
}\
|
50
|
+
| seq(:START, :symbol) {|_, sym|
|
51
|
+
@grammar.start_symbol = sym
|
52
|
+
}\
|
53
|
+
| seq(:TOKEN, :symbols) {|_, syms|
|
54
|
+
syms.each do |s|
|
55
|
+
s.should_terminal
|
56
|
+
end
|
57
|
+
}\
|
58
|
+
| seq(:OPTION, :options) {|_, syms|
|
59
|
+
syms.each do |opt|
|
60
|
+
case opt
|
61
|
+
when 'result_var'
|
62
|
+
@result.params.result_var = true
|
63
|
+
when 'no_result_var'
|
64
|
+
@result.params.result_var = false
|
65
|
+
when 'omit_action_call'
|
66
|
+
@result.params.omit_action_call = true
|
67
|
+
when 'no_omit_action_call'
|
68
|
+
@result.params.omit_action_call = false
|
69
|
+
else
|
70
|
+
raise CompileError, "unknown option: #{opt}"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
}\
|
74
|
+
| seq(:EXPECT, :DIGIT) {|_, num|
|
75
|
+
if @grammar.n_expected_srconflicts
|
76
|
+
raise CompileError, "`expect' seen twice"
|
77
|
+
end
|
78
|
+
@grammar.n_expected_srconflicts = num
|
79
|
+
}\
|
80
|
+
| seq(:ERROR_ON_EXPECT_MISMATCH) {|*|
|
81
|
+
@grammar.error_on_expect_mismatch = true
|
82
|
+
}
|
83
|
+
|
84
|
+
g.convdef = seq(:symbol, :STRING) {|sym, code|
|
85
|
+
sym.serialized = code
|
86
|
+
}
|
87
|
+
|
88
|
+
g.precdef = seq(:LEFT, :symbols) {|_, syms|
|
89
|
+
@grammar.declare_precedence :Left, syms
|
90
|
+
}\
|
91
|
+
| seq(:RIGHT, :symbols) {|_, syms|
|
92
|
+
@grammar.declare_precedence :Right, syms
|
93
|
+
}\
|
94
|
+
| seq(:NONASSOC, :symbols) {|_, syms|
|
95
|
+
@grammar.declare_precedence :Nonassoc, syms
|
96
|
+
}
|
97
|
+
|
98
|
+
g.symbols = seq(:symbol) {|sym|
|
99
|
+
[sym]
|
100
|
+
}\
|
101
|
+
| seq(:symbols, :symbol) {|list, sym|
|
102
|
+
list.push sym
|
103
|
+
list
|
104
|
+
}\
|
105
|
+
| seq(:symbols, "|")
|
106
|
+
|
107
|
+
g.symbol = seq(:SYMBOL) {|sym| @grammar.intern(sym) }\
|
108
|
+
| seq(:STRING) {|str| @grammar.intern(str) }
|
109
|
+
|
110
|
+
g.options = many(:SYMBOL) {|syms| syms.map {|s| s.to_s } }
|
111
|
+
|
112
|
+
g.rules = option(:rules_core) {|list|
|
113
|
+
add_rule_block list unless list.empty?
|
114
|
+
nil
|
115
|
+
}
|
116
|
+
|
117
|
+
g.rules_core = seq(:symbol) {|sym|
|
118
|
+
[sym]
|
119
|
+
}\
|
120
|
+
| seq(:rules_core, :rule_item) {|list, i|
|
121
|
+
list.push i
|
122
|
+
list
|
123
|
+
}\
|
124
|
+
| seq(:rules_core, ';') {|list, *|
|
125
|
+
add_rule_block list unless list.empty?
|
126
|
+
list.clear
|
127
|
+
list
|
128
|
+
}\
|
129
|
+
| seq(:rules_core, ':') {|list, *|
|
130
|
+
next_target = list.pop
|
131
|
+
add_rule_block list unless list.empty?
|
132
|
+
[next_target]
|
133
|
+
}
|
134
|
+
|
135
|
+
g.rule_item = seq(:symbol)\
|
136
|
+
| seq("|") {|*|
|
137
|
+
OrMark.new(@scanner.lineno)
|
138
|
+
}\
|
139
|
+
| seq("?") {|*|
|
140
|
+
OptionMark.new(@scanner.lineno)
|
141
|
+
}\
|
142
|
+
| seq("*") {|*|
|
143
|
+
ManyMark.new(@scanner.lineno)
|
144
|
+
}\
|
145
|
+
| seq("+") {|*|
|
146
|
+
Many1Mark.new(@scanner.lineno)
|
147
|
+
}\
|
148
|
+
| seq("(") {|*|
|
149
|
+
GroupStartMark.new(@scanner.lineno)
|
150
|
+
}\
|
151
|
+
| seq(")") {|*|
|
152
|
+
GroupEndMark.new(@scanner.lineno)
|
153
|
+
}\
|
154
|
+
| seq("=", :symbol) {|_, sym|
|
155
|
+
Prec.new(sym, @scanner.lineno)
|
156
|
+
}\
|
157
|
+
| seq(:ACTION) {|src|
|
158
|
+
UserAction.source_text(src)
|
159
|
+
}
|
160
|
+
}
|
161
|
+
|
162
|
+
GrammarFileParser = grammar.parser_class
|
163
|
+
|
164
|
+
if grammar.states.srconflict_exist?
|
165
|
+
raise 'Racc boot script fatal: S/R conflict in build'
|
166
|
+
end
|
167
|
+
if grammar.states.rrconflict_exist?
|
168
|
+
raise 'Racc boot script fatal: R/R conflict in build'
|
169
|
+
end
|
170
|
+
|
171
|
+
class GrammarFileParser # reopen
|
172
|
+
|
173
|
+
class Result
|
174
|
+
def initialize(grammar)
|
175
|
+
@grammar = grammar
|
176
|
+
@params = ParserFileGenerator::Params.new
|
177
|
+
end
|
178
|
+
|
179
|
+
attr_reader :grammar
|
180
|
+
attr_reader :params
|
181
|
+
end
|
182
|
+
|
183
|
+
def GrammarFileParser.parse_file(filename)
|
184
|
+
parse(File.read(filename), filename, 1)
|
185
|
+
end
|
186
|
+
|
187
|
+
def GrammarFileParser.parse(src, filename = '-', lineno = 1)
|
188
|
+
new().parse(src, filename, lineno)
|
189
|
+
end
|
190
|
+
|
191
|
+
def initialize(debug_flags = DebugFlags.new)
|
192
|
+
@yydebug = debug_flags.parse
|
193
|
+
end
|
194
|
+
|
195
|
+
def parse(src, filename = '-', lineno = 1)
|
196
|
+
@filename = filename
|
197
|
+
@lineno = lineno
|
198
|
+
@scanner = GrammarFileScanner.new(src, @filename)
|
199
|
+
@scanner.debug = @yydebug
|
200
|
+
@grammar = Grammar.new
|
201
|
+
@result = Result.new(@grammar)
|
202
|
+
@embedded_action_seq = 0
|
203
|
+
yyparse @scanner, :yylex
|
204
|
+
parse_user_code
|
205
|
+
@result.grammar.init
|
206
|
+
@result
|
207
|
+
end
|
208
|
+
|
209
|
+
private
|
210
|
+
|
211
|
+
def next_token
|
212
|
+
@scanner.scan
|
213
|
+
end
|
214
|
+
|
215
|
+
def on_error(tok, val, _values)
|
216
|
+
if val.respond_to?(:id2name)
|
217
|
+
v = val.id2name
|
218
|
+
elsif val.kind_of?(String)
|
219
|
+
v = val
|
220
|
+
else
|
221
|
+
v = val.inspect
|
222
|
+
end
|
223
|
+
raise CompileError, "#{location()}: unexpected token '#{v}'"
|
224
|
+
end
|
225
|
+
|
226
|
+
def location
|
227
|
+
"#{@filename}:#{@lineno - 1 + @scanner.lineno}"
|
228
|
+
end
|
229
|
+
|
230
|
+
def add_rule_block(list)
|
231
|
+
target = list.shift
|
232
|
+
case target
|
233
|
+
when OrMark, OptionMark, ManyMark, Many1Mark, GroupStartMark, GroupEndMark, UserAction, Prec
|
234
|
+
raise CompileError, "#{target.lineno}: unexpected symbol #{target.name}"
|
235
|
+
end
|
236
|
+
enum = list.each.with_index
|
237
|
+
_, sym, idx = _add_rule_block(target, enum)
|
238
|
+
if idx
|
239
|
+
# sym is Racc::GroupEndMark
|
240
|
+
raise "#{sym.lineno}: unexpected symbol ')' at pos=#{idx}"
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
def _add_rule_block(target, enum)
|
245
|
+
rules = [] # [ [seqs, sprec], .. ]
|
246
|
+
curr = []
|
247
|
+
sprec = nil
|
248
|
+
while (sym, idx = enum.next rescue nil)
|
249
|
+
case sym
|
250
|
+
when OrMark
|
251
|
+
rules << [curr, sprec]
|
252
|
+
curr = []
|
253
|
+
sprec = nil
|
254
|
+
when OptionMark
|
255
|
+
curr << _add_option_rule(curr.pop)
|
256
|
+
when ManyMark
|
257
|
+
curr << _add_many_rule(curr.pop)
|
258
|
+
when Many1Mark
|
259
|
+
curr << _add_many1_rule(curr.pop)
|
260
|
+
when GroupStartMark
|
261
|
+
curr << _add_group_rule(enum)
|
262
|
+
when GroupEndMark
|
263
|
+
rules << [curr, sprec]
|
264
|
+
return rules, sym, idx
|
265
|
+
when Prec
|
266
|
+
raise CompileError, "'=<prec>' used twice in one rule" if sprec
|
267
|
+
sprec = sym.symbol
|
268
|
+
else
|
269
|
+
curr.push sym
|
270
|
+
end
|
271
|
+
end
|
272
|
+
rules << [curr, sprec]
|
273
|
+
rules.each do |syms, sprec|
|
274
|
+
add_rule target, syms, sprec
|
275
|
+
end
|
276
|
+
nil
|
277
|
+
end
|
278
|
+
|
279
|
+
|
280
|
+
def _add_option_rule(prev)
|
281
|
+
@option_rule_registry ||= {}
|
282
|
+
target = @option_rule_registry[prev.to_s]
|
283
|
+
return target if target
|
284
|
+
target = _gen_target_name("option", prev)
|
285
|
+
@option_rule_registry[prev.to_s] = target
|
286
|
+
act = UserAction.empty
|
287
|
+
@grammar.add Rule.new(target, [], act)
|
288
|
+
@grammar.add Rule.new(target, [prev], act)
|
289
|
+
target
|
290
|
+
end
|
291
|
+
|
292
|
+
def _add_many_rule(prev)
|
293
|
+
@many_rule_registry ||= {}
|
294
|
+
target = @many_rule_registry[prev.to_s]
|
295
|
+
return target if target
|
296
|
+
target = _gen_target_name("many", prev)
|
297
|
+
@many_rule_registry[prev.to_s] = target
|
298
|
+
src = SourceText.new("result = val[1] ? val[1].unshift(val[0]) : val", @filename, @scanner.lineno + 1)
|
299
|
+
act = UserAction.source_text(src)
|
300
|
+
@grammar.add Rule.new(target, [], act)
|
301
|
+
@grammar.add Rule.new(target, [prev, target], act)
|
302
|
+
target
|
303
|
+
end
|
304
|
+
|
305
|
+
def _add_many1_rule(prev)
|
306
|
+
@many1_rule_registry ||= {}
|
307
|
+
target = @many1_rule_registry[prev.to_s]
|
308
|
+
return target if target
|
309
|
+
target = _gen_target_name("many1", prev)
|
310
|
+
@many1_rule_registry[prev.to_s] = target
|
311
|
+
src = SourceText.new("result = val[1] ? val[1].unshift(val[0]) : val", @filename, @scanner.lineno + 1)
|
312
|
+
act = UserAction.source_text(src)
|
313
|
+
@grammar.add Rule.new(target, [prev], act)
|
314
|
+
@grammar.add Rule.new(target, [prev, target], act)
|
315
|
+
target
|
316
|
+
end
|
317
|
+
|
318
|
+
def _add_group_rule(enum)
|
319
|
+
target = @grammar.intern("-temp-group", true)
|
320
|
+
rules, _ = _add_rule_block(target, enum)
|
321
|
+
target_name = rules.map{|syms, sprec| syms.join("-")}.join("|")
|
322
|
+
@group_rule_registry ||= {}
|
323
|
+
unless target = @group_rule_registry[target_name]
|
324
|
+
target = @grammar.intern("-group@#{target_name}", true)
|
325
|
+
@group_rule_registry[target_name] = target
|
326
|
+
src = SourceText.new("result = val", @filename, @scanner.lineno + 1)
|
327
|
+
act = UserAction.source_text(src)
|
328
|
+
rules.each do |syms, sprec|
|
329
|
+
rule = Rule.new(target, syms, act)
|
330
|
+
rule.specified_prec = sprec
|
331
|
+
@grammar.add rule
|
332
|
+
end
|
333
|
+
end
|
334
|
+
target
|
335
|
+
end
|
336
|
+
|
337
|
+
def _gen_target_name(type, sym)
|
338
|
+
@grammar.intern("-#{type}@#{sym.value}", true)
|
339
|
+
end
|
340
|
+
|
341
|
+
def add_rule(target, list, sprec)
|
342
|
+
if list.last.kind_of?(UserAction)
|
343
|
+
act = list.pop
|
344
|
+
else
|
345
|
+
act = UserAction.empty
|
346
|
+
end
|
347
|
+
list.map! {|s| s.kind_of?(UserAction) ? embedded_action(s) : s }
|
348
|
+
rule = Rule.new(target, list, act)
|
349
|
+
rule.specified_prec = sprec
|
350
|
+
@grammar.add rule
|
351
|
+
end
|
352
|
+
|
353
|
+
def embedded_action(act)
|
354
|
+
sym = @grammar.intern("@#{@embedded_action_seq += 1}".intern, true)
|
355
|
+
@grammar.add Rule.new(sym, [], act)
|
356
|
+
sym
|
357
|
+
end
|
358
|
+
|
359
|
+
#
|
360
|
+
# User Code Block
|
361
|
+
#
|
362
|
+
|
363
|
+
def parse_user_code
|
364
|
+
line = @scanner.lineno
|
365
|
+
_, *blocks = *@scanner.epilogue.split(/^----/)
|
366
|
+
blocks.each do |block|
|
367
|
+
header, *body = block.lines.to_a
|
368
|
+
label0, paths = *header.sub(/\A-+/, '').split('=', 2)
|
369
|
+
label = canonical_label(label0)
|
370
|
+
(paths ? paths.strip.split(' ') : []).each do |path|
|
371
|
+
add_user_code label, SourceText.new(File.read(path), path, 1)
|
372
|
+
end
|
373
|
+
add_user_code label, SourceText.new(body.join(''), @filename, line + 1)
|
374
|
+
line += (1 + body.size)
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
USER_CODE_LABELS = {
|
379
|
+
'header' => :header,
|
380
|
+
'prepare' => :header, # obsolete
|
381
|
+
'inner' => :inner,
|
382
|
+
'footer' => :footer,
|
383
|
+
'driver' => :footer # obsolete
|
384
|
+
}
|
385
|
+
|
386
|
+
def canonical_label(src)
|
387
|
+
label = src.to_s.strip.downcase.slice(/\w+/)
|
388
|
+
unless USER_CODE_LABELS.key?(label)
|
389
|
+
raise CompileError, "unknown user code type: #{label.inspect}"
|
390
|
+
end
|
391
|
+
label
|
392
|
+
end
|
393
|
+
|
394
|
+
def add_user_code(label, src)
|
395
|
+
@result.params.public_send(USER_CODE_LABELS[label]).push src
|
396
|
+
end
|
397
|
+
|
398
|
+
end
|
399
|
+
|
400
|
+
|
401
|
+
class GrammarFileScanner
|
402
|
+
|
403
|
+
def initialize(str, filename = '-')
|
404
|
+
@lines = str.b.split(/\n|\r\n|\r/)
|
405
|
+
@filename = filename
|
406
|
+
@lineno = -1
|
407
|
+
@line_head = true
|
408
|
+
@in_rule_blk = false
|
409
|
+
@in_conv_blk = false
|
410
|
+
@in_block = nil
|
411
|
+
@epilogue = ''
|
412
|
+
@debug = false
|
413
|
+
next_line
|
414
|
+
end
|
415
|
+
|
416
|
+
attr_reader :epilogue
|
417
|
+
|
418
|
+
def lineno
|
419
|
+
@lineno + 1
|
420
|
+
end
|
421
|
+
|
422
|
+
attr_accessor :debug
|
423
|
+
|
424
|
+
def yylex(&block)
|
425
|
+
unless @debug
|
426
|
+
yylex0(&block)
|
427
|
+
else
|
428
|
+
yylex0 do |sym, tok|
|
429
|
+
$stderr.printf "%7d %-10s %s\n", lineno(), sym.inspect, tok.inspect
|
430
|
+
yield [sym, tok]
|
431
|
+
end
|
432
|
+
end
|
433
|
+
end
|
434
|
+
|
435
|
+
private
|
436
|
+
|
437
|
+
def yylex0
|
438
|
+
begin
|
439
|
+
until @line.empty?
|
440
|
+
@line.sub!(/\A\s+/, '')
|
441
|
+
if /\A\#/ =~ @line
|
442
|
+
break
|
443
|
+
elsif /\A\/\*/ =~ @line
|
444
|
+
skip_comment
|
445
|
+
elsif s = reads(/\A[a-zA-Z_]\w*/)
|
446
|
+
yield [atom_symbol(s), s.intern]
|
447
|
+
elsif s = reads(/\A\d+/)
|
448
|
+
yield [:DIGIT, s.to_i]
|
449
|
+
elsif ch = reads(/\A./)
|
450
|
+
case ch
|
451
|
+
when '"', "'"
|
452
|
+
yield [:STRING, eval(scan_quoted(ch))]
|
453
|
+
when '{'
|
454
|
+
lineno = lineno()
|
455
|
+
yield [:ACTION, SourceText.new(scan_action(), @filename, lineno)]
|
456
|
+
else
|
457
|
+
if ch == '|'
|
458
|
+
@line_head = false
|
459
|
+
end
|
460
|
+
yield [ch, ch]
|
461
|
+
end
|
462
|
+
else
|
463
|
+
end
|
464
|
+
end
|
465
|
+
end while next_line()
|
466
|
+
yield nil
|
467
|
+
end
|
468
|
+
|
469
|
+
def next_line
|
470
|
+
@lineno += 1
|
471
|
+
@line = @lines[@lineno]
|
472
|
+
if not @line or /\A----/ =~ @line
|
473
|
+
@epilogue = @lines.join("\n")
|
474
|
+
@lines.clear
|
475
|
+
@line = nil
|
476
|
+
if @in_block
|
477
|
+
@lineno -= 1
|
478
|
+
scan_error! sprintf('unterminated %s', @in_block)
|
479
|
+
end
|
480
|
+
false
|
481
|
+
else
|
482
|
+
@line.sub!(/(?:\n|\r\n|\r)\z/, '')
|
483
|
+
@line_head = true
|
484
|
+
true
|
485
|
+
end
|
486
|
+
end
|
487
|
+
|
488
|
+
ReservedWord = {
|
489
|
+
'right' => :RIGHT,
|
490
|
+
'left' => :LEFT,
|
491
|
+
'nonassoc' => :NONASSOC,
|
492
|
+
'preclow' => :PRECLOW,
|
493
|
+
'prechigh' => :PRECHIGH,
|
494
|
+
'token' => :TOKEN,
|
495
|
+
'convert' => :CONV,
|
496
|
+
'options' => :OPTION,
|
497
|
+
'start' => :START,
|
498
|
+
'expect' => :EXPECT,
|
499
|
+
'error_on_expect_mismatch' => :ERROR_ON_EXPECT_MISMATCH,
|
500
|
+
'class' => :CLASS,
|
501
|
+
'rule' => :RULE,
|
502
|
+
'end' => :END
|
503
|
+
}
|
504
|
+
|
505
|
+
def atom_symbol(token)
|
506
|
+
if token == 'end'
|
507
|
+
symbol = :END
|
508
|
+
@in_conv_blk = false
|
509
|
+
@in_rule_blk = false
|
510
|
+
else
|
511
|
+
if @line_head and not @in_conv_blk and not @in_rule_blk
|
512
|
+
symbol = ReservedWord[token] || :SYMBOL
|
513
|
+
else
|
514
|
+
symbol = :SYMBOL
|
515
|
+
end
|
516
|
+
case symbol
|
517
|
+
when :RULE then @in_rule_blk = true
|
518
|
+
when :CONV then @in_conv_blk = true
|
519
|
+
end
|
520
|
+
end
|
521
|
+
@line_head = false
|
522
|
+
symbol
|
523
|
+
end
|
524
|
+
|
525
|
+
def skip_comment
|
526
|
+
@in_block = 'comment'
|
527
|
+
until m = /\*\//.match(@line)
|
528
|
+
next_line
|
529
|
+
end
|
530
|
+
@line = m.post_match
|
531
|
+
@in_block = nil
|
532
|
+
end
|
533
|
+
|
534
|
+
$raccs_print_type = false
|
535
|
+
|
536
|
+
def scan_action
|
537
|
+
buf = String.new
|
538
|
+
nest = 1
|
539
|
+
pre = nil
|
540
|
+
@in_block = 'action'
|
541
|
+
begin
|
542
|
+
pre = nil
|
543
|
+
if s = reads(/\A\s+/)
|
544
|
+
# does not set 'pre'
|
545
|
+
buf << s
|
546
|
+
end
|
547
|
+
until @line.empty?
|
548
|
+
if s = reads(/\A[^'"`{}%#\/\$]+/)
|
549
|
+
buf << (pre = s)
|
550
|
+
next
|
551
|
+
end
|
552
|
+
case ch = read(1)
|
553
|
+
when '{'
|
554
|
+
nest += 1
|
555
|
+
buf << (pre = ch)
|
556
|
+
when '}'
|
557
|
+
nest -= 1
|
558
|
+
if nest == 0
|
559
|
+
@in_block = nil
|
560
|
+
buf.sub!(/[ \t\f]+\z/, '')
|
561
|
+
return buf
|
562
|
+
end
|
563
|
+
buf << (pre = ch)
|
564
|
+
when '#' # comment
|
565
|
+
buf << ch << @line
|
566
|
+
break
|
567
|
+
when "'", '"', '`'
|
568
|
+
buf << (pre = scan_quoted(ch))
|
569
|
+
when '%'
|
570
|
+
if literal_head? pre, @line
|
571
|
+
# % string, regexp, array
|
572
|
+
buf << ch
|
573
|
+
case ch = read(1)
|
574
|
+
when /[qQx]/n
|
575
|
+
buf << ch << (pre = scan_quoted(read(1), '%string'))
|
576
|
+
when /wW/n
|
577
|
+
buf << ch << (pre = scan_quoted(read(1), '%array'))
|
578
|
+
when /s/n
|
579
|
+
buf << ch << (pre = scan_quoted(read(1), '%symbol'))
|
580
|
+
when /r/n
|
581
|
+
buf << ch << (pre = scan_quoted(read(1), '%regexp'))
|
582
|
+
when /[a-zA-Z0-9= ]/n # does not include "_"
|
583
|
+
scan_error! "unknown type of % literal '%#{ch}'"
|
584
|
+
else
|
585
|
+
buf << (pre = scan_quoted(ch, '%string'))
|
586
|
+
end
|
587
|
+
else
|
588
|
+
# operator
|
589
|
+
buf << '||op->' if $raccs_print_type
|
590
|
+
buf << (pre = ch)
|
591
|
+
end
|
592
|
+
when '/'
|
593
|
+
if literal_head? pre, @line
|
594
|
+
# regexp
|
595
|
+
buf << (pre = scan_quoted(ch, 'regexp'))
|
596
|
+
else
|
597
|
+
# operator
|
598
|
+
buf << '||op->' if $raccs_print_type
|
599
|
+
buf << (pre = ch)
|
600
|
+
end
|
601
|
+
when '$' # gvar
|
602
|
+
buf << ch << (pre = read(1))
|
603
|
+
else
|
604
|
+
raise 'racc: fatal: must not happen'
|
605
|
+
end
|
606
|
+
end
|
607
|
+
buf << "\n"
|
608
|
+
end while next_line()
|
609
|
+
raise 'racc: fatal: scan finished before parser finished'
|
610
|
+
end
|
611
|
+
|
612
|
+
def literal_head?(pre, post)
|
613
|
+
(!pre || /[a-zA-Z_0-9]/n !~ pre[-1,1]) &&
|
614
|
+
!post.empty? && /\A[\s\=]/n !~ post
|
615
|
+
end
|
616
|
+
|
617
|
+
def read(len)
|
618
|
+
s = @line[0, len]
|
619
|
+
@line = @line[len .. -1]
|
620
|
+
s
|
621
|
+
end
|
622
|
+
|
623
|
+
def reads(re)
|
624
|
+
m = re.match(@line) or return nil
|
625
|
+
@line = m.post_match
|
626
|
+
m[0]
|
627
|
+
end
|
628
|
+
|
629
|
+
def scan_quoted(left, tag = 'string')
|
630
|
+
buf = left.dup
|
631
|
+
buf = "||#{tag}->" + buf if $raccs_print_type
|
632
|
+
re = get_quoted_re(left)
|
633
|
+
sv, @in_block = @in_block, tag
|
634
|
+
begin
|
635
|
+
if s = reads(re)
|
636
|
+
buf << s
|
637
|
+
break
|
638
|
+
else
|
639
|
+
buf << @line
|
640
|
+
end
|
641
|
+
end while next_line()
|
642
|
+
@in_block = sv
|
643
|
+
buf << "<-#{tag}||" if $raccs_print_type
|
644
|
+
buf
|
645
|
+
end
|
646
|
+
|
647
|
+
LEFT_TO_RIGHT = {
|
648
|
+
'(' => ')',
|
649
|
+
'{' => '}',
|
650
|
+
'[' => ']',
|
651
|
+
'<' => '>'
|
652
|
+
}
|
653
|
+
|
654
|
+
CACHE = {}
|
655
|
+
|
656
|
+
def get_quoted_re(left)
|
657
|
+
term = Regexp.quote(LEFT_TO_RIGHT[left] || left)
|
658
|
+
CACHE[left] ||= /\A[^#{term}\\]*(?:\\.[^\\#{term}]*)*#{term}/
|
659
|
+
end
|
660
|
+
|
661
|
+
def scan_error!(msg)
|
662
|
+
raise CompileError, "#{lineno()}: #{msg}"
|
663
|
+
end
|
664
|
+
|
665
|
+
end
|
666
|
+
|
667
|
+
end # module Racc
|
data/lib/racc/info.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#--
|
3
|
+
#
|
4
|
+
#
|
5
|
+
#
|
6
|
+
# Copyright (c) 1999-2006 Minero Aoki
|
7
|
+
#
|
8
|
+
# This program is free software.
|
9
|
+
# You can distribute/modify this program under the same terms of ruby.
|
10
|
+
# see the file "COPYING".
|
11
|
+
#
|
12
|
+
#++
|
13
|
+
|
14
|
+
module Racc
|
15
|
+
VERSION = '1.8.1'
|
16
|
+
Version = VERSION
|
17
|
+
Copyright = 'Copyright (c) 1999-2006 Minero Aoki'
|
18
|
+
end
|