preprocess tft files
This commit is contained in:
+201
-40
@@ -5,13 +5,30 @@
|
||||
#include "utils.hpp"
|
||||
|
||||
using std::cerr;
|
||||
using std::string_view;
|
||||
/* using std::string_view; */
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using std::pair;
|
||||
|
||||
namespace /* internal */
|
||||
{
|
||||
char* data;
|
||||
char* data_end; /* past the end pointer */
|
||||
struct alloced
|
||||
{
|
||||
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;
|
||||
|
||||
/* state */
|
||||
@@ -39,13 +56,13 @@ namespace /* internal */
|
||||
|
||||
void proceedToNameEnd()
|
||||
{
|
||||
while(data < data_end &&
|
||||
*data != ',' &&
|
||||
*data != '\n')
|
||||
while(it_data < end_data &&
|
||||
*it_data != ',' &&
|
||||
*it_data != '\n')
|
||||
{
|
||||
if(*data == ':' /* && *data == '-' */)
|
||||
unexpected_char(*data);
|
||||
++data;
|
||||
if(*it_data == ':' /* && *it_data == '-' */)
|
||||
unexpected_char(*it_data);
|
||||
++it_data;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -53,80 +70,196 @@ namespace /* internal */
|
||||
Sex findSex()
|
||||
{
|
||||
Sex res = M;
|
||||
if(*data == ',')
|
||||
if(*it_data == ',')
|
||||
{
|
||||
++data;
|
||||
if(*data == 'M')
|
||||
++it_data;
|
||||
if(*it_data == 'M')
|
||||
res = M;
|
||||
else if(*data == 'F')
|
||||
else if(*it_data == 'F')
|
||||
res = F;
|
||||
else
|
||||
unexpected_char(*data);
|
||||
unexpected_char(*it_data);
|
||||
|
||||
++data;
|
||||
if(*data != '\n')
|
||||
unexpected_char(*data);
|
||||
++it_data;
|
||||
if(*it_data != '\n')
|
||||
unexpected_char(*it_data);
|
||||
}
|
||||
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()
|
||||
{
|
||||
for(; data < data_end; ++data)
|
||||
for(; it_data < end_data; ++it_data)
|
||||
{
|
||||
switch(*data)
|
||||
switch(*it_data)
|
||||
{
|
||||
default:
|
||||
state_person();
|
||||
return;
|
||||
break;
|
||||
case '\n':
|
||||
++line;
|
||||
break;
|
||||
/* case '#': */
|
||||
/* state = state_comment; */
|
||||
/* return; */
|
||||
case ',':
|
||||
case '-':
|
||||
case 0 ... 9:
|
||||
case ':':
|
||||
unexpected_char(*data);
|
||||
unexpected_char(*it_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void state_person()
|
||||
{
|
||||
char* name_start = data;
|
||||
person_id parent1;
|
||||
person_id parent2;
|
||||
EventTime birth;
|
||||
EventTime death;
|
||||
char* name_start = it_data;
|
||||
pair<person_id, person_id> parents;
|
||||
person_id spouse;
|
||||
EventTime birth{};
|
||||
EventTime death{};
|
||||
|
||||
proceedToNameEnd();
|
||||
/* string_view name(name_start, data); */
|
||||
string name(name_start, data);
|
||||
/* string_view name(name_start, it_data); */
|
||||
string name(name_start, it_data);
|
||||
|
||||
Sex sex = findSex();
|
||||
|
||||
for(; data < data_end; ++data)
|
||||
for(; it_data < end_data; ++it_data)
|
||||
{
|
||||
switch(*data)
|
||||
switch(*it_data)
|
||||
{
|
||||
case '\n':
|
||||
++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
|
||||
{
|
||||
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;
|
||||
/* case '#': */
|
||||
@@ -134,23 +267,51 @@ namespace /* internal */
|
||||
/* return; */
|
||||
/* case 0...9: */
|
||||
/* case ':': */
|
||||
/* unexpected_char(*data); */
|
||||
/* unexpected_char(*it_data); */
|
||||
default:
|
||||
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)
|
||||
{
|
||||
data = file.data;
|
||||
data_end = file.data + file.len;
|
||||
|
||||
Tree result("name");
|
||||
cur_tree = &result;
|
||||
|
||||
alloced preprocessed = preprocess(file);
|
||||
it_data = preprocessed.data;
|
||||
end_data = preprocessed.end;
|
||||
|
||||
state_neutral();
|
||||
|
||||
return result;
|
||||
|
||||
Reference in New Issue
Block a user