1313#include " src/util/check.h"
1414#include " src/util/forbid_copy.h"
1515
16- namespace re2c {
17-
18- struct tcmd_t ;
19-
2016// note [unreachable rules]
2117//
2218// TDFA may contain useless final states. Such states may appear as a result of:
@@ -52,6 +48,11 @@ struct tcmd_t;
5248// fallback states are not affected by these transformations, so we can calculate them here and save
5349// for future use.
5450
51+ namespace re2c {
52+ namespace {
53+
54+ struct tcmd_t ;
55+
5556// reversed DFA
5657struct RevDfa {
5758 struct arc_t {
@@ -108,30 +109,49 @@ struct RevDfa {
108109 FORBID_COPY (RevDfa);
109110};
110111
111- static void backprop (const RevDfa& rdfa, bool * live, size_t rule, size_t state) {
112- // "none-rule" is unreachable from final states: be careful to mask it before propagating
113- const RevDfa::state_t & s = rdfa.states [state];
114- if (rule == rdfa.nrules ) {
115- rule = s.rule ;
116- }
117-
118- // If the rule has already been set, than either it's a loop, or another branch of backward
119- // propagation has already been here, in both cases we should stop: there's nothing new to
120- // propagate.
121- bool & l = live[rule * rdfa.nstates + state];
122- if (l) return ;
123- l = true ;
124-
125- for (const RevDfa::arc_t * a = s.arcs ; a; a = a->next ) {
126- backprop (rdfa, live, rule, a->dest );
127- }
128- }
112+ struct DfsBackprop {
113+ size_t state;
114+ size_t rule;
115+ const RevDfa::arc_t * arc;
116+ };
129117
130- static void liveness_analyses (const RevDfa& rdfa, bool * live) {
118+ static void liveness_analysis (const RevDfa& rdfa, bool * live) {
119+ std::vector<DfsBackprop> stack;
131120 for (size_t i = 0 ; i < rdfa.nstates ; ++i) {
132121 const RevDfa::state_t & s = rdfa.states [i];
133- if (s.fallthru ) {
134- backprop (rdfa, live, s.rule , i);
122+ if (!s.fallthru ) continue ;
123+
124+ // Backward-propagate liveness from fallthrough state, following reversed DFA arcs.
125+ stack.push_back ({i, s.rule , nullptr });
126+ while (!stack.empty ()) {
127+ // Ensure that the reference to stack top won't be accidentally invalidated on push.
128+ if (stack.size () == stack.capacity ()) stack.reserve (stack.size () * 2 );
129+ DfsBackprop& x = stack.back ();
130+
131+ const RevDfa::state_t & t = rdfa.states [x.state ];
132+
133+ if (x.arc == nullptr ) {
134+ // "none-rule" is unreachable from final states: mask it before propagating.
135+ if (x.rule == rdfa.nrules ) {
136+ x.rule = t.rule ;
137+ }
138+ // If the rule has already been set, than either it's a loop, or another branch of
139+ // backward propagation has already been here, in both cases we should stop: there's
140+ // nothing new to propagate.
141+ bool & l = live[x.rule * rdfa.nstates + x.state ];
142+ if (!l) {
143+ l = true ;
144+ x.arc = t.arcs ;
145+ }
146+ } else {
147+ x.arc = x.arc ->next ;
148+ }
149+
150+ if (x.arc == nullptr ) {
151+ stack.pop_back (); // all arcs followed, this state is finished
152+ } else {
153+ stack.push_back ({x.arc ->dest , x.rule , nullptr }); // follow next arc
154+ }
135155 }
136156 }
137157}
@@ -282,6 +302,8 @@ static void remove_dead_final_states_with_eof_rule(Tdfa& dfa) {
282302 }
283303}
284304
305+ } // anonymous namespace
306+
285307void cutoff_dead_rules (Tdfa& dfa, const opt_t * opts, const std::string& cond, Msg& msg) {
286308 if (opts->eof != NOEOF ) {
287309 // See note [end-of-input rule].
@@ -295,7 +317,7 @@ void cutoff_dead_rules(Tdfa& dfa, const opt_t* opts, const std::string& cond, Ms
295317 bool * fallthru = live + nl - ns;
296318 memset (live, 0 , nl * sizeof (bool ));
297319
298- liveness_analyses (rdfa, live);
320+ liveness_analysis (rdfa, live);
299321
300322 warn_dead_rules (dfa, cond, live, msg);
301323 remove_dead_final_states (dfa, fallthru);
0 commit comments