Updated all files to GPL version 3.
[xboard.git] / parser.l
1 %a 10000\r
2 %o 10000\r
3 %e 2000\r
4 %k 2500\r
5 %p 7000\r
6 %n 1000\r
7 %{\r
8 /*\r
9  * parser.l -- lex parser of algebraic chess moves for XBoard\r
10  * $Id: parser.l,v 2.1 2003/10/27 19:21:00 mann Exp $\r
11  *\r
12  * Copyright 1991 by Digital Equipment Corporation, Maynard,\r
13  * Massachusetts.  Enhancements Copyright\r
14  * 1992-2001,2002,2003,2004,2005,2006,2007,2008,2009 Free Software\r
15  * Foundation, Inc.\r
16  *\r
17  * The following terms apply to Digital Equipment Corporation's copyright\r
18  * interest in XBoard:\r
19  * ------------------------------------------------------------------------\r
20  * All Rights Reserved\r
21  *\r
22  * Permission to use, copy, modify, and distribute this software and its\r
23  * documentation for any purpose and without fee is hereby granted,\r
24  * provided that the above copyright notice appear in all copies and that\r
25  * both that copyright notice and this permission notice appear in\r
26  * supporting documentation, and that the name of Digital not be\r
27  * used in advertising or publicity pertaining to distribution of the\r
28  * software without specific, written prior permission.\r
29  *\r
30  * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING\r
31  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL\r
32  * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR\r
33  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,\r
34  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,\r
35  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS\r
36  * SOFTWARE.\r
37  * ------------------------------------------------------------------------\r
38  *\r
39  * The following terms apply to the enhanced version of XBoard\r
40  * distributed by the Free Software Foundation:\r
41  * ------------------------------------------------------------------------\r
42  *\r
43  * GNU XBoard is free software: you can redistribute it and/or modify\r
44  * it under the terms of the GNU General Public License as published by\r
45  * the Free Software Foundation, either version 3 of the License, or (at\r
46  * your option) any later version.\r
47  *\r
48  * GNU XBoard is distributed in the hope that it will be useful, but\r
49  * WITHOUT ANY WARRANTY; without even the implied warranty of\r
50  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
51  * General Public License for more details.\r
52  *\r
53  * You should have received a copy of the GNU General Public License\r
54  * along with this program. If not, see http://www.gnu.org/licenses/.  \r
55  *\r
56  *------------------------------------------------------------------------\r
57  ** See the file ChangeLog for a revision history.  */\r
58 \r
59 /* This parser handles all forms of promotion.\r
60  * The parser resolves ambiguous moves by searching and check-testing.\r
61  * It also parses comments of the form [anything] or (anything).\r
62  *\r
63  * [HGM] Parser extensively modified for bigger boards, Shogi-like syntax,\r
64  * and unknow pieces. All pieces are now mandatory upper case, but can be\r
65  * any letter A-Z. Files must be lower case (as before), but can run upto 'l'.\r
66  * Ranks can be 0-9. The parser returns 0 for off-board files and ranks.\r
67  * For an unknown piece (as mover or promotion piece) it returns\r
68  * IllegalMove, like it does when the piece doesn't match.\r
69  * Promotions can now also be appended Shogi-style, a bare '=' or '+',\r
70  * and this is then returned as promotion character. The piece indicator\r
71  * can be prefixed by a '+' to indicate it is a promoted piece.\r
72  */\r
73 \r
74 #include "config.h"\r
75 \r
76 #define NO_CONSTRAINT   -1\r
77 #undef YYLMAX\r
78 #define YYLMAX                  4096\r
79 #define UNPUT_BUF_SIZE          YYLMAX\r
80 \r
81 #ifdef FLEX_SCANNER\r
82 /* yytext is probably a char*, but could be a char[].  yy_text is set\r
83    in YY_DECL below, because if yytext is a char*, its value is not\r
84    constant. */\r
85 char *yy_text;\r
86 #else /*!FLEX_SCANNER*/\r
87 /* yytext is definitely a char[], so yy_text can be set here, statically. */\r
88 char *yy_text = (char *) yytext;\r
89 #endif\r
90 \r
91 #ifdef FLEX_SCANNER\r
92 /* This is flex */\r
93 /* [AP] use prototypes in function declarations */\r
94 #define YY_USE_PROTOS\r
95 \r
96 #ifdef YY_USE_PROTOS\r
97 #define YY_PROTO(proto) proto\r
98 #else\r
99 #define YY_PROTO(proto) ()\r
100 #endif\r
101 /* end of [AP] fix */\r
102 \r
103 #undef YY_INPUT\r
104 #define YY_INPUT(buf, result, max_size) my_yy_input(buf, &result, max_size)\r
105 #undef YY_DECL\r
106 #define YY_DECL                     \\r
107     int _yylex YY_PROTO((void));    \\r
108     int yylex YY_PROTO((void))      \\r
109     {                               \\r
110         int result = _yylex();      \\r
111         yy_text = (char *) yytext;  \\r
112         return(result);             \\r
113     }                               \\r
114     int _yylex YY_PROTO((void))\r
115 #else\r
116 /* This is lex */\r
117 #undef input\r
118 #undef output\r
119 #undef unput\r
120 #endif\r
121 \r
122 /* The includes must be here, below the #undef input */\r
123 \r
124 #include <ctype.h>\r
125 \r
126 #if STDC_HEADERS\r
127 # include <stdlib.h>\r
128 # include <string.h>\r
129 #else /* not STDC_HEADERS */\r
130 # if HAVE_STRING_H\r
131 #  include <string.h>\r
132 # else /* not HAVE_STRING_H */\r
133 #  include <strings.h>\r
134 # endif /* not HAVE_STRING_H */\r
135 #endif /* not STDC_HEADERS */\r
136 \r
137 #if HAVE_UNISTD_H\r
138 # include <unistd.h>\r
139 #endif\r
140 \r
141 #if defined(_amigados)\r
142 # include <errno.h>\r
143 # if HAVE_FCNTL_H\r
144 #  include <fcntl.h>    /*  isatty() prototype  */\r
145 # endif /*  HAVE_FCNTL_H        */\r
146 #endif  /*  defined(_amigados)  */\r
147 \r
148 #include "common.h"\r
149 #include "backend.h"\r
150 #include "frontend.h"\r
151 #include "parser.h"\r
152 #include "moves.h"\r
153 \r
154 extern int PosFlags P((int));\r
155 \r
156 extern Board    boards[MAX_MOVES];\r
157 int             yyboardindex;\r
158 int             yyskipmoves = FALSE;\r
159 char            currentMoveString[YYLMAX];\r
160 #ifndef FLEX_SCANNER\r
161 char            unputBuffer[UNPUT_BUF_SIZE];\r
162 int             unputCount = 0;\r
163 #endif\r
164 \r
165 #ifdef FLEX_SCANNER\r
166 void my_yy_input P((char *buf, int *result, int max_size));\r
167 #else /*!FLEX_SCANNER*/\r
168 static int input P((void));\r
169 static void output P((int ch));\r
170 static void unput P((int ch));\r
171 int yylook P((void));\r
172 int yyback P((int *, int));\r
173 #endif\r
174 #undef yywrap\r
175 int yywrap P((void));\r
176 extern void CopyBoard P((Board to, Board from));\r
177 \r
178 %}\r
179 %%\r
180 \r
181 "+"?[A-Z][/]?[a-l][0-9][xX:-]?[a-l][0-9]((=?\(?[A-Z]\)?)|=)? {\r
182     /*\r
183      * Fully-qualified algebraic move, possibly with promotion\r
184      */\r
185     int skip1 = 0, skip2 = 0, skip3 = 0, promoted = 0;\r
186     ChessSquare piece;\r
187     ChessMove result;\r
188     char c;\r
189     \r
190     if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */\r
191 \r
192     if (yytext[0] == '+') skip1 = skip3 = promoted = 1; /* [HGM] Shogi promoted */\r
193 \r
194     /* remove the / */\r
195     if (yytext[1+skip1] == '/')  skip1++; \r
196     \r
197     /* remove the [xX:-] */\r
198     if ((yytext[3+skip1] == 'x') || (yytext[3+skip1] == 'X') ||\r
199         (yytext[3+skip1] == '-') || (yytext[3+skip1] == ':')) skip2 = 1;\r
200     \r
201     currentMoveString[0] = yytext[1+skip1];\r
202     currentMoveString[1] = yytext[2+skip1];\r
203     currentMoveString[2] = yytext[3+skip1+skip2];\r
204     currentMoveString[3] = yytext[4+skip1+skip2];\r
205     currentMoveString[4] = NULLCHAR;\r
206     \r
207     if (appData.debugMode) {\r
208         fprintf(debugFP, "Parser Qa1b2: yyleng=%d\n",\r
209         yyleng);\r
210     }\r
211 \r
212     if (yyleng-skip1-skip2 > 5) { char c;\r
213         if (yytext[yyleng-1] == ')') {\r
214             c = currentMoveString[4] = ToLower(yytext[yyleng-2]);\r
215         } else {\r
216             c = currentMoveString[4] = ToLower(yytext[yyleng-1]);\r
217         }\r
218         currentMoveString[5] = NULLCHAR;\r
219         if(c != '=' && c != '+' && CharToPiece(c) == EmptySquare)\r
220             return IllegalMove; /* [HGM] promotion to invalid piece */\r
221     }\r
222 \r
223     if (appData.debugMode) {\r
224         fprintf(debugFP, "parser: %s\n", currentMoveString);\r
225     }\r
226     /* [HGM] do not allow values beyond board size */\r
227     if(currentMoveString[1] - ONE >= BOARD_HEIGHT ||\r
228        currentMoveString[1] - ONE <  0            ||\r
229        currentMoveString[0] - AAA >= BOARD_RGHT   ||\r
230        currentMoveString[3] - ONE >= BOARD_HEIGHT ||\r
231        currentMoveString[3] - ONE <  0            ||\r
232        currentMoveString[2] - AAA >= BOARD_RGHT   ||\r
233        currentMoveString[0] - AAA <  BOARD_LEFT   ||\r
234        currentMoveString[2] - AAA <  BOARD_LEFT     )\r
235       return 0;\r
236 \r
237     piece = boards[yyboardindex]\r
238       [currentMoveString[1] - ONE][currentMoveString[0] - AAA];\r
239     if(promoted) piece = (ChessSquare) (DEMOTED piece);\r
240     c = PieceToChar(piece);\r
241     if(c == '~') c = PieceToChar((ChessSquare) (DEMOTED piece));\r
242     if (ToLower(yytext[skip3]) != ToLower(c))\r
243       return (int) IllegalMove;\r
244 \r
245     result = LegalityTest(boards[yyboardindex],\r
246                           PosFlags(yyboardindex), EP_UNKNOWN,\r
247                           initialRights, /* [HGM] assume all castlings allowed */\r
248                           currentMoveString[1] - ONE,\r
249                           currentMoveString[0] - AAA,\r
250                           currentMoveString[3] - ONE,\r
251                           currentMoveString[2] - AAA,\r
252                           currentMoveString[4]);\r
253 \r
254     if (currentMoveString[4] == NULLCHAR &&\r
255         (result == WhitePromotionKnight || result == BlackPromotionKnight ||\r
256          result == WhitePromotionQueen  || result == BlackPromotionQueen)) {\r
257         currentMoveString[4] = PieceToChar(BlackQueen);\r
258         currentMoveString[5] = NULLCHAR;\r
259     }\r
260 \r
261     return (int) result;\r
262 }\r
263 \r
264 [a-l][0-9][xX:-]?[a-l][0-9]((=?\(?[A-Za-z]\)?)|=)?      {\r
265     /*\r
266      * Simple algebraic move, possibly with promotion\r
267      * [HGM] Engine moves are received in this format, with lower-case promoChar!\r
268      */\r
269     int skip = 0;\r
270     ChessMove result;\r
271 \r
272     if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */\r
273 \r
274     /* remove the [xX:-] */\r
275     if ((yytext[2] == 'x') || (yytext[2] == 'X') ||\r
276         (yytext[2] == '-') || (yytext[2] == ':')) skip = 1;\r
277 \r
278     currentMoveString[0] = yytext[0];\r
279     currentMoveString[1] = yytext[1];\r
280     currentMoveString[2] = yytext[2+skip];\r
281     currentMoveString[3] = yytext[3+skip];\r
282     currentMoveString[4] = NULLCHAR;\r
283 \r
284     if (yyleng-skip > 4) { char c;\r
285         if (yytext[yyleng-1] == ')') {\r
286             c = currentMoveString[4] = ToLower(yytext[yyleng-2]);\r
287         } else {\r
288             c = currentMoveString[4] = ToLower(yytext[yyleng-1]);\r
289         }\r
290         currentMoveString[5] = NULLCHAR;\r
291         if(c != '=' && c != '+' && CharToPiece(c) == EmptySquare)\r
292             return IllegalMove;\r
293     }\r
294 \r
295     /* [HGM] do not allow values beyond board size */\r
296     if(currentMoveString[1] - ONE >= BOARD_HEIGHT ||\r
297        currentMoveString[1] - ONE <  0            ||\r
298        currentMoveString[0] - AAA >= BOARD_RGHT   ||\r
299        currentMoveString[3] - ONE >= BOARD_HEIGHT ||\r
300        currentMoveString[3] - ONE <  0            ||\r
301        currentMoveString[2] - AAA >= BOARD_RGHT   ||\r
302        currentMoveString[0] - AAA <  BOARD_LEFT   ||\r
303        currentMoveString[2] - AAA <  BOARD_LEFT     )\r
304       return 0;\r
305 \r
306     result = LegalityTest(boards[yyboardindex],\r
307                           PosFlags(yyboardindex), EP_UNKNOWN,\r
308                           initialRights, /* [HGM] assume all castlings allowed */\r
309                           currentMoveString[1] - ONE,\r
310                           currentMoveString[0] - AAA,\r
311                           currentMoveString[3] - ONE,\r
312                           currentMoveString[2] - AAA,\r
313                           currentMoveString[4]);\r
314 \r
315     if (currentMoveString[4] == NULLCHAR &&\r
316         (result == WhitePromotionKnight || result == BlackPromotionKnight ||\r
317          result == WhitePromotionQueen  || result == BlackPromotionQueen)) {\r
318         if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier)\r
319             currentMoveString[4] = PieceToChar(BlackFerz);\r
320         else if(gameInfo.variant == VariantGreat)\r
321             currentMoveString[4] = PieceToChar(BlackMan);\r
322         else\r
323             currentMoveString[4] = PieceToChar(BlackQueen);\r
324         currentMoveString[5] = NULLCHAR;\r
325     }\r
326 \r
327     return (int) result;\r
328 }\r
329 \r
330 [a-l][0-9]((=?\(?[A-Z]\)?)|=)?       {\r
331     /*\r
332      * Pawn move, possibly with promotion\r
333      */\r
334     DisambiguateClosure cl;\r
335     int skip = 0; char c;\r
336 \r
337     if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */\r
338 \r
339     /* remove the =() */\r
340     if (yytext[2] == '=' && yytext[3] != NULLCHAR) skip++;\r
341     if (yytext[2+skip] == '(') skip++;\r
342 \r
343     cl.pieceIn = WhiteOnMove(yyboardindex) ? WhitePawn : BlackPawn;\r
344     cl.rfIn = -1;\r
345     cl.ffIn = yytext[0] - AAA;\r
346     cl.rtIn = yytext[1] - ONE;\r
347     cl.ftIn = yytext[0] - AAA;\r
348     c = cl.promoCharIn = yytext[2+skip];\r
349 \r
350     /* [HGM] do not allow values beyond board size */\r
351     if(cl.rtIn >= BOARD_HEIGHT ||\r
352        cl.rtIn <  0            ||\r
353        cl.ffIn >= BOARD_RGHT   ||\r
354        cl.ftIn <  BOARD_LEFT     )\r
355       return 0;\r
356 \r
357     if(c != '=' && c != '+' && c != NULLCHAR && CharToPiece(c) == EmptySquare)\r
358       return IllegalMove;\r
359 \r
360 \r
361     Disambiguate(boards[yyboardindex],\r
362                  PosFlags(yyboardindex), EP_UNKNOWN, &cl);\r
363 \r
364     currentMoveString[0] = cl.ff + AAA;\r
365     currentMoveString[1] = cl.rf + ONE;\r
366     currentMoveString[2] = cl.ft + AAA;\r
367     currentMoveString[3] = cl.rt + ONE;\r
368     currentMoveString[4] = cl.promoChar;\r
369     currentMoveString[5] = NULLCHAR;\r
370 \r
371     return (int) cl.kind;\r
372 }\r
373 \r
374 \r
375 (ab|bc|cd|de|ef|fg|gh|hi|ij|jk|kl|lk|kj|ji|ih|hg|gf|fe|ed|dc|cb|ba|aa|bb|cc|dd|ee|ff|gg|hh|ii|jj|kk|ll|([a-l][xX:-][a-l]))((=?\(?[A-Z]\)?)|ep|"e.p."|=)? {\r
376     /*\r
377      * Pawn capture, possibly with promotion, possibly ambiguous\r
378      */\r
379     DisambiguateClosure cl;\r
380     int skip1 = 0, skip2 = 0; char c;\r
381 \r
382     if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */\r
383 \r
384     /* remove trailing ep or e.p. (nonstandard PGN) */\r
385     if (yytext[yyleng-1] == 'p') {\r
386       yyleng -= 2;\r
387       yytext[yyleng] = NULLCHAR;\r
388     } else if (yytext[yyleng-1] == '.') {\r
389       yyleng -= 4;\r
390       yytext[yyleng] = NULLCHAR;\r
391     }\r
392 \r
393     /* remove the [xX:-] and =() */\r
394     if ((yytext[1] == 'x') || (yytext[1] == 'X')\r
395         || (yytext[1] == ':') || (yytext[1] == '-')) skip1 = 1;\r
396     if (yytext[2+skip1] == '=' && yytext[3+skip1] != NULLCHAR) skip2++;\r
397     if (yytext[2+skip1+skip2] == '(') skip2++;\r
398 \r
399     cl.pieceIn = WhiteOnMove(yyboardindex) ? WhitePawn : BlackPawn;\r
400     cl.rfIn = -1;\r
401     cl.ffIn = yytext[0] - AAA;\r
402     cl.rtIn = -1;\r
403     cl.ftIn = yytext[1+skip1] - AAA;\r
404     c = cl.promoCharIn = yytext[2+skip1+skip2];\r
405 \r
406     /* [HGM] do not allow values beyond board size */\r
407     if(cl.ffIn >= BOARD_RGHT  ||\r
408        cl.ffIn <  BOARD_LEFT  ||\r
409        cl.ftIn >= BOARD_RGHT  ||\r
410        cl.ftIn <  BOARD_LEFT     )\r
411       return 0;\r
412 \r
413     if(c != '=' && c != '+' && c != NULLCHAR && CharToPiece(c) == EmptySquare)\r
414       return IllegalMove;\r
415 \r
416     Disambiguate(boards[yyboardindex],\r
417                  PosFlags(yyboardindex), EP_UNKNOWN, &cl);\r
418 \r
419     currentMoveString[0] = cl.ff + AAA;\r
420     currentMoveString[1] = cl.rf + ONE;\r
421     currentMoveString[2] = cl.ft + AAA;\r
422     currentMoveString[3] = cl.rt + ONE;\r
423     currentMoveString[4] = cl.promoChar;\r
424     currentMoveString[5] = NULLCHAR;\r
425 \r
426     return (int) cl.kind;\r
427 }\r
428 \r
429 [a-l][xX:]?[a-l][0-9]((=?\(?[A-Z]\)?)|ep|"e.p."|=)? {\r
430     /*\r
431      * unambiguously abbreviated Pawn capture, possibly with promotion\r
432      */\r
433     int skip = 0;\r
434     ChessMove result; char c;\r
435 \r
436     if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */\r
437 \r
438     /* remove trailing ep or e.p. (nonstandard PGN) */\r
439     if (yytext[yyleng-1] == 'p') {\r
440       yyleng -= 2;\r
441       yytext[yyleng] = NULLCHAR;\r
442     } else if (yytext[yyleng-1] == '.') {\r
443       yyleng -= 4;\r
444       yytext[yyleng] = NULLCHAR;\r
445     }\r
446 \r
447     /* remove the [xX:-] */\r
448     if ((yytext[1] == 'x') || (yytext[1] == 'X')\r
449         || (yytext[1] == ':') || (yytext[1] == '-')) skip = 1;\r
450 \r
451     currentMoveString[0] = yytext[0];\r
452     currentMoveString[2] = yytext[1+skip];\r
453     currentMoveString[3] = yytext[2+skip];\r
454 \r
455     /* [HGM] do not allow values beyond board size */\r
456     if(currentMoveString[0] - AAA >= BOARD_RGHT   ||\r
457        currentMoveString[3] - ONE >= BOARD_HEIGHT ||\r
458        currentMoveString[3] - ONE <  0            ||\r
459        currentMoveString[2] - AAA >= BOARD_RGHT   ||\r
460        currentMoveString[0] - AAA <  BOARD_LEFT   ||\r
461        currentMoveString[2] - AAA <  BOARD_LEFT     )\r
462       return 0;\r
463 \r
464     if (gameInfo.variant == VariantXiangqi && /* [HGM] In Xiangqi rank stays same */\r
465          currentMoveString[0] != currentMoveString[2] ) {\r
466         currentMoveString[1] = yytext[2+skip];\r
467     } else \r
468     if (WhiteOnMove(yyboardindex)) {\r
469         if (yytext[2+skip] == ONE) return (int) ImpossibleMove;\r
470         currentMoveString[1] = yytext[2+skip] - 1;\r
471     } else {\r
472         currentMoveString[1] = currentMoveString[3] + 1;\r
473         if (currentMoveString[3] == ONE+BOARD_HEIGHT-1) return (int) ImpossibleMove;\r
474     }\r
475     if (yyleng-skip > 3) {\r
476         if (yytext[yyleng-1] == ')')\r
477           c = currentMoveString[4] = ToLower(yytext[yyleng-2]);\r
478         else\r
479           c = currentMoveString[4] = ToLower(yytext[yyleng-1]);\r
480         currentMoveString[5] = NULLCHAR;\r
481         if(c != '=' && c != '+' && CharToPiece(c) == EmptySquare)\r
482             return IllegalMove;\r
483     } else {\r
484         currentMoveString[4] = NULLCHAR;\r
485     }\r
486 \r
487     result = LegalityTest(boards[yyboardindex],\r
488                           PosFlags(yyboardindex), EP_UNKNOWN,\r
489                           initialRights, /* [HGM] assume all castlings allowed */\r
490                           currentMoveString[1] - ONE,\r
491                           currentMoveString[0] - AAA,\r
492                           currentMoveString[3] - ONE,\r
493                           currentMoveString[2] - AAA,\r
494                           currentMoveString[4]);\r
495 \r
496     if (currentMoveString[4] == NULLCHAR &&\r
497         (result == WhitePromotionQueen  || result == BlackPromotionQueen ||\r
498          result == WhitePromotionKnight || result == BlackPromotionKnight)) {\r
499         currentMoveString[4] = PieceToChar(BlackQueen);\r
500         // [HGM] shatranj: take care of variants without Queen\r
501         if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier)\r
502             currentMoveString[4] = PieceToChar(BlackFerz);\r
503         if(gameInfo.variant == VariantGreat)\r
504             currentMoveString[4] = PieceToChar(BlackMan);\r
505         currentMoveString[5] = NULLCHAR;\r
506     }\r
507 \r
508     if (result != IllegalMove) return (int) result;\r
509 \r
510     /* Special case: improperly written en passant capture */\r
511     if (WhiteOnMove(yyboardindex)) {\r
512         if (currentMoveString[3] == '5') {\r
513             currentMoveString[1] = '5';\r
514             currentMoveString[3] = '6';\r
515         } else {\r
516             return (int) IllegalMove;\r
517         }\r
518     } else {\r
519         if (currentMoveString[3] == '4') {\r
520             currentMoveString[1] = '4';\r
521             currentMoveString[3] = '3';\r
522         } else {\r
523             return (int) IllegalMove;\r
524         }\r
525     }\r
526 \r
527     result = LegalityTest(boards[yyboardindex],\r
528                           PosFlags(yyboardindex), EP_UNKNOWN,\r
529                           initialRights, /* [HGM] assume all castlings allowed */\r
530                           currentMoveString[1] - ONE,\r
531                           currentMoveString[0] - AAA,\r
532                           currentMoveString[3] - ONE,\r
533                           currentMoveString[2] - AAA,\r
534                           currentMoveString[4]);\r
535 \r
536     if (result == WhiteCapturesEnPassant || result == BlackCapturesEnPassant)\r
537       return (int) result;\r
538     else\r
539       return (int) IllegalMove;\r
540 }\r
541 \r
542 "+"?[A-Z][xX:-]?[a-l][0-9]=?  {\r
543     /*\r
544      * piece move, possibly ambiguous\r
545      */\r
546     DisambiguateClosure cl;\r
547     int skip = 0, skip2 = 0, promoted = 0;\r
548 \r
549     if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */\r
550 \r
551     if(yytext[0] == '+') promoted = skip = skip2 = 1;\r
552 \r
553     /* remove the [xX:-] */\r
554     if ((yytext[1+skip] == 'x') || (yytext[1+skip] == 'X')\r
555         || (yytext[1+skip] == ':') || (yytext[1+skip] == '-')) skip++;\r
556 \r
557     if (WhiteOnMove(yyboardindex)) {\r
558         cl.pieceIn = CharToPiece(ToUpper(yytext[skip2]));\r
559     } else {\r
560         cl.pieceIn = CharToPiece(ToLower(yytext[skip2]));\r
561     }\r
562     if(promoted) cl.pieceIn = (ChessSquare) (PROMOTED cl.pieceIn);\r
563 \r
564     cl.rfIn = -1;\r
565     cl.ffIn = -1;\r
566     cl.rtIn = yytext[2+skip] - ONE;\r
567     cl.ftIn = yytext[1+skip] - AAA;\r
568     cl.promoCharIn = NULLCHAR;\r
569 \r
570     if(yyleng-skip > 3) /* [HGM] can have Shogi-style promotion */\r
571         cl.promoCharIn = yytext[yyleng-1];\r
572 \r
573     if (appData.debugMode) {\r
574         fprintf(debugFP, "Parser Qa1: yyleng=%d,  %d(%d,%d)-(%d,%d) = %d (%c)\n",\r
575         yyleng,\r
576         cl.pieceIn,cl.ffIn,cl.rfIn,cl.ftIn,cl.rtIn,cl.promoCharIn,cl.promoCharIn?cl.promoCharIn:' ');\r
577     }\r
578 \r
579     /* [HGM] but do not allow values beyond board size */\r
580     if(cl.rtIn >= BOARD_HEIGHT ||\r
581        cl.rtIn <  0            ||\r
582        cl.ftIn >= BOARD_RGHT   ||\r
583        cl.ftIn <  BOARD_LEFT     )\r
584       return 0;\r
585 \r
586     Disambiguate(boards[yyboardindex],\r
587                  PosFlags(yyboardindex), EP_UNKNOWN, &cl);\r
588 \r
589     currentMoveString[0] = cl.ff + AAA;\r
590     currentMoveString[1] = cl.rf + ONE;\r
591     currentMoveString[2] = cl.ft + AAA;\r
592     currentMoveString[3] = cl.rt + ONE;\r
593     currentMoveString[4] = cl.promoChar;\r
594     currentMoveString[5] = NULLCHAR;\r
595 \r
596     return (int) cl.kind;\r
597 }\r
598 \r
599 "+"?[A-Z][a-l0-9][xX:-]?[a-l][0-9]=?   {\r
600     /*\r
601      * piece move with rank or file disambiguator\r
602      */\r
603     DisambiguateClosure cl;\r
604     int skip = 0, skip2 = 0; int promoted=0;\r
605 \r
606     if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */\r
607 \r
608     if(yytext[0]=='+') promoted = skip = skip2 = 1;\r
609 \r
610     /* remove the [xX:-] */\r
611     if ((yytext[2+skip] == 'x') || (yytext[2+skip] == 'X')\r
612         || (yytext[2+skip] == ':') || (yytext[2+skip] == '-')) skip++;\r
613 \r
614     if (WhiteOnMove(yyboardindex)) {\r
615         cl.pieceIn = CharToPiece(ToUpper(yytext[skip2]));\r
616     } else {\r
617         cl.pieceIn = CharToPiece(ToLower(yytext[skip2]));\r
618     }\r
619     if(promoted) cl.pieceIn = (ChessSquare) (PROMOTED cl.pieceIn);\r
620 \r
621     if (isalpha(yytext[1+skip2])) {\r
622         cl.rfIn = -1;\r
623         cl.ffIn = yytext[1+skip2] - AAA;\r
624        \r
625         if(cl.ffIn >= BOARD_RGHT ||\r
626            cl.ffIn <  BOARD_LEFT   ) return 0;\r
627     } else {\r
628         cl.rfIn = yytext[1+skip2] - ONE;\r
629         cl.ffIn = -1;\r
630         if(cl.rfIn >= BOARD_HEIGHT ||\r
631            cl.rfIn <  0) return 0;\r
632     }\r
633     cl.rtIn = yytext[3+skip] - ONE;\r
634     cl.ftIn = yytext[2+skip] - AAA;\r
635     cl.promoCharIn = NULLCHAR;\r
636 \r
637     if(yyleng-skip > 4) /* [HGM] can have Shogi-style promotion */\r
638         cl.promoCharIn = yytext[yyleng-1];\r
639 \r
640     /* [HGM] do not allow values beyond board size */\r
641     if(cl.rtIn >= BOARD_HEIGHT ||\r
642        cl.rtIn <  0            ||\r
643        cl.ftIn >= BOARD_RGHT   ||\r
644        cl.ftIn <  BOARD_LEFT     )\r
645       return 0;\r
646 \r
647     Disambiguate(boards[yyboardindex],\r
648                  PosFlags(yyboardindex), EP_UNKNOWN, &cl);\r
649 \r
650     currentMoveString[0] = cl.ff + AAA;\r
651     currentMoveString[1] = cl.rf + ONE;\r
652     currentMoveString[2] = cl.ft + AAA;\r
653     currentMoveString[3] = cl.rt + ONE;\r
654     currentMoveString[4] = cl.promoChar;\r
655     currentMoveString[5] = NULLCHAR;\r
656 \r
657     return (int) cl.kind;\r
658 }\r
659 \r
660 000|0-0-0|ooo|OOO|o-o-o|O-O-O   {\r
661     int rf, ff, rt, ft;\r
662 \r
663     if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */\r
664 \r
665     /* [HGM] all squares referenced to board edges in stead of absolute */\r
666     if (WhiteOnMove(yyboardindex)) {\r
667         if (boards[yyboardindex][0][(BOARD_WIDTH-1)>>1] == WhiteKing) {\r
668             /* ICS wild castling */\r
669             rf = 0;\r
670             ff = (BOARD_WIDTH-1)>>1;\r
671             rt = 0;\r
672             ft = BOARD_RGHT-3;\r
673         } else {\r
674             rf = 0;\r
675             ff = BOARD_WIDTH>>1;\r
676             rt = 0;\r
677             ft = BOARD_LEFT+2;\r
678         }\r
679     } else{ \r
680         if (boards[yyboardindex][BOARD_HEIGHT-1][(BOARD_WIDTH-1)>>1] == BlackKing) {\r
681             /* ICS wild castling */\r
682             rf = BOARD_HEIGHT-1;\r
683             ff = (BOARD_WIDTH-1)>>1;\r
684             rt = BOARD_HEIGHT-1;\r
685             ft = BOARD_RGHT-3;\r
686         } else {\r
687             rf = BOARD_HEIGHT-1;\r
688             ff = BOARD_WIDTH>>1;\r
689             rt = BOARD_HEIGHT-1;\r
690             ft = BOARD_LEFT+2;\r
691         }\r
692     }\r
693     if(gameInfo.variant == VariantFischeRandom) {\r
694         if (WhiteOnMove(yyboardindex)) {\r
695             ff = initialRights[2];\r
696             ft = initialRights[1];\r
697         } else {\r
698             ff = initialRights[5];\r
699             ft = initialRights[4];\r
700         }\r
701         fprintf(debugFP, "Parser FRC long %d %d\n", ff, ft);\r
702         if(ff < 0 || ft < 0) return 0;\r
703     }\r
704     sprintf(currentMoveString, "%c%c%c%c",ff+AAA,rf+ONE,ft+AAA,rt+ONE);\r
705     if (appData.debugMode) {\r
706         fprintf(debugFP, "long castling %d %d\n", ff, ft);\r
707     }\r
708     return (int) LegalityTest(boards[yyboardindex],\r
709                               PosFlags(yyboardindex), EP_UNKNOWN,\r
710                               castlingRights[yyboardindex], /* [HGM] use true castling rights */\r
711                               rf, ff, rt, ft, NULLCHAR);\r
712 }\r
713 \r
714 00|0-0|oo|OO|o-o|O-O    {\r
715     int rf, ff, rt, ft;\r
716 \r
717     if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */\r
718 \r
719     if (WhiteOnMove(yyboardindex)) {\r
720         if (boards[yyboardindex][0][(BOARD_WIDTH-1)>>1] == WhiteKing) {\r
721             /* ICS wild castling */\r
722             rf = 0;\r
723             ff = (BOARD_WIDTH-1)>>1;\r
724             rt = 0;\r
725             ft = BOARD_LEFT+1;\r
726         } else {\r
727             rf = 0;\r
728             ff = BOARD_WIDTH>>1;\r
729             rt = 0;\r
730             ft = BOARD_RGHT-2;\r
731         }\r
732     } else {\r
733         if (boards[yyboardindex][BOARD_HEIGHT-1][(BOARD_WIDTH-1)>>1] == BlackKing) {\r
734             /* ICS wild castling */\r
735             rf = BOARD_HEIGHT-1;\r
736             ff = (BOARD_WIDTH-1)>>1;\r
737             rt = BOARD_HEIGHT-1;\r
738             ft = BOARD_LEFT+1;\r
739         } else {\r
740             rf = BOARD_HEIGHT-1;\r
741             ff = BOARD_WIDTH>>1;\r
742             rt = BOARD_HEIGHT-1;\r
743             ft = BOARD_RGHT-2;\r
744         }\r
745     }\r
746     if(gameInfo.variant == VariantFischeRandom) {\r
747         if (WhiteOnMove(yyboardindex)) {\r
748             ff = initialRights[2];\r
749             ft = initialRights[0];\r
750         } else {\r
751             ff = initialRights[5];\r
752             ft = initialRights[3];\r
753         }\r
754     if (appData.debugMode) {\r
755         fprintf(debugFP, "Parser FRC short %d %d\n", ff, ft);\r
756     }\r
757         if(ff < 0 || ft < 0) return 0;\r
758     }\r
759     sprintf(currentMoveString, "%c%c%c%c",ff+AAA,rf+ONE,ft+AAA,rt+ONE);\r
760     if (appData.debugMode) {\r
761         fprintf(debugFP, "short castling %d %d\n", ff, ft);\r
762     }\r
763 \r
764     return (int) LegalityTest(boards[yyboardindex],\r
765                               PosFlags(yyboardindex), EP_UNKNOWN,\r
766                               castlingRights[yyboardindex], /* [HGM] use true castling rights */\r
767                               rf, ff, rt, ft, NULLCHAR);\r
768 }\r
769 \r
770 [A-Z][@*][a-l][0-9] {\r
771     /* Bughouse piece drop.  No legality checking for now. */\r
772     currentMoveString[1] = '@';\r
773     currentMoveString[2] = yytext[2];\r
774     currentMoveString[3] = yytext[3];\r
775     currentMoveString[4] = NULLCHAR;\r
776 \r
777     if (appData.debugMode) {\r
778         fprintf(debugFP, "Drop: %s\n", currentMoveString);\r
779     }\r
780     /* [HGM] do not allow values beyond board size */\r
781     if(currentMoveString[3] - ONE >= BOARD_HEIGHT ||\r
782        currentMoveString[2] - AAA >= BOARD_WIDTH     )\r
783       return 0;\r
784 \r
785     if (WhiteOnMove(yyboardindex)) {\r
786         currentMoveString[0] = ToUpper(yytext[0]);\r
787         return (int) WhiteDrop;\r
788     } else {\r
789         currentMoveString[0] = ToLower(yytext[0]);\r
790         return (int) BlackDrop;\r
791     }\r
792 }\r
793 \r
794 [Rr]esign(s|ed)?  {\r
795     if (WhiteOnMove(yyboardindex))\r
796       return (int) BlackWins;\r
797     else\r
798       return (int) WhiteWins;\r
799 }\r
800 \r
801 (([Ww](hite)?)|([Bb](lack)?))" "(([Rr]esign)|([Ff]orfeit))(s|ed)?  {\r
802     return (int) (ToUpper(yytext[0]) == 'W' ? BlackWins : WhiteWins);\r
803 }\r
804 \r
805 (([Ww](hite)?)|([Bb](lack)?))" "[Dd]isconnect(s|ed)  {\r
806     return (int) GameUnfinished;\r
807 }\r
808 \r
809 [Ss]talemate  {\r
810     return (int) GameIsDrawn;\r
811 }\r
812 \r
813 "+-+"  {\r
814     return (int) GameIsDrawn;\r
815 }\r
816 \r
817 ([Cc]heck)?[Mm]ate {\r
818     if (WhiteOnMove(yyboardindex))\r
819       return (int) BlackWins;\r
820     else\r
821       return (int) WhiteWins;\r
822 }\r
823 \r
824 "++"  {\r
825     if (WhiteOnMove(yyboardindex))\r
826       return (int) BlackWins;\r
827     else\r
828       return (int) WhiteWins;\r
829 }\r
830 \r
831 [Dd]raw(n)?(" "by)?(" "[Rr]epetition)|(" "[Aa]gree(d|ment))  {\r
832     return (int) GameIsDrawn;\r
833 }\r
834 \r
835 [Dd]raw(n)?(" (".*")")?  {\r
836     return (int) GameIsDrawn;\r
837 }\r
838 \r
839 (([Ww](hite)?)|([Bb](lack)?))" "([Mm]ate(s|ed)?)|([Ww][io]n(s)?.*)  {\r
840     return (int) (ToUpper(yytext[0]) == 'W' ? WhiteWins : BlackWins);\r
841 }\r
842 \r
843 (([Ww](hite)?)|([Bb](lack)?))" "([Mm]ate(s|ed)?)|([Ll]os[tes]+.*)  {\r
844     return (int) (ToUpper(yytext[0]) == 'W' ? BlackWins : WhiteWins);\r
845 }\r
846 \r
847 ("{"[^\}\n]*"} ")?(1-0|"1 - 0"|"1/0"|"1 / 0"|"1:0"|"1 : 0")(" (".*")"|" {".*"}")? { \r
848     return (int) WhiteWins;\r
849 }\r
850 \r
851 ("{"[^\}\n]*"} ")?(0-1|"0 - 1"|"0/1"|"0 / 1"|"0:1"|"0 : 1")(" (".*")"|" {".*"}")? { \r
852     return (int) BlackWins;\r
853 }\r
854 \r
855 ("{"[^\}\n]*"} ")?("1/2"|"1 / 2")(" "?[-:]" "?("1/2"|"1 / 2"))?(" (".*")"|" {".*"}")? {\r
856     return (int) GameIsDrawn;\r
857 }\r
858 \r
859 ("{"[^\}\n]*"} ")?"*"(" (".*")"|" {".*"}")? {\r
860     return (int) GameUnfinished;\r
861 }\r
862 \r
863 [1-9][0-9]*/"."?[ \t\n]*[a-lNnPpRrBQqKACFEWDGHOo]    {\r
864     /* move numbers */\r
865     if ((yyleng == 1) && (yytext[0] == '1'))\r
866       return (int) MoveNumberOne;\r
867 }\r
868 \r
869 \([0-9]+:[0-9][0-9](\.[0-9]+)?\)|\{[0-9]+:[0-9][0-9](\.[0-9]+)?\} {\r
870     /* elapsed time indication, e.g. (0:12) or {10:21.071} */ \r
871     return (int) ElapsedTime;\r
872 }\r
873 \r
874 "[--"[^\]]*"--]" {\r
875     /* position diagram enclosed in [-- --] */\r
876     return (int) PositionDiagram;\r
877 }\r
878 \r
879 ^"{--------------"\n[^\}]*\n"--------------}"$ {\r
880     /* position diagram enclosed in {-- --} */\r
881     return (int) PositionDiagram;\r
882 }\r
883 \r
884 \[[ \t\n]*[A-Za-z0-9][A-Za-z0-9_+#=-]*[ \t\n]*\"[^"]*\"[ \t\n]*\] {\r
885     return (int) PGNTag;\r
886 }    \r
887 \r
888 [Gg](nu|NU)" "?[Cc](hess|HESS).*[Gg](ame|AME) {\r
889     return (int) GNUChessGame;\r
890 }\r
891 \r
892 ^[#;%]" "[^ ]*(" game file"|" position file").*$ {\r
893     return (int) XBoardGame;\r
894 }\r
895 \r
896 \$[0-9]+        {                               /* numeric annotation glyph */\r
897     return (int) NAG;\r
898 }\r
899 \r
900 \{[^\}]*\}      {                               /* anything in {} */\r
901     return (int) Comment; \r
902 }\r
903 \r
904 ;.*$ {                                          /* ; to end of line */\r
905     return (int) Comment;\r
906 }\r
907 \r
908 \[[^\]]*\]      {                               /* anything in [] */\r
909     return (int) Comment; \r
910 }\r
911 \r
912 \([^()]*(\([^()]*\)[^()]*)+[^()]*\)  {          /* nested () */\r
913     return (int) Comment; \r
914 }\r
915 \r
916 \([^)][^)]+\)   {                               /* >=2 chars in () */\r
917     return (int) Comment; \r
918 }       \r
919 \r
920 ^[-a-zA-Z0-9]+:" ".*(\n[ \t]+.*)*  {\r
921         /* Skip mail headers */\r
922 }\r
923 \r
924 [a-zA-Z0-9'-]+                  {\r
925         /* Skip random words */\r
926 }\r
927 \r
928 .|\n                            {\r
929         /* Skip everything else */\r
930 }\r
931 \r
932 %%\r
933 \r
934 \r
935 static char *StringToLex;\r
936 \r
937 #ifndef FLEX_SCANNER\r
938 static FILE *lexFP;\r
939 \r
940 static int input()\r
941 {\r
942     int ret;\r
943     \r
944     if (StringToLex != NULL) {\r
945         ret = *StringToLex;\r
946         if (ret == NULLCHAR)\r
947           ret = EOF;\r
948         else\r
949           StringToLex++;\r
950     } else if (unputCount > 0) {\r
951         ret = unputBuffer[--unputCount];\r
952     } else {\r
953         ret = fgetc(lexFP);\r
954     }    \r
955 \r
956     if (ret == EOF) \r
957       return 0;\r
958     else\r
959       return ret;\r
960 }\r
961 \r
962 /*\r
963  * Return offset of next pattern within current file\r
964  */\r
965 int yyoffset()\r
966 {\r
967     int offset = ftell(lexFP) - unputCount;\r
968 \r
969     if (offset < 0) {\r
970         offset = 0;\r
971     }\r
972     return(offset);\r
973 }\r
974  \r
975 static void output(ch)\r
976      int ch;\r
977 {\r
978     fprintf(stderr, "PARSER BUG: unmatched character '%c' (0%o)\n",\r
979             ch, ch);\r
980 }\r
981 \r
982 static void unput(ch)\r
983      int ch;\r
984 {\r
985     if (ch == 0) return;\r
986     if (StringToLex != NULL) {\r
987         StringToLex--;\r
988     } else {\r
989         if (unputCount >= UNPUT_BUF_SIZE)\r
990           fprintf(stderr, "PARSER BUG: unput buffer overflow '%c' (0%o)\n",\r
991                   ch, ch);\r
992         unputBuffer[unputCount++] = ch;\r
993     }\r
994 }\r
995 \r
996 /* Get ready to lex from a new file.  Kludge below sticks\r
997    an artificial newline at the front of the file, which the\r
998    above grammar ignores, but which makes ^ at start of pattern\r
999    match at the real start of the file.\r
1000 */\r
1001 void yynewfile(f)\r
1002      FILE *f;\r
1003 {\r
1004     lexFP = f;\r
1005     StringToLex = NULL;\r
1006     unputCount = 0;\r
1007     unput('\n'); /* kludge */\r
1008 }\r
1009 \r
1010 /* Get ready to lex from a string.  ^ at start of pattern WON'T\r
1011    match at the start of the string!\r
1012 */\r
1013 void yynewstr(s)\r
1014      char *s;\r
1015 {\r
1016     lexFP = NULL;\r
1017     StringToLex = s;\r
1018     unputCount = 0;\r
1019 }\r
1020 #endif /*!FLEX_SCANNER*/\r
1021 \r
1022 #ifdef FLEX_SCANNER\r
1023 void my_yy_input(buf, result, max_size)\r
1024      char *buf;\r
1025      int *result;\r
1026      int max_size;\r
1027 {\r
1028     int count;\r
1029 \r
1030     if (StringToLex != NULL) {\r
1031         count = 0;\r
1032         while (*StringToLex != NULLCHAR) {\r
1033             *buf++ = *StringToLex++;\r
1034             count++;\r
1035         }\r
1036         *result = count;\r
1037         return;\r
1038     } else {\r
1039         count = fread(buf, 1, max_size, yyin);\r
1040         if (count == 0) {\r
1041             *result = YY_NULL;\r
1042         } else {\r
1043             *result = count;\r
1044         }\r
1045         return;\r
1046     }    \r
1047 }\r
1048 \r
1049 static YY_BUFFER_STATE my_file_buffer = NULL;\r
1050 \r
1051 /*\r
1052     Return offset of next pattern in the current file.\r
1053 */\r
1054 int yyoffset()\r
1055 {\r
1056     int pos = yy_c_buf_p - YY_CURRENT_BUFFER->yy_ch_buf;\r
1057 \r
1058     return(ftell(YY_CURRENT_BUFFER->yy_input_file) -\r
1059          yy_n_chars + pos);\r
1060 }\r
1061 \r
1062 \r
1063 void yynewstr(s)\r
1064      char *s;\r
1065 {\r
1066     if (my_file_buffer != NULL)\r
1067       yy_delete_buffer(my_file_buffer);\r
1068     StringToLex = s;\r
1069     my_file_buffer = yy_create_buffer(stdin, YY_BUF_SIZE);\r
1070     yy_switch_to_buffer(my_file_buffer);\r
1071 }\r
1072 \r
1073 void yynewfile(f)\r
1074      FILE *f;\r
1075 {\r
1076     if (my_file_buffer != NULL)\r
1077       yy_delete_buffer(my_file_buffer);\r
1078     StringToLex = NULL;\r
1079     my_file_buffer = yy_create_buffer(f, YY_BUF_SIZE);\r
1080     yy_switch_to_buffer(my_file_buffer);\r
1081 }\r
1082 #endif /*FLEX_SCANNER*/\r
1083 \r
1084 int yywrap()\r
1085 {\r
1086     return TRUE;\r
1087 }\r
1088 \r
1089 /* Parse a move from the given string s */\r
1090 /* ^ at start of pattern WON'T work here unless using flex */\r
1091 ChessMove yylexstr(boardIndex, s)\r
1092      int boardIndex;\r
1093      char *s;\r
1094 {\r
1095     ChessMove ret;\r
1096     char *oldStringToLex;\r
1097 #ifdef FLEX_SCANNER\r
1098     YY_BUFFER_STATE buffer, oldBuffer;\r
1099 #endif\r
1100     \r
1101     yyboardindex = boardIndex;\r
1102     oldStringToLex = StringToLex;\r
1103     StringToLex = s;\r
1104 #ifdef FLEX_SCANNER\r
1105     buffer = yy_create_buffer(stdin, YY_BUF_SIZE);\r
1106     oldBuffer = YY_CURRENT_BUFFER;\r
1107     yy_switch_to_buffer(buffer);\r
1108 #endif /*FLEX_SCANNER*/\r
1109 \r
1110     ret = (ChessMove) yylex();\r
1111 \r
1112 #ifdef FLEX_SCANNER\r
1113     if (oldBuffer != NULL) \r
1114       yy_switch_to_buffer(oldBuffer);\r
1115     yy_delete_buffer(buffer);\r
1116 #endif /*FLEX_SCANNER*/\r
1117     StringToLex = oldStringToLex;\r
1118 \r
1119     return ret;\r
1120 }\r