depager 0.1.9 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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
  %%