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