13
13
#include " src/util/check.h"
14
14
#include " src/util/forbid_copy.h"
15
15
16
- namespace re2c {
17
-
18
- struct tcmd_t ;
19
-
20
16
// note [unreachable rules]
21
17
//
22
18
// TDFA may contain useless final states. Such states may appear as a result of:
@@ -52,6 +48,11 @@ struct tcmd_t;
52
48
// fallback states are not affected by these transformations, so we can calculate them here and save
53
49
// for future use.
54
50
51
+ namespace re2c {
52
+ namespace {
53
+
54
+ struct tcmd_t ;
55
+
55
56
// reversed DFA
56
57
struct RevDfa {
57
58
struct arc_t {
@@ -108,30 +109,49 @@ struct RevDfa {
108
109
FORBID_COPY (RevDfa);
109
110
};
110
111
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
+ };
129
117
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;
131
120
for (size_t i = 0 ; i < rdfa.nstates ; ++i) {
132
121
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
+ }
135
155
}
136
156
}
137
157
}
@@ -282,6 +302,8 @@ static void remove_dead_final_states_with_eof_rule(Tdfa& dfa) {
282
302
}
283
303
}
284
304
305
+ } // anonymous namespace
306
+
285
307
void cutoff_dead_rules (Tdfa& dfa, const opt_t * opts, const std::string& cond, Msg& msg) {
286
308
if (opts->eof != NOEOF) {
287
309
// 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
295
317
bool * fallthru = live + nl - ns;
296
318
memset (live, 0 , nl * sizeof (bool ));
297
319
298
- liveness_analyses (rdfa, live);
320
+ liveness_analysis (rdfa, live);
299
321
300
322
warn_dead_rules (dfa, cond, live, msg);
301
323
remove_dead_final_states (dfa, fallthru);
0 commit comments