Files
secondo/Algebras/ChessB/pgn_grammar.hpp

166 lines
6.3 KiB
C++
Raw Normal View History

2026-01-23 17:03:45 +08:00
#ifndef SECONDO_ALGEBRAS_CHESS_PGN_GRAMMAR_HPP
#define SECONDO_ALGEBRAS_CHESS_PGN_GRAMMAR_HPP
#include <map>
#include <string>
#include <vector>
//#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/classic_core.hpp>
#include <boost/spirit/include/classic_utility.hpp>
#include <boost/spirit/include/classic_actor.hpp>
namespace bs = boost::spirit::classic;
struct ply_data
{
std::string check, castling, capture, file,
afile, rank, arank, piece, promoted, ply;
};
struct game_data
{
typedef std::map< std::string, std::string > tags_t;
typedef std::vector< ply_data > moves_t;
// data
tags_t tags;
moves_t moves;
std::string result;
// temporaries
std::string name;
ply_data ply;
};
struct game_parser : public bs::grammar< game_parser >
{
game_data& data;
ply_data empty_ply;
game_parser( game_data& data_ ) : data(data_){}
template< typename ScannerT >
struct definition
{
definition( game_parser const& self )
{
game_data& g = self.data;
ply_data& p = g.ply;
root
= game >> bs::end_p
;
game
= * tag
>> * move
>> RESULT[ bs::assign_a(g.result) ]
;
tag
= bs::ch_p('[')
>> tag_name [ bs::assign_a(g.name) ]
>> bs::confix_p( '"', (*bs::print_p)[ bs::insert_at_a(g.tags, g.name) ], '"' )
[ bs::assign_a(g.name, "") ]
>> bs::ch_p(']')
;
tag_name
= *( bs::alnum_p | bs::ch_p( '_' ) )
;
move
= NUMBER
>> PLY [ bs::assign_a(p.ply) ]
[ bs::push_back_a(g.moves, p) ]
[ bs::assign_a( p, self.empty_ply ) ]
>> ! NAG
>> ! COMMENT
>> ! PLY [ bs::assign_a(p.ply) ]
[ bs::push_back_a(g.moves, p) ]
[ bs::assign_a( p, self.empty_ply ) ]
>> ! NAG
>> ! COMMENT
;
NUMBER
= bs::lexeme_d[ bs::uint_p >> bs::ch_p( '.' ) ]
;
PLY
= bs::lexeme_d
[
bs::chset_p( "NBRQK" ) [ bs::assign_a(p.piece) ]
>> ! (
bs::ch_p('x') [ bs::assign_a(p.capture) ]
| bs::ch_p('-')
)
>> bs::range_p( 'a', 'h' ) [ bs::assign_a(p.file) ]
>> bs::range_p( '1', '8' ) [ bs::assign_a(p.rank) ]
>> ! ( bs::str_p("++") | bs::ch_p('+') | bs::ch_p('#') )
[ bs::assign_a(p.check) ]
]
| bs::lexeme_d
[
bs::chset_p( "NBRQK" ) [ bs::assign_a(p.piece) ]
>> (
bs::range_p('a', 'h') [ bs::assign_a(p.afile) ]
| bs::range_p('1', '8') [ bs::assign_a(p.arank) ]
)
>> ! (
bs::ch_p('x')[ bs::assign_a(p.capture) ]
| bs::ch_p('-')
)
>> bs::range_p( 'a', 'h' ) [ bs::assign_a(p.file) ]
>> bs::range_p( '1', '8' ) [ bs::assign_a(p.rank) ]
>> ! ( bs::str_p("++") | bs::ch_p('+') | bs::ch_p('#') )
[ bs::assign_a(p.check) ]
]
| bs::lexeme_d
[
bs::range_p( 'a', 'h' ) [ bs::assign_a(p.file) ]
>> bs::range_p( '1', '8' ) [ bs::assign_a(p.rank) ]
>> ! ( bs::ch_p('=')
>> bs::chset_p( "NBRQ" ) [ bs::assign_a(p.promoted) ]
)
>> ! ( bs::str_p("++") | bs::ch_p('+') | bs::ch_p('#') )
[ bs::assign_a(p.check) ]
]
| bs::lexeme_d
[
bs::range_p( 'a', 'h' ) [ bs::assign_a(p.afile) ]
>> bs::ch_p('x') [ bs::assign_a(p.capture) ]
>> bs::range_p( 'a', 'h' ) [ bs::assign_a(p.file) ]
>> bs::range_p( '1', '8' ) [ bs::assign_a(p.rank) ]
>> ! ( bs::ch_p('=')
>> bs::chset_p( "NBRQ" ) [ bs::assign_a(p.promoted) ]
)
>> ! ( bs::str_p("++") | bs::ch_p('+') | bs::ch_p('#') )
[ bs::assign_a(p.check) ]
]
| (
bs::str_p( "O-O-O" ) [ bs::assign_a(p.castling) ]
>> ! ( bs::str_p("++") | bs::ch_p('+') | bs::ch_p('#') )
[ bs::assign_a(p.check) ]
)
| (
bs::str_p( "O-O" ) [ bs::assign_a(p.castling) ]
>> ! ( bs::str_p("++") | bs::ch_p('+') | bs::ch_p('#') )
[ bs::assign_a(p.check) ]
)
;
RESULT
= bs::str_p( "1-0" )
| bs::str_p( "0-1" )
| bs::str_p( "1/2-1/2" )
| bs::ch_p( '*' )
;
COMMENT
= bs::lexeme_d[ bs::confix_p( '{', *bs::anychar_p, '}' ) ]
;
NAG
= bs::lexeme_d[ bs::ch_p( '$' ) >> bs::uint_p ]
;
}
bs::rule<ScannerT> root, game, tag, tag_name, move,
NUMBER, PLY, NAG, COMMENT, RESULT, CASTLING;
const bs::rule<ScannerT>& start() const { return root; }
};
};
#endif // SECONDO_ALGEBRAS_CHESS_PGN_GRAMMAR_HPP