lrama 0.7.0 → 0.7.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 +4 -4
- data/.gitattributes +2 -0
- data/.github/workflows/codespell.yaml +1 -1
- data/.github/workflows/gh-pages.yml +5 -6
- data/.github/workflows/test.yaml +25 -14
- data/Gemfile +4 -3
- data/NEWS.md +370 -35
- data/README.md +7 -88
- data/Rakefile +3 -2
- data/Steepfile +11 -5
- data/doc/Index.md +1 -1
- data/doc/development/compressed_state_table/parser.rb +2 -0
- data/doc/development/profiling.md +44 -0
- data/exe/lrama +1 -1
- data/lib/lrama/bitmap.rb +18 -5
- data/lib/lrama/command.rb +95 -43
- data/lib/lrama/context.rb +22 -24
- data/lib/lrama/counterexamples/derivation.rb +14 -4
- data/lib/lrama/counterexamples/example.rb +47 -22
- data/lib/lrama/counterexamples/node.rb +30 -0
- data/lib/lrama/counterexamples/path.rb +12 -14
- data/lib/lrama/counterexamples/state_item.rb +24 -1
- data/lib/lrama/counterexamples/triple.rb +27 -9
- data/lib/lrama/counterexamples.rb +216 -88
- data/lib/lrama/diagram.rb +77 -0
- data/lib/lrama/digraph.rb +28 -7
- data/lib/lrama/erb.rb +29 -0
- data/lib/lrama/grammar/auxiliary.rb +6 -1
- data/lib/lrama/grammar/binding.rb +37 -25
- data/lib/lrama/grammar/code/destructor_code.rb +11 -0
- data/lib/lrama/grammar/code/initial_action_code.rb +3 -0
- data/lib/lrama/grammar/code/no_reference_code.rb +3 -0
- data/lib/lrama/grammar/code/printer_code.rb +11 -0
- data/lib/lrama/grammar/code/rule_action.rb +17 -0
- data/lib/lrama/grammar/code.rb +16 -1
- data/lib/lrama/grammar/counter.rb +10 -0
- data/lib/lrama/grammar/destructor.rb +14 -1
- data/lib/lrama/grammar/error_token.rb +14 -1
- data/lib/lrama/grammar/inline/resolver.rb +80 -0
- data/lib/lrama/grammar/inline.rb +3 -0
- data/lib/lrama/grammar/{parameterizing_rule → parameterized}/resolver.rb +19 -8
- data/lib/lrama/grammar/{parameterizing_rule → parameterized}/rhs.rb +7 -2
- data/lib/lrama/grammar/parameterized/rule.rb +36 -0
- data/lib/lrama/grammar/parameterized.rb +5 -0
- data/lib/lrama/grammar/percent_code.rb +12 -1
- data/lib/lrama/grammar/precedence.rb +43 -1
- data/lib/lrama/grammar/printer.rb +9 -0
- data/lib/lrama/grammar/reference.rb +13 -0
- data/lib/lrama/grammar/rule.rb +61 -1
- data/lib/lrama/grammar/rule_builder.rb +84 -69
- data/lib/lrama/grammar/stdlib.y +68 -48
- data/lib/lrama/grammar/symbol.rb +63 -19
- data/lib/lrama/grammar/symbols/resolver.rb +64 -3
- data/lib/lrama/grammar/type.rb +13 -1
- data/lib/lrama/grammar/union.rb +12 -1
- data/lib/lrama/grammar.rb +231 -35
- data/lib/lrama/lexer/location.rb +25 -8
- data/lib/lrama/lexer/token/base.rb +73 -0
- data/lib/lrama/lexer/token/char.rb +15 -2
- data/lib/lrama/lexer/token/empty.rb +14 -0
- data/lib/lrama/lexer/token/ident.rb +2 -2
- data/lib/lrama/lexer/token/instantiate_rule.rb +4 -4
- data/lib/lrama/lexer/token/int.rb +14 -0
- data/lib/lrama/lexer/token/str.rb +11 -0
- data/lib/lrama/lexer/token/tag.rb +2 -2
- data/lib/lrama/lexer/token/token.rb +11 -0
- data/lib/lrama/lexer/token/user_code.rb +63 -37
- data/lib/lrama/lexer/token.rb +6 -56
- data/lib/lrama/lexer.rb +51 -23
- data/lib/lrama/logger.rb +12 -2
- data/lib/lrama/option_parser.rb +63 -9
- data/lib/lrama/options.rb +25 -7
- data/lib/lrama/output.rb +4 -11
- data/lib/lrama/parser.rb +854 -723
- data/lib/lrama/reporter/conflicts.rb +44 -0
- data/lib/lrama/reporter/grammar.rb +39 -0
- data/lib/lrama/reporter/precedences.rb +54 -0
- data/lib/lrama/reporter/profile/call_stack.rb +45 -0
- data/lib/lrama/reporter/profile/memory.rb +44 -0
- data/lib/lrama/reporter/profile.rb +4 -0
- data/lib/lrama/reporter/rules.rb +43 -0
- data/lib/lrama/reporter/states.rb +387 -0
- data/lib/lrama/reporter/terms.rb +44 -0
- data/lib/lrama/reporter.rb +39 -0
- data/lib/lrama/state/action/goto.rb +33 -0
- data/lib/lrama/state/action/reduce.rb +71 -0
- data/lib/lrama/state/action/shift.rb +39 -0
- data/lib/lrama/state/action.rb +5 -0
- data/lib/lrama/state/inadequacy_annotation.rb +140 -0
- data/lib/lrama/{states → state}/item.rb +33 -4
- data/lib/lrama/state/reduce_reduce_conflict.rb +14 -1
- data/lib/lrama/state/resolved_conflict.rb +38 -4
- data/lib/lrama/state/shift_reduce_conflict.rb +14 -1
- data/lib/lrama/state.rb +301 -200
- data/lib/lrama/states.rb +447 -175
- data/lib/lrama/tracer/actions.rb +22 -0
- data/lib/lrama/tracer/closure.rb +30 -0
- data/lib/lrama/tracer/duration.rb +38 -0
- data/lib/lrama/tracer/only_explicit_rules.rb +24 -0
- data/lib/lrama/tracer/rules.rb +23 -0
- data/lib/lrama/tracer/state.rb +33 -0
- data/lib/lrama/tracer.rb +51 -0
- data/lib/lrama/version.rb +2 -1
- data/lib/lrama/warnings/conflicts.rb +27 -0
- data/lib/lrama/warnings/implicit_empty.rb +29 -0
- data/lib/lrama/warnings/name_conflicts.rb +63 -0
- data/lib/lrama/warnings/redefined_rules.rb +23 -0
- data/lib/lrama/warnings/required.rb +23 -0
- data/lib/lrama/warnings/useless_precedence.rb +25 -0
- data/lib/lrama/warnings.rb +33 -0
- data/lib/lrama.rb +5 -5
- data/parser.y +495 -404
- data/rbs_collection.lock.yaml +27 -3
- data/rbs_collection.yaml +2 -0
- data/sig/generated/lrama/bitmap.rbs +12 -4
- data/sig/generated/lrama/counterexamples/derivation.rbs +36 -0
- data/sig/generated/lrama/counterexamples/example.rbs +58 -0
- data/sig/generated/lrama/counterexamples/node.rbs +18 -0
- data/sig/generated/lrama/counterexamples/path.rbs +23 -0
- data/sig/generated/lrama/counterexamples/state_item.rbs +19 -0
- data/sig/generated/lrama/counterexamples/triple.rbs +32 -0
- data/sig/generated/lrama/counterexamples.rbs +98 -0
- data/sig/generated/lrama/diagram.rbs +34 -0
- data/sig/generated/lrama/digraph.rbs +26 -6
- data/sig/generated/lrama/erb.rbs +14 -0
- data/sig/generated/lrama/grammar/auxiliary.rbs +16 -0
- data/sig/generated/lrama/grammar/binding.rbs +18 -12
- data/sig/generated/lrama/grammar/code/destructor_code.rbs +26 -0
- data/sig/{lrama → generated/lrama}/grammar/code/initial_action_code.rbs +6 -0
- data/sig/{lrama → generated/lrama}/grammar/code/no_reference_code.rbs +6 -0
- data/sig/generated/lrama/grammar/code/printer_code.rbs +26 -0
- data/sig/generated/lrama/grammar/code/rule_action.rbs +63 -0
- data/sig/generated/lrama/grammar/code.rbs +38 -0
- data/sig/{lrama → generated/lrama}/grammar/counter.rbs +4 -0
- data/sig/generated/lrama/grammar/destructor.rbs +19 -0
- data/sig/generated/lrama/grammar/error_token.rbs +19 -0
- data/sig/generated/lrama/grammar/inline/resolver.rbs +26 -0
- data/sig/generated/lrama/grammar/parameterized/resolver.rbs +42 -0
- data/sig/generated/lrama/grammar/parameterized/rhs.rbs +21 -0
- data/sig/generated/lrama/grammar/parameterized/rule.rbs +28 -0
- data/sig/{lrama → generated/lrama}/grammar/percent_code.rbs +8 -0
- data/sig/generated/lrama/grammar/precedence.rbs +45 -0
- data/sig/{lrama/grammar/error_token.rbs → generated/lrama/grammar/printer.rbs} +8 -3
- data/sig/generated/lrama/grammar/reference.rbs +31 -0
- data/sig/generated/lrama/grammar/rule.rbs +83 -0
- data/sig/generated/lrama/grammar/rule_builder.rbs +91 -0
- data/sig/generated/lrama/grammar/symbol.rbs +89 -0
- data/sig/generated/lrama/grammar/symbols/resolver.rbs +131 -0
- data/sig/generated/lrama/grammar/type.rbs +21 -0
- data/sig/generated/lrama/grammar/union.rbs +17 -0
- data/sig/generated/lrama/grammar.rbs +289 -0
- data/sig/generated/lrama/lexer/location.rbs +12 -3
- data/sig/generated/lrama/lexer/token/base.rbs +53 -0
- data/sig/generated/lrama/lexer/token/char.rbs +9 -2
- data/sig/generated/lrama/lexer/token/empty.rbs +11 -0
- data/sig/generated/lrama/lexer/token/ident.rbs +2 -2
- data/sig/generated/lrama/lexer/token/instantiate_rule.rbs +5 -5
- data/sig/generated/lrama/lexer/token/int.rbs +13 -0
- data/sig/generated/lrama/lexer/token/str.rbs +10 -0
- data/sig/generated/lrama/lexer/token/tag.rbs +2 -2
- data/sig/generated/lrama/lexer/token/token.rbs +10 -0
- data/sig/generated/lrama/lexer/token/user_code.rbs +2 -2
- data/sig/generated/lrama/lexer/token.rbs +1 -39
- data/sig/generated/lrama/lexer.rbs +54 -0
- data/sig/generated/lrama/logger.rbs +6 -0
- data/sig/generated/lrama/option_parser.rbs +52 -0
- data/sig/{lrama → generated/lrama}/options.rbs +27 -3
- data/sig/generated/lrama/reporter/conflicts.rbs +18 -0
- data/sig/generated/lrama/reporter/grammar.rbs +13 -0
- data/sig/generated/lrama/reporter/precedences.rbs +15 -0
- data/sig/generated/lrama/reporter/profile/call_stack.rbs +19 -0
- data/sig/generated/lrama/reporter/profile/memory.rbs +19 -0
- data/sig/generated/lrama/reporter/rules.rbs +13 -0
- data/sig/generated/lrama/reporter/states.rbs +69 -0
- data/sig/generated/lrama/reporter/terms.rbs +13 -0
- data/sig/generated/lrama/reporter.rbs +13 -0
- data/sig/generated/lrama/state/action/goto.rbs +28 -0
- data/sig/generated/lrama/state/action/reduce.rbs +49 -0
- data/sig/generated/lrama/state/action/shift.rbs +33 -0
- data/sig/generated/lrama/state/inadequacy_annotation.rbs +45 -0
- data/sig/generated/lrama/state/item.rbs +75 -0
- data/sig/generated/lrama/state/reduce_reduce_conflict.rbs +19 -0
- data/sig/generated/lrama/state/resolved_conflict.rbs +38 -0
- data/sig/generated/lrama/state/shift_reduce_conflict.rbs +19 -0
- data/sig/generated/lrama/state.rbs +231 -0
- data/sig/generated/lrama/states.rbs +215 -0
- data/sig/generated/lrama/tracer/actions.rbs +13 -0
- data/sig/generated/lrama/tracer/closure.rbs +13 -0
- data/sig/generated/lrama/tracer/duration.rbs +18 -0
- data/sig/generated/lrama/tracer/only_explicit_rules.rbs +13 -0
- data/sig/generated/lrama/tracer/rules.rbs +13 -0
- data/sig/generated/lrama/tracer/state.rbs +16 -0
- data/sig/generated/lrama/tracer.rbs +23 -0
- data/sig/generated/lrama/version.rbs +5 -0
- data/sig/generated/lrama/warnings/conflicts.rbs +13 -0
- data/sig/generated/lrama/warnings/implicit_empty.rbs +17 -0
- data/sig/generated/lrama/warnings/name_conflicts.rbs +31 -0
- data/sig/generated/lrama/warnings/redefined_rules.rbs +13 -0
- data/sig/generated/lrama/warnings/required.rbs +13 -0
- data/sig/generated/lrama/warnings/useless_precedence.rbs +13 -0
- data/sig/generated/lrama/warnings.rbs +11 -0
- data/sig/railroad_diagrams/railroad_diagrams.rbs +16 -0
- data/template/bison/_yacc.h +8 -0
- data/template/diagram/diagram.html +102 -0
- metadata +126 -66
- data/lib/lrama/counterexamples/production_path.rb +0 -19
- data/lib/lrama/counterexamples/start_path.rb +0 -23
- data/lib/lrama/counterexamples/transition_path.rb +0 -19
- data/lib/lrama/diagnostics.rb +0 -36
- data/lib/lrama/grammar/parameterizing_rule/rule.rb +0 -24
- data/lib/lrama/grammar/parameterizing_rule.rb +0 -5
- data/lib/lrama/grammar_validator.rb +0 -37
- data/lib/lrama/report/duration.rb +0 -27
- data/lib/lrama/report/profile.rb +0 -16
- data/lib/lrama/report.rb +0 -4
- data/lib/lrama/state/reduce.rb +0 -37
- data/lib/lrama/state/shift.rb +0 -15
- data/lib/lrama/states_reporter.rb +0 -362
- data/lib/lrama/trace_reporter.rb +0 -45
- data/sig/generated/lrama/trace_reporter.rbs +0 -25
- data/sig/lrama/counterexamples/derivation.rbs +0 -33
- data/sig/lrama/counterexamples/example.rbs +0 -45
- data/sig/lrama/counterexamples/path.rbs +0 -21
- data/sig/lrama/counterexamples/production_path.rbs +0 -11
- data/sig/lrama/counterexamples/start_path.rbs +0 -13
- data/sig/lrama/counterexamples/state_item.rbs +0 -10
- data/sig/lrama/counterexamples/transition_path.rbs +0 -11
- data/sig/lrama/counterexamples/triple.rbs +0 -20
- data/sig/lrama/counterexamples.rbs +0 -29
- data/sig/lrama/grammar/auxiliary.rbs +0 -10
- data/sig/lrama/grammar/code/destructor_code.rbs +0 -14
- data/sig/lrama/grammar/code/printer_code.rbs +0 -14
- data/sig/lrama/grammar/code/rule_action.rbs +0 -19
- data/sig/lrama/grammar/code.rbs +0 -24
- data/sig/lrama/grammar/destructor.rbs +0 -13
- data/sig/lrama/grammar/parameterizing_rule/resolver.rbs +0 -24
- data/sig/lrama/grammar/parameterizing_rule/rhs.rbs +0 -14
- data/sig/lrama/grammar/parameterizing_rule/rule.rbs +0 -16
- data/sig/lrama/grammar/parameterizing_rule.rbs +0 -6
- data/sig/lrama/grammar/precedence.rbs +0 -13
- data/sig/lrama/grammar/printer.rbs +0 -13
- data/sig/lrama/grammar/reference.rbs +0 -22
- data/sig/lrama/grammar/rule.rbs +0 -45
- data/sig/lrama/grammar/rule_builder.rbs +0 -47
- data/sig/lrama/grammar/symbol.rbs +0 -38
- data/sig/lrama/grammar/symbols/resolver.rbs +0 -60
- data/sig/lrama/grammar/type.rbs +0 -11
- data/sig/lrama/grammar/union.rbs +0 -12
- data/sig/lrama/grammar.rbs +0 -108
- data/sig/lrama/report/duration.rbs +0 -11
- data/sig/lrama/report/profile.rbs +0 -7
- data/sig/lrama/state/reduce.rbs +0 -20
- data/sig/lrama/state/reduce_reduce_conflict.rbs +0 -13
- data/sig/lrama/state/resolved_conflict.rbs +0 -14
- data/sig/lrama/state/shift.rbs +0 -14
- data/sig/lrama/state/shift_reduce_conflict.rbs +0 -13
- data/sig/lrama/state.rbs +0 -79
- data/sig/lrama/states/item.rbs +0 -30
- data/sig/lrama/states.rbs +0 -101
- data/sig/lrama/warning.rbs +0 -16
data/lib/lrama/states.rb
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
# rbs_inline: enabled
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
require "forwardable"
|
|
4
|
-
require_relative "
|
|
5
|
-
require_relative "
|
|
5
|
+
require_relative "tracer/duration"
|
|
6
|
+
require_relative "state/item"
|
|
6
7
|
|
|
7
8
|
module Lrama
|
|
8
9
|
# States is passed to a template file
|
|
@@ -10,17 +11,42 @@ module Lrama
|
|
|
10
11
|
# "Efficient Computation of LALR(1) Look-Ahead Sets"
|
|
11
12
|
# https://dl.acm.org/doi/pdf/10.1145/69622.357187
|
|
12
13
|
class States
|
|
14
|
+
# TODO: rbs-inline 0.11.0 doesn't support instance variables.
|
|
15
|
+
# Move these type declarations above instance variable definitions, once it's supported.
|
|
16
|
+
# see: https://github.com/soutaro/rbs-inline/pull/149
|
|
17
|
+
#
|
|
18
|
+
# @rbs!
|
|
19
|
+
# type state_id = Integer
|
|
20
|
+
# type rule_id = Integer
|
|
21
|
+
#
|
|
22
|
+
# include Grammar::_DelegatedMethods
|
|
23
|
+
#
|
|
24
|
+
# @grammar: Grammar
|
|
25
|
+
# @tracer: Tracer
|
|
26
|
+
# @states: Array[State]
|
|
27
|
+
# @direct_read_sets: Hash[State::Action::Goto, Bitmap::bitmap]
|
|
28
|
+
# @reads_relation: Hash[State::Action::Goto, Array[State::Action::Goto]]
|
|
29
|
+
# @read_sets: Hash[State::Action::Goto, Bitmap::bitmap]
|
|
30
|
+
# @includes_relation: Hash[State::Action::Goto, Array[State::Action::Goto]]
|
|
31
|
+
# @lookback_relation: Hash[state_id, Hash[rule_id, Array[State::Action::Goto]]]
|
|
32
|
+
# @follow_sets: Hash[State::Action::Goto, Bitmap::bitmap]
|
|
33
|
+
# @la: Hash[state_id, Hash[rule_id, Bitmap::bitmap]]
|
|
34
|
+
|
|
13
35
|
extend Forwardable
|
|
14
|
-
include Lrama::
|
|
36
|
+
include Lrama::Tracer::Duration
|
|
15
37
|
|
|
16
|
-
def_delegators "@grammar", :symbols, :terms, :nterms, :rules,
|
|
17
|
-
:accept_symbol, :eof_symbol, :undef_symbol, :find_symbol_by_s_value
|
|
38
|
+
def_delegators "@grammar", :symbols, :terms, :nterms, :rules, :precedences,
|
|
39
|
+
:accept_symbol, :eof_symbol, :undef_symbol, :find_symbol_by_s_value!, :ielr_defined?
|
|
18
40
|
|
|
19
|
-
attr_reader :states
|
|
41
|
+
attr_reader :states #: Array[State]
|
|
42
|
+
attr_reader :reads_relation #: Hash[State::Action::Goto, Array[State::Action::Goto]]
|
|
43
|
+
attr_reader :includes_relation #: Hash[State::Action::Goto, Array[State::Action::Goto]]
|
|
44
|
+
attr_reader :lookback_relation #: Hash[state_id, Hash[rule_id, Array[State::Action::Goto]]]
|
|
20
45
|
|
|
21
|
-
|
|
46
|
+
# @rbs (Grammar grammar, Tracer tracer) -> void
|
|
47
|
+
def initialize(grammar, tracer)
|
|
22
48
|
@grammar = grammar
|
|
23
|
-
@
|
|
49
|
+
@tracer = tracer
|
|
24
50
|
|
|
25
51
|
@states = []
|
|
26
52
|
|
|
@@ -28,7 +54,7 @@ module Lrama
|
|
|
28
54
|
# where p is state, A is nterm, t is term.
|
|
29
55
|
#
|
|
30
56
|
# `@direct_read_sets` is a hash whose
|
|
31
|
-
# key is
|
|
57
|
+
# key is goto,
|
|
32
58
|
# value is bitmap of term.
|
|
33
59
|
@direct_read_sets = {}
|
|
34
60
|
|
|
@@ -37,14 +63,14 @@ module Lrama
|
|
|
37
63
|
# where p, r are state, A, C are nterm.
|
|
38
64
|
#
|
|
39
65
|
# `@reads_relation` is a hash whose
|
|
40
|
-
# key is
|
|
41
|
-
# value is array of
|
|
66
|
+
# key is goto,
|
|
67
|
+
# value is array of goto.
|
|
42
68
|
@reads_relation = {}
|
|
43
69
|
|
|
44
70
|
# `Read(p, A) =s DR(p, A) ∪ ∪{Read(r, C) | (p, A) reads (r, C)}`
|
|
45
71
|
#
|
|
46
72
|
# `@read_sets` is a hash whose
|
|
47
|
-
# key is
|
|
73
|
+
# key is goto,
|
|
48
74
|
# value is bitmap of term.
|
|
49
75
|
@read_sets = {}
|
|
50
76
|
|
|
@@ -52,112 +78,163 @@ module Lrama
|
|
|
52
78
|
# where p, p' are state, A, B are nterm, β, γ is sequence of symbol.
|
|
53
79
|
#
|
|
54
80
|
# `@includes_relation` is a hash whose
|
|
55
|
-
# key is
|
|
56
|
-
# value is array of
|
|
81
|
+
# key is goto,
|
|
82
|
+
# value is array of goto.
|
|
57
83
|
@includes_relation = {}
|
|
58
84
|
|
|
59
85
|
# `(q, A -> ω) lookback (p, A) iff p -(ω)-> q`
|
|
60
86
|
# where p, q are state, A -> ω is rule, A is nterm, ω is sequence of symbol.
|
|
61
87
|
#
|
|
62
|
-
# `@lookback_relation` is a hash whose
|
|
63
|
-
# key is
|
|
64
|
-
#
|
|
88
|
+
# `@lookback_relation` is a two-stage hash whose
|
|
89
|
+
# first key is state_id,
|
|
90
|
+
# second key is rule_id,
|
|
91
|
+
# value is array of goto.
|
|
65
92
|
@lookback_relation = {}
|
|
66
93
|
|
|
67
94
|
# `Follow(p, A) =s Read(p, A) ∪ ∪{Follow(p', B) | (p, A) includes (p', B)}`
|
|
68
95
|
#
|
|
69
96
|
# `@follow_sets` is a hash whose
|
|
70
|
-
# key is
|
|
97
|
+
# key is goto,
|
|
71
98
|
# value is bitmap of term.
|
|
72
99
|
@follow_sets = {}
|
|
73
100
|
|
|
74
101
|
# `LA(q, A -> ω) = ∪{Follow(p, A) | (q, A -> ω) lookback (p, A)`
|
|
75
102
|
#
|
|
76
|
-
# `@la` is a hash whose
|
|
77
|
-
# key is
|
|
103
|
+
# `@la` is a two-stage hash whose
|
|
104
|
+
# first key is state_id,
|
|
105
|
+
# second key is rule_id,
|
|
78
106
|
# value is bitmap of term.
|
|
79
107
|
@la = {}
|
|
80
108
|
end
|
|
81
109
|
|
|
110
|
+
# @rbs () -> void
|
|
82
111
|
def compute
|
|
83
|
-
# Look Ahead Sets
|
|
84
112
|
report_duration(:compute_lr0_states) { compute_lr0_states }
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
report_duration(:compute_read_sets) { compute_read_sets }
|
|
88
|
-
report_duration(:compute_includes_relation) { compute_includes_relation }
|
|
89
|
-
report_duration(:compute_lookback_relation) { compute_lookback_relation }
|
|
90
|
-
report_duration(:compute_follow_sets) { compute_follow_sets }
|
|
113
|
+
|
|
114
|
+
# Look Ahead Sets
|
|
91
115
|
report_duration(:compute_look_ahead_sets) { compute_look_ahead_sets }
|
|
92
116
|
|
|
93
117
|
# Conflicts
|
|
94
|
-
report_duration(:compute_conflicts) { compute_conflicts }
|
|
118
|
+
report_duration(:compute_conflicts) { compute_conflicts(:lalr) }
|
|
95
119
|
|
|
96
120
|
report_duration(:compute_default_reduction) { compute_default_reduction }
|
|
97
121
|
end
|
|
98
122
|
|
|
123
|
+
# @rbs () -> void
|
|
99
124
|
def compute_ielr
|
|
125
|
+
# Preparation
|
|
126
|
+
report_duration(:clear_conflicts) { clear_conflicts }
|
|
127
|
+
# Phase 1
|
|
128
|
+
report_duration(:compute_predecessors) { compute_predecessors }
|
|
129
|
+
report_duration(:compute_follow_kernel_items) { compute_follow_kernel_items }
|
|
130
|
+
report_duration(:compute_always_follows) { compute_always_follows }
|
|
131
|
+
report_duration(:compute_goto_follows) { compute_goto_follows }
|
|
132
|
+
# Phase 2
|
|
133
|
+
report_duration(:compute_inadequacy_annotations) { compute_inadequacy_annotations }
|
|
134
|
+
# Phase 3
|
|
100
135
|
report_duration(:split_states) { split_states }
|
|
101
|
-
|
|
102
|
-
report_duration(:
|
|
103
|
-
report_duration(:compute_read_sets) { compute_read_sets }
|
|
104
|
-
report_duration(:compute_includes_relation) { compute_includes_relation }
|
|
105
|
-
report_duration(:compute_lookback_relation) { compute_lookback_relation }
|
|
106
|
-
report_duration(:compute_follow_sets) { compute_follow_sets }
|
|
136
|
+
# Phase 4
|
|
137
|
+
report_duration(:clear_look_ahead_sets) { clear_look_ahead_sets }
|
|
107
138
|
report_duration(:compute_look_ahead_sets) { compute_look_ahead_sets }
|
|
108
|
-
|
|
109
|
-
|
|
139
|
+
# Phase 5
|
|
140
|
+
report_duration(:compute_conflicts) { compute_conflicts(:ielr) }
|
|
110
141
|
report_duration(:compute_default_reduction) { compute_default_reduction }
|
|
111
142
|
end
|
|
112
143
|
|
|
113
|
-
|
|
114
|
-
StatesReporter.new(self)
|
|
115
|
-
end
|
|
116
|
-
|
|
144
|
+
# @rbs () -> Integer
|
|
117
145
|
def states_count
|
|
118
146
|
@states.count
|
|
119
147
|
end
|
|
120
148
|
|
|
149
|
+
# @rbs () -> Hash[State::Action::Goto, Array[Grammar::Symbol]]
|
|
121
150
|
def direct_read_sets
|
|
122
|
-
@direct_read_sets.transform_values do |v|
|
|
151
|
+
@_direct_read_sets ||= @direct_read_sets.transform_values do |v|
|
|
123
152
|
bitmap_to_terms(v)
|
|
124
153
|
end
|
|
125
154
|
end
|
|
126
155
|
|
|
156
|
+
# @rbs () -> Hash[State::Action::Goto, Array[Grammar::Symbol]]
|
|
127
157
|
def read_sets
|
|
128
|
-
@read_sets.transform_values do |v|
|
|
158
|
+
@_read_sets ||= @read_sets.transform_values do |v|
|
|
129
159
|
bitmap_to_terms(v)
|
|
130
160
|
end
|
|
131
161
|
end
|
|
132
162
|
|
|
163
|
+
# @rbs () -> Hash[State::Action::Goto, Array[Grammar::Symbol]]
|
|
133
164
|
def follow_sets
|
|
134
|
-
@follow_sets.transform_values do |v|
|
|
165
|
+
@_follow_sets ||= @follow_sets.transform_values do |v|
|
|
135
166
|
bitmap_to_terms(v)
|
|
136
167
|
end
|
|
137
168
|
end
|
|
138
169
|
|
|
170
|
+
# @rbs () -> Hash[state_id, Hash[rule_id, Array[Grammar::Symbol]]]
|
|
139
171
|
def la
|
|
140
|
-
@la.transform_values do |
|
|
141
|
-
|
|
172
|
+
@_la ||= @la.transform_values do |second_hash|
|
|
173
|
+
second_hash.transform_values do |v|
|
|
174
|
+
bitmap_to_terms(v)
|
|
175
|
+
end
|
|
142
176
|
end
|
|
143
177
|
end
|
|
144
178
|
|
|
179
|
+
# @rbs () -> Integer
|
|
145
180
|
def sr_conflicts_count
|
|
146
181
|
@sr_conflicts_count ||= @states.flat_map(&:sr_conflicts).count
|
|
147
182
|
end
|
|
148
183
|
|
|
184
|
+
# @rbs () -> Integer
|
|
149
185
|
def rr_conflicts_count
|
|
150
186
|
@rr_conflicts_count ||= @states.flat_map(&:rr_conflicts).count
|
|
151
187
|
end
|
|
152
188
|
|
|
153
|
-
|
|
189
|
+
# @rbs (Logger logger) -> void
|
|
190
|
+
def validate!(logger)
|
|
191
|
+
validate_conflicts_within_threshold!(logger)
|
|
192
|
+
end
|
|
154
193
|
|
|
155
|
-
def
|
|
156
|
-
|
|
157
|
-
|
|
194
|
+
def compute_la_sources_for_conflicted_states
|
|
195
|
+
reflexive = {}
|
|
196
|
+
@states.each do |state|
|
|
197
|
+
state.nterm_transitions.each do |goto|
|
|
198
|
+
reflexive[goto] = [goto]
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# compute_read_sets
|
|
203
|
+
read_sets = Digraph.new(nterm_transitions, @reads_relation, reflexive).compute
|
|
204
|
+
# compute_follow_sets
|
|
205
|
+
follow_sets = Digraph.new(nterm_transitions, @includes_relation, read_sets).compute
|
|
206
|
+
|
|
207
|
+
@states.select(&:has_conflicts?).each do |state|
|
|
208
|
+
lookback_relation_on_state = @lookback_relation[state.id]
|
|
209
|
+
next unless lookback_relation_on_state
|
|
210
|
+
rules.each do |rule|
|
|
211
|
+
ary = lookback_relation_on_state[rule.id]
|
|
212
|
+
next unless ary
|
|
213
|
+
|
|
214
|
+
sources = {}
|
|
215
|
+
|
|
216
|
+
ary.each do |goto|
|
|
217
|
+
source = follow_sets[goto]
|
|
218
|
+
|
|
219
|
+
next unless source
|
|
220
|
+
|
|
221
|
+
source.each do |goto2|
|
|
222
|
+
tokens = direct_read_sets[goto2]
|
|
223
|
+
tokens.each do |token|
|
|
224
|
+
sources[token] ||= []
|
|
225
|
+
sources[token] |= [goto2]
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
state.set_look_ahead_sources(rule, sources)
|
|
231
|
+
end
|
|
158
232
|
end
|
|
159
233
|
end
|
|
160
234
|
|
|
235
|
+
private
|
|
236
|
+
|
|
237
|
+
# @rbs (Grammar::Symbol accessing_symbol, Array[State::Item] kernels, Hash[Array[State::Item], State] states_created) -> [State, bool]
|
|
161
238
|
def create_state(accessing_symbol, kernels, states_created)
|
|
162
239
|
# A item can appear in some states,
|
|
163
240
|
# so need to use `kernels` (not `kernels.first`) as a key.
|
|
@@ -204,27 +281,25 @@ module Lrama
|
|
|
204
281
|
return [state, true]
|
|
205
282
|
end
|
|
206
283
|
|
|
284
|
+
# @rbs (State state) -> void
|
|
207
285
|
def setup_state(state)
|
|
208
286
|
# closure
|
|
209
287
|
closure = []
|
|
210
|
-
visited = {}
|
|
211
288
|
queued = {}
|
|
212
289
|
items = state.kernels.dup
|
|
213
290
|
|
|
214
291
|
items.each do |item|
|
|
215
|
-
queued[item] = true
|
|
292
|
+
queued[item.rule_id] = true if item.position == 0
|
|
216
293
|
end
|
|
217
294
|
|
|
218
295
|
while (item = items.shift) do
|
|
219
|
-
visited[item] = true
|
|
220
|
-
|
|
221
296
|
if (sym = item.next_sym) && sym.nterm?
|
|
222
297
|
@grammar.find_rules_by_symbol!(sym).each do |rule|
|
|
223
|
-
|
|
224
|
-
|
|
298
|
+
next if queued[rule.id]
|
|
299
|
+
i = State::Item.new(rule: rule, position: 0)
|
|
225
300
|
closure << i
|
|
226
301
|
items << i
|
|
227
|
-
queued[i] = true
|
|
302
|
+
queued[i.rule_id] = true
|
|
228
303
|
end
|
|
229
304
|
end
|
|
230
305
|
end
|
|
@@ -232,119 +307,107 @@ module Lrama
|
|
|
232
307
|
state.closure = closure.sort_by {|i| i.rule.id }
|
|
233
308
|
|
|
234
309
|
# Trace
|
|
235
|
-
|
|
236
|
-
out << "Closure: input\n"
|
|
237
|
-
state.kernels.each do |item|
|
|
238
|
-
out << " #{item.display_rest}\n"
|
|
239
|
-
end
|
|
240
|
-
out << "\n\n"
|
|
241
|
-
out << "Closure: output\n"
|
|
242
|
-
state.items.each do |item|
|
|
243
|
-
out << " #{item.display_rest}\n"
|
|
244
|
-
end
|
|
245
|
-
out << "\n\n"
|
|
246
|
-
end
|
|
310
|
+
@tracer.trace_closure(state)
|
|
247
311
|
|
|
248
312
|
# shift & reduce
|
|
249
|
-
state.
|
|
313
|
+
state.compute_transitions_and_reduces
|
|
250
314
|
end
|
|
251
315
|
|
|
316
|
+
# @rbs (Array[State] states, State state) -> void
|
|
252
317
|
def enqueue_state(states, state)
|
|
253
318
|
# Trace
|
|
254
|
-
|
|
255
|
-
trace_state do |out|
|
|
256
|
-
out << sprintf("state_list_append (state = %d, symbol = %d (%s))\n",
|
|
257
|
-
@states.count, previous.number, previous.display_name)
|
|
258
|
-
end
|
|
319
|
+
@tracer.trace_state_list_append(@states.count, state)
|
|
259
320
|
|
|
260
321
|
states << state
|
|
261
322
|
end
|
|
262
323
|
|
|
324
|
+
# @rbs () -> void
|
|
263
325
|
def compute_lr0_states
|
|
264
326
|
# State queue
|
|
265
327
|
states = []
|
|
266
328
|
states_created = {}
|
|
267
329
|
|
|
268
|
-
state, _ = create_state(symbols.first, [Item.new(rule: @grammar.rules.first, position: 0)], states_created)
|
|
330
|
+
state, _ = create_state(symbols.first, [State::Item.new(rule: @grammar.rules.first, position: 0)], states_created)
|
|
269
331
|
enqueue_state(states, state)
|
|
270
332
|
|
|
271
333
|
while (state = states.shift) do
|
|
272
334
|
# Trace
|
|
273
|
-
|
|
274
|
-
# Bison 3.8.2 renders "(reached by "end-of-input")" for State 0 but
|
|
275
|
-
# I think it is not correct...
|
|
276
|
-
previous = state.kernels.first.previous_sym
|
|
277
|
-
trace_state do |out|
|
|
278
|
-
out << "Processing state #{state.id} (reached by #{previous.display_name})\n"
|
|
279
|
-
end
|
|
335
|
+
@tracer.trace_state(state)
|
|
280
336
|
|
|
281
337
|
setup_state(state)
|
|
282
338
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
339
|
+
# `State#transitions` can not be used here
|
|
340
|
+
# because `items_to_state` of the `state` is not set yet.
|
|
341
|
+
state._transitions.each do |next_sym, to_items|
|
|
342
|
+
new_state, created = create_state(next_sym, to_items, states_created)
|
|
343
|
+
state.set_items_to_state(to_items, new_state)
|
|
344
|
+
state.set_lane_items(next_sym, new_state)
|
|
345
|
+
enqueue_state(states, new_state) if created
|
|
290
346
|
end
|
|
291
347
|
end
|
|
292
348
|
end
|
|
293
349
|
|
|
350
|
+
# @rbs () -> Array[State::Action::Goto]
|
|
294
351
|
def nterm_transitions
|
|
295
352
|
a = []
|
|
296
353
|
|
|
297
354
|
@states.each do |state|
|
|
298
|
-
state.nterm_transitions.each do |
|
|
299
|
-
|
|
300
|
-
a << [state, nterm, next_state]
|
|
355
|
+
state.nterm_transitions.each do |goto|
|
|
356
|
+
a << goto
|
|
301
357
|
end
|
|
302
358
|
end
|
|
303
359
|
|
|
304
360
|
a
|
|
305
361
|
end
|
|
306
362
|
|
|
363
|
+
# @rbs () -> void
|
|
364
|
+
def compute_look_ahead_sets
|
|
365
|
+
report_duration(:compute_direct_read_sets) { compute_direct_read_sets }
|
|
366
|
+
report_duration(:compute_reads_relation) { compute_reads_relation }
|
|
367
|
+
report_duration(:compute_read_sets) { compute_read_sets }
|
|
368
|
+
report_duration(:compute_includes_relation) { compute_includes_relation }
|
|
369
|
+
report_duration(:compute_lookback_relation) { compute_lookback_relation }
|
|
370
|
+
report_duration(:compute_follow_sets) { compute_follow_sets }
|
|
371
|
+
report_duration(:compute_la) { compute_la }
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
# @rbs () -> void
|
|
307
375
|
def compute_direct_read_sets
|
|
308
376
|
@states.each do |state|
|
|
309
|
-
state.nterm_transitions.each do |
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
ary = next_state.term_transitions.map do |shift, _|
|
|
377
|
+
state.nterm_transitions.each do |goto|
|
|
378
|
+
ary = goto.to_state.term_transitions.map do |shift|
|
|
313
379
|
shift.next_sym.number
|
|
314
380
|
end
|
|
315
381
|
|
|
316
|
-
|
|
317
|
-
@direct_read_sets[key] = Bitmap.from_array(ary)
|
|
382
|
+
@direct_read_sets[goto] = Bitmap.from_array(ary)
|
|
318
383
|
end
|
|
319
384
|
end
|
|
320
385
|
end
|
|
321
386
|
|
|
387
|
+
# @rbs () -> void
|
|
322
388
|
def compute_reads_relation
|
|
323
389
|
@states.each do |state|
|
|
324
|
-
state.nterm_transitions.each do |
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
nterm2 = shift2.next_sym
|
|
390
|
+
state.nterm_transitions.each do |goto|
|
|
391
|
+
goto.to_state.nterm_transitions.each do |goto2|
|
|
392
|
+
nterm2 = goto2.next_sym
|
|
328
393
|
if nterm2.nullable
|
|
329
|
-
|
|
330
|
-
@reads_relation[
|
|
331
|
-
@reads_relation[key] << [next_state.id, nterm2.token_id]
|
|
394
|
+
@reads_relation[goto] ||= []
|
|
395
|
+
@reads_relation[goto] << goto2
|
|
332
396
|
end
|
|
333
397
|
end
|
|
334
398
|
end
|
|
335
399
|
end
|
|
336
400
|
end
|
|
337
401
|
|
|
402
|
+
# @rbs () -> void
|
|
338
403
|
def compute_read_sets
|
|
339
|
-
|
|
340
|
-
[state.id, nterm.token_id]
|
|
341
|
-
end
|
|
342
|
-
|
|
343
|
-
@read_sets = Digraph.new(sets, @reads_relation, @direct_read_sets).compute
|
|
404
|
+
@read_sets = Digraph.new(nterm_transitions, @reads_relation, @direct_read_sets).compute
|
|
344
405
|
end
|
|
345
406
|
|
|
346
407
|
# Execute transition of state by symbols
|
|
347
408
|
# then return final state.
|
|
409
|
+
#
|
|
410
|
+
# @rbs (State state, Array[Grammar::Symbol] symbols) -> State
|
|
348
411
|
def transition(state, symbols)
|
|
349
412
|
symbols.each do |sym|
|
|
350
413
|
state = state.transition(sym)
|
|
@@ -353,10 +416,11 @@ module Lrama
|
|
|
353
416
|
state
|
|
354
417
|
end
|
|
355
418
|
|
|
419
|
+
# @rbs () -> void
|
|
356
420
|
def compute_includes_relation
|
|
357
421
|
@states.each do |state|
|
|
358
|
-
state.nterm_transitions.each do |
|
|
359
|
-
nterm =
|
|
422
|
+
state.nterm_transitions.each do |goto|
|
|
423
|
+
nterm = goto.next_sym
|
|
360
424
|
@grammar.find_rules_by_symbol!(nterm).each do |rule|
|
|
361
425
|
i = rule.rhs.count - 1
|
|
362
426
|
|
|
@@ -366,10 +430,12 @@ module Lrama
|
|
|
366
430
|
break if sym.term?
|
|
367
431
|
state2 = transition(state, rule.rhs[0...i])
|
|
368
432
|
# p' = state, B = nterm, p = state2, A = sym
|
|
369
|
-
key =
|
|
433
|
+
key = state2.nterm_transitions.find do |goto2|
|
|
434
|
+
goto2.next_sym.token_id == sym.token_id
|
|
435
|
+
end || (raise "Goto by #{sym.name} on state #{state2.id} is not found")
|
|
370
436
|
# TODO: need to omit if state == state2 ?
|
|
371
437
|
@includes_relation[key] ||= []
|
|
372
|
-
@includes_relation[key] <<
|
|
438
|
+
@includes_relation[key] << goto
|
|
373
439
|
break unless sym.nullable
|
|
374
440
|
i -= 1
|
|
375
441
|
end
|
|
@@ -378,45 +444,46 @@ module Lrama
|
|
|
378
444
|
end
|
|
379
445
|
end
|
|
380
446
|
|
|
447
|
+
# @rbs () -> void
|
|
381
448
|
def compute_lookback_relation
|
|
382
449
|
@states.each do |state|
|
|
383
|
-
state.nterm_transitions.each do |
|
|
384
|
-
nterm =
|
|
450
|
+
state.nterm_transitions.each do |goto|
|
|
451
|
+
nterm = goto.next_sym
|
|
385
452
|
@grammar.find_rules_by_symbol!(nterm).each do |rule|
|
|
386
453
|
state2 = transition(state, rule.rhs)
|
|
387
454
|
# p = state, A = nterm, q = state2, A -> ω = rule
|
|
388
|
-
|
|
389
|
-
@lookback_relation[
|
|
390
|
-
@lookback_relation[
|
|
455
|
+
@lookback_relation[state2.id] ||= {}
|
|
456
|
+
@lookback_relation[state2.id][rule.id] ||= []
|
|
457
|
+
@lookback_relation[state2.id][rule.id] << goto
|
|
391
458
|
end
|
|
392
459
|
end
|
|
393
460
|
end
|
|
394
461
|
end
|
|
395
462
|
|
|
463
|
+
# @rbs () -> void
|
|
396
464
|
def compute_follow_sets
|
|
397
|
-
|
|
398
|
-
[state.id, nterm.token_id]
|
|
399
|
-
end
|
|
400
|
-
|
|
401
|
-
@follow_sets = Digraph.new(sets, @includes_relation, @read_sets).compute
|
|
465
|
+
@follow_sets = Digraph.new(nterm_transitions, @includes_relation, @read_sets).compute
|
|
402
466
|
end
|
|
403
467
|
|
|
404
|
-
|
|
468
|
+
# @rbs () -> void
|
|
469
|
+
def compute_la
|
|
405
470
|
@states.each do |state|
|
|
471
|
+
lookback_relation_on_state = @lookback_relation[state.id]
|
|
472
|
+
next unless lookback_relation_on_state
|
|
406
473
|
rules.each do |rule|
|
|
407
|
-
ary =
|
|
474
|
+
ary = lookback_relation_on_state[rule.id]
|
|
408
475
|
next unless ary
|
|
409
476
|
|
|
410
|
-
ary.each do |
|
|
477
|
+
ary.each do |goto|
|
|
411
478
|
# q = state, A -> ω = rule, p = state2, A = nterm
|
|
412
|
-
follows = @follow_sets[
|
|
479
|
+
follows = @follow_sets[goto]
|
|
413
480
|
|
|
414
481
|
next if follows == 0
|
|
415
482
|
|
|
416
|
-
|
|
417
|
-
@la[
|
|
418
|
-
look_ahead = @la[
|
|
419
|
-
@la[
|
|
483
|
+
@la[state.id] ||= {}
|
|
484
|
+
@la[state.id][rule.id] ||= 0
|
|
485
|
+
look_ahead = @la[state.id][rule.id] | follows
|
|
486
|
+
@la[state.id][rule.id] |= look_ahead
|
|
420
487
|
|
|
421
488
|
# No risk of conflict when
|
|
422
489
|
# * the state only has single reduce
|
|
@@ -429,6 +496,7 @@ module Lrama
|
|
|
429
496
|
end
|
|
430
497
|
end
|
|
431
498
|
|
|
499
|
+
# @rbs (Bitmap::bitmap bit) -> Array[Grammar::Symbol]
|
|
432
500
|
def bitmap_to_terms(bit)
|
|
433
501
|
ary = Bitmap.to_array(bit)
|
|
434
502
|
ary.map do |i|
|
|
@@ -436,14 +504,16 @@ module Lrama
|
|
|
436
504
|
end
|
|
437
505
|
end
|
|
438
506
|
|
|
439
|
-
|
|
440
|
-
|
|
507
|
+
# @rbs () -> void
|
|
508
|
+
def compute_conflicts(lr_type)
|
|
509
|
+
compute_shift_reduce_conflicts(lr_type)
|
|
441
510
|
compute_reduce_reduce_conflicts
|
|
442
511
|
end
|
|
443
512
|
|
|
444
|
-
|
|
513
|
+
# @rbs () -> void
|
|
514
|
+
def compute_shift_reduce_conflicts(lr_type)
|
|
445
515
|
states.each do |state|
|
|
446
|
-
state.
|
|
516
|
+
state.term_transitions.each do |shift|
|
|
447
517
|
state.reduces.each do |reduce|
|
|
448
518
|
sym = shift.next_sym
|
|
449
519
|
|
|
@@ -463,43 +533,57 @@ module Lrama
|
|
|
463
533
|
case
|
|
464
534
|
when shift_prec < reduce_prec
|
|
465
535
|
# Reduce is selected
|
|
466
|
-
|
|
536
|
+
resolved_conflict = State::ResolvedConflict.new(state: state, symbol: sym, reduce: reduce, which: :reduce, resolved_by_precedence: false)
|
|
537
|
+
state.resolved_conflicts << resolved_conflict
|
|
467
538
|
shift.not_selected = true
|
|
539
|
+
mark_precedences_used(lr_type, shift_prec, reduce_prec, resolved_conflict)
|
|
468
540
|
next
|
|
469
541
|
when shift_prec > reduce_prec
|
|
470
542
|
# Shift is selected
|
|
471
|
-
|
|
543
|
+
resolved_conflict = State::ResolvedConflict.new(state: state, symbol: sym, reduce: reduce, which: :shift, resolved_by_precedence: false)
|
|
544
|
+
state.resolved_conflicts << resolved_conflict
|
|
472
545
|
reduce.add_not_selected_symbol(sym)
|
|
546
|
+
mark_precedences_used(lr_type, shift_prec, reduce_prec, resolved_conflict)
|
|
473
547
|
next
|
|
474
548
|
end
|
|
475
549
|
|
|
476
550
|
# shift_prec == reduce_prec, then check associativity
|
|
477
551
|
case sym.precedence.type
|
|
478
552
|
when :precedence
|
|
553
|
+
# Can not resolve the conflict
|
|
554
|
+
#
|
|
479
555
|
# %precedence only specifies precedence and not specify associativity
|
|
480
556
|
# then a conflict is unresolved if precedence is same.
|
|
481
557
|
state.conflicts << State::ShiftReduceConflict.new(symbols: [sym], shift: shift, reduce: reduce)
|
|
482
558
|
next
|
|
483
559
|
when :right
|
|
484
560
|
# Shift is selected
|
|
485
|
-
|
|
561
|
+
resolved_conflict = State::ResolvedConflict.new(state: state, symbol: sym, reduce: reduce, which: :shift, resolved_by_precedence: true)
|
|
562
|
+
state.resolved_conflicts << resolved_conflict
|
|
486
563
|
reduce.add_not_selected_symbol(sym)
|
|
564
|
+
mark_precedences_used(lr_type, shift_prec, reduce_prec, resolved_conflict)
|
|
487
565
|
next
|
|
488
566
|
when :left
|
|
489
567
|
# Reduce is selected
|
|
490
|
-
|
|
568
|
+
resolved_conflict = State::ResolvedConflict.new(state: state, symbol: sym, reduce: reduce, which: :reduce, resolved_by_precedence: true)
|
|
569
|
+
state.resolved_conflicts << resolved_conflict
|
|
491
570
|
shift.not_selected = true
|
|
571
|
+
mark_precedences_used(lr_type, shift_prec, reduce_prec, resolved_conflict)
|
|
492
572
|
next
|
|
493
573
|
when :nonassoc
|
|
494
|
-
#
|
|
574
|
+
# The conflict is resolved
|
|
495
575
|
#
|
|
496
|
-
# nonassoc creates "run-time" error
|
|
497
|
-
#
|
|
576
|
+
# %nonassoc creates "run-time" error by removing both shift and reduce from
|
|
577
|
+
# the state. This makes the state to get syntax error if the conflicted token appears.
|
|
578
|
+
# On the other hand, %precedence creates "compile-time" error by keeping both
|
|
579
|
+
# shift and reduce on the state. This makes the state to be conflicted on the token.
|
|
498
580
|
#
|
|
499
581
|
# https://www.gnu.org/software/bison/manual/html_node/Using-Precedence.html
|
|
500
|
-
|
|
582
|
+
resolved_conflict = State::ResolvedConflict.new(state: state, symbol: sym, reduce: reduce, which: :error, resolved_by_precedence: false)
|
|
583
|
+
state.resolved_conflicts << resolved_conflict
|
|
501
584
|
shift.not_selected = true
|
|
502
585
|
reduce.add_not_selected_symbol(sym)
|
|
586
|
+
mark_precedences_used(lr_type, shift_prec, reduce_prec, resolved_conflict)
|
|
503
587
|
else
|
|
504
588
|
raise "Unknown precedence type. #{sym}"
|
|
505
589
|
end
|
|
@@ -508,35 +592,41 @@ module Lrama
|
|
|
508
592
|
end
|
|
509
593
|
end
|
|
510
594
|
|
|
595
|
+
# @rbs (Grammar::Precedence shift_prec, Grammar::Precedence reduce_prec, State::ResolvedConflict resolved_conflict) -> void
|
|
596
|
+
def mark_precedences_used(lr_type, shift_prec, reduce_prec, resolved_conflict)
|
|
597
|
+
case lr_type
|
|
598
|
+
when :lalr
|
|
599
|
+
shift_prec.mark_used_by_lalr(resolved_conflict)
|
|
600
|
+
reduce_prec.mark_used_by_lalr(resolved_conflict)
|
|
601
|
+
when :ielr
|
|
602
|
+
shift_prec.mark_used_by_ielr(resolved_conflict)
|
|
603
|
+
reduce_prec.mark_used_by_ielr(resolved_conflict)
|
|
604
|
+
end
|
|
605
|
+
end
|
|
606
|
+
|
|
607
|
+
# @rbs () -> void
|
|
511
608
|
def compute_reduce_reduce_conflicts
|
|
512
609
|
states.each do |state|
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
(0...count).each do |i|
|
|
516
|
-
reduce1 = state.reduces[i]
|
|
517
|
-
next if reduce1.look_ahead.nil?
|
|
610
|
+
state.reduces.combination(2) do |reduce1, reduce2|
|
|
611
|
+
next if reduce1.look_ahead.nil? || reduce2.look_ahead.nil?
|
|
518
612
|
|
|
519
|
-
|
|
520
|
-
reduce2 = state.reduces[j]
|
|
521
|
-
next if reduce2.look_ahead.nil?
|
|
613
|
+
intersection = reduce1.look_ahead & reduce2.look_ahead
|
|
522
614
|
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
unless intersection.empty?
|
|
526
|
-
state.conflicts << State::ReduceReduceConflict.new(symbols: intersection, reduce1: reduce1, reduce2: reduce2)
|
|
527
|
-
end
|
|
615
|
+
unless intersection.empty?
|
|
616
|
+
state.conflicts << State::ReduceReduceConflict.new(symbols: intersection, reduce1: reduce1, reduce2: reduce2)
|
|
528
617
|
end
|
|
529
618
|
end
|
|
530
619
|
end
|
|
531
620
|
end
|
|
532
621
|
|
|
622
|
+
# @rbs () -> void
|
|
533
623
|
def compute_default_reduction
|
|
534
624
|
states.each do |state|
|
|
535
625
|
next if state.reduces.empty?
|
|
536
626
|
# Do not set, if conflict exist
|
|
537
627
|
next unless state.conflicts.empty?
|
|
538
628
|
# Do not set, if shift with `error` exists.
|
|
539
|
-
next if state.
|
|
629
|
+
next if state.term_transitions.map {|shift| shift.next_sym }.include?(@grammar.error_symbol)
|
|
540
630
|
|
|
541
631
|
state.default_reduction_rule = state.reduces.map do |r|
|
|
542
632
|
[r.rule, r.rule.id, (r.look_ahead || []).count]
|
|
@@ -546,35 +636,171 @@ module Lrama
|
|
|
546
636
|
end
|
|
547
637
|
end
|
|
548
638
|
|
|
639
|
+
# @rbs () -> void
|
|
640
|
+
def clear_conflicts
|
|
641
|
+
states.each(&:clear_conflicts)
|
|
642
|
+
end
|
|
643
|
+
|
|
644
|
+
# Definition 3.15 (Predecessors)
|
|
645
|
+
#
|
|
646
|
+
# @rbs () -> void
|
|
647
|
+
def compute_predecessors
|
|
648
|
+
@states.each do |state|
|
|
649
|
+
state.transitions.each do |transition|
|
|
650
|
+
transition.to_state.append_predecessor(state)
|
|
651
|
+
end
|
|
652
|
+
end
|
|
653
|
+
end
|
|
654
|
+
|
|
655
|
+
# Definition 3.16 (follow_kernel_items)
|
|
656
|
+
#
|
|
657
|
+
# @rbs () -> void
|
|
658
|
+
def compute_follow_kernel_items
|
|
659
|
+
set = nterm_transitions
|
|
660
|
+
relation = compute_goto_internal_relation
|
|
661
|
+
base_function = compute_goto_bitmaps
|
|
662
|
+
Digraph.new(set, relation, base_function).compute.each do |goto, follow_kernel_items|
|
|
663
|
+
state = goto.from_state
|
|
664
|
+
state.follow_kernel_items[goto] = state.kernels.map {|kernel|
|
|
665
|
+
[kernel, Bitmap.to_bool_array(follow_kernel_items, state.kernels.count)]
|
|
666
|
+
}.to_h
|
|
667
|
+
end
|
|
668
|
+
end
|
|
669
|
+
|
|
670
|
+
# @rbs () -> Hash[State::Action::Goto, Array[State::Action::Goto]]
|
|
671
|
+
def compute_goto_internal_relation
|
|
672
|
+
relations = {}
|
|
673
|
+
|
|
674
|
+
@states.each do |state|
|
|
675
|
+
state.nterm_transitions.each do |goto|
|
|
676
|
+
relations[goto] = state.internal_dependencies(goto)
|
|
677
|
+
end
|
|
678
|
+
end
|
|
679
|
+
|
|
680
|
+
relations
|
|
681
|
+
end
|
|
682
|
+
|
|
683
|
+
# @rbs () -> Hash[State::Action::Goto, Bitmap::bitmap]
|
|
684
|
+
def compute_goto_bitmaps
|
|
685
|
+
nterm_transitions.map {|goto|
|
|
686
|
+
bools = goto.from_state.kernels.map.with_index {|kernel, i| i if kernel.next_sym == goto.next_sym && kernel.symbols_after_transition.all?(&:nullable) }.compact
|
|
687
|
+
[goto, Bitmap.from_array(bools)]
|
|
688
|
+
}.to_h
|
|
689
|
+
end
|
|
690
|
+
|
|
691
|
+
# Definition 3.20 (always_follows, one closure)
|
|
692
|
+
#
|
|
693
|
+
# @rbs () -> void
|
|
694
|
+
def compute_always_follows
|
|
695
|
+
set = nterm_transitions
|
|
696
|
+
relation = compute_goto_successor_or_internal_relation
|
|
697
|
+
base_function = compute_transition_bitmaps
|
|
698
|
+
Digraph.new(set, relation, base_function).compute.each do |goto, always_follows_bitmap|
|
|
699
|
+
goto.from_state.always_follows[goto] = bitmap_to_terms(always_follows_bitmap)
|
|
700
|
+
end
|
|
701
|
+
end
|
|
702
|
+
|
|
703
|
+
# @rbs () -> Hash[State::Action::Goto, Array[State::Action::Goto]]
|
|
704
|
+
def compute_goto_successor_or_internal_relation
|
|
705
|
+
relations = {}
|
|
706
|
+
|
|
707
|
+
@states.each do |state|
|
|
708
|
+
state.nterm_transitions.each do |goto|
|
|
709
|
+
relations[goto] = state.successor_dependencies(goto) + state.internal_dependencies(goto)
|
|
710
|
+
end
|
|
711
|
+
end
|
|
712
|
+
|
|
713
|
+
relations
|
|
714
|
+
end
|
|
715
|
+
|
|
716
|
+
# @rbs () -> Hash[State::Action::Goto, Bitmap::bitmap]
|
|
717
|
+
def compute_transition_bitmaps
|
|
718
|
+
nterm_transitions.map {|goto|
|
|
719
|
+
[goto, Bitmap.from_array(goto.to_state.term_transitions.map {|shift| shift.next_sym.number })]
|
|
720
|
+
}.to_h
|
|
721
|
+
end
|
|
722
|
+
|
|
723
|
+
# Definition 3.24 (goto_follows, via always_follows)
|
|
724
|
+
#
|
|
725
|
+
# @rbs () -> void
|
|
726
|
+
def compute_goto_follows
|
|
727
|
+
set = nterm_transitions
|
|
728
|
+
relation = compute_goto_internal_or_predecessor_dependencies
|
|
729
|
+
base_function = compute_always_follows_bitmaps
|
|
730
|
+
Digraph.new(set, relation, base_function).compute.each do |goto, goto_follows_bitmap|
|
|
731
|
+
goto.from_state.goto_follows[goto] = bitmap_to_terms(goto_follows_bitmap)
|
|
732
|
+
end
|
|
733
|
+
end
|
|
734
|
+
|
|
735
|
+
# @rbs () -> Hash[State::Action::Goto, Array[State::Action::Goto]]
|
|
736
|
+
def compute_goto_internal_or_predecessor_dependencies
|
|
737
|
+
relations = {}
|
|
738
|
+
|
|
739
|
+
@states.each do |state|
|
|
740
|
+
state.nterm_transitions.each do |goto|
|
|
741
|
+
relations[goto] = state.internal_dependencies(goto) + state.predecessor_dependencies(goto)
|
|
742
|
+
end
|
|
743
|
+
end
|
|
744
|
+
|
|
745
|
+
relations
|
|
746
|
+
end
|
|
747
|
+
|
|
748
|
+
# @rbs () -> Hash[State::Action::Goto, Bitmap::bitmap]
|
|
749
|
+
def compute_always_follows_bitmaps
|
|
750
|
+
nterm_transitions.map {|goto|
|
|
751
|
+
[goto, Bitmap.from_array(goto.from_state.always_follows[goto].map(&:number))]
|
|
752
|
+
}.to_h
|
|
753
|
+
end
|
|
754
|
+
|
|
755
|
+
# @rbs () -> void
|
|
549
756
|
def split_states
|
|
550
757
|
@states.each do |state|
|
|
551
|
-
state.transitions.each do |
|
|
552
|
-
compute_state(state,
|
|
758
|
+
state.transitions.each do |transition|
|
|
759
|
+
compute_state(state, transition, transition.to_state)
|
|
553
760
|
end
|
|
554
761
|
end
|
|
555
762
|
end
|
|
556
763
|
|
|
764
|
+
# @rbs () -> void
|
|
765
|
+
def compute_inadequacy_annotations
|
|
766
|
+
@states.each do |state|
|
|
767
|
+
state.annotate_manifestation
|
|
768
|
+
end
|
|
769
|
+
|
|
770
|
+
queue = @states.reject {|state| state.annotation_list.empty? }
|
|
771
|
+
|
|
772
|
+
while (curr = queue.shift) do
|
|
773
|
+
curr.predecessors.each do |pred|
|
|
774
|
+
cache = pred.annotation_list.dup
|
|
775
|
+
curr.annotate_predecessor(pred)
|
|
776
|
+
queue << pred if cache != pred.annotation_list && !queue.include?(pred)
|
|
777
|
+
end
|
|
778
|
+
end
|
|
779
|
+
end
|
|
780
|
+
|
|
781
|
+
# @rbs (State state, State::lookahead_set filtered_lookaheads) -> void
|
|
557
782
|
def merge_lookaheads(state, filtered_lookaheads)
|
|
558
783
|
return if state.kernels.all? {|item| (filtered_lookaheads[item] - state.item_lookahead_set[item]).empty? }
|
|
559
784
|
|
|
560
785
|
state.item_lookahead_set = state.item_lookahead_set.merge {|_, v1, v2| v1 | v2 }
|
|
561
|
-
state.transitions.each do |
|
|
562
|
-
next if
|
|
563
|
-
compute_state(state,
|
|
786
|
+
state.transitions.each do |transition|
|
|
787
|
+
next if transition.to_state.lookaheads_recomputed
|
|
788
|
+
compute_state(state, transition, transition.to_state)
|
|
564
789
|
end
|
|
565
790
|
end
|
|
566
791
|
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
792
|
+
# @rbs (State state, State::Action::Shift | State::Action::Goto transition, State next_state) -> void
|
|
793
|
+
def compute_state(state, transition, next_state)
|
|
794
|
+
propagating_lookaheads = state.propagate_lookaheads(next_state)
|
|
795
|
+
s = next_state.ielr_isocores.find {|st| st.is_compatible?(propagating_lookaheads) }
|
|
570
796
|
|
|
571
797
|
if s.nil?
|
|
572
|
-
s = next_state.
|
|
798
|
+
s = next_state.lalr_isocore
|
|
573
799
|
new_state = State.new(@states.count, s.accessing_symbol, s.kernels)
|
|
574
800
|
new_state.closure = s.closure
|
|
575
|
-
new_state.
|
|
576
|
-
s.transitions.each do |
|
|
577
|
-
new_state.set_items_to_state(
|
|
801
|
+
new_state.compute_transitions_and_reduces
|
|
802
|
+
s.transitions.each do |transition|
|
|
803
|
+
new_state.set_items_to_state(transition.to_items, transition.to_state)
|
|
578
804
|
end
|
|
579
805
|
@states << new_state
|
|
580
806
|
new_state.lalr_isocore = s
|
|
@@ -582,14 +808,60 @@ module Lrama
|
|
|
582
808
|
s.ielr_isocores.each do |st|
|
|
583
809
|
st.ielr_isocores = s.ielr_isocores
|
|
584
810
|
end
|
|
585
|
-
new_state.
|
|
586
|
-
|
|
811
|
+
new_state.lookaheads_recomputed = true
|
|
812
|
+
new_state.item_lookahead_set = propagating_lookaheads
|
|
813
|
+
state.update_transition(transition, new_state)
|
|
587
814
|
elsif(!s.lookaheads_recomputed)
|
|
588
|
-
s.
|
|
815
|
+
s.lookaheads_recomputed = true
|
|
816
|
+
s.item_lookahead_set = propagating_lookaheads
|
|
589
817
|
else
|
|
590
|
-
|
|
591
|
-
|
|
818
|
+
merge_lookaheads(s, propagating_lookaheads)
|
|
819
|
+
state.update_transition(transition, s) if state.items_to_state[transition.to_items].id != s.id
|
|
592
820
|
end
|
|
593
821
|
end
|
|
822
|
+
|
|
823
|
+
# @rbs (Logger logger) -> void
|
|
824
|
+
def validate_conflicts_within_threshold!(logger)
|
|
825
|
+
exit false unless conflicts_within_threshold?(logger)
|
|
826
|
+
end
|
|
827
|
+
|
|
828
|
+
# @rbs (Logger logger) -> bool
|
|
829
|
+
def conflicts_within_threshold?(logger)
|
|
830
|
+
return true unless @grammar.expect
|
|
831
|
+
|
|
832
|
+
[sr_conflicts_within_threshold?(logger), rr_conflicts_within_threshold?(logger)].all?
|
|
833
|
+
end
|
|
834
|
+
|
|
835
|
+
# @rbs (Logger logger) -> bool
|
|
836
|
+
def sr_conflicts_within_threshold?(logger)
|
|
837
|
+
return true if @grammar.expect == sr_conflicts_count
|
|
838
|
+
|
|
839
|
+
logger.error("shift/reduce conflicts: #{sr_conflicts_count} found, #{@grammar.expect} expected")
|
|
840
|
+
false
|
|
841
|
+
end
|
|
842
|
+
|
|
843
|
+
# @rbs (Logger logger) -> bool
|
|
844
|
+
def rr_conflicts_within_threshold?(logger, expected: 0)
|
|
845
|
+
return true if expected == rr_conflicts_count
|
|
846
|
+
|
|
847
|
+
logger.error("reduce/reduce conflicts: #{rr_conflicts_count} found, #{expected} expected")
|
|
848
|
+
false
|
|
849
|
+
end
|
|
850
|
+
|
|
851
|
+
# @rbs () -> void
|
|
852
|
+
def clear_look_ahead_sets
|
|
853
|
+
@direct_read_sets.clear
|
|
854
|
+
@reads_relation.clear
|
|
855
|
+
@read_sets.clear
|
|
856
|
+
@includes_relation.clear
|
|
857
|
+
@lookback_relation.clear
|
|
858
|
+
@follow_sets.clear
|
|
859
|
+
@la.clear
|
|
860
|
+
|
|
861
|
+
@_direct_read_sets = nil
|
|
862
|
+
@_read_sets = nil
|
|
863
|
+
@_follow_sets = nil
|
|
864
|
+
@_la = nil
|
|
865
|
+
end
|
|
594
866
|
end
|
|
595
867
|
end
|