Extend legality testing to drop moves
[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  *\r
11  * Copyright 1991 by Digital Equipment Corporation, Maynard,\r
12  * Massachusetts.\r
13  *\r
14  * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005,\r
15  * 2006, 2007, 2008, 2009 Free Software 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 ImpossibleMove;\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)&~F_MANDATORY_CAPTURE, // [HGM] losers: might think we can e.p.!\r
247                           currentMoveString[1] - ONE,\r
248                           currentMoveString[0] - AAA,\r
249                           currentMoveString[3] - ONE,\r
250                           currentMoveString[2] - AAA,\r
251                           currentMoveString[4]);\r
252 \r
253     if (currentMoveString[4] == NULLCHAR &&\r
254         (result == WhitePromotionKnight || result == BlackPromotionKnight ||\r
255          result == WhitePromotionQueen  || result == BlackPromotionQueen)) {\r
256         currentMoveString[4] = PieceToChar(BlackQueen);\r
257         currentMoveString[5] = NULLCHAR;\r
258     }\r
259 \r
260     return (int) result;\r
261 }\r
262 \r
263 [a-l][0-9][xX:-]?[a-l][0-9]((=?\(?[A-Za-z]\)?)|=)?      {\r
264     /*\r
265      * Simple algebraic move, possibly with promotion\r
266      * [HGM] Engine moves are received in this format, with lower-case promoChar!\r
267      */\r
268     int skip = 0;\r
269     ChessMove result;\r
270 \r
271     if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */\r
272 \r
273     /* remove the [xX:-] */\r
274     if ((yytext[2] == 'x') || (yytext[2] == 'X') ||\r
275         (yytext[2] == '-') || (yytext[2] == ':')) skip = 1;\r
276 \r
277     currentMoveString[0] = yytext[0];\r
278     currentMoveString[1] = yytext[1];\r
279     currentMoveString[2] = yytext[2+skip];\r
280     currentMoveString[3] = yytext[3+skip];\r
281     currentMoveString[4] = NULLCHAR;\r
282 \r
283     if (yyleng-skip > 4) { char c;\r
284         if (yytext[yyleng-1] == ')') {\r
285             c = currentMoveString[4] = ToLower(yytext[yyleng-2]);\r
286         } else {\r
287             c = currentMoveString[4] = ToLower(yytext[yyleng-1]);\r
288         }\r
289         currentMoveString[5] = NULLCHAR;\r
290         if(c != '=' && c != '+' && CharToPiece(c) == EmptySquare)\r
291             return IllegalMove;\r
292     }\r
293 \r
294     /* [HGM] do not allow values beyond board size */\r
295     if(currentMoveString[1] - ONE >= BOARD_HEIGHT ||\r
296        currentMoveString[1] - ONE <  0            ||\r
297        currentMoveString[0] - AAA >= BOARD_RGHT   ||\r
298        currentMoveString[3] - ONE >= BOARD_HEIGHT ||\r
299        currentMoveString[3] - ONE <  0            ||\r
300        currentMoveString[2] - AAA >= BOARD_RGHT   ||\r
301        currentMoveString[0] - AAA <  BOARD_LEFT   ||\r
302        currentMoveString[2] - AAA <  BOARD_LEFT     )\r
303       return ImpossibleMove;\r
304 \r
305     result = LegalityTest(boards[yyboardindex],\r
306                           PosFlags(yyboardindex)&~F_MANDATORY_CAPTURE, // [HGM] losers: might think we can e.p.!\r
307                           currentMoveString[1] - ONE,\r
308                           currentMoveString[0] - AAA,\r
309                           currentMoveString[3] - ONE,\r
310                           currentMoveString[2] - AAA,\r
311                           currentMoveString[4]);\r
312 \r
313     if (currentMoveString[4] == NULLCHAR) {
314       if(result == WhitePromotionKnight || result == BlackPromotionKnight ||
315          result == WhitePromotionQueen  || result == BlackPromotionQueen) {
316         if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier || gameInfo.variant == VariantMakruk)
317             currentMoveString[4] = PieceToChar(BlackFerz);
318         else if(gameInfo.variant == VariantGreat)
319             currentMoveString[4] = PieceToChar(BlackMan);
320         else
321             currentMoveString[4] = PieceToChar(BlackQueen);
322         currentMoveString[5] = NULLCHAR;
323       }
324     } else if(appData.testLegality && // strip off unnecessary and false promo characters
325        !(result == WhitePromotionQueen  || result == BlackPromotionQueen ||
326          result == WhiteNonPromotion    || result == BlackNonPromotion)) currentMoveString[4] = NULLCHAR;
327
328     return (int) result;
329 }
330
331 [A-L][0-9][xX:-]?[A-L][0-9]      {
332     /*
333      * Simple algebraic move, in capitals
334      * [HGM] Engine moves are received in this format, with lower-case promoChar!
335      */
336     int skip = 0;
337     ChessMove result;
338
339     if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */
340
341     /* remove the [xX:-] */
342     if ((yytext[2] == 'x') || (yytext[2] == 'X') ||
343         (yytext[2] == '-') || (yytext[2] == ':')) skip = 1;
344
345     currentMoveString[0] = yytext[0]+32;
346     currentMoveString[1] = yytext[1];
347     currentMoveString[2] = yytext[2+skip]+32;
348     currentMoveString[3] = yytext[3+skip];
349     currentMoveString[4] = NULLCHAR;
350
351     /* [HGM] do not allow values beyond board size */
352     if(currentMoveString[1] - ONE >= BOARD_HEIGHT ||
353        currentMoveString[1] - ONE <  0            ||
354        currentMoveString[0] - AAA >= BOARD_RGHT   ||
355        currentMoveString[3] - ONE >= BOARD_HEIGHT ||
356        currentMoveString[3] - ONE <  0            ||
357        currentMoveString[2] - AAA >= BOARD_RGHT   ||
358        currentMoveString[0] - AAA <  BOARD_LEFT   ||
359        currentMoveString[2] - AAA <  BOARD_LEFT     )
360       return ImpossibleMove;
361
362     result = LegalityTest(boards[yyboardindex],
363                           PosFlags(yyboardindex)&~F_MANDATORY_CAPTURE, // [HGM] losers: might think we can e.p.!
364                           currentMoveString[1] - ONE,
365                           currentMoveString[0] - AAA,
366                           currentMoveString[3] - ONE,
367                           currentMoveString[2] - AAA,
368                           currentMoveString[4]);
369
370     if (currentMoveString[4] == NULLCHAR &&\r
371         (result == WhitePromotionKnight || result == BlackPromotionKnight ||\r
372          result == WhitePromotionQueen  || result == BlackPromotionQueen)) {\r
373         if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier || gameInfo.variant == VariantMakruk)\r
374             currentMoveString[4] = PieceToChar(BlackFerz);\r
375         else if(gameInfo.variant == VariantGreat)\r
376             currentMoveString[4] = PieceToChar(BlackMan);\r
377         else\r
378             currentMoveString[4] = PieceToChar(BlackQueen);\r
379         currentMoveString[5] = NULLCHAR;\r
380     } else if(appData.testLegality && // strip off unnecessary and false promo characters
381        !(result == WhitePromotionQueen  || result == BlackPromotionQueen ||
382          result == WhiteNonPromotion    || result == BlackNonPromotion)) currentMoveString[4] = NULLCHAR;
383 \r
384     return (int) result;\r
385 }\r
386 \r
387 [a-l][0-9]((=?\(?[A-Za-z]\)?)|=)?       {\r
388     /*\r
389      * Pawn move, possibly with promotion\r
390      */\r
391     DisambiguateClosure cl;\r
392     int skip = 0; char c;\r
393 \r
394     if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */\r
395 \r
396     /* remove the =() */\r
397     if (yytext[2] == '=' && yytext[3] != NULLCHAR) skip++;\r
398     if (yytext[2+skip] == '(') skip++;\r
399 \r
400     cl.pieceIn = WhiteOnMove(yyboardindex) ? WhitePawn : BlackPawn;\r
401     cl.rfIn = -1;\r
402     cl.ffIn = yytext[0] - AAA;\r
403     cl.rtIn = yytext[1] - ONE;\r
404     cl.ftIn = yytext[0] - AAA;\r
405     c = cl.promoCharIn = ToLower(yytext[2+skip]);\r
406 \r
407     /* [HGM] do not allow values beyond board size */\r
408     if(cl.rtIn >= BOARD_HEIGHT ||\r
409        cl.rtIn <  0            ||\r
410        cl.ffIn >= BOARD_RGHT   ||\r
411        cl.ftIn <  BOARD_LEFT     )\r
412       return ImpossibleMove;\r
413 \r
414     if(c != '=' && c != '+' && c != NULLCHAR && CharToPiece(c) == EmptySquare)\r
415       return IllegalMove;\r
416 \r
417 \r
418     Disambiguate(boards[yyboardindex], PosFlags(yyboardindex), &cl);\r
419 \r
420     currentMoveString[0] = cl.ff + AAA;\r
421     currentMoveString[1] = cl.rf + ONE;\r
422     currentMoveString[2] = cl.ft + AAA;\r
423     currentMoveString[3] = cl.rt + ONE;\r
424     currentMoveString[4] = cl.promoChar;\r
425     currentMoveString[5] = NULLCHAR;\r
426 \r
427     return (int) cl.kind;\r
428 }\r
429 \r
430 \r
431 (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
432     /*\r
433      * Pawn capture, possibly with promotion, possibly ambiguous\r
434      */\r
435     DisambiguateClosure cl;\r
436     int skip1 = 0, skip2 = 0; char c;\r
437 \r
438     if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */\r
439 \r
440     /* remove trailing ep or e.p. (nonstandard PGN) */\r
441     if (yytext[yyleng-1] == 'p') {\r
442       yyleng -= 2;\r
443       yytext[yyleng] = NULLCHAR;\r
444     } else if (yytext[yyleng-1] == '.') {\r
445       yyleng -= 4;\r
446       yytext[yyleng] = NULLCHAR;\r
447     }\r
448 \r
449     /* remove the [xX:-] and =() */\r
450     if ((yytext[1] == 'x') || (yytext[1] == 'X')\r
451         || (yytext[1] == ':') || (yytext[1] == '-')) skip1 = 1;\r
452     if (yytext[2+skip1] == '=' && yytext[3+skip1] != NULLCHAR) skip2++;\r
453     if (yytext[2+skip1+skip2] == '(') skip2++;\r
454 \r
455     cl.pieceIn = WhiteOnMove(yyboardindex) ? WhitePawn : BlackPawn;\r
456     cl.rfIn = -1;\r
457     cl.ffIn = yytext[0] - AAA;\r
458     cl.rtIn = -1;\r
459     cl.ftIn = yytext[1+skip1] - AAA;\r
460     c = cl.promoCharIn = yytext[2+skip1+skip2];\r
461 \r
462     /* [HGM] do not allow values beyond board size */\r
463     if(cl.ffIn >= BOARD_RGHT  ||\r
464        cl.ffIn <  BOARD_LEFT  ||\r
465        cl.ftIn >= BOARD_RGHT  ||\r
466        cl.ftIn <  BOARD_LEFT     )\r
467       return ImpossibleMove;\r
468 \r
469     if(c != '=' && c != '+' && c != NULLCHAR && CharToPiece(c) == EmptySquare)\r
470       return IllegalMove;\r
471 \r
472     Disambiguate(boards[yyboardindex], PosFlags(yyboardindex), &cl);\r
473 \r
474     currentMoveString[0] = cl.ff + AAA;\r
475     currentMoveString[1] = cl.rf + ONE;\r
476     currentMoveString[2] = cl.ft + AAA;\r
477     currentMoveString[3] = cl.rt + ONE;\r
478     currentMoveString[4] = cl.promoChar;\r
479     currentMoveString[5] = NULLCHAR;\r
480 \r
481     return (int) cl.kind;\r
482 }\r
483 \r
484 [a-l][xX:]?[a-l][0-9]((=?\(?[A-Z]\)?)|ep|"e.p."|=)? {\r
485     /*\r
486      * unambiguously abbreviated Pawn capture, possibly with promotion\r
487      */\r
488     int skip = 0;\r
489     ChessMove result; char c;\r
490 \r
491     if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */\r
492 \r
493     /* remove trailing ep or e.p. (nonstandard PGN) */\r
494     if (yytext[yyleng-1] == 'p') {\r
495       yyleng -= 2;\r
496       yytext[yyleng] = NULLCHAR;\r
497     } else if (yytext[yyleng-1] == '.') {\r
498       yyleng -= 4;\r
499       yytext[yyleng] = NULLCHAR;\r
500     }\r
501 \r
502     /* remove the [xX:-] */\r
503     if ((yytext[1] == 'x') || (yytext[1] == 'X')\r
504         || (yytext[1] == ':') || (yytext[1] == '-')) skip = 1;\r
505 \r
506     currentMoveString[0] = yytext[0];\r
507     currentMoveString[2] = yytext[1+skip];\r
508     currentMoveString[3] = yytext[2+skip];\r
509 \r
510     /* [HGM] do not allow values beyond board size */\r
511     if(currentMoveString[0] - AAA >= BOARD_RGHT   ||\r
512        currentMoveString[3] - ONE >= BOARD_HEIGHT ||\r
513        currentMoveString[3] - ONE <  0            ||\r
514        currentMoveString[2] - AAA >= BOARD_RGHT   ||\r
515        currentMoveString[0] - AAA <  BOARD_LEFT   ||\r
516        currentMoveString[2] - AAA <  BOARD_LEFT     )\r
517       return ImpossibleMove;\r
518 \r
519     if (gameInfo.variant == VariantXiangqi && /* [HGM] In Xiangqi rank stays same */\r
520          currentMoveString[0] != currentMoveString[2] ) {\r
521         currentMoveString[1] = yytext[2+skip];\r
522     } else \r
523     if (WhiteOnMove(yyboardindex)) {\r
524         if (yytext[2+skip] == ONE) return (int) ImpossibleMove;\r
525         currentMoveString[1] = yytext[2+skip] - 1;\r
526         if(boards[yyboardindex][currentMoveString[1]-ONE][currentMoveString[0]-AAA] != WhitePawn) \r
527                 return ImpossibleMove;\r
528     } else {\r
529         currentMoveString[1] = currentMoveString[3] + 1;\r
530         if (currentMoveString[3] == ONE+BOARD_HEIGHT-1) return (int) ImpossibleMove;\r
531         if(boards[yyboardindex][currentMoveString[1]-ONE][currentMoveString[0]-AAA] != BlackPawn) \r
532                 return ImpossibleMove;\r
533     }\r
534     if (yyleng-skip > 3) {\r
535         if (yytext[yyleng-1] == ')')\r
536           c = currentMoveString[4] = ToLower(yytext[yyleng-2]);\r
537         else\r
538           c = currentMoveString[4] = ToLower(yytext[yyleng-1]);\r
539         currentMoveString[5] = NULLCHAR;\r
540         if(c != '=' && c != '+' && CharToPiece(c) == EmptySquare)\r
541             return IllegalMove;\r
542     } else {\r
543         currentMoveString[4] = NULLCHAR;\r
544     }\r
545 \r
546     result = LegalityTest(boards[yyboardindex],\r
547                           PosFlags(yyboardindex)&~F_MANDATORY_CAPTURE, // [HGM] losers: might think we can e.p.!\r
548                           currentMoveString[1] - ONE,\r
549                           currentMoveString[0] - AAA,\r
550                           currentMoveString[3] - ONE,\r
551                           currentMoveString[2] - AAA,\r
552                           currentMoveString[4]);\r
553 \r
554     if (currentMoveString[4] == NULLCHAR &&\r
555         (result == WhitePromotionQueen  || result == BlackPromotionQueen ||\r
556          result == WhitePromotionKnight || result == BlackPromotionKnight)) {\r
557         currentMoveString[4] = PieceToChar(BlackQueen);\r
558         // [HGM] shatranj: take care of variants without Queen\r
559         if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier || gameInfo.variant == VariantMakruk)\r
560             currentMoveString[4] = PieceToChar(BlackFerz);\r
561         if(gameInfo.variant == VariantGreat)\r
562             currentMoveString[4] = PieceToChar(BlackMan);\r
563         currentMoveString[5] = NULLCHAR;\r
564     }\r
565 \r
566     if (result != IllegalMove) return (int) result;\r
567 \r
568     /* Special case: improperly written en passant capture */\r
569     if (WhiteOnMove(yyboardindex)) {\r
570         if (currentMoveString[3] == '5') {\r
571             currentMoveString[1] = '5';\r
572             currentMoveString[3] = '6';\r
573         } else {\r
574             return (int) IllegalMove;\r
575         }\r
576     } else {\r
577         if (currentMoveString[3] == '4') {\r
578             currentMoveString[1] = '4';\r
579             currentMoveString[3] = '3';\r
580         } else {\r
581             return (int) IllegalMove;\r
582         }\r
583     }\r
584 \r
585     result = LegalityTest(boards[yyboardindex],\r
586                           PosFlags(yyboardindex)&~F_MANDATORY_CAPTURE, // [HGM] losers: might think we can e.p.!\r
587                           currentMoveString[1] - ONE,\r
588                           currentMoveString[0] - AAA,\r
589                           currentMoveString[3] - ONE,\r
590                           currentMoveString[2] - AAA,\r
591                           currentMoveString[4]);\r
592 \r
593     if (result == WhiteCapturesEnPassant || result == BlackCapturesEnPassant)\r
594       return (int) result;\r
595     else\r
596       return (int) IllegalMove;\r
597 }\r
598 \r
599 "+"?[A-Z][xX:-]?[a-l][0-9]=?  {\r
600     /*\r
601      * piece move, possibly ambiguous\r
602      */\r
603     DisambiguateClosure cl;\r
604     int skip = 0, skip2 = 0, 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[1+skip] == 'x') || (yytext[1+skip] == 'X')\r
612         || (yytext[1+skip] == ':') || (yytext[1+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     cl.rfIn = -1;\r
622     cl.ffIn = -1;\r
623     cl.rtIn = yytext[2+skip] - ONE;\r
624     cl.ftIn = yytext[1+skip] - AAA;\r
625     cl.promoCharIn = NULLCHAR;\r
626 \r
627     if(yyleng-skip > 3) /* [HGM] can have Shogi-style promotion */\r
628         cl.promoCharIn = yytext[yyleng-1];\r
629 \r
630     if (appData.debugMode) {\r
631         fprintf(debugFP, "Parser Qa1: yyleng=%d,  %d(%d,%d)-(%d,%d) = %d (%c)\n",\r
632         yyleng,\r
633         cl.pieceIn,cl.ffIn,cl.rfIn,cl.ftIn,cl.rtIn,cl.promoCharIn,cl.promoCharIn?cl.promoCharIn:' ');\r
634     }\r
635 \r
636     /* [HGM] but do not allow values beyond board size */\r
637     if(cl.rtIn >= BOARD_HEIGHT ||\r
638        cl.rtIn <  0            ||\r
639        cl.ftIn >= BOARD_RGHT   ||\r
640        cl.ftIn <  BOARD_LEFT     )\r
641       return ImpossibleMove;\r
642 \r
643     Disambiguate(boards[yyboardindex], PosFlags(yyboardindex), &cl);\r
644 \r
645     currentMoveString[0] = cl.ff + AAA;\r
646     currentMoveString[1] = cl.rf + ONE;\r
647     currentMoveString[2] = cl.ft + AAA;\r
648     currentMoveString[3] = cl.rt + ONE;\r
649     currentMoveString[4] = cl.promoChar;\r
650     currentMoveString[5] = NULLCHAR;\r
651 \r
652     return (int) cl.kind;\r
653 }\r
654 \r
655 "+"?[A-Z][a-l0-9][xX:-]?[a-l][0-9]=?   {\r
656     /*\r
657      * piece move with rank or file disambiguator\r
658      */\r
659     DisambiguateClosure cl;\r
660     int skip = 0, skip2 = 0; int promoted=0;\r
661 \r
662     if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */\r
663 \r
664     if(yytext[0]=='+') promoted = skip = skip2 = 1;\r
665 \r
666     /* remove the [xX:-] */\r
667     if ((yytext[2+skip] == 'x') || (yytext[2+skip] == 'X')\r
668         || (yytext[2+skip] == ':') || (yytext[2+skip] == '-')) skip++;\r
669 \r
670     if (WhiteOnMove(yyboardindex)) {\r
671         cl.pieceIn = CharToPiece(ToUpper(yytext[skip2]));\r
672     } else {\r
673         cl.pieceIn = CharToPiece(ToLower(yytext[skip2]));\r
674     }\r
675     if(promoted) cl.pieceIn = (ChessSquare) (PROMOTED cl.pieceIn);\r
676 \r
677     if (isalpha(yytext[1+skip2])) {\r
678         cl.rfIn = -1;\r
679         cl.ffIn = yytext[1+skip2] - AAA;\r
680        \r
681         if(cl.ffIn >= BOARD_RGHT ||\r
682            cl.ffIn <  BOARD_LEFT   ) return 0;\r
683     } else {\r
684         cl.rfIn = yytext[1+skip2] - ONE;\r
685         cl.ffIn = -1;\r
686         if(cl.rfIn >= BOARD_HEIGHT ||\r
687            cl.rfIn <  0) return 0;\r
688     }\r
689     cl.rtIn = yytext[3+skip] - ONE;\r
690     cl.ftIn = yytext[2+skip] - AAA;\r
691     cl.promoCharIn = NULLCHAR;\r
692 \r
693     if(yyleng-skip > 4) /* [HGM] can have Shogi-style promotion */\r
694         cl.promoCharIn = yytext[yyleng-1];\r
695 \r
696     /* [HGM] do not allow values beyond board size */\r
697     if(cl.rtIn >= BOARD_HEIGHT ||\r
698        cl.rtIn <  0            ||\r
699        cl.ftIn >= BOARD_RGHT   ||\r
700        cl.ftIn <  BOARD_LEFT     )\r
701       return ImpossibleMove;\r
702 \r
703     Disambiguate(boards[yyboardindex], PosFlags(yyboardindex), &cl);\r
704 \r
705     currentMoveString[0] = cl.ff + AAA;\r
706     currentMoveString[1] = cl.rf + ONE;\r
707     currentMoveString[2] = cl.ft + AAA;\r
708     currentMoveString[3] = cl.rt + ONE;\r
709     currentMoveString[4] = cl.promoChar;\r
710     currentMoveString[5] = NULLCHAR;\r
711 \r
712     return (int) cl.kind;\r
713 }\r
714 \r
715 000|0-0-0|ooo|OOO|o-o-o|O-O-O   {\r
716     int rf, ff, rt, ft;\r
717 \r
718     if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */\r
719 \r
720     /* [HGM] all squares referenced to board edges in stead of absolute */\r
721     if (WhiteOnMove(yyboardindex)) {\r
722         if (boards[yyboardindex][0][(BOARD_WIDTH-1)>>1] == WhiteKing) {\r
723             /* ICS wild castling */\r
724             rf = 0;\r
725             ff = (BOARD_WIDTH-1)>>1;\r
726             rt = 0;\r
727             ft = BOARD_RGHT-3;\r
728         } else {\r
729             rf = 0;\r
730             ff = BOARD_WIDTH>>1;\r
731             rt = 0;\r
732             ft = BOARD_LEFT+2;\r
733         }\r
734     } else{ \r
735         if (boards[yyboardindex][BOARD_HEIGHT-1][(BOARD_WIDTH-1)>>1] == BlackKing) {\r
736             /* ICS wild castling */\r
737             rf = BOARD_HEIGHT-1;\r
738             ff = (BOARD_WIDTH-1)>>1;\r
739             rt = BOARD_HEIGHT-1;\r
740             ft = BOARD_RGHT-3;\r
741         } else {\r
742             rf = BOARD_HEIGHT-1;\r
743             ff = BOARD_WIDTH>>1;\r
744             rt = BOARD_HEIGHT-1;\r
745             ft = BOARD_LEFT+2;\r
746         }\r
747     }\r
748     if(PosFlags(0) & F_FRC_TYPE_CASTLING) {
749         if (WhiteOnMove(yyboardindex)) {\r
750             ff = initialRights[2];\r
751             ft = initialRights[1];\r
752         } else {\r
753             ff = initialRights[5];\r
754             ft = initialRights[4];\r
755         }\r
756         if (appData.debugMode) \r
757         {\r
758           fprintf(debugFP, "Parser FRC long %d %d\n", ff, ft);\r
759         };\r
760         if(ff < 0 || ft < 0) return 0;\r
761     }\r
762     sprintf(currentMoveString, "%c%c%c%c",ff+AAA,rf+ONE,ft+AAA,rt+ONE);\r
763     if (appData.debugMode) {\r
764         fprintf(debugFP, "long castling %d %d\n", ff, ft);\r
765     }\r
766     return (int) LegalityTest(boards[yyboardindex],\r
767                               PosFlags(yyboardindex)&~F_MANDATORY_CAPTURE, // [HGM] losers: e.p.!\r
768                               rf, ff, rt, ft, NULLCHAR);\r
769 }\r
770 \r
771 00|0-0|oo|OO|o-o|O-O    {\r
772     int rf, ff, rt, ft;\r
773 \r
774     if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */\r
775 \r
776     if (WhiteOnMove(yyboardindex)) {\r
777         if (boards[yyboardindex][0][(BOARD_WIDTH-1)>>1] == WhiteKing) {\r
778             /* ICS wild castling */\r
779             rf = 0;\r
780             ff = (BOARD_WIDTH-1)>>1;\r
781             rt = 0;\r
782             ft = BOARD_LEFT+1;\r
783         } else {\r
784             rf = 0;\r
785             ff = BOARD_WIDTH>>1;\r
786             rt = 0;\r
787             ft = BOARD_RGHT-2;\r
788         }\r
789     } else {\r
790         if (boards[yyboardindex][BOARD_HEIGHT-1][(BOARD_WIDTH-1)>>1] == BlackKing) {\r
791             /* ICS wild castling */\r
792             rf = BOARD_HEIGHT-1;\r
793             ff = (BOARD_WIDTH-1)>>1;\r
794             rt = BOARD_HEIGHT-1;\r
795             ft = BOARD_LEFT+1;\r
796         } else {\r
797             rf = BOARD_HEIGHT-1;\r
798             ff = BOARD_WIDTH>>1;\r
799             rt = BOARD_HEIGHT-1;\r
800             ft = BOARD_RGHT-2;\r
801         }\r
802     }\r
803     if(PosFlags(0) & F_FRC_TYPE_CASTLING) {
804         if (WhiteOnMove(yyboardindex)) {\r
805             ff = initialRights[2];\r
806             ft = initialRights[0];\r
807         } else {\r
808             ff = initialRights[5];\r
809             ft = initialRights[3];\r
810         }\r
811     if (appData.debugMode) {\r
812         fprintf(debugFP, "Parser FRC short %d %d\n", ff, ft);\r
813     }\r
814         if(ff < 0 || ft < 0) return 0;\r
815     }\r
816     sprintf(currentMoveString, "%c%c%c%c",ff+AAA,rf+ONE,ft+AAA,rt+ONE);\r
817     if (appData.debugMode) {\r
818         fprintf(debugFP, "short castling %d %d\n", ff, ft);\r
819     }\r
820 \r
821     return (int) LegalityTest(boards[yyboardindex],\r
822                               PosFlags(yyboardindex)&~F_MANDATORY_CAPTURE, // [HGM] losers: e.p.!\r
823                               rf, ff, rt, ft, NULLCHAR);\r
824 }\r
825 \r
826 [A-Z][@*][a-l][0-9] {\r
827     /* Bughouse piece drop. */\r
828     currentMoveString[1] = '@';\r
829     currentMoveString[2] = yytext[2];\r
830     currentMoveString[3] = yytext[3];\r
831     currentMoveString[4] = NULLCHAR;\r
832 \r
833     if (appData.debugMode) {\r
834         fprintf(debugFP, "Drop: %s\n", currentMoveString);\r
835     }\r
836     /* [HGM] do not allow values beyond board size */\r
837     if(currentMoveString[3] - ONE >= BOARD_HEIGHT ||\r
838        currentMoveString[2] - AAA >= BOARD_WIDTH     )\r
839       return ImpossibleMove;\r
840 \r
841     if (WhiteOnMove(yyboardindex)) {\r
842         currentMoveString[0] = ToUpper(yytext[0]);\r
843     } else {\r
844         currentMoveString[0] = ToLower(yytext[0]);\r
845     }\r
846     return LegalityTest(boards[yyboardindex], PosFlags(yyboardindex), DROP_RANK, // [HGM] does drops now too
847                         CharToPiece(currentMoveString[0]), currentMoveString[3] - ONE, currentMoveString[2] - AAA, NULLCHAR);
848 }\r
849 \r
850 [Rr]esign(s|ed)?  {\r
851     if (WhiteOnMove(yyboardindex))\r
852       return (int) BlackWins;\r
853     else\r
854       return (int) WhiteWins;\r
855 }\r
856 \r
857 (([Ww](hite)?)|([Bb](lack)?))" "(([Rr]esign)|([Ff]orfeit))(s|ed)?  {\r
858     return (int) (ToUpper(yytext[0]) == 'W' ? BlackWins : WhiteWins);\r
859 }\r
860 \r
861 (([Ww](hite)?)|([Bb](lack)?))" "[Dd]isconnect(s|ed)  {\r
862     return (int) GameUnfinished;\r
863 }\r
864 \r
865 [Ss]talemate  {\r
866     return (int) GameIsDrawn;\r
867 }\r
868 \r
869 "+-+"  {\r
870     return (int) GameIsDrawn;\r
871 }\r
872 \r
873 ([Cc]heck)?[Mm]ate {\r
874     if (WhiteOnMove(yyboardindex))\r
875       return (int) BlackWins;\r
876     else\r
877       return (int) WhiteWins;\r
878 }\r
879 \r
880 "++"  {\r
881     if (WhiteOnMove(yyboardindex))\r
882       return (int) BlackWins;\r
883     else\r
884       return (int) WhiteWins;\r
885 }\r
886 \r
887 [Dd]raw(n)?(" "by)?(" "[Rr]epetition)|(" "[Aa]gree(d|ment))  {\r
888     return (int) GameIsDrawn;\r
889 }\r
890 \r
891 [Dd]raw(n)?(" (".*")")?  {\r
892     return (int) GameIsDrawn;\r
893 }\r
894 \r
895 (([Ww](hite)?)|([Bb](lack)?))" "(([Mm]ates)|([Ww][io]n(s)?)) { \r
896     return (int) (ToUpper(yytext[0]) == 'W' ? WhiteWins : BlackWins);\r
897 }\r
898 \r
899 (([Ww](hite)?)|([Bb](lack)?))" "(([Mm]ated)|([Ll]os[tes]+)) { \r
900     return (int) (ToUpper(yytext[0]) == 'W' ? BlackWins : WhiteWins);\r
901 }\r
902 \r
903 ("{"[^\}\n]*"} ")?(1-0|"1 - 0"|"1/0"|"1 / 0"|"1:0"|"1 : 0")(" (".*")"|" {".*"}")? { \r
904     return (int) WhiteWins;\r
905 }\r
906 \r
907 ("{"[^\}\n]*"} ")?(0-1|"0 - 1"|"0/1"|"0 / 1"|"0:1"|"0 : 1")(" (".*")"|" {".*"}")? { \r
908     return (int) BlackWins;\r
909 }\r
910 \r
911 ("{"[^\}\n]*"} ")?("1/2"|"1 / 2")(" "?[-:]" "?("1/2"|"1 / 2"))?(" (".*")"|" {".*"}")? {\r
912     return (int) GameIsDrawn;\r
913 }\r
914 \r
915 ("{"[^\}\n]*"} ")?"*"(" (".*")"|" {".*"}")? {\r
916     return (int) GameUnfinished;\r
917 }\r
918 \r
919 [1-9][0-9]*/"."?[ \t\n]*[a-lNnPpRrBQqKACFEWDGHOo]    {\r
920     /* move numbers */\r
921     if ((yyleng == 1) && (yytext[0] == '1'))\r
922       return (int) MoveNumberOne;\r
923 }\r
924 \r
925 \([0-9]+:[0-9][0-9](\.[0-9]+)?\)|\{[0-9]+:[0-9][0-9](\.[0-9]+)?\} {\r
926     /* elapsed time indication, e.g. (0:12) or {10:21.071} */ \r
927     return (int) ElapsedTime;\r
928 }\r
929 \r
930 "[--"[^\]]*"--]" {\r
931     /* position diagram enclosed in [-- --] */\r
932     return (int) PositionDiagram;\r
933 }\r
934 \r
935 ^"{--------------"\n[^\}]*\n"--------------}"$ {\r
936     /* position diagram enclosed in {-- --} */\r
937     return (int) PositionDiagram;\r
938 }\r
939 \r
940 \[[ \t\n]*[A-Za-z0-9][A-Za-z0-9_+#=-]*[ \t\n]*\"[^"]*\"[ \t\n]*\] {\r
941     return (int) PGNTag;\r
942 }    \r
943 \r
944 [Gg](nu|NU)" "?[Cc](hess|HESS).*[Gg](ame|AME) {\r
945     return (int) GNUChessGame;\r
946 }\r
947 \r
948 ^[#;%]" "[^ ]*(" game file"|" position file").*$ {\r
949     return (int) XBoardGame;\r
950 }\r
951 \r
952 \$[0-9]+        {                               /* numeric annotation glyph */\r
953     return (int) NAG;\r
954 }\r
955 \r
956 \{[^\}]*\}      {                               /* anything in {} */\r
957     return (int) Comment; \r
958 }\r
959 \r
960 ;.*$ {                                          /* ; to end of line */\r
961     return (int) Comment;\r
962 }\r
963 \r
964 \[[^\]]*\]      {                               /* anything in [] */\r
965     return (int) Comment; \r
966 }\r
967 \r
968 \([^()]*(\([^()]*(\([^()]*(\([^()]*\)[^()]*)*\)[^()]*)*\)[^()]*)+[^()]*\)  { /* very nested () */\r
969     return (int) Comment; \r
970 }\r
971 \r
972 \([^)][^)]+\)   {                               /* >=2 chars in () */\r
973     return (int) Comment; \r
974 }       \r
975 \r
976 ^[-a-zA-Z0-9]+:" ".*(\n[ \t]+.*)*  {\r
977         /* Skip mail headers */\r
978 }\r
979 \r
980 [a-zA-Z0-9'-]+                  {\r
981         /* Skip random words */\r
982 }\r
983 \r
984 .|\n                            {\r
985         /* Skip everything else */\r
986 }\r
987 \r
988 %%\r
989 \r
990 \r
991 static char *StringToLex;\r
992 \r
993 #ifndef FLEX_SCANNER\r
994 static FILE *lexFP;\r
995 \r
996 static int input()\r
997 {\r
998     int ret;\r
999     \r
1000     if (StringToLex != NULL) {\r
1001         ret = *StringToLex;\r
1002         if (ret == NULLCHAR)\r
1003           ret = EOF;\r
1004         else\r
1005           StringToLex++;\r
1006     } else if (unputCount > 0) {\r
1007         ret = unputBuffer[--unputCount];\r
1008     } else {\r
1009         ret = fgetc(lexFP);\r
1010     }    \r
1011 \r
1012     if (ret == EOF) \r
1013       return 0;\r
1014     else\r
1015       return ret;\r
1016 }\r
1017 \r
1018 /*\r
1019  * Return offset of next pattern within current file\r
1020  */\r
1021 int yyoffset()\r
1022 {\r
1023     int offset = ftell(lexFP) - unputCount;\r
1024 \r
1025     if (offset < 0) {\r
1026         offset = 0;\r
1027     }\r
1028     return(offset);\r
1029 }\r
1030  \r
1031 static void output(ch)\r
1032      int ch;\r
1033 {\r
1034     if(appData.debugMode) fprintf(debugFP, "PARSER BUG: unmatched character '%c' (0%o)\n",\r
1035             ch, ch);\r
1036 }\r
1037 \r
1038 static void unput(ch)\r
1039      int ch;\r
1040 {\r
1041     if (ch == 0) return;\r
1042     if (StringToLex != NULL) {\r
1043         StringToLex--;\r
1044     } else {\r
1045         if (unputCount >= UNPUT_BUF_SIZE)\r
1046           if(appData.debugMode) fprintf(debugFP, "PARSER BUG: unput buffer overflow '%c' (0%o)\n",\r
1047                   ch, ch);\r
1048         unputBuffer[unputCount++] = ch;\r
1049     }\r
1050 }\r
1051 \r
1052 /* Get ready to lex from a new file.  Kludge below sticks\r
1053    an artificial newline at the front of the file, which the\r
1054    above grammar ignores, but which makes ^ at start of pattern\r
1055    match at the real start of the file.\r
1056 */\r
1057 void yynewfile(f)\r
1058      FILE *f;\r
1059 {\r
1060     lexFP = f;\r
1061     StringToLex = NULL;\r
1062     unputCount = 0;\r
1063     unput('\n'); /* kludge */\r
1064 }\r
1065 \r
1066 /* Get ready to lex from a string.  ^ at start of pattern WON'T\r
1067    match at the start of the string!\r
1068 */\r
1069 void yynewstr(s)\r
1070      char *s;\r
1071 {\r
1072     lexFP = NULL;\r
1073     StringToLex = s;\r
1074     unputCount = 0;\r
1075 }\r
1076 #endif /*!FLEX_SCANNER*/\r
1077 \r
1078 #ifdef FLEX_SCANNER\r
1079 void my_yy_input(buf, result, max_size)\r
1080      char *buf;\r
1081      int *result;\r
1082      int max_size;\r
1083 {\r
1084     int count;\r
1085 \r
1086     if (StringToLex != NULL) {\r
1087         count = 0;\r
1088         while (*StringToLex != NULLCHAR) {\r
1089             *buf++ = *StringToLex++;\r
1090             count++;\r
1091         }\r
1092         *result = count;\r
1093         return;\r
1094     } else {\r
1095         count = fread(buf, 1, max_size, yyin);\r
1096         if (count == 0) {\r
1097             *result = YY_NULL;\r
1098         } else {\r
1099             *result = count;\r
1100         }\r
1101         return;\r
1102     }    \r
1103 }\r
1104 \r
1105 static YY_BUFFER_STATE my_file_buffer = NULL;\r
1106 \r
1107 /*\r
1108     Return offset of next pattern in the current file.\r
1109 */\r
1110 int yyoffset()\r
1111 {\r
1112     int pos = yy_c_buf_p - YY_CURRENT_BUFFER->yy_ch_buf;\r
1113 \r
1114     return(ftell(YY_CURRENT_BUFFER->yy_input_file) -\r
1115          yy_n_chars + pos);\r
1116 }\r
1117 \r
1118 \r
1119 void yynewstr(s)\r
1120      char *s;\r
1121 {\r
1122     if (my_file_buffer != NULL)\r
1123       yy_delete_buffer(my_file_buffer);\r
1124     StringToLex = s;\r
1125     my_file_buffer = yy_create_buffer(stdin, YY_BUF_SIZE);\r
1126     yy_switch_to_buffer(my_file_buffer);\r
1127 }\r
1128 \r
1129 void yynewfile(f)\r
1130      FILE *f;\r
1131 {\r
1132     if (my_file_buffer != NULL)\r
1133       yy_delete_buffer(my_file_buffer);\r
1134     StringToLex = NULL;\r
1135     my_file_buffer = yy_create_buffer(f, YY_BUF_SIZE);\r
1136     yy_switch_to_buffer(my_file_buffer);\r
1137 }\r
1138 #endif /*FLEX_SCANNER*/\r
1139 \r
1140 int yywrap()\r
1141 {\r
1142     return TRUE;\r
1143 }\r
1144 \r
1145 /* Parse a move from the given string s */\r
1146 /* ^ at start of pattern WON'T work here unless using flex */\r
1147 ChessMove yylexstr(boardIndex, s, text, len)\r
1148      int boardIndex, len;\r
1149      char *s, *text;\r
1150 {
1151     ChessMove ret;\r
1152     char *oldStringToLex;\r
1153 #ifdef FLEX_SCANNER\r
1154     YY_BUFFER_STATE buffer, oldBuffer;\r
1155 #endif\r
1156     \r
1157     yyboardindex = boardIndex;\r
1158     oldStringToLex = StringToLex;\r
1159     StringToLex = s;\r
1160 #ifdef FLEX_SCANNER\r
1161     buffer = yy_create_buffer(stdin, YY_BUF_SIZE);\r
1162     oldBuffer = YY_CURRENT_BUFFER;\r
1163     yy_switch_to_buffer(buffer);\r
1164 #endif /*FLEX_SCANNER*/\r
1165 \r
1166     ret = (ChessMove) yylex();
1167      strncpy(text, yy_text, len-1); // [HGM] vari: yy_text is not available to caller after buffer switch ?!?
1168      text[len-1] = NULLCHAR;\r
1169 \r
1170 #ifdef FLEX_SCANNER\r
1171     if (oldBuffer != NULL) \r
1172       yy_switch_to_buffer(oldBuffer);\r
1173     yy_delete_buffer(buffer);\r
1174 #endif /*FLEX_SCANNER*/\r
1175     StringToLex = oldStringToLex;\r
1176 \r
1177     return ret;\r
1178 }\r