From 864d40cb8174b0ef2e4198073bb90f00d511f3a4 Mon Sep 17 00:00:00 2001 From: Venelin Date: Wed, 22 Feb 2023 22:36:12 +0200 Subject: [PATCH] preprocess tft files --- src/parser.cpp | 241 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 201 insertions(+), 40 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index 04ccbd7..6b101df 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -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 processParents() + { + pair 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 parseSpouses() + { + vector 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 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;