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