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