libre2c_posix: skip fictive tags in regexec(); handle dot in parser; added more tests.
authorUlya Trofimovich <skvadrik@gmail.com>
Sun, 13 Jan 2019 10:57:53 +0000 (10:57 +0000)
committerUlya Trofimovich <skvadrik@gmail.com>
Sun, 13 Jan 2019 10:57:53 +0000 (10:57 +0000)
re2c/Makefile.libre2c_posix.am
re2c/bootstrap/libre2c_posix/lex.cc
re2c/libre2c_posix/lex.re
re2c/libre2c_posix/regcomp.cc
re2c/libre2c_posix/regex-impl.h [new file with mode: 0644]
re2c/libre2c_posix/regex.h
re2c/libre2c_posix/regexec.cc
re2c/libre2c_posix/regfree.cc
re2c/libre2c_posix/test.cpp

index 05729ede79a8563a3e14e35ff7b4d36fa6082d39..435be8e800c06b6c7cf9a08b48e1447814f76dfd 100644 (file)
@@ -7,6 +7,7 @@ libre2c_posix_a_CXXFLAGS = $(AM_CXXFLAGS) -fPIC
 libre2c_posix_a_HDR = \
        libre2c_posix/lex.h \
        libre2c_posix/regex.h \
+       libre2c_posix/regex-impl.h \
        src/codegen/bitmap.h \
        src/codegen/emit.h \
        src/codegen/go.h \
index 1e1fdff2fa3797fcccb48f08eb1699133ab54c42..f7c8d14850f6964354a37840beb12e913cf84b76 100644 (file)
@@ -1,4 +1,4 @@
-/* Generated by re2c 1.1.1 on Sat Jan 12 12:49:21 2019 */
+/* Generated by re2c 1.1.1 on Sat Jan 12 23:45:53 2019 */
 #line 1 "../libre2c_posix/lex.re"
 #include <stdio.h>
 
@@ -21,24 +21,24 @@ int lex(const char *&cur)
 {
        char yych;
        yych = *cur;
-       if (yych <= '>') {
+       if (yych <= '9') {
                if (yych <= '+') {
                        if (yych <= 0x00) goto yy2;
                        if (yych <= '\'') goto yy4;
                        goto yy6;
                } else {
+                       if (yych == '.') goto yy8;
                        if (yych <= '/') goto yy4;
-                       if (yych <= '9') goto yy8;
-                       goto yy4;
+                       goto yy10;
                }
        } else {
                if (yych <= 'Z') {
-                       if (yych <= '?') goto yy6;
+                       if (yych == '?') goto yy6;
                        if (yych <= '@') goto yy4;
-                       goto yy10;
+                       goto yy12;
                } else {
                        if (yych <= '`') goto yy4;
-                       if (yych <= 'z') goto yy10;
+                       if (yych <= 'z') goto yy12;
                        if (yych <= '}') goto yy6;
                        goto yy4;
                }
@@ -62,13 +62,21 @@ yy8:
        ++cur;
 #line 26 "../libre2c_posix/lex.re"
        {
-            yylval.number = static_cast<uint32_t>(cur[-1] - '0');
-            return DIGIT;
+            yylval.regexp = ast_dot(0, 0);
+            return REGEXP;
         }
 #line 69 "libre2c_posix/lex.cc"
 yy10:
        ++cur;
 #line 31 "../libre2c_posix/lex.re"
+       {
+            yylval.number = static_cast<uint32_t>(cur[-1] - '0');
+            return DIGIT;
+        }
+#line 77 "libre2c_posix/lex.cc"
+yy12:
+       ++cur;
+#line 36 "../libre2c_posix/lex.re"
        {
             ASTChar c(static_cast<uint32_t>(cur[-1]), 0);
             std::vector<ASTChar> *str = new std::vector<ASTChar>;
@@ -76,9 +84,9 @@ yy10:
             yylval.regexp = ast_str(0, 0, str, false);
             return REGEXP;
         }
-#line 80 "libre2c_posix/lex.cc"
+#line 88 "libre2c_posix/lex.cc"
 }
-#line 38 "../libre2c_posix/lex.re"
+#line 43 "../libre2c_posix/lex.re"
 
 }
 
index a160ebd7cf5d5d13cf88dc20a92e2dc11a4816db..7c2ec2c0df9d5865ad83aebbbca99606303f5faa 100644 (file)
@@ -23,6 +23,11 @@ int lex(const char *&cur)
         "\x00"     { return 0; }
         [{}()|*+?] { return cur[-1]; }
 
+        "." {
+            yylval.regexp = ast_dot(0, 0);
+            return REGEXP;
+        }
+
         [0-9] {
             yylval.number = static_cast<uint32_t>(cur[-1] - '0');
             return DIGIT;
index 3c8334c829edced2855fb3d979e645737d52f85a..5bd53ff062f3e61d73a4633c95ef4d9f923b9107 100644 (file)
@@ -1,5 +1,6 @@
 #include "libre2c_posix/lex.h"
 #include "libre2c_posix/regex.h"
+#include "libre2c_posix/regex-impl.h"
 #include "src/options/opt.h"
 #include "src/options/warn.h"
 #include "src/nfa/nfa.h"
@@ -27,12 +28,12 @@ int regcomp(regex_t *preg, const char *pattern, int /* cflags */)
 
     const AST *a = parse(pattern);
 
-    RangeMgr rangemgr;
+    preg->rmgr = new RangeMgr;
 
     ASTRule ar(a, new Code ("", 0));
     std::vector<ASTRule> arv;
     arv.push_back(ar);
-    RESpec re(arv, opt, warn, rangemgr);
+    RESpec re(arv, opt, warn, *preg->rmgr);
 
     split_charset(re);
     for (uint32_t i = 1, j = 0; i < re.charset.size(); ++i) {
diff --git a/re2c/libre2c_posix/regex-impl.h b/re2c/libre2c_posix/regex-impl.h
new file mode 100644 (file)
index 0000000..b2b0520
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef _RE2C_LIB_REGEX_IMPL_
+#define _RE2C_LIB_REGEX_IMPL_
+
+#include <stddef.h>
+
+#include "libre2c_posix/regex.h"
+#include "src/util/c99_stdint.h"
+
+// fwd
+namespace re2c {
+
+struct nfa_t;
+struct dfa_t;
+struct RangeMgr;
+
+} // namespace re2c
+
+struct regex_t
+{
+    re2c::RangeMgr *rmgr;
+    const re2c::nfa_t *nfa;
+    const re2c::dfa_t *dfa;
+    size_t char2class[256];
+};
+
+#endif // _RE2C_LIB_REGEX_IMPL_
index ef166b431671af4b24d2e774cbf2f85ca9c7a627..55adc97f879dcbd900a27375753746b156bcabd3 100644 (file)
@@ -6,21 +6,13 @@
 
 #include "src/util/c99_stdint.h"
 
-// fwd
-namespace re2c {
-struct nfa_t;
-struct dfa_t;
-}
 
 typedef ptrdiff_t regoff_t;
 
-struct regex_t {
-    const re2c::nfa_t *nfa;
-    const re2c::dfa_t *dfa;
-    size_t char2class[256];
-};
+struct regex_t;
 
-struct regmatch_t {
+struct regmatch_t
+{
     regoff_t rm_so;
     regoff_t rm_eo;
 };
index b21b61542dc3605a88f29329aae4624e1dca4581..6e3f46f981a5848b54fa0bc3f44b7e27e3ab077f 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "libre2c_posix/lex.h"
 #include "libre2c_posix/regex.h"
+#include "libre2c_posix/regex-impl.h"
 #include "src/options/opt.h"
 #include "src/options/warn.h"
 #include "src/nfa/nfa.h"
@@ -66,24 +67,25 @@ int regexec(const regex_t *preg, const char *string, size_t nmatch,
 
         apply_regops(regs, s->tcmd[dfa->nchars], mlen);
 
-        const Rule &rule = dfa->rules[0];
-        const size_t last = std::min(nmatch * 2, rule.htag);
-
         pmatch[0].rm_so = 0;
         pmatch[0].rm_eo = mlen;
 
-        for (size_t t = rule.ltag; t < last; ++t) {
+        const Rule &rule = dfa->rules[0];
+        for (size_t t = rule.ltag; t < rule.htag; ++t) {
+
             const Tag &tag = dfa->tags[t];
             if (fictive(tag)) continue;
+            if (tag.ncap >= nmatch * 2) break;
 
             regoff_t off;
             if (!fixed(tag)) {
                 off = regs[dfa->finvers[t]];
             }
             else {
-                off = -static_cast<regoff_t>(tag.dist);
-                off += tag.base == Tag::RIGHTMOST
+                off = tag.base == Tag::RIGHTMOST
                     ? mlen : regs[dfa->finvers[tag.base]];
+                DASSERT (off != -1);
+                off -= static_cast<regoff_t>(tag.dist);
             }
 
             regmatch_t *rm = &pmatch[tag.ncap / 2 + 1];
index d0d95962717a19de45a5f0b25e8cdfdc5435c082..c4aeb5791909dc5e6302e1e4f28d8daef470f0f1 100644 (file)
@@ -1,4 +1,5 @@
 #include "libre2c_posix/regex.h"
+#include "libre2c_posix/regex-impl.h"
 #include "src/nfa/nfa.h"
 #include "src/dfa/dfa.h"
 
@@ -7,16 +8,16 @@ using namespace re2c;
 
 void regfree(regex_t *preg)
 {
-    const nfa_t *nfa = preg->nfa;
-    const dfa_t *dfa = preg->dfa;
+    delete preg->rmgr;
+
+    delete preg->nfa;
 
+    const dfa_t *dfa = preg->dfa;
     delete &dfa->charset;
     delete &dfa->rules;
     delete &dfa->tags;
     delete &dfa->mtagvers;
     delete[] dfa->finvers;
     delete &dfa->tcpool;
-
     delete dfa;
-    delete nfa;
 }
index 36c6243ff74be0698309f80739a446c073e712fc..ab013aa01b9199a3700c5e31e76af9518aa8744f 100644 (file)
@@ -1,7 +1,9 @@
 #include <stdio.h>
+#include <stdlib.h>
 
+#include "libre2c_posix/regex.h"
+#include "libre2c_posix/regex-impl.h"
 #include "src/util/c99_stdint.h"
-#include "regex.h"
 
 
 static int test(const char *pattern, const char *string
@@ -18,11 +20,16 @@ static int test(const char *pattern, const char *string
     }
 
     result = regexec(&re, string, nmatch, pmatch, 0);
-    if (result != 0) {
+    if (result != 0 && nmatch > 0) {
         fprintf(stderr, "regexec() failed for RE %s and string %s\n"
             , pattern, string);
         goto end;
     }
+    else if (result == 0 && nmatch == 0) {
+        fprintf(stderr, "regexec() didn't fail while it should"
+            " for RE %s and string %s\n", pattern, string);
+        goto end;
+    }
 
     for (uint32_t i = 0; i < nmatch; ++i) {
         regoff_t so = submatch[2 * i];
@@ -48,35 +55,135 @@ end:
     return result;
 }
 
+// Poor man's replacement for C++11 initializer lists. :)
+// Variadic macros are non-standard in c++98. Variadic functions have
+// subtle problems with types: literals are 'int' by default, so passing
+// 'long' as vararg requres suffix 'L', which is easy to forget and hard
+// to notice (the problem is platform/toolchain-specific).
+#define GS                                  static const regoff_t gs[]
+#define T(r,s,gs)                           e |= test(r,s,sizeof(gs)/sizeof(gs[0])/2,gs);
+#define T0(r,s)                             e |= test(r,s,0,NULL);
+#define T1(r,s,a,b)                         { GS = {a,b};                         T(r,s,gs); }
+#define T2(r,s,a,b,c,d)                     { GS = {a,b,c,d};                     T(r,s,gs); }
+#define T3(r,s,a,b,c,d,e,f)                 { GS = {a,b,c,d,e,f};                 T(r,s,gs); }
+#define T4(r,s,a,b,c,d,e,f,g,h)             { GS = {a,b,c,d,e,f,g,h};             T(r,s,gs); }
+#define T5(r,s,a,b,c,d,e,f,g,h,i,j)         { GS = {a,b,c,d,e,f,g,h,i,j};         T(r,s,gs); }
+#define T6(r,s,a,b,c,d,e,f,g,h,i,j,k,l)     { GS = {a,b,c,d,e,f,g,h,i,j,k,l};     T(r,s,gs); }
+#define T7(r,s,a,b,c,d,e,f,g,h,i,j,k,l,m,n) { GS = {a,b,c,d,e,f,g,h,i,j,k,l,m,n}; T(r,s,gs); }
+
 int main()
 {
     int e = 0;
 
-    // poor man's replacement for C++11 initializer lists :)
-#define GS                              static const regoff_t gs[]
-#define T1(r,s,a,b)                     { GS = {a,b};                     T(r,s,gs); }
-#define T2(r,s,a,b,c,d)                 { GS = {a,b,c,d};                 T(r,s,gs); }
-#define T3(r,s,a,b,c,d,e,f)             { GS = {a,b,c,d,e,f};             T(r,s,gs); }
-#define T4(r,s,a,b,c,d,e,f,g,h)         { GS = {a,b,c,d,e,f,g,h};         T(r,s,gs); }
-#define T5(r,s,a,b,c,d,e,f,g,h,i,j)     { GS = {a,b,c,d,e,f,g,h,i,j};     T(r,s,gs); }
-#define T6(r,s,a,b,c,d,e,f,g,h,i,j,k,l) { GS = {a,b,c,d,e,f,g,h,i,j,k,l}; T(r,s,gs); }
-#define T(r,s,gs) { \
-    e |= test(r,s,sizeof(gs)/sizeof(gs[0])/2,gs); \
-}
-
     T1("a",        "a",    0,1);
     T2("(a)",      "a",    0,1, 0,1);
     T2("(a*)",     "aaa",  0,3, 0,3);
     T3("(a*)(b*)", "aabb", 0,4, 0,2, 2,4);
     T3("(a*)(a*)", "aa",   0,2, 0,2, 2,2);
+    T2("(a|aa)*",  "aa",   0,2, 0,2);
+    T3("(a)|(a)",  "a",    0,1, 0,1, -1,-1);
+    T3("(a)*(a)*", "a",    0,1, 0,1, -1,-1);
+
+    // categorize
+    T4("(a*)(ab)*(b*)",            "abc",    0,2, 0,1, -1,-1, 1,2);
+    T7("((a*)(ab)*)((b*)(a*))",    "aba",    0,3, 0,2, 0,0, 0,2, 2,3, 2,2, 2,3);
+    T2("(...?.?)*",                "xxxxxx", 0,6, 4,6);
+    T3("(a|ab)(bc|c)",             "abcabc", 0,3, 0,2, 2,3);
+    T3("(aba|a*b)(aba|a*b)",       "ababa",  0,5, 0,2, 2,5);
+    T2("(a*){2}",                  "xxxxx",  0,0, 0,0);
+    T2("(a*)*",                    "a",      0,1, 0,1);
+    T2("(aba|a*b)*",               "ababa",  0,5, 2,5);
+    T3("(a(b)?)+",                 "aba",    0,3, 2,3, -1,-1);
+    T2(".*(.*)",                   "ab",     0,2, 2,2);
+    T6("(a?)((ab)?)(b?)a?(ab)?b?", "abab",   0,4, 0,1, 1,1, -1,-1, 1,2, -1,-1);
+
+    // forcedassoc
+    T3("(a|ab)(c|bcd)",       "abcd", 0,4, 0,1, 1,4);
+    T3("(a|ab)(bcd|c)",       "abcd", 0,4, 0,1, 1,4);
+    T3("(ab|a)(c|bcd)",       "abcd", 0,4, 0,1, 1,4);
+    T3("(ab|a)(bcd|c)",       "abcd", 0,4, 0,1, 1,4);
+    T5("((a|ab)(c|bcd))(d*)", "abcd", 0,4, 0,4, 0,1, 1,4, 4,4);
+    T5("((a|ab)(bcd|c))(d*)", "abcd", 0,4, 0,4, 0,1, 1,4, 4,4);
+    T5("((ab|a)(c|bcd))(d*)", "abcd", 0,4, 0,4, 0,1, 1,4, 4,4);
+    T5("((ab|a)(bcd|c))(d*)", "abcd", 0,4, 0,4, 0,1, 1,4, 4,4);
+    T5("(a|ab)((c|bcd)(d*))", "abcd", 0,4, 0,2, 2,4, 2,3, 3,4);
+    T5("(a|ab)((bcd|c)(d*))", "abcd", 0,4, 0,2, 2,4, 2,3, 3,4);
+    T5("(ab|a)((c|bcd)(d*))", "abcd", 0,4, 0,2, 2,4, 2,3, 3,4);
+    T5("(ab|a)((bcd|c)(d*))", "abcd", 0,4, 0,2, 2,4, 2,3, 3,4);
+    T3("(a*)(b|abc)",         "abc",  0,3, 0,0, 0,3);
+    T3("(a*)(abc|b)",         "abc",  0,3, 0,0, 0,3);
+    T5("((a*)(b|abc))(c*)",   "abc",  0,3, 0,3, 0,0, 0,3, 3,3);
+    T5("((a*)(abc|b))(c*)",   "abc",  0,3, 0,3, 0,0, 0,3, 3,3);
+    T5("(a*)((b|abc)(c*))",   "abc",  0,3, 0,1, 1,3, 1,2, 2,3);
+    T5("(a*)((abc|b)(c*))",   "abc",  0,3, 0,1, 1,3, 1,2, 2,3);
+    T3("(a*)(b|abc)",         "abc",  0,3, 0,0, 0,3);
+    T3("(a*)(abc|b)",         "abc",  0,3, 0,0, 0,3);
+    T5("((a*)(b|abc))(c*)",   "abc",  0,3, 0,3, 0,0, 0,3, 3,3);
+    T5("((a*)(abc|b))(c*)",   "abc",  0,3, 0,3, 0,0, 0,3, 3,3);
+    T5("(a*)((b|abc)(c*))",   "abc",  0,3, 0,1, 1,3, 1,2, 2,3);
+    T5("(a*)((abc|b)(c*))",   "abc",  0,3, 0,1, 1,3, 1,2, 2,3);
+    T2("(a|ab)",              "ab",   0,2, 0,2);
+    T2("(ab|a)",              "ab",   0,2, 0,2);
+    T3("(a|ab)(b*)",          "ab",   0,2, 0,2, 2,2);
+    T3("(ab|a)(b*)",          "ab",   0,2, 0,2, 2,2);
 
+    // glennfowler
+    T4("(a?)((ab)?)",                    "ab",      0,2, 0,0, 0,2, 0,2);
+    T5("(a?)((ab)?)(b?)",                "ab",      0,2, 0,1, 1,1, -1,-1, 1,2);
+    T6("((a?)((ab)?))(b?)",              "ab",      0,2, 0,2, 0,0, 0,2, 0,2, 2,2);
+    T6("(a?)(((ab)?)(b?))",              "ab",      0,2, 0,1, 1,2, 1,1, -1,-1, 1,2);
+    T2("(.?)",                           "x",       0,1, 0,1);
+    T2("(.?){1}",                        "x",       0,1, 0,1);
+    T3("(.?)(.?)",                       "x",       0,1, 0,1, 1,1);
+    T2("(.?){2}",                        "x",       0,1, 1,1);
+    T2("(.?)*",                          "x",       0,1, 0,1);
+    T2("(.?.?)",                         "xxx",     0,2, 0,2);
+    T2("(.?.?){1}",                      "xxx",     0,2, 0,2);
+    T3("(.?.?)(.?.?)",                   "xxx",     0,3, 0,2, 2,3);
+    T2("(.?.?){2}",                      "xxx",     0,3, 2,3);
+    T4("(.?.?)(.?.?)(.?.?)",             "xxx",     0,3, 0,2, 2,3, 3,3);
+    T2("(.?.?){3}",                      "xxx",     0,3, 3,3);
+    T2("(.?.?)*",                        "xxx",     0,3, 2,3);
+    T4("a?((ab)?)(b?)",                  "ab",      0,2, 1,1, -1,-1, 1,2);
+    T4("(a?)((ab)?)b?",                  "ab",      0,2, 0,1, 1,1, -1,-1);
+    T3("a?((ab)?)b?",                    "ab",      0,2, 1,1, -1,-1);
+    T2("(a*){2}",                        "xxxxx",   0,0, 0,0);
+    T3("(ab?)(b?a)",                     "aba",     0,3, 0,2, 2,3);
+    T3("(a|ab)(ba|a)",                   "aba",     0,3, 0,2, 2,3);
+    T2("(a|ab|ba)",                      "aba",     0,2, 0,2);
+    T3("(a|ab|ba)(a|ab|ba)",             "aba",     0,3, 0,2, 2,3);
+    T2("(a|ab|ba)*",                     "aba",     0,3, 2,3);
+    T2("(aba|a*b)",                      "ababa",   0,3, 0,3);
+    T3("(aba|a*b)(aba|a*b)",             "ababa",   0,5, 0,2, 2,5);
+    T0("(aba|a*b)(aba|a*b)(aba|a*b)",    "ababa");
+    T2("(aba|a*b)*",                     "ababa",   0,5, 2,5);
+    T2("(aba|ab|a)",                     "ababa",   0,3, 0,3);
+    T3("(aba|ab|a)(aba|ab|a)",           "ababa",   0,5, 0,2, 2,5);
+    T4("(aba|ab|a)(aba|ab|a)(aba|ab|a)", "ababa",   0,5, 0,2, 2,4, 4,5);
+    T2("(aba|ab|a)*",                    "ababa",   0,5, 2,5);
+    T3("(a(b)?)",                        "aba",     0,2, 0,2, 1,2);
+    T5("(a(b)?)(a(b)?)",                 "aba",     0,3, 0,2, 1,2, 2,3, -1,-1);
+    T3("(a(b)?)+",                       "aba",     0,3, 2,3, -1,-1);
+    T3("(.*)(.*)",                       "xx",      0,2, 0,2, 2,2);
+    T2(".*(.*)",                         "xx",      0,2, 2,2);
+    T2("(a.*z|b.*y)",                    "azbazby", 0,5, 0,5);
+    T3("(a.*z|b.*y)(a.*z|b.*y)",         "azbazby", 0,7, 0,5, 5,7);
+    T2("(a.*z|b.*y)*",                   "azbazby", 0,7, 5,7);
+    T3("(.|..)(.*)",                     "ab",      0,2, 0,2, 2,2);
+    T4("((..)*(...)*)",                  "xxx",     0,3, 0,3, -1,-1, 0,3);
+    T7("((..)*(...)*)((..)*(...)*)",     "xxx",     0,3, 0,3, -1,-1, 0,3, 3,3, -1,-1, -1,-1);
+    T4("((..)*(...)*)*",                 "xxx",     0,3, 0,3, -1,-1, 0,3);
+
+    return e;
+}
+
+#undef GS
 #undef T
+#undef T0
 #undef T1
 #undef T2
 #undef T3
 #undef T4
 #undef T5
 #undef T6
-
-    return e;
-}
+#undef T7