depager 0.1.9 → 0.2.0

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.
Files changed (63) hide show
  1. data/ChangeLog +4 -0
  2. data/bin/depager +1 -0
  3. data/data/depager/misc/depager-mode.el +35 -24
  4. data/data/depager/pre-setup.rb +3 -0
  5. data/examples/Rakefile +36 -0
  6. data/examples/c89/c89.dr +496 -0
  7. data/examples/c89/c89.tab.rb +2197 -0
  8. data/examples/c89/test.c89 +10 -0
  9. data/{data/depager/sample → examples}/extension/paction.dr +0 -0
  10. data/{data/depager/sample → examples}/extension/pactiontest.dr +0 -0
  11. data/{data/depager/sample → examples}/pl0d/pl0ds.dr +0 -0
  12. data/examples/pl0d/pl0ds.tab.rb +1702 -0
  13. data/{data/depager/sample/pl0d/pl0test.pl0 → examples/pl0d/test.pl0ds} +0 -0
  14. data/{data/depager/sample → examples}/sample_calc/calc.action.dr +0 -0
  15. data/examples/sample_calc/calc.action.tab.rb +283 -0
  16. data/{data/depager/sample → examples}/sample_calc/calc.astdf.dr +0 -0
  17. data/examples/sample_calc/calc.astdf.tab.rb +476 -0
  18. data/{data/depager/sample → examples}/sample_calc/calc.astl.action.dr +0 -0
  19. data/examples/sample_calc/calc.astl.action.tab.rb +593 -0
  20. data/{data/depager/sample → examples}/sample_calc/calc.astl.dr +0 -0
  21. data/examples/sample_calc/calc.astl.tab.rb +501 -0
  22. data/{data/depager/sample → examples}/sample_calc/calc.atree.dr +0 -0
  23. data/examples/sample_calc/calc.atree.tab.rb +277 -0
  24. data/{data/depager/sample → examples}/sample_calc/calc.cst.dr +0 -0
  25. data/examples/sample_calc/calc.cst.tab.rb +478 -0
  26. data/{data/depager/sample → examples}/sample_calc/calc.dr +0 -0
  27. data/{data/depager/sample → examples}/sample_calc/calc.lex.dr +0 -0
  28. data/examples/sample_calc/calc.lex.tab.rb +192 -0
  29. data/{data/depager/sample → examples}/sample_calc/calc.nvaction.dr +0 -0
  30. data/examples/sample_calc/calc.nvaction.tab.rb +291 -0
  31. data/examples/sample_calc/calc.tab.rb +183 -0
  32. data/{data/depager/sample → examples}/sample_calc/calc_prec.nvaction.dr +0 -0
  33. data/examples/sample_calc/calc_prec.nvaction.tab.rb +257 -0
  34. data/examples/sample_calc/test.calc +1 -0
  35. data/{data/depager/sample/slex_test/slextest1.dr → examples/slex_test/divreg.slex.dr} +3 -11
  36. data/examples/slex_test/divreg.slex.tab.rb +227 -0
  37. data/{data/depager/sample/slex_test/slextest2.dr → examples/slex_test/ljoin.slex.dr} +10 -7
  38. data/examples/slex_test/ljoin.slex.tab.rb +277 -0
  39. data/examples/slex_test/test.divreg +1 -0
  40. data/examples/slex_test/test.ljoin +3 -0
  41. data/lib/depager.rb +194 -127
  42. data/lib/depager/Rakefile +8 -4
  43. data/lib/depager/ast_base.dr +3 -3
  44. data/lib/depager/ast_base.rb +197 -144
  45. data/lib/depager/atree.rb +55 -36
  46. data/lib/depager/cst.dr +6 -4
  47. data/lib/depager/cst.rb +69 -49
  48. data/lib/depager/grammar.rb +136 -0
  49. data/lib/depager/lex.dr +22 -8
  50. data/lib/depager/lex.rb +94 -53
  51. data/lib/depager/lr.rb +101 -167
  52. data/lib/depager/parse_action.rb +1 -1
  53. data/lib/depager/parser.rb +34 -7
  54. data/lib/depager/slex.dr +76 -36
  55. data/lib/depager/slex.rb +345 -151
  56. data/lib/depager/srp.rb +3 -2
  57. data/lib/depager/template/extension_lalr_slave.erb +1 -1
  58. data/lib/depager/template/single_lalr_parser.erb +1 -1
  59. data/lib/depager/utils.rb +2 -1
  60. data/lib/depager/version.rb +2 -2
  61. metadata +42 -28
  62. data/Manifest.txt +0 -52
  63. data/lib/depager/psrtmpl.rb +0 -33
data/lib/depager/lr.rb CHANGED
@@ -1,31 +1,32 @@
1
- module Depager
2
- class G
3
- attr_accessor :rulelist, :gh, :syms, :nonterms, :terms, :closure, :ismap, :nssize, :tla
4
- attr_accessor :precs, :epr, :epr2, :f0e, :first1
5
- Eps = 0x3fffffff #epsilon
6
- #Eps = []
7
- def initialize rulelist, ts, ns, precs = nil
8
- @nssize = ns.size
9
- @precs = precs
10
- @syms = ns.invert.merge(ts.invert)
11
- @tla = @syms.size
12
-
13
- @rulelist = rulelist
14
- @gh = []; @nssize.times{|i| @gh[i] = []}
15
- @epr = {}
16
- @f0e = {}
17
- @rulelist.each_with_index do |rule, rx|
18
- rule.g = self
19
- rule.n = rx
20
- @gh[rule.l].push rule
21
- if rule.r.empty?
22
- @epr[rule.l] = rule.n
23
- @f0e[rule.l] = { rule.n => [Eps] }
24
- end
25
- end
26
- make_sym_first
1
+ require 'pp'
2
+ require 'depager/grammar.rb'
3
+ module Depager::LALR
4
+ class SingleParserGenerator < Simple::SingleGenerator
5
+ Tmplfile = 'single_lalr_parser.erb'
6
+ def initialize d_parser
7
+ super
8
+ @parsing_method = LALR
9
+ @basis_name = @d_parser.target_name + '.new()'
10
+ end
11
+ end
12
+
13
+ class ExtensionParserGenerator < Simple::ExtensionGenerator
14
+ TmplfileMaster = "#{Tmpldir}/extension_lalr_master.erb"
15
+ TmplfileSlave = "#{Tmpldir}/extension_lalr_slave.erb"
16
+ def initialize d_parser
17
+ super
18
+ @parsing_method = LALR
19
+ @basis_name = 'self'
20
+ end
21
+ end
22
+
23
+ Eps = Depager::ParsingMethodCommon::G::Eps
24
+ class Grammar < Depager::ParsingMethodCommon::G
25
+ attr_accessor :closure, :memo_closure1
26
+ def initialize_depend
27
27
  make_sym_f0e
28
28
  @closure = {}
29
+ @memo_closure1 = {}
29
30
  end
30
31
 
31
32
  def make_sym_f0e
@@ -60,127 +61,46 @@ module Depager
60
61
  end
61
62
  end while cnt
62
63
  end
63
-
64
- def make_sym_first
65
- @first1 = {@tla => [@tla]}
66
- @syms.each_key do |s|
67
- if terms? s
68
- @first1[s] = [s]
69
- else
70
- @first1[s] = []
71
- @first1[s].push Eps if @epr[s]
72
- end
73
- end
74
- begin
75
- cnt = false
76
- @syms.each_key do |s|
77
- @gh[s].each do |rule|
78
- rule.r.each do |es|
79
- ss = @first1[es] - @first1[s]
80
- unless ss.empty?
81
- @first1[s] |= ss
82
- cnt = true
83
- end
84
- break unless @first1[es].include? Eps
85
- end
86
- unless @first1[s].include? Eps
87
- if rule.r.all?{|i| @first1[i].include? Eps }
88
- @first1.push Eps
89
- cnt = true
90
- end
91
- end
92
- end if nonterms? s
93
- end
94
- end while cnt
95
- end
96
-
97
- def first p
98
- r = []
99
- x = 0
100
- p.each do |i|
101
- if i == Eps
102
- elsif i.class == Array
103
- i.each do |j|
104
- r |= @first1[j]
105
- end
106
- break unless i.any?{|j| @epr[j] || j==Eps }
107
- else
108
- r |= @first1[i]
109
- break unless @epr[i]
110
- end
111
- x += 1
112
- end
113
- r -= [Eps]
114
- r |= [Eps] if x == p.size
115
- return r
116
- end
117
-
118
- def terms? i
119
- i && i >= @nssize
120
- end
121
-
122
- def nonterms? i
123
- i && i < @nssize
124
- end
125
-
126
- def [](n)
127
- @rulelist[n]
128
- end
129
64
  end
130
-
131
- class Rule
132
- attr_accessor :l, :r, :g, :n, :act, :epr, :prec
133
- def initialize l, r, g = nil, n = nil, act = nil, prec = nil
134
- @l = l
135
- @r = r
136
- @g = g
137
- @n = n
138
- @act = act
139
- @epr = []
140
- @prec = prec
141
- end
142
- def self.[] l, r, prec = nil
143
- Rule.new l, r, nil, nil, nil, prec
144
- end
145
-
146
- def to_s
147
- r = @r.map{|i| @g.syms[i]}.join(' ')
148
- "(#{'%03s'%@n}) #{@g.syms[@l]} : #{r}"
65
+ class Rule < Depager::ParsingMethodCommon::Rule
66
+ def initialize_depend
149
67
  end
150
-
151
- def hash
152
- (@l.hash % 37) * (@r.hash % 37)
153
- end
154
- def eql? i
155
- @l == i.l && @r == i.r
156
- end
157
- alias == eql?
158
-
159
68
  def closure1 n, la
160
- i = 0
161
- j = [ LRItem[self, n, la] ]
162
- h = {j[0] => j.size-1}
69
+ key = [self.n, n, la]
70
+ return @g.memo_closure1[key] if @g.memo_closure1[key]
71
+ _G = @g
72
+ _I = [ LRItem[self, n, la] ]
73
+ memo = { _I[0].rule.n => _I[0] }
74
+ _I.each do |_IA|
75
+ _B, beta = _IA.dotsym, _IA.dotrest
76
+ next if !_B or !_G.gh[_B]
77
+
78
+ b = _G.first(beta)
79
+ if b.include? Eps
80
+ b.delete(Eps)
81
+ b |= _IA.la
82
+ end
163
83
 
164
- while i < j.size
165
- ji = j[i]
166
- b = ji.rule.r[(ji.n+1) .. ji.rule.r.size]
167
- b = [] unless b
168
-
169
- if (x = ji.rule.r[ji.n]) && (a = @g.gh[x])
170
- a.each do |rule|
171
- li = LRItem[rule, 0]
172
- if x = h[li]
173
- j[x].la.concat @g.first(b + [ji.la])
174
- else
175
- li.la = @g.first(b + [ji.la])
176
- j << li
177
- h[li] = j.size-1
84
+ _G.gh[_B].each do |_Brule|
85
+ if li = memo[_Brule.n]
86
+ #warn "= #{li} ;"+
87
+ # " [#{(beta+[a]).map{|i| @g.syms[i] || '$' }}]"+
88
+ # " :: #{b.map{|i| @g.syms[i] }}"
89
+ s0 = li.la.size
90
+ li.la |= b
91
+ if li.la.size > s0 # (b - li.la).empty?
92
+ _I << li
93
+ # warn "! #{b.map{|i| @g.syms[i]}}; #{li}"
178
94
  end
95
+ else
96
+ li = memo[_Brule.n] = LRItem[_Brule, 0, b]
97
+ _I << li
98
+ # warn "+ #{memo[_Brule.n]}"
179
99
  end
180
100
  end
181
- i += 1
182
101
  end
183
- j
102
+ @g.memo_closure1[key] = _I
103
+ _I
184
104
  end
185
105
 
186
106
  def closure n, base=nil
@@ -249,6 +169,12 @@ module Depager
249
169
  @goto[x] = I[]
250
170
  end
251
171
  end
172
+ def dotsym
173
+ @rule.r[@n]
174
+ end
175
+ def dotrest
176
+ @rule.r[@n+1 .. -1]
177
+ end
252
178
  end
253
179
 
254
180
  class I
@@ -309,13 +235,14 @@ module Depager
309
235
  end
310
236
  end
311
237
 
312
- class LALRTable
238
+ class Table
313
239
  attr_accessor :g, :action_table, :goto_table
314
240
  attr_accessor :defred_table, :defred_after_shift_table
315
241
  def initialize g
316
242
  @g = g
317
243
  @c = nil
318
-
244
+ @warnings = []
245
+
319
246
  items
320
247
  mkset
321
248
  mktable
@@ -378,7 +305,7 @@ module Depager
378
305
  def checkconf newv, oldv, key, g = nil
379
306
  return newv unless oldv
380
307
  if oldv == 'ACC'
381
- warn "'ACC' conflict #{g}."
308
+ @warnings << "'ACC' conflict #{g}."
382
309
  return oldv
383
310
  end
384
311
  # warn "\n-- N:#{newv} O:#{oldv} K:#{@g.syms[key]} "
@@ -392,7 +319,7 @@ module Depager
392
319
  # warn "+:reduce #{@g[-newv]}"
393
320
  newv
394
321
  else
395
- warn "shift/reduce conflict #{@g.syms[key]} #{g}."
322
+ @warnings << "shift/reduce conflict '#{@g.syms[key]}'\n#{g}."
396
323
  oldv
397
324
  end
398
325
  elsif newv > 0 and oldv < 0
@@ -404,7 +331,7 @@ module Depager
404
331
  # warn "reduce"
405
332
  oldv
406
333
  else
407
- warn "shift/reduce conflict #{g}."
334
+ @warnings << "shift/reduce conflict\n#{g}."
408
335
  newv
409
336
  end
410
337
  elsif newv < 0 and oldv < 0
@@ -412,7 +339,7 @@ module Depager
412
339
  warn "?? newv == oldv == #{newv}."
413
340
  newv
414
341
  else
415
- warn "reduce/reduce conflict #{g}."
342
+ @warnings << "reduce/reduce conflict\n#{g}."
416
343
  newv
417
344
  end
418
345
  else
@@ -494,6 +421,10 @@ module Depager
494
421
  put_table if $DEBUG
495
422
  end
496
423
 
424
+ def check_table dp
425
+ @warnings.each{|i| dp.warning i }
426
+ end
427
+
497
428
  def put_table
498
429
  syms, first1, f0e, rulelist = @g.syms, @g.first1, @g.f0e, @g.rulelist
499
430
 
@@ -501,14 +432,14 @@ module Depager
501
432
 
502
433
  f_ = first1.map {|k, v|
503
434
  "#{syms[k]} => " << v.map{|i|
504
- i == G::Eps ? ':eps' : syms[i]
435
+ i == Eps ? ':eps' : syms[i]
505
436
  }.join(' ')
506
437
  }.join("\n")
507
438
 
508
439
  e = f0e.map {|k, v|
509
440
  "#{syms[k].inspect} => " << v.map{|n, f|
510
441
  " #{rulelist[n]} ? " << f.map{|i|
511
- i == G::Eps ? ':eps' : syms[i].inspect
442
+ i == Eps ? ':eps' : syms[i].inspect
512
443
  }.join(' ')
513
444
  }.join("\n")
514
445
  }.join("\n")
@@ -546,10 +477,16 @@ module Depager
546
477
  g << "\n"
547
478
  }
548
479
 
480
+ gh = ""
481
+ @g.gh.each_with_index{|i, x|
482
+ gh << "#{syms[x]}(#{x}) => #{i}\n"
483
+ }
484
+
549
485
  warn "** SYMS **\n\n#{s}\n\n" <<
550
486
  "** FIRST1 **\n\n#{f_}\n\n" <<
551
487
  "** Eps Reduce Rule **\n\n#{e}\n\n" <<
552
488
  "*** Grammar ***\n\n#{r}\n\n" <<
489
+ "** GH **\n\n#{gh}\n\n" <<
553
490
  "*** States ***\n\n#{c}\n\n" <<
554
491
  "*** Action Table ***\n\n#{a}\n" <<
555
492
  "*** Goto Table ***\n\n#{g}\n"
@@ -558,39 +495,36 @@ module Depager
558
495
  def mkset
559
496
  warn '** cal LA **' if $MP_DEBUG
560
497
  trn = []
561
- @c.each do |ci|
562
- ci.items.each do |k|
563
- k.closure1([@g.tla]).each do |j|
564
- j.la.each do |ai|
565
- if ai != @g.tla
566
- ci.goto(j.rule.r[j.n]).items.each do |i|
567
- if i.rule == j.rule && i.n == j.n+1
568
- i.la.push ai unless i.la.include?(ai)
569
- break
570
- end
571
- end
572
- elsif ai == @g.tla
573
- ci.goto(j.rule.r[j.n]).items.each do |i|
574
- if i.rule == j.rule && i.n == j.n+1
575
- trn.push [k, i]
576
- break
498
+ @c.each do |_K|
499
+ _K.items.each do |_B|
500
+ _B.closure1([@g.tla]).each do |_A|
501
+ _K.goto(_A.dotsym).items.each do |i|
502
+ if i.rule == _A.rule and i.n == _A.n+1
503
+ _A.la.each do |a|
504
+ if a != @g.tla
505
+ i.la << a unless i.la.include?(a)
506
+ else
507
+ trn.push [_B, i, _K, _K.goto(_A.dotsym)]
577
508
  end
578
509
  end
510
+ break
579
511
  end
580
512
  end
581
513
  end
582
514
  end
583
515
  end
584
516
 
517
+ #puts @g.closure.values.join("\n")
518
+ #puts "-----"
519
+ #puts @g.memo_closure1.sort_by{|k,v| k}.map{|k,v| "#{k.inspect}:\n#{v.join("\n")}"}
585
520
  #puts 'mk'; mk.each{|k, v| p "#{k}=>#{v}"}
586
- #puts 'trn',trn.sort{|a,b| a[0].rule.l.to_s <=> b[0].rule.l.to_s}\
587
- # .map{|a| "#{a[0]} => #{a[1]}"}
588
-
521
+ #trn = trn.uniq
522
+ #puts 'trn',trn.map{|a| "<#{a[2].n}>#{a[0]} => <#{a[3].n}>#{a[1]}"}
589
523
  warn '** mk LALR(1) **' if $MP_DEBUG
590
524
  @c[0].items[0].la = [@g.nssize] # '$'
591
525
  begin
592
526
  change = false
593
- trn.each do |k, v|
527
+ trn.each do |k, v, _|
594
528
  k.la.each do |i|
595
529
  unless v.la.include? i
596
530
  change = true
@@ -18,7 +18,7 @@ module Depager::ActionParser
18
18
  end
19
19
  end
20
20
  @line = $'
21
- #warn val
21
+ # warn "--action--\n#{val}"
22
22
  return val
23
23
  end
24
24
  end
@@ -1,11 +1,38 @@
1
1
  require "depager/utils.rb"
2
- module Depager
3
- #
4
- # Token
5
- #
6
- Token = Struct.new(:value, :lineno, :filename)
7
2
 
8
- # = Parser Runtime
3
+ #
4
+ # Token
5
+ #
6
+ class Depager::Token
7
+ def self.[] *args
8
+ self.new(*args)
9
+ end
10
+ attr_accessor :value, :lineno, :filename
11
+ def initialize value, lineno=nil, filename=nil
12
+ @value = value
13
+ @lineno = lineno
14
+ @filename = filename
15
+ end
16
+ def [](n)
17
+ case n
18
+ when 0 ; @value
19
+ when 1 ; @lineno
20
+ when 2 ; @filename
21
+ else ; nil
22
+ end
23
+ end
24
+ def to_s
25
+ "#{@value.inspect}:#{@lineno}@#{@filename}"
26
+ end
27
+ def inspect
28
+ "#<#{self.class.name}:0x#{object_id.to_s(16)}" <<
29
+ " #{@value.inspect}:#{@lineno}@#{@filename}>"
30
+ end
31
+ end
32
+
33
+ # LALR runtime
34
+ module Depager::LALR
35
+ # = Parser runtime
9
36
  # == Stack
10
37
  # s:: state
11
38
  # la:: look ahead
@@ -107,7 +134,7 @@ module Depager
107
134
 
108
135
  def _Token sym, val=nil, lineno=nil
109
136
  lineno ||= file.lineno
110
- return sym, Token[val, lineno, file.path]
137
+ return sym, Depager::Token[val, lineno, file.path]
111
138
  end
112
139
 
113
140
  public
data/lib/depager/slex.dr CHANGED
@@ -25,30 +25,45 @@
25
25
  def postRhs
26
26
  j = 0
27
27
  rhs = g_parser.rhs
28
- @ins.each do |i, m|
28
+ @ins.each do |i, option_list, debug|
29
29
  state_name = "#{lhs_name}_#{nrhs}_#{i}"
30
+ m_name = "_lex_#{state_name}"
30
31
  if i != rhs.size
31
- isym = g_parser.add_nonterm("__#{state_name}__".intern)
32
- new_rule = Rule[isym, []]
33
- val = ( ":_lex_#{state_name}" )
34
- @addition << [ new_rule, rhs, val, i+j, isym ]
32
+ nt_name = "__#{state_name}__"
33
+ isym = g_parser.add_nonterm(nt_name)
34
+ g_parser.rhs_insert_sym(i+j, isym, nt_name)
35
+ @addition << [ isym, m_name ]
35
36
  j += 1
36
37
  else
37
- @on_reduce[nrules] = ( ":_lex_#{state_name}" )
38
+ @on_reduce[nrules] = ':'+m_name
39
+ end
40
+
41
+ codes = option_list.map do |k, m|
42
+ case k
43
+ when :GOTO
44
+ "@basis.lex_state = #{m}" <<
45
+ (debug ? ";warn 'MODE:->#{m}'" : '')
46
+ when :ADD
47
+ "@basis.lex_context[#{m}] = true" <<
48
+ (debug ? ";warn 'CONTEXT:+#{m}/\#{@context.inspect}'" : '')
49
+ when :SUB
50
+ "@basis.lex_context.delete #{m}" <<
51
+ (debug ? ";warn 'CONTEXT:-#{m}'/\#{@context.inspect}" : '')
52
+ else
53
+ end
38
54
  end
39
55
  @optouter.push << %{
40
- def _lex_#{lhs_name}_#{nrhs}_#{i} val
41
- @basis.lex_state = #{m}
56
+ def #{m_name} val
57
+ #{codes.join("\n ")}
42
58
  end
43
59
  }
44
60
  end
45
61
  @ins.clear
46
62
  end
47
63
  def postRhsList
48
- @addition.each do |new_rule, rhs, val, pos, isym|
49
- g_parser.g << new_rule
50
- rhs.insert(pos, isym)
51
- @on_reduce[nrules] = val
64
+ @addition.each do |isym, m_name|
65
+ g_parser.add_rule isym, []
66
+ @on_reduce[nrules] = ':'+m_name
52
67
  end
53
68
  @addition.clear
54
69
  end
@@ -63,10 +78,18 @@
63
78
  %LEX{
64
79
  /\s+/, /#.*\Z/ { }
65
80
  /[A-Z]+/ { yield _Token(:ID, $&) }
66
- /\%\}\s*\Z/ { @line = $'; yield nil,nil }
67
- /\/(([^\/\\]+|\\.)*)\//,
68
- /'([^'\\]+|\\.)*\'/ { yield _Token(:LEX, "/\\A#{$1}/") }
69
- /\{/ { ln = lineno; yield :ACTION, Token[parse_action, ln]; //=~'' }
81
+ /\%\}\s*\Z/ { yield nil,nil }
82
+ /\/(([^\/\\]+|\\.)*)\// { yield _Token(:LEX, "/\\A#{$1}/") }
83
+ /'([^'\\]+|\\.)*'/,
84
+ /"([^"\\]+|\\.)*"/
85
+ {
86
+ yield _Token(:LEX, "/\\A#{Regexp.escape($1).gsub('/', '\/')}/")
87
+ }
88
+ '{' !
89
+ {
90
+ _lineno = lineno
91
+ yield _Token(:ACTION, parse_action, _lineno)
92
+ }
70
93
  /./ { yield _Token($&, $&) }
71
94
  %}
72
95
  #begin-rule
@@ -75,32 +98,31 @@
75
98
  {
76
99
  ll = ''
77
100
  _mode_list.each do |m, s, l|
78
- elsec = if s
79
- "_rest = lex_#{s}(&block)"
80
- else
81
- %!raise RuntimeError, "must not happen \#{@line}"!
82
- end
101
+ else_code = if s
102
+ "lex_#{s}(&block)"
103
+ else
104
+ 'raise RuntimeError, "must not happen #{@line}"'
105
+ end
83
106
  ll << %{
84
107
  def lex_#{m}(&block)
85
- _rest = ''
86
108
  case @line
87
109
  #{l.map{|i| ' '*4+i}}
88
110
  else
89
- #{elsec}
111
+ #{else_code}
90
112
  end
91
- return _rest
92
113
  end
93
114
  }; #code
94
115
  end
95
116
  g_parser.optinner << ll << %{
96
- attr_accessor :lex_state
117
+ attr_accessor :lex_state, :lex_context
97
118
  def lex(&block)
98
- @lex_state ||= :START
119
+ @lex_state ||= :START
120
+ @lex_context ||= {}
99
121
  begin
100
122
  until @line.empty?
101
- @line = self.send "lex_\#{@lex_state}", &block
123
+ self.send "lex_\#{@lex_state}", &block
102
124
  end
103
- end while @line = getline
125
+ end while @line0 = @line = getline
104
126
  yield nil, nil
105
127
  end
106
128
  }; #code
@@ -122,15 +144,19 @@
122
144
  | lexactlist lexact { _lexactlist << _lexact }
123
145
  ;
124
146
  lexact:
125
- lexlist ACTION
147
+ lexlist opt_noskip ACTION
126
148
  {
127
149
  %{
128
150
  when #{_lexlist.join(', ')}
129
- _rest = $'
151
+ #{ _opt_noskip ? '#' : "@oldline = @line; @line = $'" }
130
152
  #{ _ACTION.value }
131
153
  }; #code
132
154
  }
133
155
  ;
156
+ opt_noskip:
157
+ { false }
158
+ | '!' { true }
159
+ ;
134
160
  lexlist:
135
161
  LEX { [ _LEX.value ] }
136
162
  | lexlist ',' LEX { _lexlist.push _LEX }
@@ -144,18 +170,32 @@
144
170
  %banner '[> ...]'
145
171
  %%
146
172
  %LEX{
147
- /\s+/ { }
148
- /:[a-zA-Z_]+/ { yield _Token(:SYMBOL, $&) }
149
- /\]/ { yield _Token($&, $&); @line = $'; yield nil, nil }
150
- /./ { yield _Token($&, $&) }
173
+ /\s+/ { }
174
+ /:[a-zA-Z_]+\??/ { yield _Token(:SYMBOL, $&) }
175
+ /\]/ { yield _Token($&, $&); @line = $'; yield nil, nil }
176
+ /./ { yield _Token($&, $&) }
151
177
  %}
152
178
 
153
179
  #begin-rule
154
180
  start:
155
- '[' '>' SYMBOL ']'
181
+ '[' option_list ']'
156
182
  {
157
- master.ins.push [g_parser.rhs.size, _SYMBOL.value]
183
+ master.ins.push [g_parser.rhs.size, _option_list, false]
158
184
  }
185
+ | '[' option_list '?' ']'
186
+ {
187
+ master.ins.push [g_parser.rhs.size, _option_list, true]
188
+ }
189
+
190
+ ;
191
+ option_list:
192
+ option { [_option] }
193
+ | option_list option { _option_list << _option }
194
+ ;
195
+ option:
196
+ '>' SYMBOL { [:GOTO, _SYMBOL.value] }
197
+ | '+' SYMBOL { [:ADD, _SYMBOL.value] }
198
+ | '-' SYMBOL { [:SUB, _SYMBOL.value] }
159
199
  ;
160
200
  #end-rule
161
201
  %%