]> granicus.if.org Git - re2c/commitdiff
Address skeleton nodes by indices rather than by pointers.
authorUlya Trofimovich <skvadrik@gmail.com>
Wed, 16 Mar 2016 09:41:02 +0000 (09:41 +0000)
committerUlya Trofimovich <skvadrik@gmail.com>
Wed, 16 Mar 2016 09:44:24 +0000 (09:44 +0000)
This way it is more convenient to add various graph algorithms:
each algorithm can keep its own data in array indexed by skeleton
node numbers (instead of pushing all relevant data inside of the
node).

17 files changed:
re2c/Makefile.am
re2c/bootstrap/src/parse/lex.cc
re2c/bootstrap/src/parse/parser.cc
re2c/src/codegen/emit_action.cc
re2c/src/codegen/emit_dfa.cc
re2c/src/conf/warn.cc
re2c/src/conf/warn.h
re2c/src/ir/skeleton/control_flow.cc
re2c/src/ir/skeleton/generate_code.cc
re2c/src/ir/skeleton/generate_data.cc
re2c/src/ir/skeleton/maxlen.cc [deleted file]
re2c/src/ir/skeleton/maxpath.cc [new file with mode: 0644]
re2c/src/ir/skeleton/path.h
re2c/src/ir/skeleton/skeleton.cc
re2c/src/ir/skeleton/skeleton.h
re2c/src/ir/skeleton/unreachable_nullable.cc
re2c/src/parse/parser.ypp

index 243bc036ef75b586d7bfcd2070da5835777c3e2c..8087739bea7879444113d0fd0d93b7d5f62aaaf1 100644 (file)
@@ -101,7 +101,7 @@ SRC = \
        src/ir/skeleton/control_flow.cc \
        src/ir/skeleton/generate_code.cc \
        src/ir/skeleton/generate_data.cc \
-       src/ir/skeleton/maxlen.cc \
+       src/ir/skeleton/maxpath.cc \
        src/ir/skeleton/skeleton.cc \
        src/ir/skeleton/unreachable_nullable.cc \
        src/main.cc \
index 8c5b6235e36072e90b1266cb4cb63c85209c640b..2b0858388a5011f62200110cc26ff405bd9aea1d 100644 (file)
@@ -1,4 +1,4 @@
-/* Generated by re2c 0.16 on Mon Mar 14 22:45:09 2016 */
+/* Generated by re2c 0.16 on Tue Mar 15 17:24:03 2016 */
 #line 1 "../src/parse/lex.re"
 #include "src/util/c99_stdint.h"
 #include <stddef.h>
index 9f7e54ee788eae4df0e43525781e0d22cc2bd1f1..0a0ae13e5ab78785a8988d39bd5d1a00cbeedb55 100644 (file)
@@ -2260,7 +2260,7 @@ void parse(Scanner& i, Output & o)
                .wline_info (in->get_cline (), in->get_fname ().c_str ());
        if (opts->target == opt_t::SKELETON)
        {
-               Skeleton::emit_prolog (o.source);
+               emit_prolog(o.source);
        }
 
        Enc encodingOld = opts->encoding;
@@ -2429,7 +2429,7 @@ void parse(Scanner& i, Output & o)
 
        if (opts->target == opt_t::SKELETON)
        {
-               Skeleton::emit_epilog (o.source, o.skeletons);
+               emit_epilog(o.source, o.skeletons);
        }
 
        parse_cleanup();
index d091c55ad4ff3a956ba100b23455701429f02555..e41bbbafe6ce95ca865d1cac7c392e9218d62581 100644 (file)
@@ -275,7 +275,7 @@ void emit_rule (OutputFile & o, uint32_t ind, const State * const s, const RuleI
 
        if (opts->target == opt_t::SKELETON)
        {
-               skeleton->emit_action (o, ind, rule->rank);
+               emit_action(*skeleton, o, ind, rule->rank);
        }
        else
        {
index 16cccfa2e697ebb0f09b2ae648434f15091bed46..97b049b2b8fda55dbd44c29ca7187d35f2257862 100644 (file)
@@ -136,18 +136,18 @@ void DFA::emit(Output & output, uint32_t& ind, bool isLastCond, bool& bPrologBra
 
        head->action.set_initial (initial_label, head->action.type == Action::SAVE);
 
-       skeleton->warn_undefined_control_flow ();
-       skeleton->warn_unreachable_nullable_rules ();
+       warn_undefined_control_flow(*skeleton);
+       warn_unreachable_nullable_rules(*skeleton);
 
        if (opts->target == opt_t::SKELETON)
        {
                if (output.skeletons.insert (name).second)
                {
-                       skeleton->emit_data (o.file_name);
-                       skeleton->emit_start (o, max_fill, need_backup, need_backupctx, need_accept);
+                       emit_data(*skeleton, o.file_name);
+                       emit_start(*skeleton, o, max_fill, need_backup, need_backupctx, need_accept);
                        uint32_t i = 2;
                        emit_body (o, i, used_labels, initial_label);
-                       skeleton->emit_end (o, need_backup, need_backupctx);
+                       emit_end(*skeleton, o, need_backup, need_backupctx);
                }
        }
        else
index 01f15915629e1ad9f4c600cc5766ee7cd96fb51a..275466d3d52eadd062a9f59551d881458dbf1e6b 100644 (file)
@@ -128,7 +128,7 @@ void Warn::swapped_range (uint32_t line, uint32_t l, uint32_t u)
        }
 }
 
-void Warn::undefined_control_flow (uint32_t line, const std::string & cond, std::vector<path_t> & paths, bool overflow)
+void Warn::undefined_control_flow (const Skeleton &skel, std::vector<path_t> & paths, bool overflow)
 {
        if (mask[UNDEFINED_CONTROL_FLOW] & WARNING)
        {
@@ -136,21 +136,21 @@ void Warn::undefined_control_flow (uint32_t line, const std::string & cond, std:
                error_accuml |= e;
 
                // report shorter patterns first
-               std::sort (paths.begin (), paths.end (), compare_default_paths);
+               std::sort (paths.begin (), paths.end ());
 
-               warning_start (line, e);
-               fprintf (stderr, "control flow %sis undefined for strings that match ", incond (cond).c_str ());
+               warning_start (skel.line, e);
+               fprintf (stderr, "control flow %sis undefined for strings that match ", incond (skel.cond).c_str ());
                const size_t count = paths.size ();
                if (count == 1)
                {
-                       fprint_default_path (stderr, paths[0]);
+                       fprint_default_path (stderr, skel, paths[0]);
                }
                else
                {
                        for (size_t i = 0; i < count; ++i)
                        {
                                fprintf (stderr, "\n\t");
-                               fprint_default_path (stderr, paths[i]);
+                               fprint_default_path (stderr, skel, paths[i]);
                        }
                        fprintf (stderr, "\n");
                }
index ac653fc9419393923d35c0534d67327e43ef99a6..f427dbc7fa5cbc81940d745ed9c5dc3e3705fd46 100644 (file)
@@ -10,6 +10,7 @@
 namespace re2c {
 
 struct path_t;
+struct Skeleton;
 
 #define RE2C_WARNING_TYPES \
        W (CONDITION_ORDER,        "condition-order"), \
@@ -58,7 +59,7 @@ public:
        void empty_class (uint32_t line);
        void match_empty_string (uint32_t line);
        void swapped_range (uint32_t line, uint32_t l, uint32_t u);
-       void undefined_control_flow (uint32_t line, const std::string & cond, std::vector<path_t> & paths, bool overflow);
+       void undefined_control_flow (const Skeleton &skel, std::vector<path_t> & paths, bool overflow);
        void unreachable_rule (const std::string & cond, const RuleInfo *rule);
        void useless_escape (uint32_t line, uint32_t col, char c);
 };
index 31a980246acc3da2ca7480ee5c5bf5cb186abfd0..92f57c7ef358b7c7e51f2b9279d5822dc67afca3 100644 (file)
@@ -1,5 +1,3 @@
-#include <map>
-#include <utility>
 #include <vector>
 
 #include "src/conf/warn.h"
 namespace re2c
 {
 
+// See note [counting skeleton edges].
+// Type for counting arcs in paths that cause undefined behaviour.
+// These paths are stored on heap, so the limit should be low.
+// Most real-world cases have only a few short paths.
+// We don't need all paths anyway, just some examples.
+typedef u32lim_t<1024> nakeds_t; // ~1Kb
+
 // We don't need all patterns that cause undefined behaviour.
 // We only need some examples, the shorter the better.
-// See also note [counting skeleton edges].
-void Node::naked_paths(
-       path_t &prefix,
+static void naked_paths(
+       Skeleton &skel,
        std::vector<path_t> &paths,
-       nakeds_t &size)
+       path_t &prefix,
+       nakeds_t &size,
+       size_t i)
 {
-       if (rule) {
+       const Node &node = skel.nodes[i];
+       uint8_t &loop = skel.loops[i];
+
+       if (node.rule) {
                return;
-       } else if (end()) {
+       } else if (node.end()) {
                paths.push_back(prefix);
                size = size + nakeds_t::from64(prefix.len());
        } else if (loop < 2) {
                local_inc _(loop);
-               for (arcsets_t::iterator i = arcsets.begin();
-                       i != arcsets.end() && !size.overflow(); ++i) {
-                       prefix.push(i->first);
-                       i->first->naked_paths(prefix, paths, size);
+               Node::arcsets_t::const_iterator
+                       arc = node.arcsets.begin(),
+                       end = node.arcsets.end();
+               for (; arc != end && !size.overflow(); ++arc) {
+                       const size_t j = arc->first;
+                       prefix.push(j);
+                       naked_paths(skel, paths, prefix, size, j);
                        prefix.pop();
                }
        }
 }
 
-void Skeleton::warn_undefined_control_flow()
+void warn_undefined_control_flow(Skeleton &skel)
 {
-       path_t prefix(&nodes[0]);
+       path_t prefix(0);
        std::vector<path_t> paths;
-       Node::nakeds_t size = Node::nakeds_t::from32(0u);
+       nakeds_t size = nakeds_t::from32(0u);
 
-       nodes->naked_paths(prefix, paths, size);
+       naked_paths(skel, paths, prefix, size, 0);
 
        if (!paths.empty()) {
-               warn.undefined_control_flow(line, cond, paths, size.overflow());
+               warn.undefined_control_flow(skel, paths, size.overflow());
        } else if (size.overflow()) {
-               warn.fail(Warn::UNDEFINED_CONTROL_FLOW, line,
+               warn.fail(Warn::UNDEFINED_CONTROL_FLOW, skel.line,
                        "DFA is too large to check undefined control flow");
        }
 }
 
-// define strict weak ordering on patterns:
-// 1st criterion is length (short patterns go first)
-// 2nd criterion is lexicographical order (applies to patterns of equal length)
-bool compare_default_paths(const path_t &p1, const path_t &p2)
-{
-       const size_t l1 = p1.len();
-       const size_t l2 = p2.len();
-       if (l1 == l2) {
-               for (size_t i = 0; i < l1; ++i) {
-                       const Node::arcset_t
-                               &a1 = p1.arcset(i),
-                               &a2 = p2.arcset(i);
-                       const size_t s1 = a1.size();
-                       const size_t s2 = a2.size();
-                       for (size_t j = 0; j < s1; ++j) {
-                               if (j == s2 || a2[j] < a1[j]) {
-                                       return false;
-                               } else if (a1[j] < a2[j]) {
-                                       return true;
-                               }
-                       }
-               }
-               return false;
-       } else {
-               return l1 < l2;
-       }
-}
-
 static void fprint_default_arc(FILE *f, const Node::arcset_t &arc)
 {
        const size_t ranges = arc.size();
@@ -99,7 +83,10 @@ static void fprint_default_arc(FILE *f, const Node::arcset_t &arc)
        }
 }
 
-void fprint_default_path(FILE *f, const path_t &p)
+void fprint_default_path(
+       FILE *f,
+       const Skeleton &skel,
+       const path_t &p)
 {
        fprintf(f, "'");
        const size_t len = p.len();
@@ -107,7 +94,7 @@ void fprint_default_path(FILE *f, const path_t &p)
                if (i > 0) {
                        fprintf(f, " ");
                }
-               const Node::arcset_t &arc = p.arcset(i);
+               const Node::arcset_t &arc = p.arcset(skel, i);
                fprint_default_arc(stderr, arc);
        }
        fprintf(f, "'");
index 38940ae77a2b8e19fb6c21da8c9d79ca0abe3be7..1b38f2867a3cf22a3b89e39ef7d8c6643334928d 100644 (file)
 namespace re2c
 {
 
-static void exact_uint (OutputFile & o, size_t width)
+static void exact_uint(OutputFile &o, size_t width)
 {
-       if (width == sizeof (char))
-       {
+       if (width == sizeof(char)) {
                o.ws("unsigned char");
-       }
-       else if (width == sizeof (short))
-       {
+       } else if (width == sizeof(short)) {
                o.ws("unsigned short");
-       }
-       else if (width == sizeof (int))
-       {
+       } else if (width == sizeof(int)) {
                o.ws("unsigned int");
-       }
-       else if (width == sizeof (long))
-       {
+       } else if (width == sizeof(long)) {
                o.ws("unsigned long");
-       }
-       else
-       {
-               o.ws("uint").wu64 (width * 8).ws("_t");
+       } else {
+               o.ws("uint").wu64(width * 8).ws("_t");
        }
 }
 
@@ -44,14 +35,13 @@ static void from_le(OutputFile &o, uint32_t ind, size_t size, const char *expr)
        o.ws("\n").wind(ind).ws("/* from little-endian to host-endian */");
        o.ws("\n").wind(ind).ws("unsigned char *p = (unsigned char*)&").ws(expr).ws(";");
        o.ws("\n").wind(ind).ws(expr).ws(" = p[0]");
-       for (uint32_t i = 1; i < size; ++i)
-       {
+       for (uint32_t i = 1; i < size; ++i) {
                o.ws(" + (p[").wu32(i).ws("] << ").wu32(i * 8).ws("u)");
        }
        o.ws(";");
 }
 
-void Skeleton::emit_prolog (OutputFile & o)
+void emit_prolog(OutputFile &o)
 {
        o.ws("\n#include <stdio.h>");
        o.ws("\n#include <stdlib.h> /* malloc, free */");
@@ -103,16 +93,14 @@ void Skeleton::emit_prolog (OutputFile & o)
        o.ws("\n");
 }
 
-void Skeleton::emit_start
-       ( OutputFile & o
-       , size_t maxfill
-       , bool backup
-       , bool backupctx
-       , bool accept
-       ) const
+void emit_start(const Skeleton &skel, OutputFile &o, size_t maxfill,
+       bool backup, bool backupctx, bool accept)
 {
-       const size_t sizeof_cunit = opts->encoding.szCodeUnit();
-       const uint32_t default_rule = rule2key (rule_rank_t::none ());
+       const size_t
+               sizeof_cunit = opts->encoding.szCodeUnit(),
+               sizeof_key = skel.sizeof_key;
+       const uint32_t default_rule = skel.rule2key(rule_rank_t::none());
+       const std::string &name = skel.name;
 
        o.ws("\n#define YYCTYPE ");
        exact_uint (o, sizeof_cunit);
@@ -120,13 +108,11 @@ void Skeleton::emit_start
        exact_uint (o, sizeof_key);
        o.ws("\n#define YYPEEK() *cursor");
        o.ws("\n#define YYSKIP() ++cursor");
-       if (backup)
-       {
+       if (backup) {
                o.ws("\n#define YYBACKUP() marker = cursor");
                o.ws("\n#define YYRESTORE() cursor = marker");
        }
-       if (backupctx)
-       {
+       if (backupctx) {
                o.ws("\n#define YYBACKUPCTX() ctxmarker = cursor");
                o.ws("\n#define YYRESTORECTX() cursor = ctxmarker");
        }
@@ -200,8 +186,7 @@ void Skeleton::emit_start
        o.ws("\n").wind(2).ws("goto end;");
        o.ws("\n").wind(1).ws("}");
        o.ws("\n");
-       if (sizeof_cunit > 1)
-       {
+       if (sizeof_cunit > 1) {
                o.ws("\n").wind(1).ws("for (i = 0; i < input_len; ++i) {");
                from_le(o, 2, sizeof_cunit, "input[i]");
                o.ws("\n").wind(1).ws("}");
@@ -231,33 +216,27 @@ void Skeleton::emit_start
        o.ws("\n");
        o.ws("\n").wind(1).ws("for (i = 0; status == 0 && i < keys_count; ++i) {");
        o.ws("\n").wind(2).ws("token = cursor;");
-       if (backup)
-       {
+       if (backup) {
                o.ws("\n").wind(2).ws("const YYCTYPE *marker = NULL;");
        }
-       if (backupctx)
-       {
+       if (backupctx) {
                o.ws("\n").wind(2).ws("const YYCTYPE *ctxmarker = NULL;");
        }
        o.ws("\n").wind(2).ws("YYCTYPE yych;");
-       if (accept)
-       {
+       if (accept) {
                o.ws("\n").wind(2).ws("unsigned int yyaccept = 0;");
        }
        o.ws("\n");
-       if (opts->bFlag && BitMap::first)
-       {
-               BitMap::gen (o, 2, 0, std::min (0x100u, opts->encoding.nCodeUnits ()));
+       if (opts->bFlag && BitMap::first) {
+               BitMap::gen(o, 2, 0, std::min(0x100u, opts->encoding.nCodeUnits()));
        }
        o.ws("\n");
 }
 
-void Skeleton::emit_end
-       ( OutputFile & o
-       , bool backup
-       , bool backupctx
-       ) const
+void emit_end(const Skeleton &skel, OutputFile &o, bool backup, bool backupctx)
 {
+       const std::string &name = skel.name;
+
        o.ws("\n").wind(1).ws("}");
        o.ws("\n").wind(1).ws("if (status == 0) {");
        o.ws("\n").wind(2).ws("if (cursor != eof) {");
@@ -282,13 +261,11 @@ void Skeleton::emit_end
        o.ws("\n#undef YYKEYTYPE");
        o.ws("\n#undef YYPEEK");
        o.ws("\n#undef YYSKIP");
-       if (backup)
-       {
+       if (backup) {
                o.ws("\n#undef YYBACKUP");
                o.ws("\n#undef YYRESTORE");
        }
-       if (backupctx)
-       {
+       if (backupctx) {
                o.ws("\n#undef YYBACKUPCTX");
                o.ws("\n#undef YYRESTORECTX");
        }
@@ -297,13 +274,12 @@ void Skeleton::emit_end
        o.ws("\n");
 }
 
-void Skeleton::emit_epilog (OutputFile & o, const std::set<std::string> & names)
+void emit_epilog(OutputFile &o, const std::set<std::string> &names)
 {
        o.ws("\n").ws("int main()");
        o.ws("\n").ws("{");
 
-       for (std::set<std::string>::const_iterator i = names.begin (); i != names.end (); ++i)
-       {
+       for (std::set<std::string>::const_iterator i = names.begin(); i != names.end(); ++i) {
                o.ws("\n").wind(1).ws("if(lex_").wstring(*i).ws("() != 0) {");
                o.ws("\n").wind(2).ws("return 1;");
                o.ws("\n").wind(1).ws("}");
@@ -314,9 +290,9 @@ void Skeleton::emit_epilog (OutputFile & o, const std::set<std::string> & names)
        o.ws("\n");
 }
 
-void Skeleton::emit_action (OutputFile & o, uint32_t ind, rule_rank_t rank) const
+void emit_action(const Skeleton &skel, OutputFile &o, uint32_t ind, rule_rank_t rank)
 {
-       o.wind(ind).ws("status = action_").wstring(name).ws("(i, keys, input, token, &cursor, ").wu32(rule2key (rank)).ws(");\n");
+       o.wind(ind).ws("status = action_").wstring(skel.name).ws("(i, keys, input, token, &cursor, ").wu32(skel.rule2key(rank)).ws(");\n");
        o.wind(ind).ws("continue;\n");
 }
 
index 36e757822ffdbada795b43c9cb527bd53067b99f..d4bb59475d20cd15060cd182a9efb31bd58f729e 100644 (file)
 namespace re2c
 {
 
-template <typename cunit_t, typename key_t>
-       static Node::covers_t cover_one (FILE * input, FILE * keys, const path_t & path);
+/*
+ * note [counting skeleton edges]
+ *
+ * To avoid any possible overflows all size calculations are wrapped in
+ * a special truncated unsigned 32-bit integer type that checks overflow
+ * on each binary operation or conversion from another type.
+ *
+ * Two things contribute to size calculation: path length and the number
+ * of outgoing arcs in each node. Some considerations on why these values
+ * will not overflow before they are converted to truncated type:
+ *
+ *   - Maximal number of outgoing arcs in each node cannot exceed 32 bits:
+ *     it is bounded by the number of code units in current encoding, and
+ *     re2c doesn't support any encoding with more than 2^32 code units.
+ *     Conversion is safe.
+ *
+ *   - Maximal path length cannot exceed 32 bits: we estimate it right
+ *     after skeleton construction and check for overflow. If path length
+ *     does overflow, an error is reported and re2c aborts.
+ */
+
+// See note [counting skeleton edges].
+// Type for calculating the size of path cover.
+// Paths are dumped to file as soon as generated and don't eat
+// heap space. The total size of path cover (measured in edges)
+// is O(N^2) where N is the number of edges in skeleton.
+typedef u32lim_t<1024 * 1024 * 1024> covers_t; // ~1Gb
+
+template<typename uintn_t> static uintn_t to_le(uintn_t n)
+{
+       uintn_t m;
+       uint8_t *p = reinterpret_cast<uint8_t*>(&m);
+       for (size_t i = 0; i < sizeof(uintn_t); ++i) {
+               p[i] = static_cast<uint8_t>(n >> (i * 8));
+       }
+       return m;
+}
+
+template<typename key_t> static void keygen(FILE *f, size_t count,
+       size_t len, size_t len_match, rule_rank_t match)
+{
+       const key_t m = Skeleton::rule2key<key_t>(match);
+
+       const size_t keys_size = 3 * count;
+       key_t * keys = new key_t[keys_size];
+       for (uint32_t i = 0; i < keys_size;) {
+               keys[i++] = to_le<key_t>(static_cast<key_t>(len));
+               keys[i++] = to_le<key_t>(static_cast<key_t>(len_match));
+               keys[i++] = to_le<key_t>(m);
+       }
+       fwrite(keys, sizeof(key_t), keys_size, f);
+       delete[] keys;
+}
+
+template<typename cunit_t, typename key_t> static covers_t cover_one(
+       Skeleton &skel, FILE *input, FILE * keys, const path_t & path)
+{
+       const size_t len = path.len();
+
+       size_t count = 0;
+       for (size_t i = 0; i < len; ++i) {
+               count = std::max (count, path.arc(skel, i).size());
+       }
+
+       const covers_t size = covers_t::from64(len)
+               * covers_t::from64(count);
+       if (!size.overflow()) {
+               // input
+               const size_t buffer_size = size.uint32();
+               cunit_t *buffer = new cunit_t [buffer_size];
+               for (size_t i = 0; i < len; ++i) {
+                       const std::vector<uint32_t> &arc = path.arc(skel, i);
+                       const size_t width = arc.size();
+                       for (size_t j = 0; j < count; ++j) {
+                               const size_t k = j % width;
+                               buffer[j * len + i] = to_le<cunit_t>(static_cast<cunit_t>(arc[k]));
+                       }
+               }
+               fwrite (buffer, sizeof(cunit_t), buffer_size, input);
+               delete[] buffer;
+
+               // keys
+               keygen<key_t>(keys, count, len, path.len_matching(skel), path.match(skel));
+       }
+
+       return size;
+}
 
 /*
  * note [generating skeleton path cover]
@@ -52,164 +137,101 @@ template <typename cunit_t, typename key_t>
  * See also note [counting skeleton edges].
  *
  */
-template <typename cunit_t, typename key_t>
-       void Node::cover (path_t & prefix, FILE * input, FILE * keys, covers_t &size)
+template <typename cunit_t, typename key_t> static void cover(
+       Skeleton &skel,
+       FILE *input,
+       FILE *keys,
+       path_t &prefix,
+       covers_t &size,
+       size_t i)
 {
-       if (end () && suffix == NULL)
-       {
-               suffix = new path_t(this);
+       const Node &node = skel.nodes[i];
+       uint8_t &loop = skel.loops[i];
+       path_t *&suffix = skel.suffixes[i];
+
+       if (node.end() && suffix == NULL) {
+               suffix = new path_t(i);
        }
+
        if (suffix != NULL)
        {
-               prefix.append (suffix);
-               size = size + cover_one<cunit_t, key_t> (input, keys, prefix);
-       }
-       else if (loop < 2)
-       {
-               local_inc _ (loop);
-               for (arcs_t::iterator i = arcs.begin ();
-                       i != arcs.end () && !size.overflow(); ++i)
-               {
+               prefix.append(suffix);
+               size = size + cover_one<cunit_t, key_t>(skel, input, keys, prefix);
+       } else if (loop < 2) {
+               local_inc _(loop);
+               Node::arcs_t::const_iterator
+                       arc = node.arcs.begin(),
+                       end = node.arcs.end();
+               for (; arc != end && !size.overflow(); ++arc) {
+                       const size_t j = arc->first;
+
                        path_t new_prefix = prefix;
-                       new_prefix.push (i->first);
-                       i->first->cover<cunit_t, key_t> (new_prefix, input, keys, size);
-                       if (i->first->suffix != NULL && suffix == NULL)
-                       {
-                               suffix = new path_t(this);
-                               suffix->push (i->first);
-                               suffix->append (i->first->suffix);
+                       new_prefix.push(j);
+                       cover<cunit_t, key_t>(skel, input, keys, new_prefix, size, j);
+
+                       const path_t *sfx = skel.suffixes[j];
+                       if (sfx != NULL && suffix == NULL) {
+                               suffix = new path_t(i);
+                               suffix->push(j);
+                               suffix->append(sfx);
                        }
                }
        }
 }
 
-template <typename cunit_t, typename key_t>
-       void Skeleton::generate_paths_cunit_key (FILE * input, FILE * keys)
+template<typename cunit_t, typename key_t> static void generate_paths_cunit_key(
+       Skeleton &skel, FILE *input, FILE *keys)
 {
-       path_t prefix (nodes);
-       Node::covers_t size = Node::covers_t::from32(0u);
+       path_t prefix(0);
+       covers_t size = covers_t::from32(0u);
 
-       nodes->cover<cunit_t, key_t> (prefix, input, keys, size);
+       cover<cunit_t, key_t>(skel, input, keys, prefix, size, 0);
 
-       if (size.overflow ())
-       {
-               warning
-                       ( NULL
-                       , line
-                       , false
-                       , "DFA %sis too large: can only generate partial path cover"
-                       , incond (cond).c_str ()
-                       );
+       if (size.overflow()) {
+               warning(NULL, skel.line, false,
+                       "DFA %sis too large: can only generate partial path cover",
+                       incond(skel.cond).c_str());
        }
 }
 
-template <typename cunit_t>
-       void Skeleton::generate_paths_cunit (FILE * input, FILE * keys)
+template<typename cunit_t> static void generate_paths_cunit(
+       Skeleton &skel, FILE *input, FILE *keys)
 {
-       switch (sizeof_key)
-       {
-               case 4: generate_paths_cunit_key<cunit_t, uint32_t> (input, keys); break;
-               case 2: generate_paths_cunit_key<cunit_t, uint16_t> (input, keys); break;
-               case 1: generate_paths_cunit_key<cunit_t, uint8_t> (input, keys);  break;
+       switch (skel.sizeof_key) {
+               case 4: generate_paths_cunit_key<cunit_t, uint32_t>(skel, input, keys); break;
+               case 2: generate_paths_cunit_key<cunit_t, uint16_t>(skel, input, keys); break;
+               case 1: generate_paths_cunit_key<cunit_t, uint8_t>(skel, input, keys); break;
        }
 }
 
-void Skeleton::generate_paths (FILE * input, FILE * keys)
+static void generate_paths(Skeleton &skel, FILE *input, FILE *keys)
 {
-       switch (opts->encoding.szCodeUnit ())
-       {
-               case 4: generate_paths_cunit<uint32_t> (input, keys); break;
-               case 2: generate_paths_cunit<uint16_t> (input, keys); break;
-               case 1: generate_paths_cunit<uint8_t>  (input, keys); break;
-       }
-}
-
-void Skeleton::emit_data (const char * fname)
-{
-       const std::string input_name = std::string (fname) + "." + name + ".input";
-       FILE * input = fopen (input_name.c_str (), "wb");
-       if (!input)
-       {
-               error ("cannot open file: %s", input_name.c_str ());
-               exit (1);
-       }
-       const std::string keys_name = std::string (fname) + "." + name + ".keys";
-       FILE * keys = fopen (keys_name.c_str (), "wb");
-       if (!keys)
-       {
-               error ("cannot open file: %s", keys_name.c_str ());
-               exit (1);
-       }
-
-       generate_paths (input, keys);
-
-       fclose (input);
-       fclose (keys);
-}
-
-template <typename uintn_t> static uintn_t to_le(uintn_t n)
-{
-       uintn_t m;
-       uint8_t *p = reinterpret_cast<uint8_t*>(&m);
-       for (size_t i = 0; i < sizeof(uintn_t); ++i)
-       {
-               p[i] = static_cast<uint8_t>(n >> (i * 8));
+       switch (opts->encoding.szCodeUnit()) {
+               case 4: generate_paths_cunit<uint32_t>(skel, input, keys); break;
+               case 2: generate_paths_cunit<uint16_t>(skel, input, keys); break;
+               case 1: generate_paths_cunit<uint8_t>(skel, input, keys); break;
        }
-       return m;
 }
 
-template <typename key_t>
-       static void keygen (FILE * f, size_t count, size_t len, size_t len_match, rule_rank_t match)
+void emit_data(Skeleton &skel, const char *fname)
 {
-       const key_t m = Skeleton::rule2key<key_t> (match);
-
-       const size_t keys_size = 3 * count;
-       key_t * keys = new key_t [keys_size];
-       for (uint32_t i = 0; i < keys_size;)
-       {
-               keys[i++] = to_le<key_t>(static_cast<key_t> (len));
-               keys[i++] = to_le<key_t>(static_cast<key_t> (len_match));
-               keys[i++] = to_le<key_t>(m);
+       const std::string input_name = std::string(fname) + "." + skel.name + ".input";
+       FILE *input = fopen(input_name.c_str(), "wb");
+       if (!input) {
+               error("cannot open file: %s", input_name.c_str());
+               exit(1);
        }
-       fwrite (keys, sizeof (key_t), keys_size, f);
-       delete [] keys;
-}
-
-template <typename cunit_t, typename key_t>
-       static Node::covers_t cover_one (FILE * input, FILE * keys, const path_t & path)
-{
-       const size_t len = path.len ();
-
-       size_t count = 0;
-       for (size_t i = 0; i < len; ++i)
-       {
-               count = std::max (count, path.arc(i).size ());
+       const std::string keys_name = std::string(fname) + "." + skel.name + ".keys";
+       FILE *keys = fopen (keys_name.c_str(), "wb");
+       if (!keys) {
+               error("cannot open file: %s", keys_name.c_str());
+               exit(1);
        }
 
-       const Node::covers_t size = Node::covers_t::from64(len) * Node::covers_t::from64(count);
-       if (!size.overflow ())
-       {
-               // input
-               const size_t buffer_size = size.uint32 ();
-               cunit_t * buffer = new cunit_t [buffer_size];
-               for (size_t i = 0; i < len; ++i)
-               {
-                       const std::vector<uint32_t> & arc = path.arc(i);
-                       const size_t width = arc.size ();
-                       for (size_t j = 0; j < count; ++j)
-                       {
-                               const size_t k = j % width;
-                               buffer[j * len + i] = to_le<cunit_t>(static_cast<cunit_t> (arc[k]));
-                       }
-               }
-               fwrite (buffer, sizeof (cunit_t), buffer_size, input);
-               delete [] buffer;
-
-               // keys
-               keygen<key_t> (keys, count, len, path.len_matching (), path.match ());
-       }
+       generate_paths(skel, input, keys);
 
-       return size;
+       fclose(input);
+       fclose(keys);
 }
 
 } // namespace re2c
diff --git a/re2c/src/ir/skeleton/maxlen.cc b/re2c/src/ir/skeleton/maxlen.cc
deleted file mode 100644 (file)
index 3f1d933..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-#include "src/util/c99_stdint.h"
-#include <algorithm>
-#include <limits>
-#include <map>
-#include <utility>
-
-#include "src/ir/skeleton/skeleton.h"
-
-namespace re2c
-{
-
-// 0 < DIST_MAX < DIST_ERROR <= std::numeric_limits<uint32_t>::max()
-const uint32_t Node::DIST_ERROR = std::numeric_limits<uint32_t>::max();
-const uint32_t Node::DIST_MAX = DIST_ERROR - 1;
-
-// different from YYMAXFILL calculation
-// in the way it handles loops and empty regexp
-void Node::calc_dist ()
-{
-       if (dist != DIST_ERROR)
-       {
-               return;
-       }
-       else if (end ())
-       {
-               dist = 0;
-       }
-       else if (loop < 2)
-       {
-               local_inc _ (loop);
-               for (arcs_t::iterator i = arcs.begin (); i != arcs.end (); ++i)
-               {
-                       i->first->calc_dist ();
-                       if (i->first->dist != DIST_ERROR)
-                       {
-                               if (dist == DIST_ERROR)
-                               {
-                                       dist = i->first->dist;
-                               }
-                               else
-                               {
-                                       dist = std::max (dist, i->first->dist);
-                               }
-                       }
-               }
-               dist = std::min (dist + 1, DIST_MAX);
-       }
-}
-
-} // namespace re2c
diff --git a/re2c/src/ir/skeleton/maxpath.cc b/re2c/src/ir/skeleton/maxpath.cc
new file mode 100644 (file)
index 0000000..a5ea777
--- /dev/null
@@ -0,0 +1,65 @@
+#include "src/util/c99_stdint.h"
+#include <algorithm>
+#include <limits>
+
+#include "src/conf/msg.h"
+#include "src/ir/skeleton/skeleton.h"
+
+namespace re2c
+{
+
+// 0 < DIST_MAX < DIST_ERROR <= std::numeric_limits<uint32_t>::max()
+static const uint32_t DIST_ERROR = std::numeric_limits<uint32_t>::max();
+static const uint32_t DIST_MAX = DIST_ERROR - 1;
+
+// maximal distance to end node (assuming one iteration per loop)
+// different from YYMAXFILL calculation
+// in the way it handles loops and empty regexp
+static void calc_dist(
+       Skeleton &skel,
+       std::vector<uint32_t> &dists,
+       size_t i)
+{
+       const Node &node = skel.nodes[i];
+       uint8_t &loop = skel.loops[i];
+       uint32_t &dist = dists[i];
+
+       if (dist != DIST_ERROR) {
+               return;
+       } else if (node.end()) {
+               dist = 0;
+       } 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_dist(skel, dists, j);
+                       uint32_t &d = dists[j];
+                       if (d != DIST_ERROR) {
+                               if (dist == DIST_ERROR) {
+                                       dist = d;
+                               } else {
+                                       dist = std::max(dist, d);
+                               }
+                       }
+               }
+               dist = std::min(dist + 1, DIST_MAX);
+       }
+}
+
+// calculate maximal path length, check overflow
+uint32_t maxpath(Skeleton &skel)
+{
+       std::vector<uint32_t> dists(skel.nodes_count);
+       calc_dist(skel, dists, 0);
+       const uint32_t maxlen = dists[0];
+       if (maxlen == DIST_MAX) {
+               error("DFA path %sis too long", incond(skel.cond).c_str());
+               exit(1);
+       }
+       return maxlen;
+}
+
+} // namespace re2c
index 8f5fce878a9808209e72c68b1fd3b89426181544..a5865b228699df615f7fa442b3f36aaf533d55a8 100644 (file)
@@ -11,30 +11,24 @@ namespace re2c
 
 class path_t
 {
-       std::vector<Node*> arcs;
+       std::vector<size_t> arcs;
 
 public:
-       explicit path_t(Node *n) : arcs()
+       explicit path_t(size_t i) : arcs()
        {
-               arcs.push_back(n);
-       }
-       path_t(const path_t &p) : arcs(p.arcs) {}
-       path_t &operator=(const path_t &p)
-       {
-               new (this) path_t(p);
-               return *this;
+               arcs.push_back(i);
        }
        size_t len() const
        {
                return arcs.size() - 1;
        }
-       size_t len_matching () const
+       size_t len_matching(const Skeleton &skel) const
        {
-               std::vector<Node*>::const_reverse_iterator
+               std::vector<size_t>::const_reverse_iterator
                        tail = arcs.rbegin(),
                        head = arcs.rend();
                for (; tail != head; ++tail) {
-                       RuleInfo *rule = (*tail)->rule;
+                       RuleInfo *rule = skel.nodes[*tail].rule;
                        if (rule == NULL) {
                                continue;
                        }
@@ -44,7 +38,7 @@ public:
                                        return len;
                                case ~0u:
                                        for (; tail != head; ++tail) {
-                                               if ((*tail)->ctx) {
+                                               if (skel.nodes[*tail].ctx) {
                                                        return static_cast<size_t>(head - tail) - 1;
                                                }
                                        }
@@ -55,28 +49,28 @@ public:
                }
                return 0;
        }
-       rule_rank_t match() const
+       rule_rank_t match(const Skeleton &skel) const
        {
-               std::vector<Node*>::const_reverse_iterator
+               std::vector<size_t>::const_reverse_iterator
                        tail = arcs.rbegin(),
                        head = arcs.rend();
                for (; tail != head; ++tail) {
-                       RuleInfo *rule = (*tail)->rule;
+                       RuleInfo *rule = skel.nodes[*tail].rule;
                        if (rule != NULL) {
                                return rule->rank;
                        }
                }
                return rule_rank_t::none();
        }
-       const Node::arc_t& arc(size_t i) const
+       const Node::arc_t& arc(const Skeleton &skel, size_t i) const
        {
-               return arcs[i]->arcs[arcs[i + 1]];
+               return skel.nodes[arcs[i]].arcs[arcs[i + 1]];
        }
-       const Node::arcset_t& arcset(size_t i) const
+       const Node::arcset_t& arcset(const Skeleton &skel, size_t i) const
        {
-               return arcs[i]->arcsets[arcs[i + 1]];
+               return skel.nodes[arcs[i]].arcsets[arcs[i + 1]];
        }
-       void push(Node *n)
+       void push(size_t n)
        {
                arcs.push_back(n);
        }
@@ -89,6 +83,14 @@ public:
                assert(arcs.back() == p->arcs.front());
                arcs.insert(arcs.end(), p->arcs.begin() + 1, p->arcs.end());
        }
+       bool operator<(const path_t &p) const
+       {
+               const size_t
+                       s1 = arcs.size(),
+                       s2 = p.arcs.size();
+               return (s1 == s2 && arcs < p.arcs)
+                       || s1 < s2;
+       }
 };
 
 } // namespace re2c
index 91ca12880e3566f7a909f28910ed43e7c29ebab4..7baa656adb497178a76a5062f112bebb2ff8af8a 100644 (file)
@@ -1,40 +1,34 @@
-#include <stdlib.h>
+#include <string.h>
 #include <algorithm>
-#include <utility>
 
-#include "src/codegen/go.h"
-#include "src/conf/msg.h"
 #include "src/ir/dfa/dfa.h"
-#include "src/ir/regexp/regexp.h"
 #include "src/ir/skeleton/path.h"
 #include "src/ir/skeleton/skeleton.h"
 
 namespace re2c
 {
 
-Node::Node ()
-       : arcs ()
-       , arcsets ()
-       , loop (0)
-       , rule (NULL)
-       , ctx (false)
-       , dist (DIST_ERROR)
-       , reachable ()
-       , suffix (NULL)
+Node::Node() :
+       arcs(),
+       arcsets(),
+       rule(NULL),
+       ctx(false)
 {}
 
-void Node::init(bool c, RuleInfo *r, const std::vector<std::pair<Node*, uint32_t> > &a)
+void Node::init(
+       bool c,
+       RuleInfo *r,
+       const std::vector<std::pair<size_t, uint32_t> > &a)
 {
        rule = r;
        ctx = c;
 
        uint32_t lb = 0;
-       std::vector<std::pair<Node*, uint32_t> >::const_iterator
+       std::vector<std::pair<size_t, uint32_t> >::const_iterator
                i = a.begin(),
                e = a.end();
-       for (; i != e; ++i)
-       {
-               Node *n = i->first;
+       for (; i != e; ++i) {
+               const size_t n = i->first;
                const uint32_t ub = i->second - 1;
 
                // pick at most 0x100 unique edges from this range
@@ -43,115 +37,101 @@ void Node::init(bool c, RuleInfo *r, const std::vector<std::pair<Node*, uint32_t
                //   - values should be evenly distributed
                //   - values should be deterministic
                const uint32_t step = 1 + (ub - lb) / 0x100;
-               for (uint32_t c = lb; c < ub; c += step)
-               {
-                       arcs[n].push_back (c);
+               for (uint32_t c = lb; c < ub; c += step) {
+                       arcs[n].push_back(c);
                }
-               arcs[n].push_back (ub);
+               arcs[n].push_back(ub);
 
-               arcsets[n].push_back (std::make_pair (lb, ub));
+               arcsets[n].push_back(std::make_pair(lb, ub));
                lb = ub + 1;
        }
 }
 
-Node::~Node ()
+bool Node::end() const
 {
-       delete suffix;
+       return arcs.size() == 0;
 }
 
-bool Node::end () const
+Skeleton::Skeleton(
+       const dfa_t &dfa,
+       const charset_t &cs,
+       const rules_t &rs,
+       const std::string &dfa_name,
+       const std::string &dfa_cond,
+       uint32_t dfa_line) :
+               name(dfa_name),
+               cond(dfa_cond),
+               line(dfa_line),
+               nodes_count(dfa.states.size() + 1), // +1 for default state
+               nodes(new Node[nodes_count]),
+               loops(new uint8_t[nodes_count]),
+               suffixes(new path_t*[nodes_count]),
+               sizeof_key(4),
+               rules(rs)
 {
-       return arcs.size () == 0;
-}
+       memset(loops, 0, sizeof(uint8_t) * nodes_count);
+       memset(suffixes, 0, sizeof(path_t*) * nodes_count);
 
-Skeleton::Skeleton
-       ( const dfa_t &dfa
-       , const charset_t &cs
-       , const rules_t &rs
-       , const std::string &dfa_name
-       , const std::string &dfa_cond
-       , uint32_t dfa_line
-       )
-       : name (dfa_name)
-       , cond (dfa_cond)
-       , line (dfa_line)
-       , nodes_count (dfa.states.size())
-       , nodes (new Node [nodes_count + 1]) // +1 for default state
-       , sizeof_key (4)
-       , rules (rs)
-{
        const size_t nc = cs.size() - 1;
 
        // initialize skeleton nodes
-       Node *nil = &nodes[nodes_count];
-       for (size_t i = 0; i < nodes_count; ++i)
-       {
+       for (size_t i = 0; i < nodes_count - 1; ++i) {
                dfa_state_t *s = dfa.states[i];
-               std::vector<std::pair<Node*, uint32_t> > arcs;
-               for (size_t c = 0; c < nc;)
-               {
+               std::vector<std::pair<size_t, uint32_t> > arcs;
+               for (size_t c = 0; c < nc;) {
                        const size_t j = s->arcs[c];
                        for (;++c < nc && s->arcs[c] == j;);
-                       Node *to = j == dfa_t::NIL
-                               ? nil
-                               : &nodes[j];
+                       const size_t to = j == dfa_t::NIL
+                               ? nodes_count - 1
+                               : j;
                        arcs.push_back(std::make_pair(to, cs[c]));
                }
                // all arcs go to default node => this node is final, drop arcs
-               if (arcs.size() == 1 && arcs[0].first == nil)
-               {
+               if (arcs.size() == 1 && arcs[0].first == nodes_count - 1) {
                        arcs.clear();
                }
                nodes[i].init(s->ctx, s->rule, arcs);
        }
 
-       // calculate maximal path length, check overflow
-       nodes->calc_dist ();
-       const uint32_t maxlen = nodes->dist;
-       if (maxlen == Node::DIST_MAX)
-       {
-               error ("DFA path %sis too long", incond (cond).c_str ());
-               exit (1);
-       }
+       const uint32_t maxlen = maxpath(*this);
 
        // calculate maximal rule rank (disregarding default and none rules)
        uint32_t maxrule = 0;
-       for (uint32_t i = 0; i < nodes_count; ++i)
-       {
+       for (uint32_t i = 0; i < nodes_count; ++i) {
                const RuleInfo *r = nodes[i].rule;
-               if (r && !r->rank.is_def())
-               {
-                       maxrule = std::max (maxrule, r->rank.uint32 ());
+               if (r && !r->rank.is_def()) {
+                       maxrule = std::max(maxrule, r->rank.uint32());
                }
        }
        // two upper values reserved for default and none rules)
        maxrule += 2;
 
        // initialize size of key
-       const uint32_t max = std::max (maxlen, maxrule);
-       if (max <= std::numeric_limits<uint8_t>::max())
-       {
+       const uint32_t max = std::max(maxlen, maxrule);
+       if (max <= std::numeric_limits<uint8_t>::max()) {
                sizeof_key = 1;
-       }
-       else if (max <= std::numeric_limits<uint16_t>::max())
-       {
+       } else if (max <= std::numeric_limits<uint16_t>::max()) {
                sizeof_key = 2;
        }
 }
 
-Skeleton::~Skeleton ()
+Skeleton::~Skeleton()
 {
-       delete [] nodes;
+       delete[] nodes;
+       delete[] loops;
+       for (size_t i = 0; i < nodes_count; ++i) {
+               delete suffixes[i];
+       }
+       delete[] suffixes;
 }
 
-uint32_t Skeleton::rule2key (rule_rank_t r) const
+uint32_t Skeleton::rule2key(rule_rank_t r) const
 {
-       switch (sizeof_key)
-       {
+       switch (sizeof_key) {
                default: // shouldn't happen
-               case 4: return rule2key<uint32_t> (r);
-               case 2: return rule2key<uint16_t> (r);
-               case 1: return rule2key<uint8_t>  (r);
+               case 4: return rule2key<uint32_t>(r);
+               case 2: return rule2key<uint16_t>(r);
+               case 1: return rule2key<uint8_t>(r);
        }
 }
 
index 786fa75413d0d3dec50fa9095f74b10512d113ad..93460ed8a9bf60c407037c60a2a2ade578eea187 100644 (file)
@@ -2,7 +2,6 @@
 #define _RE2C_IR_SKELETON_SKELETON_
 
 #include "src/util/c99_stdint.h"
-#include <stddef.h>
 #include <stdio.h>
 #include <limits>
 #include <map>
 #include <utility>
 
 #include "src/ir/regexp/regexp.h"
-#include "src/ir/rule_rank.h"
 #include "src/parse/rules.h"
 #include "src/util/local_increment.h"
 #include "src/util/forbid_copy.h"
-#include "src/util/u32lim.h"
 
 namespace re2c
 {
 
 struct dfa_t;
 struct OutputFile;
-class RuleInfo;
 struct path_t;
 
+typedef local_increment_t<uint8_t> local_inc;
+
 struct Node
 {
-       /*
-        * note [counting skeleton edges]
-        *
-        * To avoid any possible overflows all size calculations are wrapped in
-        * a special truncated unsigned 32-bit integer type that checks overflow
-        * on each binary operation or conversion from another type.
-        *
-        * Two things contribute to size calculation: path length and the number
-        * of outgoing arcs in each node. Some considerations on why these values
-        * will not overflow before they are converted to truncated type:
-        *
-        *   - Maximal number of outgoing arcs in each node cannot exceed 32 bits:
-        *     it is bounded by the number of code units in current encoding, and
-        *     re2c doesn't support any encoding with more than 2^32 code units.
-        *     Conversion is safe.
-        *
-        *   - Maximal path length cannot exceed 32 bits: we estimate it right
-        *     after skeleton construction and check for overflow. If path length
-        *     does overflow, an error is reported and re2c aborts.
-        */
-
-       // Type for calculating the size of path cover.
-       // Paths are dumped to file as soon as generated and don't eat
-       // heap space. The total size of path cover (measured in edges)
-       // is O(N^2) where N is the number of edges in skeleton.
-       typedef u32lim_t<1024 * 1024 * 1024> covers_t; // ~1Gb
-
-       // Type for counting arcs in paths that cause undefined behaviour.
-       // These paths are stored on heap, so the limit should be low.
-       // Most real-world cases have only a few short paths.
-       // We don't need all paths anyway, just some examples.
-       typedef u32lim_t<1024> nakeds_t; // ~1Kb
-
        typedef std::vector<std::pair<uint32_t, uint32_t> > arcset_t;
-       typedef std::map<Node *, arcset_t> arcsets_t;
+       typedef std::map<size_t, arcset_t> arcsets_t;
 
        typedef std::vector<uint32_t> arc_t;
-       typedef std::map<Node *, arc_t> arcs_t;
+       typedef std::map<size_t, arc_t> arcs_t;
 
-       typedef local_increment_t<uint8_t> local_inc;
-
-       // outgoing arcs
        arcs_t arcs;
        arcsets_t arcsets;
-
-       // how many times this node has been visited
-       // (controls looping in graph traversals)
-       uint8_t loop;
-
-       // rule for corresponding DFA state (if any)
        RuleInfo *rule;
-
-       // start of trailing context
        bool ctx;
 
-       // maximal distance to end node (assuming one iteration per loop)
-       static const uint32_t DIST_ERROR;
-       static const uint32_t DIST_MAX;
-       uint32_t dist;
-
-       // rules reachable from this node (including absent rule)
-       std::set<RuleInfo*> reachable;
+       Node();
+       void init(bool b, RuleInfo *r,
+               const std::vector<std::pair<size_t, uint32_t> > &arcs);
+       bool end() const;
 
-       // path to end node (for constructing path cover)
-       path_t * suffix;
-
-       Node ();
-       void init(bool b, RuleInfo *r, const std::vector<std::pair<Node*, uint32_t> > &arcs);
-       ~Node ();
-       bool end () const;
-       void calc_dist ();
-       void calc_reachable ();
-       template <typename cunit_t, typename key_t>
-               void cover (path_t & prefix, FILE * input, FILE * keys, covers_t &size);
-       void naked_paths(path_t &prefix, std::vector<path_t> &paths, nakeds_t &size);
-
-       FORBID_COPY (Node);
+       FORBID_COPY(Node);
 };
 
 struct Skeleton
@@ -114,52 +52,28 @@ struct Skeleton
        const uint32_t line;
 
        const size_t nodes_count;
-       Node * nodes;
+       Node *nodes;
+
+       // visit counters (for graph traversal)
+       uint8_t *loops;
+
+       // paths to end node (for constructing path cover)
+       path_t **suffixes;
+
        size_t sizeof_key;
        rules_t rules;
 
-       Skeleton
-               ( const dfa_t &dfa
-               , const charset_t &cs
-               , const rules_t & rs
-               , const std::string &dfa_name
-               , const std::string &dfa_cond
-               , uint32_t dfa_line
-               );
+       Skeleton(const dfa_t &dfa, const charset_t &cs, const rules_t &rs,
+               const std::string &dfa_name, const std::string &dfa_cond,
+               uint32_t dfa_line);
        ~Skeleton ();
-       void warn_undefined_control_flow ();
-       void warn_unreachable_nullable_rules ();
-       void emit_data (const char * fname);
-       static void emit_prolog (OutputFile & o);
-       void emit_start
-               ( OutputFile & o
-               , size_t maxfill
-               , bool backup
-               , bool backupctx
-               , bool accept
-               ) const;
-       void emit_end
-               ( OutputFile & o
-               , bool backup
-               , bool backupctx
-               ) const;
-       static void emit_epilog (OutputFile & o, const std::set<std::string> & names);
-       void emit_action (OutputFile & o, uint32_t ind, rule_rank_t rank) const;
-
-       template <typename key_t> static key_t rule2key (rule_rank_t r);
-       uint32_t rule2key (rule_rank_t r) const;
-
-private:
-       template <typename cunit_t, typename key_t>
-               void generate_paths_cunit_key (FILE * input, FILE * keys);
-       template <typename cunit_t>
-               void generate_paths_cunit (FILE * input, FILE * keys);
-       void generate_paths (FILE * input, FILE * keys);
-
-       FORBID_COPY (Skeleton);
+       uint32_t rule2key(rule_rank_t r) const;
+       template<typename key_t> static key_t rule2key(rule_rank_t r);
+
+       FORBID_COPY(Skeleton);
 };
 
-template<typename key_t> key_t Skeleton::rule2key (rule_rank_t r)
+template<typename key_t> key_t Skeleton::rule2key(rule_rank_t r)
 {
        if (r.is_none()) {
                return std::numeric_limits<key_t>::max();
@@ -171,8 +85,18 @@ template<typename key_t> key_t Skeleton::rule2key (rule_rank_t r)
        }
 }
 
-bool compare_default_paths(const path_t &p1, const path_t &p2);
-void fprint_default_path(FILE *f, const path_t &p);
+uint32_t maxpath(Skeleton &skel);
+void warn_undefined_control_flow(Skeleton &skel);
+void fprint_default_path(FILE *f, const Skeleton &skel, const path_t &p);
+void warn_unreachable_nullable_rules(Skeleton &skel);
+void emit_data(Skeleton &skel, const char *fname);
+void emit_prolog(OutputFile & o);
+void emit_start(const Skeleton &skel, OutputFile &o, size_t maxfill,
+       bool backup, bool backupctx, bool accept);
+void emit_end(const Skeleton &skel, OutputFile &o, bool backup, bool backupctx);
+void emit_epilog(OutputFile &o, const std::set<std::string> &names);
+void emit_action(const Skeleton &skel, OutputFile &o, uint32_t ind,
+       rule_rank_t rank);
 
 } // namespace re2c
 
index 7dbfd3ddf92a266aa76e0bde95826dfee247cf14..4c7111ce89df49f9bb1ecbec4ab7b89c23ea4d70 100644 (file)
@@ -1,7 +1,5 @@
 #include "src/util/c99_stdint.h"
-#include <map>
 #include <set>
-#include <utility>
 
 #include "src/conf/warn.h"
 #include "src/globals.h"
 namespace re2c
 {
 
-void Node::calc_reachable ()
+static void calc_reachable(
+       Skeleton &skel,
+       std::vector<std::set<RuleInfo*> > &reachs,
+       size_t i)
 {
-       if (!reachable.empty ())
-       {
+       const Node &node = skel.nodes[i];
+       uint8_t &loop = skel.loops[i];
+       std::set<RuleInfo*> &reach = reachs[i];
+
+       if (!reach.empty()) {
                return;
-       }
-       else if (end ())
-       {
-               reachable.insert (rule);
-       }
-       else if (loop < 2)
-       {
-               local_inc _ (loop);
-               for (arcs_t::iterator i = arcs.begin (); i != arcs.end (); ++i)
-               {
-                       i->first->calc_reachable ();
-                       reachable.insert (i->first->reachable.begin (), i->first->reachable.end ());
+       } 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, reachs, j);
+                       reach.insert(reachs[j].begin(), reachs[j].end());
                }
        }
 }
 
-void Skeleton::warn_unreachable_nullable_rules ()
+void warn_unreachable_nullable_rules(Skeleton &skel)
 {
        // calculate reachable rules
-       nodes->calc_reachable();
-       for (uint32_t i = 0; i < nodes_count; ++i)
-       {
-               RuleInfo *r1 = nodes[i].rule;
+       std::vector<std::set<RuleInfo*> > reachs(skel.nodes_count);
+       calc_reachable(skel, reachs, 0);
+
+       for (uint32_t i = 0; i < skel.nodes_count; ++i) {
+               RuleInfo *r1 = skel.nodes[i].rule;
                if (!r1) {
                        continue;
                }
-               const std::set<RuleInfo*> & rs = nodes[i].reachable;
-               for (std::set<RuleInfo*>::const_iterator j = rs.begin(); j != rs.end(); ++j)
-               {
-                       RuleInfo* r2 = *j;
-                       if (!r2 || r1->rank == r2->rank)
-                       {
+               std::set<RuleInfo*>::const_iterator
+                       rule = reachs[i].begin(),
+                       end = reachs[i].end();
+               for (; rule != end; ++rule) {
+                       RuleInfo* r2 = *rule;
+                       if (!r2 || r1->rank == r2->rank) {
                                r1->reachable = true;
-                       }
-                       else
-                       {
+                       } else {
                                r1->shadow.insert(r2->loc.line);
                        }
                }
@@ -64,12 +66,10 @@ void Skeleton::warn_unreachable_nullable_rules ()
        //   - 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 (rules_t::const_iterator i = rules.begin(); i != rules.end(); ++i)
-       {
+       for (rules_t::const_iterator i = skel.rules.begin(); i != skel.rules.end(); ++i) {
                const RuleInfo *r = *i;
-               if (!r->rank.is_def() && !r->reachable)
-               {
-                       warn.unreachable_rule(cond, r);
+               if (!r->rank.is_def() && !r->reachable) {
+                       warn.unreachable_rule(skel.cond, r);
                }
        }
 
@@ -78,11 +78,9 @@ void Skeleton::warn_unreachable_nullable_rules ()
        //    - rules that match empty strins with nonempty trailing context
        // false positives on partially shadowed (yet reachable) rules, e.g.:
        //     [^]?
-       for (rules_t::const_iterator i = rules.begin(); i != rules.end(); ++i)
-       {
+       for (rules_t::const_iterator i = skel.rules.begin(); i != skel.rules.end(); ++i) {
                const RuleInfo *r = *i;
-               if (r->nullable && r->reachable)
-               {
+               if (r->nullable && r->reachable) {
                        warn.match_empty_string(r->loc.line);
                }
        }
index 7f46af1b7afcd25d1da363a7c490a3793c4e07ab..8db2c44a7c76c0b3a872c5bab3bd4b3b9bb1ac5c 100644 (file)
@@ -572,7 +572,7 @@ void parse(Scanner& i, Output & o)
                .wline_info (in->get_cline (), in->get_fname ().c_str ());
        if (opts->target == opt_t::SKELETON)
        {
-               Skeleton::emit_prolog (o.source);
+               emit_prolog(o.source);
        }
 
        Enc encodingOld = opts->encoding;
@@ -741,7 +741,7 @@ void parse(Scanner& i, Output & o)
 
        if (opts->target == opt_t::SKELETON)
        {
-               Skeleton::emit_epilog (o.source, o.skeletons);
+               emit_epilog(o.source, o.skeletons);
        }
 
        parse_cleanup();