lrama 0.5.3 → 0.5.5
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 +4 -4
- data/.github/workflows/test.yaml +24 -1
- data/Gemfile +3 -2
- data/README.md +11 -1
- data/doc/TODO.md +5 -1
- data/exe/lrama +0 -1
- data/lib/lrama/command.rb +5 -10
- data/lib/lrama/context.rb +0 -2
- data/lib/lrama/counterexamples/derivation.rb +63 -0
- data/lib/lrama/counterexamples/example.rb +124 -0
- data/lib/lrama/counterexamples/path.rb +69 -0
- data/lib/lrama/counterexamples/state_item.rb +6 -0
- data/lib/lrama/counterexamples/triple.rb +21 -0
- data/lib/lrama/counterexamples.rb +283 -0
- data/lib/lrama/digraph.rb +2 -3
- data/lib/lrama/grammar/auxiliary.rb +7 -0
- data/lib/lrama/grammar/code.rb +0 -1
- data/lib/lrama/grammar/rule.rb +6 -0
- data/lib/lrama/grammar/symbol.rb +4 -11
- data/lib/lrama/grammar.rb +44 -8
- data/lib/lrama/lexer/token/type.rb +8 -0
- data/lib/lrama/lexer/token.rb +4 -2
- data/lib/lrama/lexer.rb +3 -4
- data/lib/lrama/output.rb +1 -1
- data/lib/lrama/parser/token_scanner.rb +3 -6
- data/lib/lrama/parser.rb +9 -0
- data/lib/lrama/state/reduce_reduce_conflict.rb +9 -0
- data/lib/lrama/state/shift_reduce_conflict.rb +9 -0
- data/lib/lrama/state.rb +11 -4
- data/lib/lrama/states/item.rb +38 -2
- data/lib/lrama/states.rb +28 -34
- data/lib/lrama/states_reporter.rb +29 -16
- data/lib/lrama/type.rb +4 -0
- data/lib/lrama/version.rb +1 -1
- data/lib/lrama.rb +2 -0
- data/template/bison/yacc.c +103 -95
- metadata +13 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: d79363afacc07dac12ab5c1a861123e099626591104079c962e02f3df74a24f3
         | 
| 4 | 
            +
              data.tar.gz: d8ddf78087e27510ab9da808301505a10ec0151ef55d1df3a59cc80ffde81b53
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: acc15bb56862ea03c6b195253ba881786acf498719f930b8a8435a60f86b44d4383778cc215e7497971833c4be596a9c41a6c5134f77703a9f5cd0a6b5714ad2
         | 
| 7 | 
            +
              data.tar.gz: d45b2ec3a22ce2e29beb6a5ec0f4d7b142cebca3b6ca76786fa19b841c257d3841d5a7a43d7d564459b8f9c5b05faa7229bd9b2e2178592ec3988b64f77b535c
         | 
    
        data/.github/workflows/test.yaml
    CHANGED
    
    | @@ -22,6 +22,29 @@ jobs: | |
| 22 22 | 
             
                      bundler-cache: true
         | 
| 23 23 | 
             
                  - run: bundle install
         | 
| 24 24 | 
             
                  - run: bundle exec rspec
         | 
| 25 | 
            +
              test-windows:
         | 
| 26 | 
            +
                runs-on: windows-2022
         | 
| 27 | 
            +
                strategy:
         | 
| 28 | 
            +
                  fail-fast: false
         | 
| 29 | 
            +
                  matrix:
         | 
| 30 | 
            +
                    ruby: ['head']
         | 
| 31 | 
            +
                steps:
         | 
| 32 | 
            +
                  - uses: actions/checkout@v3
         | 
| 33 | 
            +
                  - uses: ruby/setup-ruby@v1
         | 
| 34 | 
            +
                    with:
         | 
| 35 | 
            +
                      ruby-version: ${{ matrix.ruby }}
         | 
| 36 | 
            +
                      bundler-cache: true
         | 
| 37 | 
            +
                  - run: bundle install
         | 
| 38 | 
            +
                  - run: bundle exec rspec
         | 
| 39 | 
            +
              check-misc:
         | 
| 40 | 
            +
                runs-on: ubuntu-20.04
         | 
| 41 | 
            +
                steps:
         | 
| 42 | 
            +
                  - uses: actions/checkout@v3
         | 
| 43 | 
            +
                  # Copy from https://github.com/ruby/ruby/blob/089227e94823542acfdafa68541d330eee42ffea/.github/workflows/check_misc.yml#L27
         | 
| 44 | 
            +
                  - name: Check for trailing spaces
         | 
| 45 | 
            +
                    run: |
         | 
| 46 | 
            +
                      git grep -I -n '[	 ]$' -- '*.rb' '*.[chy]' '*.rs' && exit 1 || :
         | 
| 47 | 
            +
                      git grep -n '^[	 ][	 ]*$' -- '*.md' && exit 1 || :
         | 
| 25 48 | 
             
              steep-check:
         | 
| 26 49 | 
             
                runs-on: ubuntu-20.04
         | 
| 27 50 | 
             
                strategy:
         | 
| @@ -58,7 +81,7 @@ jobs: | |
| 58 81 | 
             
                  - run: mkdir -p tool/lrama
         | 
| 59 82 | 
             
                    working-directory: ../ruby
         | 
| 60 83 | 
             
                  - name: Copy Lrama to ruby/tool
         | 
| 61 | 
            -
                    run: cp -r exe lib template ../ruby/tool/lrama
         | 
| 84 | 
            +
                    run: cp -r LEGAL.md MIT exe lib template ../ruby/tool/lrama
         | 
| 62 85 | 
             
                    working-directory:
         | 
| 63 86 | 
             
                  - run: tree tool/lrama
         | 
| 64 87 | 
             
                    working-directory: ../ruby
         | 
    
        data/Gemfile
    CHANGED
    
    | @@ -4,8 +4,9 @@ gemspec | |
| 4 4 |  | 
| 5 5 | 
             
            gem "rspec"
         | 
| 6 6 | 
             
            gem "pry"
         | 
| 7 | 
            -
             | 
| 7 | 
            +
            # stackprof doesn't support Windows
         | 
| 8 | 
            +
            gem "stackprof", platforms: [:ruby]
         | 
| 8 9 | 
             
            gem "rake"
         | 
| 9 10 | 
             
            gem "rbs", require: false
         | 
| 10 11 | 
             
            gem "steep", require: false
         | 
| 11 | 
            -
            gem "simplecov", require: false
         | 
| 12 | 
            +
            gem "simplecov", require: false
         | 
    
        data/README.md
    CHANGED
    
    | @@ -49,10 +49,20 @@ Enter the formula: | |
| 49 49 |  | 
| 50 50 | 
             
            ## Versions and Branches
         | 
| 51 51 |  | 
| 52 | 
            +
            ### v0_5 (`master` branch)
         | 
| 53 | 
            +
             | 
| 54 | 
            +
            This branch is for Ruby 3.3. `lrama_0_5` branch is created from this branch, once Ruby 3.3 is released.
         | 
| 55 | 
            +
             | 
| 52 56 | 
             
            ### v0_4 (`lrama_0_4` branch)
         | 
| 53 57 |  | 
| 54 58 | 
             
            This branch generates "parse.c" compatible with Bison 3.8.2 for ruby 3.0, 3.1, 3.2. The first version migrated to ruby is ["0.4.0"](https://github.com/ruby/ruby/pull/7798) therefore keep this branch for Bison compatible branch.
         | 
| 55 59 |  | 
| 60 | 
            +
            ## Supported Ruby version
         | 
| 61 | 
            +
             | 
| 62 | 
            +
            Lrama is executed with BASERUBY when building ruby from source code. Therefore Lrama needs to support BASERUBY, currently 2.5, or later version.
         | 
| 63 | 
            +
             | 
| 64 | 
            +
            This also requires Lrama to be able to run with only default gems and bundled gems.
         | 
| 65 | 
            +
             | 
| 56 66 | 
             
            ## Build Ruby
         | 
| 57 67 |  | 
| 58 68 | 
             
            1. Install Lrama
         | 
| @@ -62,7 +72,7 @@ This branch generates "parse.c" compatible with Bison 3.8.2 for ruby 3.0, 3.1, 3 | |
| 62 72 |  | 
| 63 73 | 
             
            1. Update `Lrama::VERSION`
         | 
| 64 74 | 
             
            2. Release as a gem by `rake release`
         | 
| 65 | 
            -
            3. Update Lrama in ruby/ruby by `cp -r LEGAL.md MIT exe lib ruby/tool/lrama`
         | 
| 75 | 
            +
            3. Update Lrama in ruby/ruby by `cp -r LEGAL.md MIT exe lib template ruby/tool/lrama`
         | 
| 66 76 | 
             
            4. Create new release on [GitHub](https://github.com/ruby/lrama/releases)
         | 
| 67 77 |  | 
| 68 78 | 
             
            ## License
         | 
    
        data/doc/TODO.md
    CHANGED
    
    | @@ -44,10 +44,14 @@ | |
| 44 44 | 
             
            * Reporting
         | 
| 45 45 | 
             
              * [ ] Bison style
         | 
| 46 46 | 
             
                * [ ] Wrap not selected reduce with "[]". See basic.output file generated by Bison.
         | 
| 47 | 
            +
            * Counterexamples
         | 
| 48 | 
            +
              * [x] Nonunifying Counterexamples
         | 
| 49 | 
            +
              * [ ] Unifying Counterexamples
         | 
| 50 | 
            +
              * [ ] Performance improvement using reverse_transitions and reverse_productions
         | 
| 47 51 | 
             
            * Error Tolerance
         | 
| 48 52 | 
             
              * [x] Corchuelo et al. algorithm with N = 1 (this means the next token when error is raised)
         | 
| 49 53 | 
             
              * [x] Add new decl for error token semantic value initialization (%error-token)
         | 
| 50 | 
            -
              * [ | 
| 54 | 
            +
              * [x] Use YYMALLOC & YYFREE
         | 
| 51 55 | 
             
            * Lex state
         | 
| 52 56 | 
             
            * CI
         | 
| 53 57 | 
             
              * [x] Setup CI
         | 
    
        data/exe/lrama
    CHANGED
    
    
    
        data/lib/lrama/command.rb
    CHANGED
    
    | @@ -5,7 +5,6 @@ module Lrama | |
| 5 5 | 
             
                def initialize(argv)
         | 
| 6 6 | 
             
                  @argv = argv
         | 
| 7 7 |  | 
| 8 | 
            -
                  @version = nil
         | 
| 9 8 | 
             
                  @skeleton = "bison/yacc.c"
         | 
| 10 9 | 
             
                  @header = false
         | 
| 11 10 | 
             
                  @header_file = nil
         | 
| @@ -23,15 +22,11 @@ module Lrama | |
| 23 22 | 
             
                def run
         | 
| 24 23 | 
             
                  parse_option
         | 
| 25 24 |  | 
| 26 | 
            -
                  if @version
         | 
| 27 | 
            -
                    puts Lrama::VERSION
         | 
| 28 | 
            -
                    exit 0
         | 
| 29 | 
            -
                  end
         | 
| 30 | 
            -
             | 
| 31 25 | 
             
                  Report::Duration.enable if @trace_opts[:time]
         | 
| 32 26 |  | 
| 33 27 | 
             
                  warning = Lrama::Warning.new
         | 
| 34 28 | 
             
                  grammar = Lrama::Parser.new(@y.read).parse
         | 
| 29 | 
            +
                  @y.close if @y != STDIN
         | 
| 35 30 | 
             
                  states = Lrama::States.new(grammar, warning, trace_state: (@trace_opts[:automaton] || @trace_opts[:closure]))
         | 
| 36 31 | 
             
                  states.compute
         | 
| 37 32 | 
             
                  context = Lrama::Context.new(states)
         | 
| @@ -67,7 +62,7 @@ module Lrama | |
| 67 62 | 
             
                  bison_list = %w[states itemsets lookaheads solved counterexamples cex all none]
         | 
| 68 63 | 
             
                  others = %w[verbose]
         | 
| 69 64 | 
             
                  list = bison_list + others
         | 
| 70 | 
            -
                  not_supported = %w[ | 
| 65 | 
            +
                  not_supported = %w[cex none]
         | 
| 71 66 | 
             
                  h = { grammar: true }
         | 
| 72 67 |  | 
| 73 68 | 
             
                  report.each do |r|
         | 
| @@ -112,7 +107,7 @@ module Lrama | |
| 112 107 | 
             
                  opt = OptionParser.new
         | 
| 113 108 |  | 
| 114 109 | 
             
                  # opt.on('-h') {|v| p v }
         | 
| 115 | 
            -
                  opt.on('-V', '--version') {|v|  | 
| 110 | 
            +
                  opt.on('-V', '--version') {|v| puts "lrama #{Lrama::VERSION}"; exit 0 }
         | 
| 116 111 |  | 
| 117 112 | 
             
                  # Tuning the Parser
         | 
| 118 113 | 
             
                  opt.on('-S', '--skeleton=FILE') {|v| @skeleton = v }
         | 
| @@ -121,13 +116,13 @@ module Lrama | |
| 121 116 | 
             
                  # Output Files:
         | 
| 122 117 | 
             
                  opt.on('-h', '--header=[FILE]') {|v| @header = true; @header_file = v }
         | 
| 123 118 | 
             
                  opt.on('-d') { @header = true }
         | 
| 124 | 
            -
                  opt.on('-r', '--report=THINGS') {|v| @report = v | 
| 119 | 
            +
                  opt.on('-r', '--report=THINGS', Array) {|v| @report = v }
         | 
| 125 120 | 
             
                  opt.on('--report-file=FILE')    {|v| @report_file = v }
         | 
| 126 121 | 
             
                  opt.on('-v') {  } # Do nothing
         | 
| 127 122 | 
             
                  opt.on('-o', '--output=FILE')   {|v| @outfile = v }
         | 
| 128 123 |  | 
| 129 124 | 
             
                  # Hidden
         | 
| 130 | 
            -
                  opt.on('--trace=THINGS') {|v| @trace = v | 
| 125 | 
            +
                  opt.on('--trace=THINGS', Array) {|v| @trace = v }
         | 
| 131 126 |  | 
| 132 127 | 
             
                  # Error Recovery
         | 
| 133 128 | 
             
                  opt.on('-e') {|v| @error_recovery = true }
         | 
    
        data/lib/lrama/context.rb
    CHANGED
    
    | @@ -401,7 +401,6 @@ module Lrama | |
| 401 401 | 
             
                  end
         | 
| 402 402 | 
             
                  print sprintf("]\n\n")
         | 
| 403 403 |  | 
| 404 | 
            -
             | 
| 405 404 | 
             
                  print sprintf("width [\n")
         | 
| 406 405 | 
             
                  vectors_count.times do |i|
         | 
| 407 406 | 
             
                    print sprintf("%d, ", ary[i] ? ary[i][3] : 0)
         | 
| @@ -409,7 +408,6 @@ module Lrama | |
| 409 408 | 
             
                  end
         | 
| 410 409 | 
             
                  print sprintf("]\n\n")
         | 
| 411 410 |  | 
| 412 | 
            -
             | 
| 413 411 | 
             
                  print sprintf("tally [\n")
         | 
| 414 412 | 
             
                  vectors_count.times do |i|
         | 
| 415 413 | 
             
                    print sprintf("%d, ", ary[i] ? ary[i][2] : 0)
         | 
| @@ -0,0 +1,63 @@ | |
| 1 | 
            +
            module Lrama
         | 
| 2 | 
            +
              class Counterexamples
         | 
| 3 | 
            +
                class Derivation
         | 
| 4 | 
            +
                  attr_reader :item, :left, :right
         | 
| 5 | 
            +
                  attr_writer :right
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                  def initialize(item, left, right = nil)
         | 
| 8 | 
            +
                    @item = item
         | 
| 9 | 
            +
                    @left = left
         | 
| 10 | 
            +
                    @right = right
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  def to_s
         | 
| 14 | 
            +
                    "#<Derivation(#{item.display_name})>"
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
                  alias :inspect :to_s
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  def render_strings_for_report
         | 
| 19 | 
            +
                    result = []
         | 
| 20 | 
            +
                    _render_for_report(self, 0, result, 0)
         | 
| 21 | 
            +
                    result.map(&:rstrip)
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  def render_for_report
         | 
| 25 | 
            +
                    render_strings_for_report.join("\n")
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  private
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  def _render_for_report(derivation, offset, strings, index)
         | 
| 31 | 
            +
                    item = derivation.item
         | 
| 32 | 
            +
                    if strings[index]
         | 
| 33 | 
            +
                      strings[index] << " " * (offset - strings[index].length)
         | 
| 34 | 
            +
                    else
         | 
| 35 | 
            +
                      strings[index] = " " * offset
         | 
| 36 | 
            +
                    end
         | 
| 37 | 
            +
                    str = strings[index]
         | 
| 38 | 
            +
                    str << "#{item.rule_id}: #{item.symbols_before_dot.map(&:display_name).join(" ")} "
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                    if derivation.left
         | 
| 41 | 
            +
                      len = str.length
         | 
| 42 | 
            +
                      str << "#{item.next_sym.display_name}"
         | 
| 43 | 
            +
                      length = _render_for_report(derivation.left, len, strings, index + 1)
         | 
| 44 | 
            +
                      # I want String#ljust!
         | 
| 45 | 
            +
                      str << " " * (length - str.length)
         | 
| 46 | 
            +
                    else
         | 
| 47 | 
            +
                      str << " • #{item.symbols_after_dot.map(&:display_name).join(" ")} "
         | 
| 48 | 
            +
                      return str.length
         | 
| 49 | 
            +
                    end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                    if derivation.right&.left
         | 
| 52 | 
            +
                      length = _render_for_report(derivation.right.left, str.length, strings, index + 1)
         | 
| 53 | 
            +
                      str << "#{item.symbols_after_dot[1..-1].map(&:display_name).join(" ")} "
         | 
| 54 | 
            +
                      str << " " * (length - str.length) if length > str.length
         | 
| 55 | 
            +
                    elsif item.next_next_sym
         | 
| 56 | 
            +
                      str << "#{item.symbols_after_dot[1..-1].map(&:display_name).join(" ")} "
         | 
| 57 | 
            +
                    end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                    return str.length
         | 
| 60 | 
            +
                  end
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
              end
         | 
| 63 | 
            +
            end
         | 
| @@ -0,0 +1,124 @@ | |
| 1 | 
            +
            module Lrama
         | 
| 2 | 
            +
              class Counterexamples
         | 
| 3 | 
            +
                class Example
         | 
| 4 | 
            +
                  attr_reader :path1, :path2, :conflict, :conflict_symbol
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  # path1 is shift conflict when S/R conflict
         | 
| 7 | 
            +
                  # path2 is always reduce conflict
         | 
| 8 | 
            +
                  def initialize(path1, path2, conflict, conflict_symbol, counterexamples)
         | 
| 9 | 
            +
                    @path1 = path1
         | 
| 10 | 
            +
                    @path2 = path2
         | 
| 11 | 
            +
                    @conflict = conflict
         | 
| 12 | 
            +
                    @conflict_symbol = conflict_symbol
         | 
| 13 | 
            +
                    @counterexamples = counterexamples
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  def type
         | 
| 17 | 
            +
                    @conflict.type
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  def path1_item
         | 
| 21 | 
            +
                    @path1.last.to.item
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  def path2_item
         | 
| 25 | 
            +
                    @path2.last.to.item
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  def derivations1
         | 
| 29 | 
            +
                    @derivations1 ||= _derivations(path1)
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                  def derivations2
         | 
| 33 | 
            +
                    @derivations2 ||= _derivations(path2)
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  private
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                  def _derivations(paths)
         | 
| 39 | 
            +
                    derivation = nil
         | 
| 40 | 
            +
                    current = :production
         | 
| 41 | 
            +
                    lookahead_sym = paths.last.to.item.end_of_rule? ? @conflict_symbol : nil
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                    paths.reverse.each do |path|
         | 
| 44 | 
            +
                      item = path.to.item
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                      case current
         | 
| 47 | 
            +
                      when :production
         | 
| 48 | 
            +
                        case path
         | 
| 49 | 
            +
                        when StartPath
         | 
| 50 | 
            +
                          derivation = Derivation.new(item, derivation)
         | 
| 51 | 
            +
                          current = :start
         | 
| 52 | 
            +
                        when TransitionPath
         | 
| 53 | 
            +
                          derivation = Derivation.new(item, derivation)
         | 
| 54 | 
            +
                          current = :transition
         | 
| 55 | 
            +
                        when ProductionPath
         | 
| 56 | 
            +
                          derivation = Derivation.new(item, derivation)
         | 
| 57 | 
            +
                          current = :production
         | 
| 58 | 
            +
                        end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                        if lookahead_sym && item.next_next_sym && item.next_next_sym.first_set.include?(lookahead_sym)
         | 
| 61 | 
            +
                          state_item = @counterexamples.transitions[[path.to, item.next_sym]]
         | 
| 62 | 
            +
                          derivation2 = find_derivation_for_symbol(state_item, lookahead_sym)
         | 
| 63 | 
            +
                          derivation.right = derivation2
         | 
| 64 | 
            +
                          lookahead_sym = nil
         | 
| 65 | 
            +
                        end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                      when :transition
         | 
| 68 | 
            +
                        case path
         | 
| 69 | 
            +
                        when StartPath
         | 
| 70 | 
            +
                          derivation = Derivation.new(item, derivation)
         | 
| 71 | 
            +
                          current = :start
         | 
| 72 | 
            +
                        when TransitionPath
         | 
| 73 | 
            +
                          # ignore
         | 
| 74 | 
            +
                          current = :transition
         | 
| 75 | 
            +
                        when ProductionPath
         | 
| 76 | 
            +
                          # ignore
         | 
| 77 | 
            +
                          current = :production
         | 
| 78 | 
            +
                        end
         | 
| 79 | 
            +
                      else
         | 
| 80 | 
            +
                        raise "BUG: Unknown #{current}"
         | 
| 81 | 
            +
                      end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                      break if current == :start
         | 
| 84 | 
            +
                    end
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                    derivation
         | 
| 87 | 
            +
                  end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                  def find_derivation_for_symbol(state_item, sym)
         | 
| 90 | 
            +
                    queue = []
         | 
| 91 | 
            +
                    queue << [state_item]
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                    while (sis = queue.shift)
         | 
| 94 | 
            +
                      si = sis.last
         | 
| 95 | 
            +
                      next_sym = si.item.next_sym
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                      if next_sym == sym
         | 
| 98 | 
            +
                        derivation = nil
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                        sis.reverse.each do |si|
         | 
| 101 | 
            +
                          derivation = Derivation.new(si.item, derivation)
         | 
| 102 | 
            +
                        end
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                        return derivation
         | 
| 105 | 
            +
                      end
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                      if next_sym.nterm? && next_sym.first_set.include?(sym)
         | 
| 108 | 
            +
                        @counterexamples.productions[si].each do |next_item|
         | 
| 109 | 
            +
                          next if next_item.empty_rule?
         | 
| 110 | 
            +
                          next_si = StateItem.new(si.state, next_item)
         | 
| 111 | 
            +
                          next if sis.include?(next_si)
         | 
| 112 | 
            +
                          queue << (sis + [next_si])
         | 
| 113 | 
            +
                        end
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                        if next_sym.nullable
         | 
| 116 | 
            +
                          next_si = @counterexamples.transitions[[si, next_sym]]
         | 
| 117 | 
            +
                          queue << (sis + [next_si])
         | 
| 118 | 
            +
                        end
         | 
| 119 | 
            +
                      end
         | 
| 120 | 
            +
                    end
         | 
| 121 | 
            +
                  end
         | 
| 122 | 
            +
                end
         | 
| 123 | 
            +
              end
         | 
| 124 | 
            +
            end
         | 
| @@ -0,0 +1,69 @@ | |
| 1 | 
            +
            module Lrama
         | 
| 2 | 
            +
              class Counterexamples
         | 
| 3 | 
            +
                class Path
         | 
| 4 | 
            +
                  def initialize(from_state_item, to_state_item)
         | 
| 5 | 
            +
                    @from_state_item = from_state_item
         | 
| 6 | 
            +
                    @to_state_item = to_state_item
         | 
| 7 | 
            +
                  end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  def from
         | 
| 10 | 
            +
                    @from_state_item
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  def to
         | 
| 14 | 
            +
                    @to_state_item
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  def to_s
         | 
| 18 | 
            +
                    "#<Path(#{type})>"
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
                  alias :inspect :to_s
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                class StartPath < Path
         | 
| 24 | 
            +
                  def initialize(to_state_item)
         | 
| 25 | 
            +
                    super nil, to_state_item
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  def type
         | 
| 29 | 
            +
                    :start
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                  def transition?
         | 
| 33 | 
            +
                    false
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  def production?
         | 
| 37 | 
            +
                    false
         | 
| 38 | 
            +
                  end
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                class TransitionPath < Path
         | 
| 42 | 
            +
                  def type
         | 
| 43 | 
            +
                    :transition
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                  def transition?
         | 
| 47 | 
            +
                    true
         | 
| 48 | 
            +
                  end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  def production?
         | 
| 51 | 
            +
                    false
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                class ProductionPath < Path
         | 
| 56 | 
            +
                  def type
         | 
| 57 | 
            +
                    :production
         | 
| 58 | 
            +
                  end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                  def transition?
         | 
| 61 | 
            +
                    false
         | 
| 62 | 
            +
                  end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                  def production?
         | 
| 65 | 
            +
                    true
         | 
| 66 | 
            +
                  end
         | 
| 67 | 
            +
                end
         | 
| 68 | 
            +
              end
         | 
| 69 | 
            +
            end
         | 
| @@ -0,0 +1,21 @@ | |
| 1 | 
            +
            module Lrama
         | 
| 2 | 
            +
              class Counterexamples
         | 
| 3 | 
            +
                # s: state
         | 
| 4 | 
            +
                # itm: item within s
         | 
| 5 | 
            +
                # l: precise lookahead set
         | 
| 6 | 
            +
                class Triple < Struct.new(:s, :itm, :l)
         | 
| 7 | 
            +
                  alias :state :s
         | 
| 8 | 
            +
                  alias :item :itm
         | 
| 9 | 
            +
                  alias :precise_lookahead_set :l
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  def state_item
         | 
| 12 | 
            +
                    StateItem.new(state, item)
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  def inspect
         | 
| 16 | 
            +
                    "#{state.inspect}. #{item.display_name}. #{l.map(&:id).map(&:s_value)}"
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
                  alias :to_s :inspect
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
            end
         |