PgnGrammar.h
Go to the documentation of this file.
1 // cwchessboard -- A C++ chessboard tool set
2 //
3 //! @file PgnGrammar.h This file contains the declaration of class PgnGrammar.
4 //
5 // Copyright (C) 2010, by
6 //
7 // Carlo Wood, Run on IRC <carlo@alinoe.com>
8 // RSA-1024 0x624ACAD5 1997-01-26 Sign & Encrypt
9 // Fingerprint16 = 32 EC A7 B6 AC DB 65 A6 F6 F6 55 DD 1C DC FF 61
10 //
11 // This program is free software: you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation, either version 2 of the License, or
14 // (at your option) any later version.
15 //
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 
24 #ifndef PGNGRAMMAR_H
25 #define PGNGRAMMAR_H
26 
27 #ifndef USE_PCH
28 #include "sys.h"
29 #endif
30 
31 #ifndef CWCHESS_PGN_ANALYSIS
32 #include <boost/spirit/include/classic_spirit.hpp>
33 #include <boost/spirit/include/classic_numerics.hpp>
34 #endif
35 
36 namespace cwchess {
37 namespace pgn {
38 namespace grammar {
39 
40 namespace imp {
41 }
42 
43 // Define whether the rules should generate debug output.
44 #define TRACE_PGN_GRAMMAR 1
45 #define TRACE_PGN_WHITESPACE 0
46 #define TRACE_PGN_PRINTABLE 0
47 #define TRACE_PGN_ANNOTATION 0
48 #define TRACE_PGN_INTEGER 0
49 #define TRACE_PGN_COMMENT 0
50 #define TRACE_PGN_SAN_MOVE 0
51 #define TRACE_PGN_SAN_INTERNAL 0
52 #define TRACE_PGN_PUNCTUATION_JUNK 0
53 
54 class PgnGrammar : public boost::spirit::classic::grammar<PgnGrammar> {
55  private:
56  typedef PgnGrammar grammar_t;
57 
58  public:
59  PgnGrammar(void)
60  {
61  BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME(*this, "PgnGrammar", 1);
62  }
63 
64  public:
65  template <typename ScannerT>
66  struct definition {
67  // Non-parse_tree generating rule type.
68  typedef typename ScannerT::iteration_policy_t iteration_policy_t;
69  typedef boost::spirit::classic::match_policy match_policy_t;
70  typedef typename ScannerT::action_policy_t action_policy_t;
71  typedef boost::spirit::classic::scanner_policies<iteration_policy_t, match_policy_t, action_policy_t> policies_t;
72  typedef boost::spirit::classic::scanner<typename ScannerT::iterator_t, policies_t> non_tree_scanner_t;
73  typedef boost::spirit::classic::rule<non_tree_scanner_t> no_tree_rule_t;
74  // Normal (parse_tree generating) rule type.
75  typedef boost::spirit::classic::rule<ScannerT> rule_t;
76  // An integer parser for unsigned integers of 1 to 3 digits.
77  boost::spirit::classic::uint_parser<unsigned, 10, 1, 3> uint3_p;
78 
79  // RULE DECLARATION START
80  rule_t leading_junk;
81  rule_t file;
82  rule_t rank;
83  rule_t piece;
84  rule_t check;
85  rule_t punctuation_junk;
86  rule_t tagname_begin;
87  rule_t tagname_continuation;
88  rule_t printable;
89  rule_t printable_string;
90  rule_t printable_comment;
91  rule_t promotion;
92  no_tree_rule_t blank;
93  no_tree_rule_t white_space;
94  no_tree_rule_t escaped_data;
95  no_tree_rule_t eol;
96  rule_t integer;
97  rule_t square;
98  rule_t disambiguation;
99  rule_t string;
100  rule_t tag_name;
101  rule_t tag_value;
102  rule_t game_termination;
103  rule_t elipsis;
104  rule_t move_number_indication;
105  rule_t SAN_move;
106  rule_t annotation;
107  rule_t numeric_annotation_glyph;
108  rule_t text_annotation1_junk;
109  rule_t text_annotation2_junk;
110  rule_t comment;
111  rule_t parenthesis_junk;
112  rule_t tag_pair;
113  rule_t tag_section;
114  rule_t move;
115  rule_t white_move;
116  rule_t last_white_move;
117  rule_t arena_junk;
118  rule_t black_move;
119  rule_t movetext_section_white;
120  rule_t movetext_section_black;
121  rule_t white_black_move;
122  rule_t recursive_variation_white;
123  rule_t recursive_variation_black;
124  rule_t wrong_color_white_junk;
125  rule_t wrong_color_black_junk;
126  rule_t movetext_section;
127  rule_t PGN_game;
128  rule_t PGN_database;
129  // RULE DECLARATION END
130 
131  // Start rule of this grammar.
132  rule_t const& start(void) const { return PGN_database; }
133 
134  definition(PgnGrammar const& UNUSED_ARG(self))
135  {
136  using namespace boost::spirit::classic;
137 
138  leading_junk
139  =
140  * ((*~ch_p('\n') >>* ch_p('\n')) - tag_pair)
141  ;
142 
143  file // TRACE_PGN_SAN_INTERNAL
144  =
145  range_p('a', 'h')
146  ;
147 
148  rank // TRACE_PGN_SAN_INTERNAL
149  =
150  range_p('1', '8')
151  ;
152 
153  piece // TRACE_PGN_SAN_INTERNAL
154  =
155  ch_p('R')
156  | ch_p('N')
157  | ch_p('B')
158  | ch_p('Q')
159  | ch_p('K')
160  ;
161 
162  check // TRACE_PGN_SAN_INTERNAL
163  =
164  ch_p('+')
165  | ch_p('#')
166  ;
167 
168  punctuation_junk // TRACE_PGN_PUNCTUATION_JUNK
169  =
170  ch_p(',')
171  | ch_p(';')
172  ;
173 
174  tagname_begin
175  =
176  alnum_p
177  ;
178 
179  tagname_continuation
180  =
181  alnum_p
182  | ch_p('_')
183  ;
184 
185  printable // TRACE_PGN_PRINTABLE
186  =
187  range_p(32, 126)
188  | range_p(-96, -1)
189  ;
190 
191  printable_string // TRACE_PGN_PRINTABLE
192  =
193  ( range_p(35, 91)
194  | ch_p(' ')
195  | range_p(93, 126)
196  | ch_p('!')
197  | range_p(-96, -1)
198  )
199  | ( ch_p('\\') >> (ch_p('\\') | ch_p('"')))
200  ;
201 
202  printable_comment // TRACE_PGN_PRINTABLE
203  =
204  range_p(32, 124)
205  | ch_p('~')
206  | blank
207  | eol
208  | range_p(-96, -1)
209  ;
210 
211  promotion // TRACE_PGN_SAN_INTERNAL
212  =
213  ch_p('=') >> piece
214  ;
215 
216  blank // TRACE_PGN_WHITESPACE
217  =
218  ch_p(' ')
219  | ch_p('\t')
220  | ch_p('\v')
221  ;
222 
223  white_space // TRACE_PGN_WHITESPACE
224  =
225  blank >> !white_space
226  | eol >> !white_space
227  ;
228 
229  escaped_data // TRACE_PGN_WHITESPACE
230  =
231  ch_p('%') >>* (anychar_p - eol_p) >> eol_p
232  ;
233 
234  eol // TRACE_PGN_WHITESPACE
235  =
236  eol_p >>* escaped_data
237  ;
238 
239  integer // TRACE_PGN_INTEGER
240  =
241  uint3_p
242  ;
243 
244  square // TRACE_PGN_SAN_INTERNAL
245  =
246  file >> rank
247  ;
248 
249  disambiguation // TRACE_PGN_SAN_INTERNAL
250  =
251  file
252  | rank
253  | square
254  ;
255 
256  string
257  =
258  ch_p('"') >>* printable_string >> ch_p('"')
259  ;
260 
261  tag_name
262  =
263  tagname_begin >>* tagname_continuation
264  ;
265 
266  tag_value
267  =
268  string
269  ;
270 
271  game_termination
272  =
273  str_p("1-0")
274  | str_p("0-1")
275  | str_p("1/2-1/2")
276  | ch_p('*')
277  ;
278 
279  elipsis
280  =
281  str_p("..") >> !ch_p('.')
282  ;
283 
284  move_number_indication
285  =
286  integer >> (ch_p('.') | ch_p(' '))
287  ;
288 
289  SAN_move // TRACE_PGN_SAN_MOVE
290  =
291  ( piece >> !ch_p('x') >> square
292  | piece >> disambiguation >> !ch_p('x') >> square
293  | file >> ch_p('x') >> square >> !promotion
294  | square >> !promotion
295  | str_p("O-O-O")
296  | str_p("O-O")
297  | str_p("0-0-0")
298  | str_p("0-0")
299  )
300  >> !check
301  ;
302 
303  annotation
304  =
305  !(text_annotation1_junk >> !white_space) >>* (!comment >> (numeric_annotation_glyph | text_annotation2_junk) >> !white_space)
306  ;
307 
308  numeric_annotation_glyph// TRACE_PGN_ANNOTATION
309  =
310  ch_p('$') >> uint3_p
311  ;
312 
313  text_annotation1_junk // TRACE_PGN_ANNOTATION
314  =
315  ( ch_p('!')
316  | ch_p('?')
317  ) >>
318  !( ch_p('!')
319  | ch_p('?')
320  )
321  ;
322 
323  text_annotation2_junk // TRACE_PGN_ANNOTATION
324  =
325  ch_p('=') >> !( ch_p('-')
326  | ch_p('+')
327  )
328  | ch_p('-') >> ( ch_p('=')
329  | (!ch_p('/') >> ch_p('+'))
330  )
331  | ch_p('+') >> ( (!ch_p('/') >> ch_p('-'))
332  | ch_p('=')
333  )
334  | ch_p('~')
335  ;
336 
337  comment // TRACE_PGN_COMMENT
338  =
339  ch_p('{') >>* printable_comment >> ch_p('}') >> !white_space >> !comment
340  | ch_p(';') >>* printable >> eol >> !white_space >> !comment
341  | parenthesis_junk >> !white_space >> !comment
342  ;
343 
344  // Allow '(...)' to be be empty, if it contains a brace comment.
345  parenthesis_junk // TRACE_PGN_COMMENT
346  =
347  ch_p('(') >> !white_space >> ch_p('{') >>* printable_comment >> ch_p('}') >> !white_space >> ch_p(')')
348  ;
349 
350  tag_pair
351  =
352  ch_p('[') >> !white_space >> tag_name >> !white_space >> tag_value >> !white_space >> ch_p(']') >> !white_space
353  ;
354 
355  tag_section
356  =
357  tag_pair >> !tag_section
358  ;
359 
360  // Allow a SAN move to be directly followed by some punctuation,
361  // although such punctuation should really be part of a comment.
362  // Most notably this will cause a semicolon to NOT result the
363  // rest of line to be considered as a comment if the semi colon
364  // directly follows a SAN move.
365  //
366  // For example:
367  //
368  // {At which point he did} 11. b4; {and went to the bathroom.} 11. ... Rb8
369  //
370  // will be read as:
371  //
372  // {At which point he did} 11. b4 {; and went to the bathroom.} 11. ... Rb8
373  //
374  // Rather than,
375  //
376  // {At which point he did} 11. b4 { and went to the bathroom. 11. ... Rb8}
377  move
378  =
379  SAN_move >> !punctuation_junk >> !white_space >> !(annotation >> !white_space)
380  ;
381 
382  white_move
383  =
384  move_number_indication >> !white_space >> move >> !comment >>* recursive_variation_white
385  ;
386 
387  last_white_move
388  =
389  white_move
390  | arena_junk
391  ;
392 
393  arena_junk
394  =
395  move_number_indication >> !white_space >> elipsis >> !white_space >> comment
396  ;
397 
398  black_move
399  =
400  move_number_indication >> !white_space >> elipsis >> !white_space >> move >> !comment >>* recursive_variation_black
401  ;
402 
403  movetext_section_white
404  =
405  white_black_move >>* white_black_move >> !last_white_move
406  | last_white_move
407  ;
408 
409  movetext_section_black
410  =
411  black_move >> !movetext_section_white
412  ;
413 
414  white_black_move
415  =
416  move_number_indication >> !white_space >> move >> !comment >> move >> !comment >>* recursive_variation_black
417  | white_move >> black_move
418  ;
419 
420  recursive_variation_white
421  =
422  ch_p('(') >> !white_space >> !comment >> (movetext_section_white | wrong_color_black_junk) >> ch_p(')') >> !white_space >> !comment
423  ;
424 
425  recursive_variation_black
426  =
427  ch_p('(') >> !white_space >> !comment >> (movetext_section_black | wrong_color_white_junk) >> ch_p(')') >> !white_space >> !comment
428  ;
429 
430  wrong_color_white_junk
431  =
432  movetext_section_white
433  ;
434 
435  wrong_color_black_junk
436  =
437  movetext_section_black
438  ;
439 
440  movetext_section
441  =
442  !comment >> (movetext_section_white | movetext_section_black)
443  ;
444 
445  PGN_game
446  =
447  !tag_section >> !movetext_section >> game_termination >> !white_space >> !comment
448  ;
449 
450  PGN_database
451  =
452  !white_space >> leading_junk >>* PGN_game;
453  ;
454 
455  // DEBUG MACROS START
456  BOOST_SPIRIT_DEBUG_TRACE_RULE(leading_junk, TRACE_PGN_GRAMMAR);
457  BOOST_SPIRIT_DEBUG_TRACE_RULE(file, TRACE_PGN_GRAMMAR & TRACE_PGN_SAN_INTERNAL);
458  BOOST_SPIRIT_DEBUG_TRACE_RULE(rank, TRACE_PGN_GRAMMAR & TRACE_PGN_SAN_INTERNAL);
459  BOOST_SPIRIT_DEBUG_TRACE_RULE(piece, TRACE_PGN_GRAMMAR & TRACE_PGN_SAN_INTERNAL);
460  BOOST_SPIRIT_DEBUG_TRACE_RULE(check, TRACE_PGN_GRAMMAR & TRACE_PGN_SAN_INTERNAL);
461  BOOST_SPIRIT_DEBUG_TRACE_RULE(punctuation_junk, TRACE_PGN_GRAMMAR & TRACE_PGN_PUNCTUATION_JUNK);
462  BOOST_SPIRIT_DEBUG_TRACE_RULE(tagname_begin, TRACE_PGN_GRAMMAR);
463  BOOST_SPIRIT_DEBUG_TRACE_RULE(tagname_continuation, TRACE_PGN_GRAMMAR);
464  BOOST_SPIRIT_DEBUG_TRACE_RULE(printable, TRACE_PGN_GRAMMAR & TRACE_PGN_PRINTABLE);
465  BOOST_SPIRIT_DEBUG_TRACE_RULE(printable_string, TRACE_PGN_GRAMMAR & TRACE_PGN_PRINTABLE);
466  BOOST_SPIRIT_DEBUG_TRACE_RULE(printable_comment, TRACE_PGN_GRAMMAR & TRACE_PGN_PRINTABLE);
467  BOOST_SPIRIT_DEBUG_TRACE_RULE(promotion, TRACE_PGN_GRAMMAR & TRACE_PGN_SAN_INTERNAL);
468  BOOST_SPIRIT_DEBUG_TRACE_RULE(blank, TRACE_PGN_GRAMMAR & TRACE_PGN_WHITESPACE);
469  BOOST_SPIRIT_DEBUG_TRACE_RULE(white_space, TRACE_PGN_GRAMMAR & TRACE_PGN_WHITESPACE);
470  BOOST_SPIRIT_DEBUG_TRACE_RULE(escaped_data, TRACE_PGN_GRAMMAR & TRACE_PGN_WHITESPACE);
471  BOOST_SPIRIT_DEBUG_TRACE_RULE(eol, TRACE_PGN_GRAMMAR & TRACE_PGN_WHITESPACE);
472  BOOST_SPIRIT_DEBUG_TRACE_RULE(integer, TRACE_PGN_GRAMMAR & TRACE_PGN_INTEGER);
473  BOOST_SPIRIT_DEBUG_TRACE_RULE(square, TRACE_PGN_GRAMMAR & TRACE_PGN_SAN_INTERNAL);
474  BOOST_SPIRIT_DEBUG_TRACE_RULE(disambiguation, TRACE_PGN_GRAMMAR & TRACE_PGN_SAN_INTERNAL);
475  BOOST_SPIRIT_DEBUG_TRACE_RULE(string, TRACE_PGN_GRAMMAR);
476  BOOST_SPIRIT_DEBUG_TRACE_RULE(tag_name, TRACE_PGN_GRAMMAR);
477  BOOST_SPIRIT_DEBUG_TRACE_RULE(tag_value, TRACE_PGN_GRAMMAR);
478  BOOST_SPIRIT_DEBUG_TRACE_RULE(game_termination, TRACE_PGN_GRAMMAR);
479  BOOST_SPIRIT_DEBUG_TRACE_RULE(elipsis, TRACE_PGN_GRAMMAR);
480  BOOST_SPIRIT_DEBUG_TRACE_RULE(move_number_indication, TRACE_PGN_GRAMMAR);
481  BOOST_SPIRIT_DEBUG_TRACE_RULE(SAN_move, TRACE_PGN_GRAMMAR & TRACE_PGN_SAN_MOVE);
482  BOOST_SPIRIT_DEBUG_TRACE_RULE(annotation, TRACE_PGN_GRAMMAR);
483  BOOST_SPIRIT_DEBUG_TRACE_RULE(numeric_annotation_glyph, TRACE_PGN_GRAMMAR & TRACE_PGN_ANNOTATION);
484  BOOST_SPIRIT_DEBUG_TRACE_RULE(text_annotation1_junk, TRACE_PGN_GRAMMAR & TRACE_PGN_ANNOTATION);
485  BOOST_SPIRIT_DEBUG_TRACE_RULE(text_annotation2_junk, TRACE_PGN_GRAMMAR & TRACE_PGN_ANNOTATION);
486  BOOST_SPIRIT_DEBUG_TRACE_RULE(comment, TRACE_PGN_GRAMMAR & TRACE_PGN_COMMENT);
487  BOOST_SPIRIT_DEBUG_TRACE_RULE(parenthesis_junk, TRACE_PGN_GRAMMAR & TRACE_PGN_COMMENT);
488  BOOST_SPIRIT_DEBUG_TRACE_RULE(tag_pair, TRACE_PGN_GRAMMAR);
489  BOOST_SPIRIT_DEBUG_TRACE_RULE(tag_section, TRACE_PGN_GRAMMAR);
490  BOOST_SPIRIT_DEBUG_TRACE_RULE(move, TRACE_PGN_GRAMMAR);
491  BOOST_SPIRIT_DEBUG_TRACE_RULE(white_move, TRACE_PGN_GRAMMAR);
492  BOOST_SPIRIT_DEBUG_TRACE_RULE(last_white_move, TRACE_PGN_GRAMMAR);
493  BOOST_SPIRIT_DEBUG_TRACE_RULE(arena_junk, TRACE_PGN_GRAMMAR);
494  BOOST_SPIRIT_DEBUG_TRACE_RULE(black_move, TRACE_PGN_GRAMMAR);
495  BOOST_SPIRIT_DEBUG_TRACE_RULE(movetext_section_white, TRACE_PGN_GRAMMAR);
496  BOOST_SPIRIT_DEBUG_TRACE_RULE(movetext_section_black, TRACE_PGN_GRAMMAR);
497  BOOST_SPIRIT_DEBUG_TRACE_RULE(white_black_move, TRACE_PGN_GRAMMAR);
498  BOOST_SPIRIT_DEBUG_TRACE_RULE(recursive_variation_white, TRACE_PGN_GRAMMAR);
499  BOOST_SPIRIT_DEBUG_TRACE_RULE(recursive_variation_black, TRACE_PGN_GRAMMAR);
500  BOOST_SPIRIT_DEBUG_TRACE_RULE(wrong_color_white_junk, TRACE_PGN_GRAMMAR);
501  BOOST_SPIRIT_DEBUG_TRACE_RULE(wrong_color_black_junk, TRACE_PGN_GRAMMAR);
502  BOOST_SPIRIT_DEBUG_TRACE_RULE(movetext_section, TRACE_PGN_GRAMMAR);
503  BOOST_SPIRIT_DEBUG_TRACE_RULE(PGN_game, TRACE_PGN_GRAMMAR);
504  BOOST_SPIRIT_DEBUG_TRACE_RULE(PGN_database, TRACE_PGN_GRAMMAR);
505  // DEBUG MACROS END
506  }
507  };
508 };
509 
510 } // namespace grammar
511 } // namespace pgn
512 } // namespace cwchess
513 
514 #endif // PGNGRAMMAR_H
A namespace for all chess related objects that are not related to the GUI.
Definition: Array.h:39

Copyright © 2006 - 2010 Carlo Wood.  All rights reserved.