]> granicus.if.org Git - re2c/commitdiff
Forbid 2-cycles in tag commands; fixed topsort to skip cycles.
authorUlya Trofimovich <skvadrik@gmail.com>
Wed, 8 Mar 2017 14:16:19 +0000 (14:16 +0000)
committerUlya Trofimovich <skvadrik@gmail.com>
Wed, 8 Mar 2017 14:16:19 +0000 (14:16 +0000)
re2c/src/dfa/find_state.cc
re2c/src/dfa/tcmd.cc
re2c/test/tags/topsort3.i--tags--no-lookahead.c [new file with mode: 0644]
re2c/test/tags/topsort3.i--tags--no-lookahead.re [new file with mode: 0644]

index 8e2f1a971196d32dd5f8f2bc31badc56e90ecffd..0a8340159d537ebeacc9e11d3a153a23f0013777 100644 (file)
@@ -94,6 +94,13 @@ bool kernels_t::operator()(const kernel_t *k1, const kernel_t *k2)
                        }
                }
        }
+
+       // forbid 2-cycles 'x = y; y = x;': to avoid temporary variables
+       for (tagver_t x = -max; x < max; ++x) {
+               const tagver_t y = x2y[x];
+               if (x != y && x2y[y] == x) return false;
+       }
+
        return true;
 }
 
index 6e9aed1fb86d4d6d5d7b32603be453fbdb7fb0b2..92e7914c3755452827c3ccbb75c644c3a542ead7 100644 (file)
@@ -51,8 +51,8 @@ bool tagcopy_t::equal(const tagcopy_t &x, const tagcopy_t &y)
  * overwrites 'y' before its precious value is copied to 'x').
  *
  * To avoid overwrites, commands should be topologically sorted.
- * This is always possible because there's no cyclic dependencies
- * by construction.
+ * Cycles of length 2 are not allowed by construction; cycles of
+ * length 3 or more are left as is.
  *
  * For the purpose of topsort, we treat commands as arcs of directed
  * acyclic graph: command 'x = y' yields arc X -> Y. Topsort works
@@ -60,38 +60,48 @@ bool tagcopy_t::equal(const tagcopy_t &x, const tagcopy_t &y)
  * (they correspond to commands with no dependencies).
  * Commands in the order of removal are topologically sorted.
  *
- * The algorithm iterates the list of commands twice. First time it
- * counts initial in-degree of nodes. Second time it examines each
- * arc X -> Y: if X has zero in-degree, the algoritm reduces Y's
- * in-degree by one and goes to the next arc. Otherwise, the arc is
- * misplaced: the algorithm moves it to the end of the list (next
- * time this arc will be examined, it will have smaller in-degree).
+ * The algorithm iterates graph and removes arcs with zero in-degree
+ * until either the graph is empty or all remaining arcs belong to
+ * cycles.
  *
  * The algorithm starts and ends with all-zero in-degree buffer.
  */
+
 void tagcopy_t::topsort(tagcopy_t **phead, uint32_t *indeg)
 {
-       tagcopy_t *head = *phead;
-       if (!head) return;
+       tagcopy_t
+               *x0 = *phead, **px, *x,
+               *y0 = NULL,   **py, **py1;
 
-       tagcopy_t *tail = head;
-       for (;;) {
-               ++indeg[tail->rhs];
-               if (!tail->next) break;
-               tail = tail->next;
+       // initialize in-degree
+       for (x = x0; x; x = x->next) {
+               ++indeg[x->rhs];
        }
 
-       for (; head; head = *phead) {
-               if (indeg[head->lhs] == 0) {
-                       phead = &head->next;
-                       --indeg[head->rhs];
-               } else {
-                       *phead = head->next;
-                       tail->next = head;
-                       tail = tail->next;
-                       tail->next = NULL;
+       for (py = &y0;;) {
+               // reached end of list
+               if (!x0) break;
+
+               px = &x0;
+               py1 = py;
+               for (x = x0; x; x = x->next) {
+                       if (indeg[x->lhs] == 0) {
+                               --indeg[x->rhs];
+                               *py = x;
+                               py = &x->next;
+                       } else {
+                               *px = x;
+                               px = &x->next;
+                       }
                }
+               *px = NULL;
+
+               // only cycles left
+               if (py == py1) break;
        }
+       *py = x0;
+
+       *phead = y0;
 }
 
 tcmd_t::tcmd_t(): save(NULL), copy(NULL) {}
diff --git a/re2c/test/tags/topsort3.i--tags--no-lookahead.c b/re2c/test/tags/topsort3.i--tags--no-lookahead.c
new file mode 100644 (file)
index 0000000..6f982fc
--- /dev/null
@@ -0,0 +1,71 @@
+/* Generated by re2c */
+
+{
+       YYCTYPE yych;
+       yyt1 = YYCURSOR;
+       if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3);
+       yych = *(YYMARKER = YYCURSOR++);
+       yyt2 = NULL;
+       switch (yych) {
+       case 'a':       goto yy4;
+       case 'b':       goto yy6;
+       default:        goto yy3;
+       }
+yy2:
+       {}
+yy3:
+       yych = *YYCURSOR++;
+       switch (yych) {
+       case 'a':       goto yy9;
+       case 'b':       goto yy10;
+       default:        goto yy8;
+       }
+yy4:
+       yych = *YYCURSOR;
+       switch (yych) {
+       case 'a':       goto yy5;
+       default:
+               ++YYCURSOR;
+               goto yy10;
+       }
+yy5:
+       YYCURSOR = YYMARKER;
+       goto yy2;
+yy6:
+       yych = *YYCURSOR;
+       switch (yych) {
+       case 'b':       goto yy7;
+       default:
+               ++YYCURSOR;
+               goto yy9;
+       }
+yy7:
+       c = yyt2;
+       {}
+yy8:
+       yych = *YYCURSOR;
+       switch (yych) {
+       case 'b':
+               yyt2 = yyt1;
+               goto yy7;
+       default:
+               ++YYCURSOR;
+               yyt1 = yyt2;
+               goto yy9;
+       }
+yy9:
+       yyt2 = yyt1;
+       goto yy7;
+yy10:
+       yych = *YYCURSOR;
+       switch (yych) {
+       case 'b':       goto yy5;
+       default:
+               ++YYCURSOR;
+               yyt1 = yyt2;
+               goto yy9;
+       }
+}
+
+re2c: warning: line 4: rule matches empty string [-Wmatch-empty-string]
+re2c: warning: line 3: tag 'c' is non-deterministic and induces 2 parallel instances [-Wnondeterministic-tags]
diff --git a/re2c/test/tags/topsort3.i--tags--no-lookahead.re b/re2c/test/tags/topsort3.i--tags--no-lookahead.re
new file mode 100644 (file)
index 0000000..d64c7f1
--- /dev/null
@@ -0,0 +1,6 @@
+/*!re2c
+
+("b"|((@c |[^b])([^a][^b]))) {}
+"" {}
+
+*/