53 return (elem == 0) ? 0x27ffb80800000000 : 0x47fffffe87ffffff;
93 return high > 1 ? false : tok_map[high] & (1ULL << low);
101 inline bool is_PGNdigit(
unsigned char ch) {
return ch >=
'0' && ch <=
'9'; }
110 return (ch ==
' ' || ch ==
'\n' || ch ==
'\r' || ch ==
'\t' || ch ==
'\v');
128 auto n_chars = std::distance(tok.first, tok.second);
130 if (std::equal(tok.first, tok.first + 3,
"1-0"))
132 if (std::equal(tok.first, tok.first + 3,
"0-1"))
134 if (std::equal(tok.first, tok.first + 3,
"1/2"))
136 if (std::equal(tok.first, tok.first + 3,
"1:0"))
138 if (std::equal(tok.first, tok.first + 3,
"0:1"))
140 }
else if (n_chars == 7) {
141 if (std::equal(tok.first, tok.first + 7,
"1/2-1/2") ||
142 std::equal(tok.first, tok.first + 7,
"1/2:1/2"))
157 template <
typename TInput,
typename TVisitor>
167 return parser.visitPGN_EndOfLine();
179 return parser.visitPGN_ResultFinal(
'*');
182 return parser.visitPGN_VariationStart();
185 return parser.visitPGN_VariationEnd();
190 auto skip_spaces = [&]() {
192 while (spaces.first != spaces.second) {
193 if (*spaces.first++ ==
'\n')
194 parser.visitPGN_EndOfLine();
201 auto value = input.read_until(
']');
205 if (value.first != value.second && *value.first ==
'"') {
206 auto is_terminated = [&]() {
207 for (
auto it = value.first; it != value.second; ++it) {
210 if (*it ==
'\\' && ++it == value.second)
216 while (!input.last_column() && !is_terminated()) {
217 value.second = input.read_until(
']').second;
221 while (value.first != value.second) {
222 auto last_ch = *--value.second;
223 if (last_ch ==
'"') {
231 parser.visitPGN_EndOfLine();
233 return parser.visitPGN_TagPair(tag, value);
236 parser.visitPGN_inputUnexpectedPGNHeader();
240 return parser.visitPGN_Comment(input.read_until(
'}'));
243 return parser.visitPGN_Comment(input.read_line());
246 if (input.first_column()) {
247 return parser.visitPGN_Escape(input.read_line());
249 return parser.visitPGN_Unknown(
250 input.read_token([](
char c) { return c ==
'%'; }));
253 return parser.visitPGN_NAG(input.read_token(
is_PGNdigit));
257 return parser.visitPGN_Suffix(
258 input.read_token([](
char c) { return c ==
'!' || c ==
'?'; }));
264 bool epd = (section < 0 && std::count(tok.first, tok.second,
'/') == 7);
268 tok.second = input.read_line().second;
269 parser.visitPGN_EPD(tok);
273 auto notdigit = std::find_if_not(tok.first, tok.second,
is_PGNdigit);
274 if (notdigit == tok.first)
275 return parser.visitPGN_SANMove(tok);
277 if (notdigit == tok.second)
278 return parser.visitPGN_MoveNum(tok);
281 return parser.visitPGN_ResultFinal(result);
283 return parser.visitPGN_Unknown(tok);
287 const char*
const begin_;
288 const char*
const end_;
293 : begin_(begin), end_(end), it_(begin) {}
303 assert(it_ != begin_ && it_ != end_);
308 bool eof()
const {
return it_ == end_; };
311 std::size_t
n_read()
const {
return std::distance(begin_, it_); }
334 auto second = (it_ == end_) ? it_ : it_++;
335 return {first, second};
339 template <
typename Cond>
342 it_ = std::find_if_not(it_, end_, cond);
348 template <
typename Cond>
350 assert(it_ != begin_);
351 auto first = it_ - 1;
352 it_ = std::find_if_not(it_, end_, cond);
370 template <
typename TVisitor>
377 parser.visitPGN_inputEOF();
382 return {input.
n_read(), section >= 0};
401 template <
bool unescape = false,
typename TString>
403 std::size_t n_newlines = 0;
404 for (std::size_t i = pos, n = str.size(); i < n; ++i) {
405 unsigned char ch = str[i];
408 unsigned char nxt = (i + 1 != n) ? str[i + 1] : 0;
409 if (nxt < 0x80 || nxt > 0xBF) {
410 str[i] =
static_cast<unsigned char>(ch & 0xBF);
411 str.insert(str.begin() + i,
static_cast<unsigned char>(0xC3));
415 }
else if (ch ==
'\n' || ch ==
'\r' || ch ==
'\t' || ch ==
'\v') {
432 }
else if (unescape && ch ==
'\\' && i + 1 != n) {
436 if (str[i + 1] ==
'\\' || str[i + 1] ==
'"') {
453 template <
typename TString>
void escape_string(TString& str, std::size_t pos) {
454 auto it = str.begin() + pos;
456 it = std::find_if(it, str.end(),
457 [](
char ch) {
return ch ==
'\\' || ch ==
'\"'; });
459 it = str.insert(it,
'\\') + 2;
470 template <
typename TView> std::size_t
trim(TView& str) {
471 std::size_t n_newlines = 0;
472 auto is_space = [&n_newlines](
char ch) {
475 }
else if (ch !=
' ' && ch !=
'\r' && ch !=
'\t' && ch !=
'\v') {
480 str.first = std::find_if_not(str.first, str.second, is_space);
482 using RevIt = std::reverse_iterator<decltype(str.first)>;
484 std::find_if_not(RevIt(str.second), RevIt(str.first), is_space).base();
491 #endif // _PGN_LEXER_H
std::pair< std::size_t, bool > parse_game(pgn_impl::InputMemory input, TVisitor &&parser)
Read a PGN game from memory, grouping characters in tokens and dispatching them to a PGN parser...
char is_PGNtermination(TView tok)
Checks if a token is the game termination marker.
int find(const char *filename)
find() - search for a database.
bool is_PGNdigit(unsigned char ch)
Checks if the given character is one of the 10 decimal digits: 0123456789.
bool is_PGNsymbol(unsigned char ch)
Checks if the given character is a PGN symbol.
std::size_t trim(TView &str)
Trim leading and trailing white spaces.
bool is_PGNwhitespace(unsigned char ch)
Checks if the given character is a white space ("white space characters include space, newline, and tab characters").
void escape_string(TString &str, std::size_t pos)
Escape quote and backslash chars according to the PGN standard: "A quote inside a string is represent...
constexpr unsigned long long init_symbol_map(unsigned elem)
Creates a 128 bits bitmap of PGN symbol characters.
std::size_t normalize(TString &str, std::size_t pos)
Normalize white spaces and converts Latin-1 chars to UTF-8 sequences.
bool parse_token(char ch, TInput &input, TVisitor &parser, int §ion)
Read a token and dispatch it to a PGN parser.