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