/* Generated by re2c */
#line 1 "c/submatch/02_mtags.re"
// re2c $INPUT -o $OUTPUT
#include <assert.h>
#include <stddef.h>
#include <vector>

static const int MTAG_ROOT = -1;

// An m-tag tree is a way to store histories with an O(1) copy operation.
// Histories naturally form a tree, as they have common start and fork at some
// point. The tree is stored as an array of pairs (tag value, link to parent).
// An m-tag is represented with a single link in the tree (array index).
struct Mtag {
    const char *elem; // tag value
    int pred; // index of the predecessor node or root
};
typedef std::vector<Mtag> MtagTrie;

typedef std::vector<int> Ver; // unbounded number of version components

static 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;
}

// Append a single value to an m-tag history.
static void add_mtag(MtagTrie &trie, int &mtag, const char *value) {
    Mtag m = {value, mtag};
    mtag = (int)trie.size();
    trie.push_back(m);
}

// Recursively unwind tag histories and collect version components.
static void unfold(const MtagTrie &trie, int x, int y, Ver &ver) {
    // Reached the root of the m-tag tree, stop recursion.
    if (x == MTAG_ROOT && y == MTAG_ROOT) return;

    // Unwind history further.
    unfold(trie, trie[x].pred, trie[y].pred, ver);

    // Get tag values. Tag histories must have equal length.
    assert(x != MTAG_ROOT && y != MTAG_ROOT);
    const char *ex = trie[x].elem, *ey = trie[y].elem;

    if (ex != NULL && ey != NULL) {
        // Both tags are valid pointers, extract component.
        ver.push_back(s2n(ex, ey));
    } else {
        // Both tags are NULL (this corresponds to zero repetitions).
        assert(ex == NULL && ey == NULL);
    }
}

static bool parse(const char *str, Ver &ver) {
    const char *YYCURSOR = str, *YYMARKER;
    MtagTrie mt;

    // User-defined tag variables that are available in semantic action.
    const char *t1, *t2;
    int t3, t4;

    // Autogenerated tag variables used by the lexer to track tag values.
    
#line 67 "c/submatch/02_mtags.c"
const char *yyt1 = NULL;const char *yyt2 = NULL;
#line 63 "c/submatch/02_mtags.re"

    
#line 72 "c/submatch/02_mtags.c"
int yytm3 = MTAG_ROOT;int yytm4 = MTAG_ROOT;
#line 64 "c/submatch/02_mtags.re"


    
#line 78 "c/submatch/02_mtags.c"
{
	unsigned char yych;
	yych = *YYCURSOR;
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			yyt1 = YYCURSOR;
			goto yy3;
		default: goto yy1;
	}
yy1:
	++YYCURSOR;
yy2:
#line 84 "c/submatch/02_mtags.re"
	{ return false; }
#line 102 "c/submatch/02_mtags.c"
yy3:
	yych = *(YYMARKER = ++YYCURSOR);
	switch (yych) {
		case 0x00:
			add_mtag(mt, yytm4, NULL);
			add_mtag(mt, yytm3, NULL);
			yyt2 = YYCURSOR;
			goto yy4;
		case '.':
			yyt2 = YYCURSOR;
			goto yy5;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy7;
		default: goto yy2;
	}
yy4:
	++YYCURSOR;
	t1 = yyt1;
	t2 = yyt2;
	t3 = yytm3;
	t4 = yytm4;
#line 78 "c/submatch/02_mtags.re"
	{
            ver.clear();
            ver.push_back(s2n(t1, t2));
            unfold(mt, t3, t4, ver);
            return true;
        }
#line 139 "c/submatch/02_mtags.c"
yy5:
	yych = *++YYCURSOR;
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			add_mtag(mt, yytm3, YYCURSOR);
			goto yy8;
		default: goto yy6;
	}
yy6:
	YYCURSOR = YYMARKER;
	goto yy2;
yy7:
	yych = *++YYCURSOR;
	switch (yych) {
		case 0x00:
			add_mtag(mt, yytm4, NULL);
			add_mtag(mt, yytm3, NULL);
			yyt2 = YYCURSOR;
			goto yy4;
		case '.':
			yyt2 = YYCURSOR;
			goto yy5;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy7;
		default: goto yy6;
	}
yy8:
	yych = *++YYCURSOR;
	switch (yych) {
		case 0x00:
			add_mtag(mt, yytm4, YYCURSOR);
			goto yy4;
		case '.':
			add_mtag(mt, yytm4, YYCURSOR);
			goto yy5;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy8;
		default: goto yy6;
	}
}
#line 85 "c/submatch/02_mtags.re"

}

int main() {
    Ver v;
    assert(parse("1", v) && v == Ver({1}));
    assert(parse("1.2.3.4.5.6.7", v) && v == Ver({1, 2, 3, 4, 5, 6, 7}));
    assert(!parse("1.2.", v));
    return 0;
}
