]> granicus.if.org Git - re2c/commitdiff
Fixed rule reachability analyses.
authorUlya Trofimovich <skvadrik@gmail.com>
Mon, 23 May 2016 11:49:33 +0000 (12:49 +0100)
committerUlya Trofimovich <skvadrik@gmail.com>
Mon, 23 May 2016 13:28:19 +0000 (14:28 +0100)
The previous algorithm handled loops incorrectly: if deep-first search
from current DFA state happened to visit looping paths before non-looping
paths, then result accumulated from non-looping paths was not propagated
into loopback states.

Now we use back propagation (from states that have transitions to default
state), which handles loops correctly.

22 files changed:
re2c/Makefile.am
re2c/src/codegen/emit_dfa.cc
re2c/src/ir/compile.cc
re2c/src/ir/dfa/dead_rules.cc [new file with mode: 0644]
re2c/src/ir/dfa/dfa.h
re2c/src/ir/rule.h
re2c/src/ir/skeleton/skeleton.h
re2c/src/ir/skeleton/unreachable.cc [deleted file]
re2c/test/bug61.i--empty-class(match-none).c
re2c/test/bug61_difference_full.i--empty-class(match-none).c
re2c/test/bug61_difference_negative.i--empty-class(match-none).c
re2c/test/bug61_difference_positive.i--empty-class(match-none).c
re2c/test/bug61_negative.i--empty-class(match-none).c
re2c/test/bug61_positive.i--empty-class(match-none).c
re2c/test/php20150211_zend_ini_scanner.c--emit-dot--flex-syntax--case-inverted.c
re2c/test/php20150211_zend_ini_scanner.igcd--flex-syntax--case-inverted.c
re2c/test/php20150211_zend_ini_scanner.igcd--skeleton--flex-syntax--case-inverted.c
re2c/test/php20150211_zend_ini_scanner_trimmed.ic--flex-syntax.c
re2c/test/php20150211_zend_ini_scanner_trimmed.icwb--flex-syntax.c
re2c/test/rexx.--empty-class(match-none).c
re2c/test/wunreachable_rules.i.c [new file with mode: 0644]
re2c/test/wunreachable_rules.i.re [new file with mode: 0644]

index 408e3bfaa644ebf8607e93367cda6ca300bd9da0..e39bdf921ccb83eff253cdc7def1b95293bb0104 100644 (file)
@@ -89,6 +89,7 @@ SRC = \
        src/ir/nfa/regexps2nfa.cc \
        src/ir/adfa/adfa.cc \
        src/ir/adfa/prepare.cc \
+       src/ir/dfa/dead_rules.cc \
        src/ir/dfa/determinization.cc \
        src/ir/dfa/fallback.cc \
        src/ir/dfa/fillpoints.cc \
@@ -112,7 +113,6 @@ SRC = \
        src/ir/skeleton/generate_data.cc \
        src/ir/skeleton/maxpath.cc \
        src/ir/skeleton/skeleton.cc \
-       src/ir/skeleton/unreachable.cc \
        src/ir/tag.cc \
        src/ir/tagpool.cc \
        src/main.cc \
index 0800f6c7b4cd8eb8eb778da8c4fcc48a8e0b4a84..5c220d6bdf2be10641ed5da0e5b3ca72fa776384 100644 (file)
@@ -175,7 +175,6 @@ void DFA::emit(Output & output, uint32_t& ind, bool isLastCond, bool& bPrologBra
        head->action.set_initial (initial_label, head->action.type == Action::SAVE);
 
        warn_undefined_control_flow(*skeleton);
-       warn_unreachable(*skeleton);
 
        if (opts->target == opt_t::SKELETON) {
                if (output.skeletons.insert (name).second)
index 803f20c595859788ef5b02626889247ac3a98cde..c3466885ce8e5ab623386a3cfa63902827ec8762 100644 (file)
@@ -64,6 +64,8 @@ static smart_ptr<DFA> compile_rules(
        // but prior to any other DFA transformations
        Skeleton *skeleton = new Skeleton(dfa, cs, defrule, name, cond, line);
 
+       cutoff_dead_rules(dfa, defrule, cond);
+
        // try to minimize the number of tag variables
        const size_t used_tags = deduplicate_tags(dfa);
 
diff --git a/re2c/src/ir/dfa/dead_rules.cc b/re2c/src/ir/dfa/dead_rules.cc
new file mode 100644 (file)
index 0000000..4c9b02e
--- /dev/null
@@ -0,0 +1,174 @@
+#include "src/conf/opt.h"
+#include "src/ir/dfa/dfa.h"
+#include "src/util/forbid_copy.h"
+#include "src/globals.h"
+
+namespace re2c
+{
+
+/* note [unreachable rules]
+ *
+ * DFA may contain useless final states. Such states may
+ * appear as a result of:
+ *   - (part of) one rule being shadowed by another rule,
+ *     e.g. rule [ab] partially shadows [ac] and completely
+ *     shadows [a]
+ *
+ *   - infinite rules that greedily eat all input characters
+ *     and never stop (they either fail on YYFILL or crash),
+ *     e.g. [^]*
+ *
+ *   - rules that contain never-matching link, e.g. '[]'
+ *     with option '--empty-class match-none'
+ *
+ * Useless final states should be eliminated so that they
+ * don't interfere with further analyses and optimizations.
+ * If all final states of a rule are useless, then the whole
+ * rule is unreachable and should be reported.
+ *
+ * In order to find out if a given final state is useless,
+ * we have to find out if all outgoing paths from this state
+ * match longer rules (otherwise, some paths go to default
+ * state and fallback to this state). We do this by finding
+ * all states that have transitions to default state and back
+ * propagation of "none-rule" from these states. As the back
+ * propagation meets the first final state on its way, it
+ * substitutes "none-rule" with the corresponding rule,
+ * which is further propagated back to the start state of DFA.
+ */
+
+// reversed DFA
+struct rdfa_t
+{
+       struct arc_t
+       {
+               size_t dest;
+               arc_t *next;
+       };
+
+       struct state_t
+       {
+               arc_t *arcs;
+               size_t rule;
+               bool fallthru;
+       };
+
+       size_t nstates;
+       size_t nrules;
+       state_t *states;
+       arc_t *arcs;
+
+       explicit rdfa_t(const dfa_t &dfa)
+               : nstates(dfa.states.size())
+               , nrules(dfa.rules.size())
+               , states(new state_t[nstates]())
+               , arcs(new arc_t[nstates * dfa.nchars])
+       {
+               // init states
+               for (size_t i = 0; i < nstates; ++i) {
+                       state_t &s = states[i];
+                       s.arcs = NULL;
+                       const size_t r = dfa.states[i]->rule;
+                       s.rule = r == Rule::NONE ? nrules : r;
+                       s.fallthru = false;
+               }
+               // init arcs
+               arc_t *a = arcs;
+               for (size_t i = 0; i < nstates; ++i) {
+                       dfa_state_t *s = dfa.states[i];
+                       for (size_t c = 0; c < dfa.nchars; ++c) {
+                               const size_t j = s->arcs[c];
+                               if (j != dfa_t::NIL) {
+                                       a->dest = i;
+                                       a->next = states[j].arcs;
+                                       states[j].arcs = a++;
+                               } else {
+                                       states[i].fallthru = true;
+                               }
+                       }
+               }
+       }
+
+       ~rdfa_t()
+       {
+               delete[] states;
+               delete[] arcs;
+       }
+
+       FORBID_COPY(rdfa_t);
+};
+
+static void backprop(const rdfa_t &rdfa,
+       bool *reachable,
+       size_t rule,
+       size_t state)
+{
+       // "none-rule" is unreachable from final states:
+       // be careful to mask it before propagating
+       const rdfa_t::state_t &s = rdfa.states[state];
+       if (rule == rdfa.nrules) {
+               rule = s.rule;
+       }
+
+       // if the rule has already been set, than either it's a loop
+       // or another branch of back propagation has already been here,
+       // in both cases we should stop: there's nothing new to propagate
+       bool &reach = reachable[state * (rdfa.nrules + 1) + rule];
+       if (reach) return;
+       reach = true;
+
+       for (const rdfa_t::arc_t *a = s.arcs; a; a = a->next) {
+               backprop(rdfa, reachable, rule, a->dest);
+       }
+}
+
+static void calc_reachable(const rdfa_t &rdfa, bool *reachable)
+{
+       for (size_t i = 0; i < rdfa.nstates; ++i) {
+               const rdfa_t::state_t &s = rdfa.states[i];
+               if (s.fallthru) {
+                       backprop(rdfa, reachable, s.rule, i);
+               }
+       }
+}
+
+static void warn_unreachable(const dfa_t &dfa, size_t defrule,
+       const std::string &cond, const bool *reachable)
+{
+       const size_t nstates = dfa.states.size();
+       const size_t nrules = dfa.rules.size();
+
+       for (size_t i = 0; i < nstates; ++i) {
+               const bool *reach = &reachable[i * (nrules + 1)];
+               const size_t r = dfa.states[i]->rule;
+               if (r != Rule::NONE && !reach[r]) {
+                       // skip last rule (it's the NONE-rule)
+                       for (size_t j = 0; j < nrules; ++j) {
+                               if (reach[j]) {
+                                       dfa.rules[r].shadow.insert(dfa.rules[j].info->loc.line);
+                               }
+                       }
+               }
+       }
+
+       for (size_t i = 0; i < nrules; ++i) {
+               // default rule '*' should not be reported
+               if (i != defrule && !reachable[i]) {
+                       warn.unreachable_rule(cond, dfa.rules[i]);
+               }
+       }
+}
+
+void cutoff_dead_rules(dfa_t &dfa, size_t defrule, const std::string &cond)
+{
+       const rdfa_t rdfa(dfa);
+       bool *reachable = new bool[rdfa.nstates * (rdfa.nrules + 1)]();
+
+       calc_reachable(rdfa, reachable);
+       warn_unreachable(dfa, defrule, cond, reachable);
+
+       delete[] reachable;
+}
+
+} // namespace re2c
+
index 7b4f9e04d3e5ac844ce07140385d101e9c7e8499..4821c9b449ad2c0801da8b523e5f104a1c5753e5 100644 (file)
@@ -65,6 +65,7 @@ enum dfa_minimization_t
 void minimization(dfa_t &dfa);
 void fillpoints(const dfa_t &dfa, std::vector<size_t> &fill);
 bool fallback_state(const dfa_t &dfa, size_t i);
+void cutoff_dead_rules(dfa_t &dfa, size_t defrule, const std::string &cond);
 size_t deduplicate_tags(dfa_t &dfa);
 
 } // namespace re2c
index 1824c8d64219c69f4f01b7684a077d2c520f9b11..e6fda6bd0a7699edf0d9438f1fe82d6ea204bf7a 100644 (file)
@@ -40,7 +40,6 @@ struct Rule
        size_t trail;
        size_t tags;
        std::set<uint32_t> shadow;
-       bool reachable;
 
        Rule()
                : info(NULL)
@@ -49,7 +48,6 @@ struct Rule
                , trail(Tag::NONE)
                , tags(0)
                , shadow()
-               , reachable(false)
        {}
 
        FORBID_COPY(Rule);
index 255f0974d3c5e505615f45e20eb4416bab4e042e..6d7b9a6de2191ec3d10fa52919d05bb3e88164cf 100644 (file)
@@ -85,7 +85,6 @@ template<typename key_t> key_t Skeleton::rule2key(size_t r, size_t def) const
 uint32_t maxpath(const Skeleton &skel);
 void warn_undefined_control_flow(const Skeleton &skel);
 void fprint_default_path(FILE *f, const Skeleton &skel, const path_t &p);
-void warn_unreachable(const Skeleton &skel);
 void emit_data(const Skeleton &skel);
 void emit_prolog(OutputFile & o);
 void emit_start(const Skeleton &skel, OutputFile &o, size_t maxfill,
diff --git a/re2c/src/ir/skeleton/unreachable.cc b/re2c/src/ir/skeleton/unreachable.cc
deleted file mode 100644 (file)
index 3c0dc8e..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-#include "src/util/c99_stdint.h"
-#include <set>
-
-#include "src/conf/warn.h"
-#include "src/globals.h"
-#include "src/ir/skeleton/path.h"
-#include "src/ir/skeleton/skeleton.h"
-
-namespace re2c
-{
-
-static void calc_reachable(
-       const Skeleton &skel,
-       std::vector<uint8_t> &loops,
-       std::vector<std::set<size_t> > &reachs,
-       size_t i)
-{
-       const Node &node = skel.nodes[i];
-       uint8_t &loop = loops[i];
-       std::set<size_t> &reach = reachs[i];
-
-       if (!reach.empty()) {
-               return;
-       } else if (node.end()) {
-               reach.insert(node.rule);
-       } else if (loop < 2) {
-               local_inc _(loop);
-               Node::arcs_t::const_iterator
-                       arc = node.arcs.begin(),
-                       end = node.arcs.end();
-               for (; arc != end; ++arc) {
-                       const size_t j = arc->first;
-                       calc_reachable(skel, loops, reachs, j);
-                       reach.insert(reachs[j].begin(), reachs[j].end());
-               }
-       }
-}
-
-void warn_unreachable(const Skeleton &skel)
-{
-       // calculate reachable rules
-       const size_t nnodes = skel.nodes_count;
-       std::vector<uint8_t> loops(nnodes);
-       std::vector<std::set<size_t> > reachs(nnodes);
-       calc_reachable(skel, loops, reachs, 0);
-
-       std::valarray<Rule> &rules = skel.rules;
-       const size_t nrules = rules.size();
-
-       for (size_t i = 0; i < nnodes; ++i) {
-               const size_t r1 = skel.nodes[i].rule;
-               if (r1 == Rule::NONE) {
-                       continue;
-               }
-               std::set<size_t>::const_iterator
-                       rule = reachs[i].begin(),
-                       end = reachs[i].end();
-               for (; rule != end; ++rule) {
-                       const size_t r2 = *rule;
-                       if (r2 == Rule::NONE || r1 == r2) {
-                               rules[r1].reachable = true;
-                       } else {
-                               rules[r1].shadow.insert(rules[r2].info->loc.line);
-                       }
-               }
-       }
-
-       // warn about unreachable rules:
-       //   - rules that are shadowed by other rules, e.g. rule '[a]' is shadowed by '[a] [^]'
-       //   - infinite rules that consume infinitely many characters and fail on YYFILL, e.g. '[^]*'
-       //   - rules that contain never-matching link, e.g. '[]' with option '--empty-class match-none'
-       // default rule '*' should not be reported
-       for (size_t i = 0; i < nrules; ++i) {
-               const Rule &rule = rules[i];
-               if (i != skel.defrule && !rule.reachable) {
-                       warn.unreachable_rule(skel.cond, rule);
-               }
-       }
-}
-
-} // namespace re2c
index 32db514329e87ad6758f1f9605b97a23bb2e5bdf..023d2274ee0830b6fab0f0b227a067df296c4892 100644 (file)
 }
 
 re2c: warning: line 2: empty character class [-Wempty-character-class]
-re2c: warning: line 3: control flow is undefined for strings that match '', use default rule '*' [-Wundefined-control-flow]
 re2c: warning: line 2: unreachable rule  [-Wunreachable-rules]
+re2c: warning: line 3: control flow is undefined for strings that match '', use default rule '*' [-Wundefined-control-flow]
 re2c: warning: line 6: empty character class [-Wempty-character-class]
-re2c: warning: line 7: control flow is undefined for strings that match '', use default rule '*' [-Wundefined-control-flow]
 re2c: warning: line 6: unreachable rule  [-Wunreachable-rules]
+re2c: warning: line 7: control flow is undefined for strings that match '', use default rule '*' [-Wundefined-control-flow]
 re2c: warning: line 10: empty character class [-Wempty-character-class]
-re2c: warning: line 11: control flow is undefined for strings that match '', use default rule '*' [-Wundefined-control-flow]
 re2c: warning: line 10: unreachable rule  [-Wunreachable-rules]
+re2c: warning: line 11: control flow is undefined for strings that match '', use default rule '*' [-Wundefined-control-flow]
 re2c: warning: line 14: empty character class [-Wempty-character-class]
 re2c: warning: line 14: empty character class [-Wempty-character-class]
 re2c: warning: line 14: empty character class [-Wempty-character-class]
-re2c: warning: line 15: control flow is undefined for strings that match '', use default rule '*' [-Wundefined-control-flow]
 re2c: warning: line 14: unreachable rule  [-Wunreachable-rules]
+re2c: warning: line 15: control flow is undefined for strings that match '', use default rule '*' [-Wundefined-control-flow]
 re2c: warning: line 18: empty character class [-Wempty-character-class]
 re2c: warning: line 18: empty character class [-Wempty-character-class]
 re2c: warning: line 18: empty character class [-Wempty-character-class]
-re2c: warning: line 19: control flow is undefined for strings that match '', use default rule '*' [-Wundefined-control-flow]
 re2c: warning: line 18: unreachable rule  [-Wunreachable-rules]
+re2c: warning: line 19: control flow is undefined for strings that match '', use default rule '*' [-Wundefined-control-flow]
index 1062a8caf591fb4a4e51d73e51bc02facf26e5e9..cae24e181309b116663232193102a208e6e3f6db 100644 (file)
@@ -5,5 +5,5 @@
 }
 
 re2c: warning: line 2: empty character class [-Wempty-character-class]
-re2c: warning: line 3: control flow is undefined for strings that match '', use default rule '*' [-Wundefined-control-flow]
 re2c: warning: line 2: unreachable rule  [-Wunreachable-rules]
+re2c: warning: line 3: control flow is undefined for strings that match '', use default rule '*' [-Wundefined-control-flow]
index 77d6d3ce6ef175e9bc7acda5b7ed2a1813fe0ed3..28e06b1177a6d7d319c8d85541fc17e34e28a8af 100644 (file)
@@ -7,5 +7,5 @@
 re2c: warning: line 2: empty character class [-Wempty-character-class]
 re2c: warning: line 2: empty character class [-Wempty-character-class]
 re2c: warning: line 2: empty character class [-Wempty-character-class]
-re2c: warning: line 3: control flow is undefined for strings that match '', use default rule '*' [-Wundefined-control-flow]
 re2c: warning: line 2: unreachable rule  [-Wunreachable-rules]
+re2c: warning: line 3: control flow is undefined for strings that match '', use default rule '*' [-Wundefined-control-flow]
index 77d6d3ce6ef175e9bc7acda5b7ed2a1813fe0ed3..28e06b1177a6d7d319c8d85541fc17e34e28a8af 100644 (file)
@@ -7,5 +7,5 @@
 re2c: warning: line 2: empty character class [-Wempty-character-class]
 re2c: warning: line 2: empty character class [-Wempty-character-class]
 re2c: warning: line 2: empty character class [-Wempty-character-class]
-re2c: warning: line 3: control flow is undefined for strings that match '', use default rule '*' [-Wundefined-control-flow]
 re2c: warning: line 2: unreachable rule  [-Wunreachable-rules]
+re2c: warning: line 3: control flow is undefined for strings that match '', use default rule '*' [-Wundefined-control-flow]
index 1062a8caf591fb4a4e51d73e51bc02facf26e5e9..cae24e181309b116663232193102a208e6e3f6db 100644 (file)
@@ -5,5 +5,5 @@
 }
 
 re2c: warning: line 2: empty character class [-Wempty-character-class]
-re2c: warning: line 3: control flow is undefined for strings that match '', use default rule '*' [-Wundefined-control-flow]
 re2c: warning: line 2: unreachable rule  [-Wunreachable-rules]
+re2c: warning: line 3: control flow is undefined for strings that match '', use default rule '*' [-Wundefined-control-flow]
index 1062a8caf591fb4a4e51d73e51bc02facf26e5e9..cae24e181309b116663232193102a208e6e3f6db 100644 (file)
@@ -5,5 +5,5 @@
 }
 
 re2c: warning: line 2: empty character class [-Wempty-character-class]
-re2c: warning: line 3: control flow is undefined for strings that match '', use default rule '*' [-Wundefined-control-flow]
 re2c: warning: line 2: unreachable rule  [-Wunreachable-rules]
+re2c: warning: line 3: control flow is undefined for strings that match '', use default rule '*' [-Wundefined-control-flow]
index 8225e764670d023e0cc0b5a97929e607d595dbd4..b1edac8911373cabb948f3aff804d416cddddaa2 100644 (file)
@@ -580,6 +580,7 @@ re2c: warning: line 384: column 13: escape has no effect: '\.' [-Wuseless-escape
 re2c: warning: line 384: column 32: escape has no effect: '\.' [-Wuseless-escape]
 re2c: warning: line 391: column 27: escape has no effect: '\[' [-Wuseless-escape]
 re2c: warning: line 392: column 11: escape has no effect: '\[' [-Wuseless-escape]
+re2c: warning: line 648: unreachable rule in condition 'INITIAL' (shadowed by rules at lines 406, 481, 491, 555, 627, 632, 637) [-Wunreachable-rules]
 re2c: warning: line 648: unreachable rule in condition 'ST_DOUBLE_QUOTES' (shadowed by rules at lines 582, 587) [-Wunreachable-rules]
 re2c: warning: line 623: unreachable rule in condition 'ST_OFFSET' (shadowed by rule at line 573) [-Wunreachable-rules]
 re2c: warning: line 648: unreachable rule in condition 'ST_RAW' (shadowed by rules at lines 500, 541, 643) [-Wunreachable-rules]
index deda0de9ea1b6038c04006d536f2e4ca14895874..d80f37b8b237738e2416617fb8b89611cce6fe28 100644 (file)
@@ -3854,6 +3854,7 @@ re2c: warning: line 384: column 13: escape has no effect: '\.' [-Wuseless-escape
 re2c: warning: line 384: column 32: escape has no effect: '\.' [-Wuseless-escape]
 re2c: warning: line 391: column 27: escape has no effect: '\[' [-Wuseless-escape]
 re2c: warning: line 392: column 11: escape has no effect: '\[' [-Wuseless-escape]
+re2c: warning: line 648: unreachable rule in condition 'INITIAL' (shadowed by rules at lines 406, 481, 491, 555, 627, 632, 637) [-Wunreachable-rules]
 re2c: warning: line 648: unreachable rule in condition 'ST_DOUBLE_QUOTES' (shadowed by rules at lines 582, 587) [-Wunreachable-rules]
 re2c: warning: line 623: unreachable rule in condition 'ST_OFFSET' (shadowed by rule at line 573) [-Wunreachable-rules]
 re2c: warning: line 648: unreachable rule in condition 'ST_RAW' (shadowed by rules at lines 500, 541, 643) [-Wunreachable-rules]
index f0ffca9913b6bf05fefea09b51fee1d7192ad508..e00253294479658d7de7a8a36954c9397cef2a0a 100644 (file)
@@ -22239,6 +22239,7 @@ u\rv!w"x$y&z(\7f)
 re2c: warning: line 384: column 32: escape has no effect: '\.' [-Wuseless-escape]
 re2c: warning: line 391: column 27: escape has no effect: '\[' [-Wuseless-escape]
 re2c: warning: line 392: column 11: escape has no effect: '\[' [-Wuseless-escape]
+re2c: warning: line 648: unreachable rule in condition 'INITIAL' (shadowed by rules at lines 406, 481, 491, 555, 627, 632, 637) [-Wunreachable-rules]
 re2c: warning: line 648: unreachable rule in condition 'ST_DOUBLE_QUOTES' (shadowed by rules at lines 582, 587) [-Wunreachable-rules]
 re2c: warning: line 623: unreachable rule in condition 'ST_OFFSET' (shadowed by rule at line 573) [-Wunreachable-rules]
 re2c: warning: line 648: unreachable rule in condition 'ST_RAW' (shadowed by rules at lines 500, 541, 643) [-Wunreachable-rules]
index 7d2eabb7504a7763f38a71e46a3e5c2f60e13f5f..f3baafaef783f66129027ee5de82bd59d78d35b4 100644 (file)
@@ -3318,6 +3318,7 @@ re2c: warning: line 4: column 13: escape has no effect: '\.' [-Wuseless-escape]
 re2c: warning: line 4: column 32: escape has no effect: '\.' [-Wuseless-escape]
 re2c: warning: line 11: column 27: escape has no effect: '\[' [-Wuseless-escape]
 re2c: warning: line 12: column 11: escape has no effect: '\[' [-Wuseless-escape]
+re2c: warning: line 55: unreachable rule in condition 'INITIAL' (shadowed by rules at lines 24, 35, 36, 42, 51, 52, 53) [-Wunreachable-rules]
 re2c: warning: line 55: unreachable rule in condition 'ST_DOUBLE_QUOTES' (shadowed by rules at lines 48, 49) [-Wunreachable-rules]
 re2c: warning: line 50: unreachable rule in condition 'ST_OFFSET' (shadowed by rule at line 46) [-Wunreachable-rules]
 re2c: warning: line 55: unreachable rule in condition 'ST_RAW' (shadowed by rules at lines 37, 39, 54) [-Wunreachable-rules]
index 3933db66327c6a7eddeb363772d07141794de633..60cf1e5b85594f9e6995a13310e8f6ff5fe54b6d 100644 (file)
@@ -2880,6 +2880,7 @@ re2c: warning: line 4: column 13: escape has no effect: '\.' [-Wuseless-escape]
 re2c: warning: line 4: column 32: escape has no effect: '\.' [-Wuseless-escape]
 re2c: warning: line 11: column 27: escape has no effect: '\[' [-Wuseless-escape]
 re2c: warning: line 12: column 11: escape has no effect: '\[' [-Wuseless-escape]
+re2c: warning: line 55: unreachable rule in condition 'INITIAL' (shadowed by rules at lines 24, 35, 36, 42, 51, 52, 53) [-Wunreachable-rules]
 re2c: warning: line 55: unreachable rule in condition 'ST_DOUBLE_QUOTES' (shadowed by rules at lines 48, 49) [-Wunreachable-rules]
 re2c: warning: line 50: unreachable rule in condition 'ST_OFFSET' (shadowed by rule at line 46) [-Wunreachable-rules]
 re2c: warning: line 55: unreachable rule in condition 'ST_RAW' (shadowed by rules at lines 37, 39, 54) [-Wunreachable-rules]
index b7bbd8a35044687daf46c326f982e164bf739542..16c951c52b90dec2d1fe6c78641632bd7e3a500f 100644 (file)
@@ -6885,8 +6885,8 @@ yy445:
 }
 re2c: warning: line 253: rule matches empty string [-Wmatch-empty-string]
 re2c: warning: line 288: empty character class [-Wempty-character-class]
+re2c: warning: line 289: unreachable rule  [-Wunreachable-rules]
 re2c: warning: line 290: control flow is undefined for strings that match 
        '[\x0-\x8\xA-\xC\xE-\x1F\x21-\x2E\x30-\xFF]'
        '\x2F [\x0-\x29\x2B-\xFF]'
 , use default rule '*' [-Wundefined-control-flow]
-re2c: warning: line 289: unreachable rule  [-Wunreachable-rules]
diff --git a/re2c/test/wunreachable_rules.i.c b/re2c/test/wunreachable_rules.i.c
new file mode 100644 (file)
index 0000000..192ec2c
--- /dev/null
@@ -0,0 +1,145 @@
+/* Generated by re2c */
+
+{
+       YYCTYPE yych;
+       if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3);
+       yych = *YYCURSOR;
+       switch (yych) {
+       case 'a':       goto yy4;
+       default:        goto yy2;
+       }
+yy2:
+       ++YYCURSOR;
+       yych = *YYCURSOR;
+       goto yy7;
+       { 1 }
+yy4:
+       ++YYCURSOR;
+       switch ((yych = *YYCURSOR)) {
+       case 'a':       goto yy8;
+       default:        goto yy5;
+       }
+yy5:
+       { 0 }
+yy6:
+       ++YYCURSOR;
+       if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
+       yych = *YYCURSOR;
+yy7:
+       switch (yych) {
+       case 'a':       goto yy4;
+       default:        goto yy6;
+       }
+yy8:
+       ++YYCURSOR;
+       yych = *YYCURSOR;
+       goto yy5;
+}
+
+
+
+{
+       YYCTYPE yych;
+       if ((YYLIMIT - YYCURSOR) < 4) YYFILL(4);
+       yych = *YYCURSOR;
+       switch (yych) {
+       case 'a':       goto yy13;
+       default:        goto yy11;
+       }
+yy11:
+       ++YYCURSOR;
+       yych = *YYCURSOR;
+       goto yy16;
+       { 1 }
+yy13:
+       ++YYCURSOR;
+       switch ((yych = *YYCURSOR)) {
+       case 'a':       goto yy17;
+       default:        goto yy14;
+       }
+yy14:
+       { 0 }
+yy15:
+       ++YYCURSOR;
+       if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3);
+       yych = *YYCURSOR;
+yy16:
+       switch (yych) {
+       case 'a':       goto yy13;
+       default:        goto yy15;
+       }
+yy17:
+       yych = *++YYCURSOR;
+       switch (yych) {
+       case 'a':       goto yy18;
+       default:        goto yy14;
+       }
+yy18:
+       ++YYCURSOR;
+       yych = *YYCURSOR;
+       goto yy14;
+}
+
+
+
+{
+       YYCTYPE yych;
+       goto yy19;
+yy20:
+       ++YYCURSOR;
+yy19:
+       if (YYLIMIT <= YYCURSOR) YYFILL(1);
+       yych = *YYCURSOR;
+       switch (yych) {
+       case 'a':       goto yy23;
+       default:        goto yy20;
+       }
+yy22:
+       { 0 }
+yy23:
+       ++YYCURSOR;
+       yych = *YYCURSOR;
+       goto yy22;
+}
+
+
+
+{
+       YYCTYPE yych;
+       if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
+       yych = *YYCURSOR;
+       switch (yych) {
+       case 'a':       goto yy28;
+       default:        goto yy26;
+       }
+yy26:
+       ++YYCURSOR;
+       yych = *YYCURSOR;
+       goto yy32;
+       { 1 }
+yy28:
+       ++YYCURSOR;
+       if (YYLIMIT <= YYCURSOR) YYFILL(1);
+       yych = *YYCURSOR;
+       switch (yych) {
+       case 'a':       goto yy28;
+       default:        goto yy30;
+       }
+yy30:
+       { 0 }
+yy31:
+       ++YYCURSOR;
+       if (YYLIMIT <= YYCURSOR) YYFILL(1);
+       yych = *YYCURSOR;
+yy32:
+       switch (yych) {
+       case 'a':       goto yy28;
+       default:        goto yy31;
+       }
+}
+
+re2c: warning: line 3: unreachable rule (shadowed by rule at line 2) [-Wunreachable-rules]
+re2c: warning: line 8: unreachable rule (shadowed by rule at line 7) [-Wunreachable-rules]
+re2c: warning: line 12: rule matches empty string [-Wmatch-empty-string]
+re2c: warning: line 13: unreachable rule (shadowed by rule at line 12) [-Wunreachable-rules]
+re2c: warning: line 18: unreachable rule (shadowed by rule at line 17) [-Wunreachable-rules]
diff --git a/re2c/test/wunreachable_rules.i.re b/re2c/test/wunreachable_rules.i.re
new file mode 100644 (file)
index 0000000..1184116
--- /dev/null
@@ -0,0 +1,19 @@
+/*!re2c
+    [^a]* ("aa"|"a") { 0 }
+    [^]              { 1 }
+*/
+
+/*!re2c
+    [^a]* "a"{1,3} { 0 }
+    [^]            { 1 }
+*/
+
+/*!re2c
+    [^a]* "a"? { 0 }
+    [^]        { 1 }
+*/
+
+/*!re2c
+    [^a]* "a"+ { 0 }
+    [^]        { 1 }
+*/