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