preprocess tft files
This commit is contained in:
+201
-40
@@ -5,13 +5,30 @@
|
|||||||
#include "utils.hpp"
|
#include "utils.hpp"
|
||||||
|
|
||||||
using std::cerr;
|
using std::cerr;
|
||||||
using std::string_view;
|
/* using std::string_view; */
|
||||||
using std::string;
|
using std::string;
|
||||||
|
using std::vector;
|
||||||
|
using std::pair;
|
||||||
|
|
||||||
namespace /* internal */
|
namespace /* internal */
|
||||||
{
|
{
|
||||||
char* data;
|
struct alloced
|
||||||
char* data_end; /* past the end pointer */
|
{
|
||||||
|
char* const data;
|
||||||
|
char* const end;
|
||||||
|
alloced(U32 len)
|
||||||
|
: data(new char[len])
|
||||||
|
, end(data + len)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
~alloced()
|
||||||
|
{
|
||||||
|
delete[] data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
char* it_data;
|
||||||
|
char* end_data; /* past the end pointer */
|
||||||
unsigned line = 1;
|
unsigned line = 1;
|
||||||
|
|
||||||
/* state */
|
/* state */
|
||||||
@@ -39,13 +56,13 @@ namespace /* internal */
|
|||||||
|
|
||||||
void proceedToNameEnd()
|
void proceedToNameEnd()
|
||||||
{
|
{
|
||||||
while(data < data_end &&
|
while(it_data < end_data &&
|
||||||
*data != ',' &&
|
*it_data != ',' &&
|
||||||
*data != '\n')
|
*it_data != '\n')
|
||||||
{
|
{
|
||||||
if(*data == ':' /* && *data == '-' */)
|
if(*it_data == ':' /* && *it_data == '-' */)
|
||||||
unexpected_char(*data);
|
unexpected_char(*it_data);
|
||||||
++data;
|
++it_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -53,80 +70,196 @@ namespace /* internal */
|
|||||||
Sex findSex()
|
Sex findSex()
|
||||||
{
|
{
|
||||||
Sex res = M;
|
Sex res = M;
|
||||||
if(*data == ',')
|
if(*it_data == ',')
|
||||||
{
|
{
|
||||||
++data;
|
++it_data;
|
||||||
if(*data == 'M')
|
if(*it_data == 'M')
|
||||||
res = M;
|
res = M;
|
||||||
else if(*data == 'F')
|
else if(*it_data == 'F')
|
||||||
res = F;
|
res = F;
|
||||||
else
|
else
|
||||||
unexpected_char(*data);
|
unexpected_char(*it_data);
|
||||||
|
|
||||||
++data;
|
++it_data;
|
||||||
if(*data != '\n')
|
if(*it_data != '\n')
|
||||||
unexpected_char(*data);
|
unexpected_char(*it_data);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void processAtribute()
|
I32 processDatePart()
|
||||||
{
|
{
|
||||||
|
I32 sign = 1;
|
||||||
|
I32 val = 0;
|
||||||
|
for(; it_data < end_data; ++it_data)
|
||||||
|
{
|
||||||
|
switch(*it_data)
|
||||||
|
{
|
||||||
|
case '-':
|
||||||
|
sign = -1;
|
||||||
|
break;
|
||||||
|
case '0' ... '9':
|
||||||
|
val = val*10 + *it_data;
|
||||||
|
break;
|
||||||
|
case '.':
|
||||||
|
if(val == 0)
|
||||||
|
unexpected_char('.');
|
||||||
|
else
|
||||||
|
return sign * val;
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
++line;
|
||||||
|
return sign * val;
|
||||||
|
/* case '?': todo */
|
||||||
|
default:
|
||||||
|
unexpected_char(*it_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unexpected_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
EventTime processDate() /* todo validate */
|
||||||
|
{
|
||||||
|
EventTime date;
|
||||||
|
date.year = processDatePart();
|
||||||
|
if(*it_data == '.')
|
||||||
|
{
|
||||||
|
++it_data;
|
||||||
|
date.month = processDatePart();
|
||||||
|
|
||||||
|
if(*it_data == '.')
|
||||||
|
{
|
||||||
|
++it_data;
|
||||||
|
date.day = processDatePart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
|
||||||
|
pair<person_id, person_id> processParents()
|
||||||
|
{
|
||||||
|
pair<person_id, person_id> res(Nobody, Nobody);
|
||||||
|
string name; /* todo dont use string */
|
||||||
|
for(; it_data < end_data; ++it_data)
|
||||||
|
{
|
||||||
|
switch(*it_data)
|
||||||
|
{
|
||||||
|
/* case '-':todo */
|
||||||
|
case ',':
|
||||||
|
if(res.first == Nobody)
|
||||||
|
res.first = cur_tree->findId(name.data());
|
||||||
|
else if(res.second == Nobody)
|
||||||
|
res.second = cur_tree->findId(name.data());
|
||||||
|
else
|
||||||
|
/* todo */exit(1);
|
||||||
|
name.clear();
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
++line;
|
||||||
|
if(res.first == Nobody)
|
||||||
|
res.first = cur_tree->findId(name.data());
|
||||||
|
else
|
||||||
|
res.second = cur_tree->findId(name.data());
|
||||||
|
return res;
|
||||||
|
default:
|
||||||
|
name.push_back(*it_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<person_id> parseSpouses()
|
||||||
|
{
|
||||||
|
vector<person_id> res;
|
||||||
|
string name;
|
||||||
|
for(; it_data < end_data; ++it_data)
|
||||||
|
{
|
||||||
|
switch(*it_data)
|
||||||
|
{
|
||||||
|
case ',':
|
||||||
|
res.push_back( cur_tree->findId(name.data()) );
|
||||||
|
name.clear();
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
++line;
|
||||||
|
res.push_back( cur_tree->findId(name.data()) );
|
||||||
|
return res;
|
||||||
|
default:
|
||||||
|
name.push_back(*it_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* return res;todo */
|
||||||
}
|
}
|
||||||
|
|
||||||
void state_neutral()
|
void state_neutral()
|
||||||
{
|
{
|
||||||
for(; data < data_end; ++data)
|
for(; it_data < end_data; ++it_data)
|
||||||
{
|
{
|
||||||
switch(*data)
|
switch(*it_data)
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
state_person();
|
state_person();
|
||||||
return;
|
|
||||||
break;
|
break;
|
||||||
case '\n':
|
case '\n':
|
||||||
++line;
|
++line;
|
||||||
break;
|
break;
|
||||||
/* case '#': */
|
|
||||||
/* state = state_comment; */
|
|
||||||
/* return; */
|
|
||||||
case ',':
|
case ',':
|
||||||
case '-':
|
case '-':
|
||||||
case 0 ... 9:
|
case 0 ... 9:
|
||||||
case ':':
|
case ':':
|
||||||
unexpected_char(*data);
|
unexpected_char(*it_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void state_person()
|
void state_person()
|
||||||
{
|
{
|
||||||
char* name_start = data;
|
char* name_start = it_data;
|
||||||
person_id parent1;
|
pair<person_id, person_id> parents;
|
||||||
person_id parent2;
|
person_id spouse;
|
||||||
EventTime birth;
|
EventTime birth{};
|
||||||
EventTime death;
|
EventTime death{};
|
||||||
|
|
||||||
proceedToNameEnd();
|
proceedToNameEnd();
|
||||||
/* string_view name(name_start, data); */
|
/* string_view name(name_start, it_data); */
|
||||||
string name(name_start, data);
|
string name(name_start, it_data);
|
||||||
|
|
||||||
Sex sex = findSex();
|
Sex sex = findSex();
|
||||||
|
|
||||||
for(; data < data_end; ++data)
|
for(; it_data < end_data; ++it_data)
|
||||||
{
|
{
|
||||||
switch(*data)
|
switch(*it_data)
|
||||||
{
|
{
|
||||||
case '\n':
|
case '\n':
|
||||||
++line;
|
++line;
|
||||||
if(data[1] == ':') /* todo */
|
++it_data;
|
||||||
|
if(it_data[1] == ':') /* todo */
|
||||||
{
|
{
|
||||||
processAtribute();
|
switch(*it_data)
|
||||||
|
{
|
||||||
|
case 'b':
|
||||||
|
it_data += 2;
|
||||||
|
birth = processDate();
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
it_data += 2;
|
||||||
|
death = processDate();
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
it_data += 2;
|
||||||
|
processParents();
|
||||||
|
case 's':
|
||||||
|
it_data += 2;
|
||||||
|
parseSpouses();
|
||||||
|
default:
|
||||||
|
unexpected_char(it_data[-1]);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cur_tree->addPerson(name.c_str(), sex/* , parent1, parent2, birth, death */);
|
cur_tree->addPerson(name.c_str(), sex, parents.first, parents.second, birth, death);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
/* case '#': */
|
/* case '#': */
|
||||||
@@ -134,23 +267,51 @@ namespace /* internal */
|
|||||||
/* return; */
|
/* return; */
|
||||||
/* case 0...9: */
|
/* case 0...9: */
|
||||||
/* case ':': */
|
/* case ':': */
|
||||||
/* unexpected_char(*data); */
|
/* unexpected_char(*it_data); */
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
alloced preprocess(MappedFile file) /* remove whitespace and comments */
|
||||||
|
{
|
||||||
|
alloced res(file.len);
|
||||||
|
|
||||||
|
char* end = file.data + file.len;
|
||||||
|
for(char* it = file.data, * itres = res.data; it < end; ++it)
|
||||||
|
{
|
||||||
|
switch(*it)
|
||||||
|
{
|
||||||
|
case '#':
|
||||||
|
while(++it != end && *it != '\n'); /* skip comment */
|
||||||
|
*itres++ = '\n'; /* add \n */
|
||||||
|
break;
|
||||||
|
case ' ':
|
||||||
|
case '\t':
|
||||||
|
case '\r':
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
*itres = *it;
|
||||||
|
++itres;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Tree parseTftFile(MappedFile file)
|
Tree parseTftFile(MappedFile file)
|
||||||
{
|
{
|
||||||
data = file.data;
|
|
||||||
data_end = file.data + file.len;
|
|
||||||
|
|
||||||
Tree result("name");
|
Tree result("name");
|
||||||
cur_tree = &result;
|
cur_tree = &result;
|
||||||
|
|
||||||
|
alloced preprocessed = preprocess(file);
|
||||||
|
it_data = preprocessed.data;
|
||||||
|
end_data = preprocessed.end;
|
||||||
|
|
||||||
state_neutral();
|
state_neutral();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
Reference in New Issue
Block a user