/* Generated by re2d */
#line 1 "d/submatch/04_posix_captures.re"
// re2d $INPUT -o $OUTPUT
module main;

// Maximum number of capturing groups among all rules.
#line 8 "d/submatch/04_posix_captures.d"
enum YYMaxNMatch = 4;
#line 5 "d/submatch/04_posix_captures.re"


struct SemVer { int major, minor, patch; };

private int s2n(const(char)* s, const(char)* e) { // pre-parsed string to number
    int n = 0;
    for (; s < e; ++s) n = n * 10 + (*s - '0');
    return n;
}

private bool lex(const(char)* str, ref SemVer ver) {
    const(char)* yycursor = str, yymarker;

    // Allocate memory for capturing parentheses (twice the number of groups).
    const(char)*[YYMaxNMatch * 2] yypmatch;
    size_t yynmatch;

    // Intermediate tag variables used by the lexer (must be autogenerated).
    
#line 30 "d/submatch/04_posix_captures.d"
const(char)* yyt1;
const(char)* yyt2;
const(char)* yyt3;
const(char)* yyt4;
const(char)* yyt5;
#line 23 "d/submatch/04_posix_captures.re"


    
#line 40 "d/submatch/04_posix_captures.d"
{
    char yych;
    yych = *yycursor;
    switch (yych) {
        case '0': .. case '9':
            yyt1 = yycursor;
            goto yy3;
        default: goto yy1;
    }
yy1:
    ++yycursor;
yy2:
#line 42 "d/submatch/04_posix_captures.re"
    { return false; }
#line 55 "d/submatch/04_posix_captures.d"
yy3:
    yych = *(yymarker = ++yycursor);
    switch (yych) {
        case '.': goto yy4;
        case '0': .. case '9': goto yy6;
        default: goto yy2;
    }
yy4:
    yych = *++yycursor;
    switch (yych) {
        case '0': .. case '9':
            yyt2 = yycursor;
            goto yy7;
        default: goto yy5;
    }
yy5:
    yycursor = yymarker;
    goto yy2;
yy6:
    yych = *++yycursor;
    switch (yych) {
        case '.': goto yy4;
        case '0': .. case '9': goto yy6;
        default: goto yy5;
    }
yy7:
    yych = *++yycursor;
    switch (yych) {
        case 0x00:
            yyt3 = yycursor;
            yyt4 = null;
            yyt5 = null;
            goto yy8;
        case '.':
            yyt3 = yycursor;
            yyt5 = yycursor;
            goto yy9;
        case '0': .. case '9': goto yy7;
        default: goto yy5;
    }
yy8:
    ++yycursor;
    yynmatch = 4;
    yypmatch[2] = yyt1;
    yypmatch[4] = yyt2;
    yypmatch[5] = yyt3;
    yypmatch[6] = yyt5;
    yypmatch[7] = yyt4;
    yypmatch[0] = yyt1;
    yypmatch[1] = yycursor;
    yypmatch[3] = yyt2;
    yypmatch[3] -= 1;
#line 32 "d/submatch/04_posix_captures.re"
    {
            // `yynmatch` is the number of capturing groups
            assert(yynmatch == 4);
            // Even `yypmatch` values are for opening parentheses, odd values
            // are for closing parentheses, the first group is the whole match.
            ver.major = s2n(yypmatch[2], yypmatch[3]);
            ver.minor = s2n(yypmatch[4], yypmatch[5]);
            ver.patch = yypmatch[6] ? s2n(yypmatch[6] + 1, yypmatch[7]) : 0;
            return true;
        }
#line 119 "d/submatch/04_posix_captures.d"
yy9:
    yych = *++yycursor;
    if (yych <= 0x00) goto yy5;
    goto yy11;
yy10:
    yych = *++yycursor;
yy11:
    switch (yych) {
        case 0x00:
            yyt4 = yycursor;
            goto yy8;
        case '0': .. case '9': goto yy10;
        default: goto yy5;
    }
}
#line 43 "d/submatch/04_posix_captures.re"

}

void main() {
    SemVer v;
    assert(lex("23.34", v) && v.major == 23 && v.minor == 34 && v.patch == 0);
    assert(lex("1.2.999", v) && v.major == 1 && v.minor == 2 && v.patch == 999);
    assert(!lex("1.a", v));
}
