File: //usr/share/doc/re2c/examples/c/submatch/02_mtags.c
/* 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"
{
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;
}