X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=parser.l;h=82957eb41b19cd497b761c42cebb4580bddd6baf;hb=a5b8066ad78ddeec1ddcca3b31ee26fe1052fc89;hp=39264f518da237a0d3147c71f4508ce0a035e3b1;hpb=05bc30b15e31c427ce208495a889e9ff36e6642b;p=xboard.git diff --git a/parser.l b/parser.l old mode 100644 new mode 100755 index 39264f5..82957eb --- a/parser.l +++ b/parser.l @@ -1,922 +1,1130 @@ -%a 10000 -%o 10000 -%e 2000 -%k 2500 -%p 7000 -%n 1000 -%{ -/* - * parser.l -- lex parser of algebraic chess moves for XBoard - * $Id$ - * - * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts. - * Enhancements Copyright 1992-95 Free Software Foundation, Inc. - * - * The following terms apply to Digital Equipment Corporation's copyright - * interest in XBoard: - * ------------------------------------------------------------------------ - * All Rights Reserved - * - * Permission to use, copy, modify, and distribute this software and its - * documentation for any purpose and without fee is hereby granted, - * provided that the above copyright notice appear in all copies and that - * both that copyright notice and this permission notice appear in - * supporting documentation, and that the name of Digital not be - * used in advertising or publicity pertaining to distribution of the - * software without specific, written prior permission. - * - * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING - * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL - * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR - * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, - * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, - * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - * SOFTWARE. - * ------------------------------------------------------------------------ - * - * The following terms apply to the enhanced version of XBoard distributed - * by the Free Software Foundation: - * ------------------------------------------------------------------------ - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * ------------------------------------------------------------------------ - */ - -/* This parser handles all forms of promotion. - * The parser resolves ambiguous moves by searching and check-testing. - * It also parses comments of the form [anything] or (anything). - */ - -#include "config.h" - -#define NO_CONSTRAINT -1 -#undef YYLMAX -#define YYLMAX 4096 -#define UNPUT_BUF_SIZE YYLMAX - -#ifdef FLEX_SCANNER -/* yytext is probably a char*, but could be a char[]. yy_text is set - in YY_DECL below, because if yytext is a char*, its value is not - constant. */ -char *yy_text; -#else /*!FLEX_SCANNER*/ -/* yytext is definitely a char[], so yy_text can be set here, statically. */ -char *yy_text = (char *) yytext; -#endif - -#ifdef FLEX_SCANNER -/* This is flex */ -#undef YY_INPUT -#define YY_INPUT(buf, result, max_size) my_yy_input(buf, &result, max_size) -#undef YY_DECL -#define YY_DECL \ - int _yylex YY_PROTO((void)); \ - int yylex YY_PROTO((void)) \ - { \ - int result = _yylex(); \ - yy_text = (char *) yytext; \ - return(result); \ - } \ - int _yylex YY_PROTO((void)) -#else -/* This is lex */ -#undef input -#undef output -#undef unput -#endif - -/* The includes must be here, below the #undef input */ - -#include - -#if STDC_HEADERS -# include -# include -#else /* not STDC_HEADERS */ -# if HAVE_STRING_H -# include -# else /* not HAVE_STRING_H */ -# include -# endif /* not HAVE_STRING_H */ -#endif /* not STDC_HEADERS */ - -#if HAVE_UNISTD_H -# include -#endif - -#if defined(_amigados) -# include -# if HAVE_FCNTL_H -# include /* isatty() prototype */ -# endif /* HAVE_FCNTL_H */ -#endif /* defined(_amigados) */ - -#include "common.h" -#include "backend.h" -#include "frontend.h" -#include "parser.h" -#include "moves.h" - -extern int PosFlags P((int)); - -extern Board boards[MAX_MOVES]; -int yyboardindex; -int yyskipmoves = FALSE; -char currentMoveString[YYLMAX]; -#ifndef FLEX_SCANNER -char unputBuffer[UNPUT_BUF_SIZE]; -int unputCount = 0; -#endif - -#ifdef FLEX_SCANNER -void my_yy_input P((char *buf, int *result, int max_size)); -#else /*!FLEX_SCANNER*/ -static int input P((void)); -static void output P((int ch)); -static void unput P((int ch)); -int yylook P((void)); -int yyback P((int *, int)); -#endif -#undef yywrap -int yywrap P((void)); -extern void CopyBoard P((Board to, Board from)); - -%} -%% - -[RrBbNnQqKkPp][/]?[a-h][1-8][xX:-]?[a-h][1-8](=?\(?[RrBbNnQqKk]\)?)? { - /* - * Fully-qualified algebraic move, possibly with promotion - */ - int skip1 = 0, skip2 = 0; - ChessSquare piece; - ChessMove result; - - if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */ - - /* remove the / */ - if (yytext[1] == '/') skip1 = 1; - - /* remove the [xX:-] */ - if ((yytext[3+skip1] == 'x') || (yytext[3+skip1] == 'X') || - (yytext[3+skip1] == '-') || (yytext[3+skip1] == ':')) skip2 = 1; - - currentMoveString[0] = yytext[1+skip1]; - currentMoveString[1] = yytext[2+skip1]; - currentMoveString[2] = yytext[3+skip1+skip2]; - currentMoveString[3] = yytext[4+skip1+skip2]; - currentMoveString[4] = NULLCHAR; - - if (yyleng-skip1-skip2 > 5) { - if (yytext[yyleng-1] == ')') { - currentMoveString[4] = ToLower(yytext[yyleng-2]); - } else { - currentMoveString[4] = ToLower(yytext[yyleng-1]); - } - currentMoveString[5] = NULLCHAR; - } - - piece = boards[yyboardindex] - [currentMoveString[1] - '1'][currentMoveString[0] - 'a']; - if (ToLower(yytext[0]) != ToLower(PieceToChar(piece))) - return (int) IllegalMove; - - result = LegalityTest(boards[yyboardindex], - PosFlags(yyboardindex), EP_UNKNOWN, - currentMoveString[1] - '1', - currentMoveString[0] - 'a', - currentMoveString[3] - '1', - currentMoveString[2] - 'a', - currentMoveString[4]); - - if (currentMoveString[4] == NULLCHAR && - (result == WhitePromotionQueen || result == BlackPromotionQueen)) { - currentMoveString[4] = 'q'; - currentMoveString[5] = NULLCHAR; - } - - return (int) result; -} - -[a-h][1-8][xX:-]?[a-h][1-8](=?\(?[RrBbNnQqKk]\)?)? { - /* - * Simple algebraic move, possibly with promotion - */ - int skip = 0; - ChessMove result; - - if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */ - - /* remove the [xX:-] */ - if ((yytext[2] == 'x') || (yytext[2] == 'X') || - (yytext[2] == '-') || (yytext[2] == ':')) skip = 1; - - currentMoveString[0] = yytext[0]; - currentMoveString[1] = yytext[1]; - currentMoveString[2] = yytext[2+skip]; - currentMoveString[3] = yytext[3+skip]; - currentMoveString[4] = NULLCHAR; - - if (yyleng-skip > 4) { - if (yytext[yyleng-1] == ')') { - currentMoveString[4] = ToLower(yytext[yyleng-2]); - } else { - currentMoveString[4] = ToLower(yytext[yyleng-1]); - } - currentMoveString[5] = NULLCHAR; - } - - result = LegalityTest(boards[yyboardindex], - PosFlags(yyboardindex), EP_UNKNOWN, - currentMoveString[1] - '1', - currentMoveString[0] - 'a', - currentMoveString[3] - '1', - currentMoveString[2] - 'a', - currentMoveString[4]); - - if (currentMoveString[4] == NULLCHAR && - (result == WhitePromotionQueen || result == BlackPromotionQueen)) { - currentMoveString[4] = 'q'; - currentMoveString[5] = NULLCHAR; - } - - return (int) result; -} - -[a-h][1-8](=?\(?[RrBbNnQqKk]\)?)? { - /* - * Pawn move, possibly with promotion - */ - DisambiguateClosure cl; - int skip = 0; - - if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */ - - /* remove the =() */ - if (yytext[2] == '=') skip++; - if (yytext[2+skip] == '(') skip++; - - cl.pieceIn = WhiteOnMove(yyboardindex) ? WhitePawn : BlackPawn; - cl.rfIn = -1; - cl.ffIn = yytext[0] - 'a'; - cl.rtIn = yytext[1] - '1'; - cl.ftIn = yytext[0] - 'a'; - cl.promoCharIn = yytext[2+skip]; - Disambiguate(boards[yyboardindex], - PosFlags(yyboardindex), EP_UNKNOWN, &cl); - - currentMoveString[0] = cl.ff + 'a'; - currentMoveString[1] = cl.rf + '1'; - currentMoveString[2] = cl.ft + 'a'; - currentMoveString[3] = cl.rt + '1'; - currentMoveString[4] = cl.promoChar; - currentMoveString[5] = NULLCHAR; - - return (int) cl.kind; -} - - -(ab|bc|cd|de|ef|fg|gh|hg|gf|fe|ed|dc|cb|ba|([a-h][xX:-][a-h]))(=?\(?[RrBbNnQqKk]\)?)?(ep|"e.p.")? { - /* - * Pawn capture, possibly with promotion, possibly ambiguous - */ - DisambiguateClosure cl; - int skip1 = 0, skip2 = 0; - - if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */ - - /* remove trailing ep or e.p. (nonstandard PGN) */ - if (yytext[yyleng-1] == 'p') { - yyleng -= 2; - yytext[yyleng] = NULLCHAR; - } else if (yytext[yyleng-1] == '.') { - yyleng -= 4; - yytext[yyleng] = NULLCHAR; - } - - /* remove the [xX:-] and =() */ - if ((yytext[1] == 'x') || (yytext[1] == 'X') - || (yytext[1] == ':') || (yytext[1] == '-')) skip1 = 1; - if (yytext[2+skip1] == '=') skip2++; - if (yytext[2+skip1+skip2] == '(') skip2++; - - cl.pieceIn = WhiteOnMove(yyboardindex) ? WhitePawn : BlackPawn; - cl.rfIn = -1; - cl.ffIn = yytext[0] - 'a'; - cl.rtIn = -1; - cl.ftIn = yytext[1+skip1] - 'a'; - cl.promoCharIn = yytext[2+skip1+skip2]; - Disambiguate(boards[yyboardindex], - PosFlags(yyboardindex), EP_UNKNOWN, &cl); - - currentMoveString[0] = cl.ff + 'a'; - currentMoveString[1] = cl.rf + '1'; - currentMoveString[2] = cl.ft + 'a'; - currentMoveString[3] = cl.rt + '1'; - currentMoveString[4] = cl.promoChar; - currentMoveString[5] = NULLCHAR; - - return (int) cl.kind; -} - -[a-h][xX:]?[a-h][1-8](=?\(?[RrBbNnQqKk]\)?)?(ep|"e.p.")? { - /* - * unambiguously abbreviated Pawn capture, possibly with promotion - */ - int skip = 0; - ChessMove result; - - if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */ - - /* remove trailing ep or e.p. (nonstandard PGN) */ - if (yytext[yyleng-1] == 'p') { - yyleng -= 2; - yytext[yyleng] = NULLCHAR; - } else if (yytext[yyleng-1] == '.') { - yyleng -= 4; - yytext[yyleng] = NULLCHAR; - } - - /* remove the [xX:-] */ - if ((yytext[1] == 'x') || (yytext[1] == 'X') - || (yytext[1] == ':') || (yytext[1] == '-')) skip = 1; - - currentMoveString[0] = yytext[0]; - currentMoveString[2] = yytext[1+skip]; - currentMoveString[3] = yytext[2+skip]; - if (WhiteOnMove(yyboardindex)) { - if (yytext[2+skip] == '1') return (int) ImpossibleMove; - currentMoveString[1] = yytext[2+skip] - 1; - } else { - if (yytext[2+skip] == '8') return (int) ImpossibleMove; - currentMoveString[1] = yytext[2+skip] + 1; - } - if (yyleng-skip > 3) { - if (yytext[yyleng-1] == ')') - currentMoveString[4] = ToLower(yytext[yyleng-2]); - else - currentMoveString[4] = ToLower(yytext[yyleng-1]); - currentMoveString[5] = NULLCHAR; - } else { - currentMoveString[4] = NULLCHAR; - } - - result = LegalityTest(boards[yyboardindex], - PosFlags(yyboardindex), EP_UNKNOWN, - currentMoveString[1] - '1', - currentMoveString[0] - 'a', - currentMoveString[3] - '1', - currentMoveString[2] - 'a', - currentMoveString[4]); - - if (currentMoveString[4] == NULLCHAR && - (result == WhitePromotionQueen || result == BlackPromotionQueen)) { - currentMoveString[4] = 'q'; - currentMoveString[5] = NULLCHAR; - } - - if (result != IllegalMove) return (int) result; - - /* Special case: improperly written en passant capture */ - if (WhiteOnMove(yyboardindex)) { - if (currentMoveString[3] == '5') { - currentMoveString[1] = '5'; - currentMoveString[3] = '6'; - } else { - return (int) IllegalMove; - } - } else { - if (currentMoveString[3] == '4') { - currentMoveString[1] = '4'; - currentMoveString[3] = '3'; - } else { - return (int) IllegalMove; - } - } - - result = LegalityTest(boards[yyboardindex], - PosFlags(yyboardindex), EP_UNKNOWN, - currentMoveString[1] - '1', - currentMoveString[0] - 'a', - currentMoveString[3] - '1', - currentMoveString[2] - 'a', - currentMoveString[4]); - - if (result == WhiteCapturesEnPassant || result == BlackCapturesEnPassant) - return (int) result; - else - return (int) IllegalMove; -} - -[RrBbNnQqKk][xX:-]?[a-h][1-8] { - /* - * piece move, possibly ambiguous - */ - DisambiguateClosure cl; - int skip = 0; - - if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */ - - /* remove the [xX:-] */ - if ((yytext[1] == 'x') || (yytext[1] == 'X') - || (yytext[1] == ':') || (yytext[1] == '-')) skip = 1; - - if (WhiteOnMove(yyboardindex)) { - cl.pieceIn = CharToPiece(ToUpper(yytext[0])); - } else { - cl.pieceIn = CharToPiece(ToLower(yytext[0])); - } - cl.rfIn = -1; - cl.ffIn = -1; - cl.rtIn = yytext[2+skip] - '1'; - cl.ftIn = yytext[1+skip] - 'a'; - cl.promoCharIn = NULLCHAR; - Disambiguate(boards[yyboardindex], - PosFlags(yyboardindex), EP_UNKNOWN, &cl); - - currentMoveString[0] = cl.ff + 'a'; - currentMoveString[1] = cl.rf + '1'; - currentMoveString[2] = cl.ft + 'a'; - currentMoveString[3] = cl.rt + '1'; - currentMoveString[4] = cl.promoChar; - currentMoveString[5] = NULLCHAR; - - return (int) cl.kind; -} - -[RrBbNnQqKk][a-h1-8][xX:-]?[a-h][1-8] { - /* - * piece move with rank or file disambiguator - */ - DisambiguateClosure cl; - int skip = 0; - - if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */ - - /* remove the [xX:-] */ - if ((yytext[2] == 'x') || (yytext[2] == 'X') - || (yytext[2] == ':') || (yytext[2] == '-')) skip = 1; - - if (WhiteOnMove(yyboardindex)) { - cl.pieceIn = CharToPiece(ToUpper(yytext[0])); - } else { - cl.pieceIn = CharToPiece(ToLower(yytext[0])); - } - if (isalpha(yytext[1])) { - cl.rfIn = -1; - cl.ffIn = yytext[1] - 'a'; - } else { - cl.rfIn = yytext[1] - '1'; - cl.ffIn = -1; - } - cl.rtIn = yytext[3+skip] - '1'; - cl.ftIn = yytext[2+skip] - 'a'; - cl.promoCharIn = NULLCHAR; - Disambiguate(boards[yyboardindex], - PosFlags(yyboardindex), EP_UNKNOWN, &cl); - - currentMoveString[0] = cl.ff + 'a'; - currentMoveString[1] = cl.rf + '1'; - currentMoveString[2] = cl.ft + 'a'; - currentMoveString[3] = cl.rt + '1'; - currentMoveString[4] = cl.promoChar; - currentMoveString[5] = NULLCHAR; - - return (int) cl.kind; -} - -000|0-0-0|ooo|OOO|o-o-o|O-O-O { - int rf, ff, rt, ft; - - if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */ - - if (WhiteOnMove(yyboardindex)) { - if (boards[yyboardindex][0][3] == WhiteKing) { - /* ICS wild castling */ - strcpy(currentMoveString, "d1f1"); - rf = 0; - ff = 3; - rt = 0; - ft = 5; - } else { - strcpy(currentMoveString, "e1c1"); - rf = 0; - ff = 4; - rt = 0; - ft = 2; - } - } else{ - if (boards[yyboardindex][7][3] == BlackKing) { - /* ICS wild castling */ - strcpy(currentMoveString, "d8f8"); - rf = 7; - ff = 3; - rt = 7; - ft = 5; - } else { - strcpy(currentMoveString, "e8c8"); - rf = 7; - ff = 4; - rt = 7; - ft = 2; - } - } - return (int) LegalityTest(boards[yyboardindex], - PosFlags(yyboardindex), EP_UNKNOWN, - rf, ff, rt, ft, NULLCHAR); -} - -00|0-0|oo|OO|o-o|O-O { - int rf, ff, rt, ft; - - if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */ - - if (WhiteOnMove(yyboardindex)) { - if (boards[yyboardindex][0][3] == WhiteKing) { - /* ICS wild castling */ - strcpy(currentMoveString, "d1b1"); - rf = 0; - ff = 3; - rt = 0; - ft = 1; - } else { - strcpy(currentMoveString, "e1g1"); - rf = 0; - ff = 4; - rt = 0; - ft = 6; - } - } else { - if (boards[yyboardindex][7][3] == BlackKing) { - /* ICS wild castling */ - strcpy(currentMoveString, "d8b8"); - rf = 7; - ff = 3; - rt = 7; - ft = 1; - } else { - strcpy(currentMoveString, "e8g8"); - rf = 7; - ff = 4; - rt = 7; - ft = 6; - } - } - return (int) LegalityTest(boards[yyboardindex], - PosFlags(yyboardindex), EP_UNKNOWN, - rf, ff, rt, ft, NULLCHAR); -} - -[PpNnBbRrQq]@[a-h][1-8] { - /* Bughouse piece drop. No legality checking for now. */ - currentMoveString[1] = '@'; - currentMoveString[2] = yytext[2]; - currentMoveString[3] = yytext[3]; - currentMoveString[4] = NULLCHAR; - if (WhiteOnMove(yyboardindex)) { - currentMoveString[0] = ToUpper(yytext[0]); - return (int) WhiteDrop; - } else { - currentMoveString[0] = ToLower(yytext[0]); - return (int) BlackDrop; - } -} - -[Rr]esign(s|ed)? { - if (WhiteOnMove(yyboardindex)) - return (int) BlackWins; - else - return (int) WhiteWins; -} - -(([Ww](hite)?)|([Bb](lack)?))" "(([Rr]esign)|([Ff]orfeit))(s|ed)? { - return (int) (ToUpper(yytext[0]) == 'W' ? BlackWins : WhiteWins); -} - -(([Ww](hite)?)|([Bb](lack)?))" "[Dd]isconnect(s|ed) { - return (int) GameUnfinished; -} - -[Ss]talemate { - return (int) GameIsDrawn; -} - -"+-+" { - return (int) GameIsDrawn; -} - -([Cc]heck)?[Mm]ate { - if (WhiteOnMove(yyboardindex)) - return (int) BlackWins; - else - return (int) WhiteWins; -} - -"++" { - if (WhiteOnMove(yyboardindex)) - return (int) BlackWins; - else - return (int) WhiteWins; -} - -[Dd]raw(n)?(" "by)?(" "[Rr]epetition)|(" "[Aa]gree(d|ment)) { - return (int) GameIsDrawn; -} - -[Dd]raw(n)?(" (".*")")? { - return (int) GameIsDrawn; -} - -(([Ww](hite)?)|([Bb](lack)?))" "([Mm]ate(s|ed)?)|([Ww][io]n(s)?.*) { - return (int) (ToUpper(yytext[0]) == 'W' ? WhiteWins : BlackWins); -} - -(([Ww](hite)?)|([Bb](lack)?))" "([Mm]ate(s|ed)?)|([Ll]os[tes]+.*) { - return (int) (ToUpper(yytext[0]) == 'W' ? BlackWins : WhiteWins); -} - -("{"[^\}\n]*"} ")?(1-0|"1 - 0"|"1/0"|"1 / 0"|"1:0"|"1 : 0")(" (".*")"|" {".*"}")? { - return (int) WhiteWins; -} - -("{"[^\}\n]*"} ")?(0-1|"0 - 1"|"0/1"|"0 / 1"|"0:1"|"0 : 1")(" (".*")"|" {".*"}")? { - return (int) BlackWins; -} - -("{"[^\}\n]*"} ")?("1/2"|"1 / 2")(" "?[-:]" "?("1/2"|"1 / 2"))?(" (".*")"|" {".*"}")? { - return (int) GameIsDrawn; -} - -("{"[^\}\n]*"} ")?"*"(" (".*")"|" {".*"}")? { - return (int) GameUnfinished; -} - -[1-9][0-9]*/"."?[ \t\n]*[a-hNnPpRrBQqKkOo] { - /* move numbers */ - if ((yyleng == 1) && (yytext[0] == '1')) - return (int) MoveNumberOne; -} - -\([0-9]+:[0-9][0-9](\.[0-9]+)?\)|\{[0-9]+:[0-9][0-9](\.[0-9]+)?\} { - /* elapsed time indication, e.g. (0:12) or {10:21.071} */ - return (int) ElapsedTime; -} - -"[--"[^\]]*"--]" { - /* position diagram enclosed in [-- --] */ - return (int) PositionDiagram; -} - -^"{--------------"\n[^\}]*\n"--------------}"$ { - /* position diagram enclosed in {-- --} */ - return (int) PositionDiagram; -} - -\[[ \t\n]*[A-Za-z0-9][A-Za-z0-9_+#=-]*[ \t\n]*\"[^"]*\"[ \t\n]*\] { - return (int) PGNTag; -} - -[Gg](nu|NU)" "?[Cc](hess|HESS).*[Gg](ame|AME) { - return (int) GNUChessGame; -} - -^[#;%]" "[^ ]*(" game file"|" position file").*$ { - return (int) XBoardGame; -} - -\$[0-9]+ { /* numeric annotation glyph */ - return (int) NAG; -} - -\{[^\}]*\} { /* anything in {} */ - return (int) Comment; -} - -;.*$ { /* ; to end of line */ - return (int) Comment; -} - -\[[^\]]*\] { /* anything in [] */ - return (int) Comment; -} - -\([^()]*(\([^()]*\)[^()]*)+[^()]*\) { /* nested () */ - return (int) Comment; -} - -\([^)][^)]+\) { /* >=2 chars in () */ - return (int) Comment; -} - -^[-a-zA-Z0-9]+:" ".*(\n[ \t]+.*)* { - /* Skip mail headers */ -} - -[a-zA-Z0-9'-]+ { - /* Skip random words */ -} - -.|\n { - /* Skip everything else */ -} - -%% - - -static char *StringToLex; - -#ifndef FLEX_SCANNER -static FILE *lexFP; - -static int input() -{ - int ret; - - if (StringToLex != NULL) { - ret = *StringToLex; - if (ret == NULLCHAR) - ret = EOF; - else - StringToLex++; - } else if (unputCount > 0) { - ret = unputBuffer[--unputCount]; - } else { - ret = fgetc(lexFP); - } - - if (ret == EOF) - return 0; - else - return ret; -} - -/* - * Return offset of next pattern within current file - */ -int yyoffset() -{ - int offset = ftell(lexFP) - unputCount; - - if (offset < 0) { - offset = 0; - } - return(offset); -} - -static void output(ch) - int ch; -{ - fprintf(stderr, "PARSER BUG: unmatched character '%c' (0%o)\n", - ch, ch); -} - -static void unput(ch) - int ch; -{ - if (ch == 0) return; - if (StringToLex != NULL) { - StringToLex--; - } else { - if (unputCount >= UNPUT_BUF_SIZE) - fprintf(stderr, "PARSER BUG: unput buffer overflow '%c' (0%o)\n", - ch, ch); - unputBuffer[unputCount++] = ch; - } -} - -/* Get ready to lex from a new file. Kludge below sticks - an artificial newline at the front of the file, which the - above grammar ignores, but which makes ^ at start of pattern - match at the real start of the file. -*/ -void yynewfile(f) - FILE *f; -{ - lexFP = f; - StringToLex = NULL; - unputCount = 0; - unput('\n'); /* kludge */ -} - -/* Get ready to lex from a string. ^ at start of pattern WON'T - match at the start of the string! -*/ -void yynewstr(s) - char *s; -{ - lexFP = NULL; - StringToLex = s; - unputCount = 0; -} -#endif /*!FLEX_SCANNER*/ - -#ifdef FLEX_SCANNER -void my_yy_input(buf, result, max_size) - char *buf; - int *result; - int max_size; -{ - int count; - - if (StringToLex != NULL) { - count = 0; - while (*StringToLex != NULLCHAR) { - *buf++ = *StringToLex++; - count++; - } - *result = count; - return; - } else { - count = fread(buf, 1, max_size, yyin); - if (count == 0) { - *result = YY_NULL; - } else { - *result = count; - } - return; - } -} - -static YY_BUFFER_STATE my_file_buffer = NULL; - -/* - Return offset of next pattern in the current file. -*/ -int yyoffset() -{ - int pos = yy_c_buf_p - yy_current_buffer->yy_ch_buf; - - return(ftell(yy_current_buffer->yy_input_file) - - yy_n_chars + pos); -} - - -void yynewstr(s) - char *s; -{ - if (my_file_buffer != NULL) - yy_delete_buffer(my_file_buffer); - StringToLex = s; - my_file_buffer = yy_create_buffer(stdin, YY_BUF_SIZE); - yy_switch_to_buffer(my_file_buffer); -} - -void yynewfile(f) - FILE *f; -{ - if (my_file_buffer != NULL) - yy_delete_buffer(my_file_buffer); - StringToLex = NULL; - my_file_buffer = yy_create_buffer(f, YY_BUF_SIZE); - yy_switch_to_buffer(my_file_buffer); -} -#endif /*FLEX_SCANNER*/ - -int yywrap() -{ - return TRUE; -} - -/* Parse a move from the given string s */ -/* ^ at start of pattern WON'T work here unless using flex */ -ChessMove yylexstr(boardIndex, s) - int boardIndex; - char *s; -{ - ChessMove ret; - char *oldStringToLex; -#ifdef FLEX_SCANNER - YY_BUFFER_STATE buffer, oldBuffer; -#endif - - yyboardindex = boardIndex; - oldStringToLex = StringToLex; - StringToLex = s; -#ifdef FLEX_SCANNER - buffer = yy_create_buffer(stdin, YY_BUF_SIZE); - oldBuffer = YY_CURRENT_BUFFER; - yy_switch_to_buffer(buffer); -#endif /*FLEX_SCANNER*/ - - ret = (ChessMove) yylex(); - -#ifdef FLEX_SCANNER - if (oldBuffer != NULL) - yy_switch_to_buffer(oldBuffer); - yy_delete_buffer(buffer); -#endif /*FLEX_SCANNER*/ - StringToLex = oldStringToLex; - - return ret; -} +%a 10000 +%o 10000 +%e 2000 +%k 2500 +%p 7000 +%n 1000 +%{ +/* + * parser.l -- lex parser of algebraic chess moves for XBoard + * + * Copyright 1991 by Digital Equipment Corporation, Maynard, + * Massachusetts. + * + * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, + * 2006, 2007, 2008, 2009 Free Software Foundation, Inc. + * + * The following terms apply to Digital Equipment Corporation's copyright + * interest in XBoard: + * ------------------------------------------------------------------------ + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of Digital not be + * used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING + * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL + * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR + * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * ------------------------------------------------------------------------ + * + * The following terms apply to the enhanced version of XBoard + * distributed by the Free Software Foundation: + * ------------------------------------------------------------------------ + * + * GNU XBoard is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * GNU XBoard is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + *------------------------------------------------------------------------ + ** See the file ChangeLog for a revision history. */ + +/* This parser handles all forms of promotion. + * The parser resolves ambiguous moves by searching and check-testing. + * It also parses comments of the form [anything] or (anything). + * + * [HGM] Parser extensively modified for bigger boards, Shogi-like syntax, + * and unknow pieces. All pieces are now mandatory upper case, but can be + * any letter A-Z. Files must be lower case (as before), but can run upto 'l'. + * Ranks can be 0-9. The parser returns 0 for off-board files and ranks. + * For an unknown piece (as mover or promotion piece) it returns + * IllegalMove, like it does when the piece doesn't match. + * Promotions can now also be appended Shogi-style, a bare '=' or '+', + * and this is then returned as promotion character. The piece indicator + * can be prefixed by a '+' to indicate it is a promoted piece. + */ + +#include "config.h" + +#define NO_CONSTRAINT -1 +#undef YYLMAX +#define YYLMAX 4096 +#define UNPUT_BUF_SIZE YYLMAX + +#ifdef FLEX_SCANNER +/* yytext is probably a char*, but could be a char[]. yy_text is set + in YY_DECL below, because if yytext is a char*, its value is not + constant. */ +char *yy_text; +#else /*!FLEX_SCANNER*/ +/* yytext is definitely a char[], so yy_text can be set here, statically. */ +char *yy_text = (char *) yytext; +#endif + +#ifdef FLEX_SCANNER +/* This is flex */ +/* [AP] use prototypes in function declarations */ +#define YY_USE_PROTOS + +#ifdef YY_USE_PROTOS +#define YY_PROTO(proto) proto +#else +#define YY_PROTO(proto) () +#endif +/* end of [AP] fix */ + +#undef YY_INPUT +#define YY_INPUT(buf, result, max_size) my_yy_input(buf, &result, max_size) +#undef YY_DECL +#define YY_DECL \ + int _yylex YY_PROTO((void)); \ + int yylex YY_PROTO((void)) \ + { \ + int result = _yylex(); \ + yy_text = (char *) yytext; \ + return(result); \ + } \ + int _yylex YY_PROTO((void)) +#else +/* This is lex */ +#undef input +#undef output +#undef unput +#endif + +/* The includes must be here, below the #undef input */ + +#include + +#if STDC_HEADERS +# include +# include +#else /* not STDC_HEADERS */ +# if HAVE_STRING_H +# include +# else /* not HAVE_STRING_H */ +# include +# endif /* not HAVE_STRING_H */ +#endif /* not STDC_HEADERS */ + +#if HAVE_UNISTD_H +# include +#endif + +#if defined(_amigados) +# include +# if HAVE_FCNTL_H +# include /* isatty() prototype */ +# endif /* HAVE_FCNTL_H */ +#endif /* defined(_amigados) */ + +#include "common.h" +#include "backend.h" +#include "frontend.h" +#include "parser.h" +#include "moves.h" + +extern int PosFlags P((int)); + +extern Board boards[MAX_MOVES]; +int yyboardindex; +int yyskipmoves = FALSE; +char currentMoveString[YYLMAX]; +#ifndef FLEX_SCANNER +char unputBuffer[UNPUT_BUF_SIZE]; +int unputCount = 0; +#endif + +#ifdef FLEX_SCANNER +void my_yy_input P((char *buf, int *result, int max_size)); +#else /*!FLEX_SCANNER*/ +static int input P((void)); +static void output P((int ch)); +static void unput P((int ch)); +int yylook P((void)); +int yyback P((int *, int)); +#endif +#undef yywrap +int yywrap P((void)); +extern void CopyBoard P((Board to, Board from)); + +%} +%% + +"+"?[A-Z][/]?[a-l][0-9][xX:-]?[a-l][0-9]((=?\(?[A-Z]\)?)|=)? { + /* + * Fully-qualified algebraic move, possibly with promotion + */ + int skip1 = 0, skip2 = 0, skip3 = 0, promoted = 0; + ChessSquare piece; + ChessMove result; + char c; + + if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */ + + if (yytext[0] == '+') skip1 = skip3 = promoted = 1; /* [HGM] Shogi promoted */ + + /* remove the / */ + if (yytext[1+skip1] == '/') skip1++; + + /* remove the [xX:-] */ + if ((yytext[3+skip1] == 'x') || (yytext[3+skip1] == 'X') || + (yytext[3+skip1] == '-') || (yytext[3+skip1] == ':')) skip2 = 1; + + currentMoveString[0] = yytext[1+skip1]; + currentMoveString[1] = yytext[2+skip1]; + currentMoveString[2] = yytext[3+skip1+skip2]; + currentMoveString[3] = yytext[4+skip1+skip2]; + currentMoveString[4] = NULLCHAR; + + if (appData.debugMode) { + fprintf(debugFP, "Parser Qa1b2: yyleng=%d\n", + yyleng); + } + + if (yyleng-skip1-skip2 > 5) { char c; + if (yytext[yyleng-1] == ')') { + c = currentMoveString[4] = ToLower(yytext[yyleng-2]); + } else { + c = currentMoveString[4] = ToLower(yytext[yyleng-1]); + } + currentMoveString[5] = NULLCHAR; + if(c != '=' && c != '+' && CharToPiece(c) == EmptySquare) + return IllegalMove; /* [HGM] promotion to invalid piece */ + } + + if (appData.debugMode) { + fprintf(debugFP, "parser: %s\n", currentMoveString); + } + /* [HGM] do not allow values beyond board size */ + if(currentMoveString[1] - ONE >= BOARD_HEIGHT || + currentMoveString[1] - ONE < 0 || + currentMoveString[0] - AAA >= BOARD_RGHT || + currentMoveString[3] - ONE >= BOARD_HEIGHT || + currentMoveString[3] - ONE < 0 || + currentMoveString[2] - AAA >= BOARD_RGHT || + currentMoveString[0] - AAA < BOARD_LEFT || + currentMoveString[2] - AAA < BOARD_LEFT ) + return 0; + + piece = boards[yyboardindex] + [currentMoveString[1] - ONE][currentMoveString[0] - AAA]; + if(promoted) piece = (ChessSquare) (DEMOTED piece); + c = PieceToChar(piece); + if(c == '~') c = PieceToChar((ChessSquare) (DEMOTED piece)); + if (ToLower(yytext[skip3]) != ToLower(c)) + return (int) IllegalMove; + + result = LegalityTest(boards[yyboardindex], + PosFlags(yyboardindex)&~F_MANDATORY_CAPTURE, // [HGM] losers: might think we can e.p.! + EP_UNKNOWN, + initialRights, /* [HGM] assume all castlings allowed */ + currentMoveString[1] - ONE, + currentMoveString[0] - AAA, + currentMoveString[3] - ONE, + currentMoveString[2] - AAA, + currentMoveString[4]); + + if (currentMoveString[4] == NULLCHAR && + (result == WhitePromotionKnight || result == BlackPromotionKnight || + result == WhitePromotionQueen || result == BlackPromotionQueen)) { + currentMoveString[4] = PieceToChar(BlackQueen); + currentMoveString[5] = NULLCHAR; + } + + return (int) result; +} + +[a-l][0-9][xX:-]?[a-l][0-9]((=?\(?[A-Za-z]\)?)|=)? { + /* + * Simple algebraic move, possibly with promotion + * [HGM] Engine moves are received in this format, with lower-case promoChar! + */ + int skip = 0; + ChessMove result; + + if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */ + + /* remove the [xX:-] */ + if ((yytext[2] == 'x') || (yytext[2] == 'X') || + (yytext[2] == '-') || (yytext[2] == ':')) skip = 1; + + currentMoveString[0] = yytext[0]; + currentMoveString[1] = yytext[1]; + currentMoveString[2] = yytext[2+skip]; + currentMoveString[3] = yytext[3+skip]; + currentMoveString[4] = NULLCHAR; + + if (yyleng-skip > 4) { char c; + if (yytext[yyleng-1] == ')') { + c = currentMoveString[4] = ToLower(yytext[yyleng-2]); + } else { + c = currentMoveString[4] = ToLower(yytext[yyleng-1]); + } + currentMoveString[5] = NULLCHAR; + if(c != '=' && c != '+' && CharToPiece(c) == EmptySquare) + return IllegalMove; + } + + /* [HGM] do not allow values beyond board size */ + if(currentMoveString[1] - ONE >= BOARD_HEIGHT || + currentMoveString[1] - ONE < 0 || + currentMoveString[0] - AAA >= BOARD_RGHT || + currentMoveString[3] - ONE >= BOARD_HEIGHT || + currentMoveString[3] - ONE < 0 || + currentMoveString[2] - AAA >= BOARD_RGHT || + currentMoveString[0] - AAA < BOARD_LEFT || + currentMoveString[2] - AAA < BOARD_LEFT ) + return 0; + + result = LegalityTest(boards[yyboardindex], + PosFlags(yyboardindex)&~F_MANDATORY_CAPTURE, // [HGM] losers: might think we can e.p.! + EP_UNKNOWN, + initialRights, /* [HGM] assume all castlings allowed */ + currentMoveString[1] - ONE, + currentMoveString[0] - AAA, + currentMoveString[3] - ONE, + currentMoveString[2] - AAA, + currentMoveString[4]); + + if (currentMoveString[4] == NULLCHAR && + (result == WhitePromotionKnight || result == BlackPromotionKnight || + result == WhitePromotionQueen || result == BlackPromotionQueen)) { + if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier) + currentMoveString[4] = PieceToChar(BlackFerz); + else if(gameInfo.variant == VariantGreat) + currentMoveString[4] = PieceToChar(BlackMan); + else + currentMoveString[4] = PieceToChar(BlackQueen); + currentMoveString[5] = NULLCHAR; + } + + return (int) result; +} + +[a-l][0-9]((=?\(?[A-Z]\)?)|=)? { + /* + * Pawn move, possibly with promotion + */ + DisambiguateClosure cl; + int skip = 0; char c; + + if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */ + + /* remove the =() */ + if (yytext[2] == '=' && yytext[3] != NULLCHAR) skip++; + if (yytext[2+skip] == '(') skip++; + + cl.pieceIn = WhiteOnMove(yyboardindex) ? WhitePawn : BlackPawn; + cl.rfIn = -1; + cl.ffIn = yytext[0] - AAA; + cl.rtIn = yytext[1] - ONE; + cl.ftIn = yytext[0] - AAA; + c = cl.promoCharIn = yytext[2+skip]; + + /* [HGM] do not allow values beyond board size */ + if(cl.rtIn >= BOARD_HEIGHT || + cl.rtIn < 0 || + cl.ffIn >= BOARD_RGHT || + cl.ftIn < BOARD_LEFT ) + return 0; + + if(c != '=' && c != '+' && c != NULLCHAR && CharToPiece(c) == EmptySquare) + return IllegalMove; + + + Disambiguate(boards[yyboardindex], + PosFlags(yyboardindex), EP_UNKNOWN, &cl); + + currentMoveString[0] = cl.ff + AAA; + currentMoveString[1] = cl.rf + ONE; + currentMoveString[2] = cl.ft + AAA; + currentMoveString[3] = cl.rt + ONE; + currentMoveString[4] = cl.promoChar; + currentMoveString[5] = NULLCHAR; + + return (int) cl.kind; +} + + +(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."|=)? { + /* + * Pawn capture, possibly with promotion, possibly ambiguous + */ + DisambiguateClosure cl; + int skip1 = 0, skip2 = 0; char c; + + if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */ + + /* remove trailing ep or e.p. (nonstandard PGN) */ + if (yytext[yyleng-1] == 'p') { + yyleng -= 2; + yytext[yyleng] = NULLCHAR; + } else if (yytext[yyleng-1] == '.') { + yyleng -= 4; + yytext[yyleng] = NULLCHAR; + } + + /* remove the [xX:-] and =() */ + if ((yytext[1] == 'x') || (yytext[1] == 'X') + || (yytext[1] == ':') || (yytext[1] == '-')) skip1 = 1; + if (yytext[2+skip1] == '=' && yytext[3+skip1] != NULLCHAR) skip2++; + if (yytext[2+skip1+skip2] == '(') skip2++; + + cl.pieceIn = WhiteOnMove(yyboardindex) ? WhitePawn : BlackPawn; + cl.rfIn = -1; + cl.ffIn = yytext[0] - AAA; + cl.rtIn = -1; + cl.ftIn = yytext[1+skip1] - AAA; + c = cl.promoCharIn = yytext[2+skip1+skip2]; + + /* [HGM] do not allow values beyond board size */ + if(cl.ffIn >= BOARD_RGHT || + cl.ffIn < BOARD_LEFT || + cl.ftIn >= BOARD_RGHT || + cl.ftIn < BOARD_LEFT ) + return 0; + + if(c != '=' && c != '+' && c != NULLCHAR && CharToPiece(c) == EmptySquare) + return IllegalMove; + + Disambiguate(boards[yyboardindex], + PosFlags(yyboardindex), EP_UNKNOWN, &cl); + + currentMoveString[0] = cl.ff + AAA; + currentMoveString[1] = cl.rf + ONE; + currentMoveString[2] = cl.ft + AAA; + currentMoveString[3] = cl.rt + ONE; + currentMoveString[4] = cl.promoChar; + currentMoveString[5] = NULLCHAR; + + return (int) cl.kind; +} + +[a-l][xX:]?[a-l][0-9]((=?\(?[A-Z]\)?)|ep|"e.p."|=)? { + /* + * unambiguously abbreviated Pawn capture, possibly with promotion + */ + int skip = 0; + ChessMove result; char c; + + if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */ + + /* remove trailing ep or e.p. (nonstandard PGN) */ + if (yytext[yyleng-1] == 'p') { + yyleng -= 2; + yytext[yyleng] = NULLCHAR; + } else if (yytext[yyleng-1] == '.') { + yyleng -= 4; + yytext[yyleng] = NULLCHAR; + } + + /* remove the [xX:-] */ + if ((yytext[1] == 'x') || (yytext[1] == 'X') + || (yytext[1] == ':') || (yytext[1] == '-')) skip = 1; + + currentMoveString[0] = yytext[0]; + currentMoveString[2] = yytext[1+skip]; + currentMoveString[3] = yytext[2+skip]; + + /* [HGM] do not allow values beyond board size */ + if(currentMoveString[0] - AAA >= BOARD_RGHT || + currentMoveString[3] - ONE >= BOARD_HEIGHT || + currentMoveString[3] - ONE < 0 || + currentMoveString[2] - AAA >= BOARD_RGHT || + currentMoveString[0] - AAA < BOARD_LEFT || + currentMoveString[2] - AAA < BOARD_LEFT ) + return 0; + + if (gameInfo.variant == VariantXiangqi && /* [HGM] In Xiangqi rank stays same */ + currentMoveString[0] != currentMoveString[2] ) { + currentMoveString[1] = yytext[2+skip]; + } else + if (WhiteOnMove(yyboardindex)) { + if (yytext[2+skip] == ONE) return (int) ImpossibleMove; + currentMoveString[1] = yytext[2+skip] - 1; + if(boards[yyboardindex][currentMoveString[1]-ONE][currentMoveString[0]-AAA] != WhitePawn) + return ImpossibleMove; + } else { + currentMoveString[1] = currentMoveString[3] + 1; + if (currentMoveString[3] == ONE+BOARD_HEIGHT-1) return (int) ImpossibleMove; + if(boards[yyboardindex][currentMoveString[1]-ONE][currentMoveString[0]-AAA] != BlackPawn) + return ImpossibleMove; + } + if (yyleng-skip > 3) { + if (yytext[yyleng-1] == ')') + c = currentMoveString[4] = ToLower(yytext[yyleng-2]); + else + c = currentMoveString[4] = ToLower(yytext[yyleng-1]); + currentMoveString[5] = NULLCHAR; + if(c != '=' && c != '+' && CharToPiece(c) == EmptySquare) + return IllegalMove; + } else { + currentMoveString[4] = NULLCHAR; + } + + result = LegalityTest(boards[yyboardindex], + PosFlags(yyboardindex)&~F_MANDATORY_CAPTURE, // [HGM] losers: might think we can e.p.! + EP_UNKNOWN, + initialRights, /* [HGM] assume all castlings allowed */ + currentMoveString[1] - ONE, + currentMoveString[0] - AAA, + currentMoveString[3] - ONE, + currentMoveString[2] - AAA, + currentMoveString[4]); + + if (currentMoveString[4] == NULLCHAR && + (result == WhitePromotionQueen || result == BlackPromotionQueen || + result == WhitePromotionKnight || result == BlackPromotionKnight)) { + currentMoveString[4] = PieceToChar(BlackQueen); + // [HGM] shatranj: take care of variants without Queen + if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier) + currentMoveString[4] = PieceToChar(BlackFerz); + if(gameInfo.variant == VariantGreat) + currentMoveString[4] = PieceToChar(BlackMan); + currentMoveString[5] = NULLCHAR; + } + + if (result != IllegalMove) return (int) result; + + /* Special case: improperly written en passant capture */ + if (WhiteOnMove(yyboardindex)) { + if (currentMoveString[3] == '5') { + currentMoveString[1] = '5'; + currentMoveString[3] = '6'; + } else { + return (int) IllegalMove; + } + } else { + if (currentMoveString[3] == '4') { + currentMoveString[1] = '4'; + currentMoveString[3] = '3'; + } else { + return (int) IllegalMove; + } + } + + result = LegalityTest(boards[yyboardindex], + PosFlags(yyboardindex)&~F_MANDATORY_CAPTURE, // [HGM] losers: might think we can e.p.! + EP_UNKNOWN, + initialRights, /* [HGM] assume all castlings allowed */ + currentMoveString[1] - ONE, + currentMoveString[0] - AAA, + currentMoveString[3] - ONE, + currentMoveString[2] - AAA, + currentMoveString[4]); + + if (result == WhiteCapturesEnPassant || result == BlackCapturesEnPassant) + return (int) result; + else + return (int) IllegalMove; +} + +"+"?[A-Z][xX:-]?[a-l][0-9]=? { + /* + * piece move, possibly ambiguous + */ + DisambiguateClosure cl; + int skip = 0, skip2 = 0, promoted = 0; + + if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */ + + if(yytext[0] == '+') promoted = skip = skip2 = 1; + + /* remove the [xX:-] */ + if ((yytext[1+skip] == 'x') || (yytext[1+skip] == 'X') + || (yytext[1+skip] == ':') || (yytext[1+skip] == '-')) skip++; + + if (WhiteOnMove(yyboardindex)) { + cl.pieceIn = CharToPiece(ToUpper(yytext[skip2])); + } else { + cl.pieceIn = CharToPiece(ToLower(yytext[skip2])); + } + if(promoted) cl.pieceIn = (ChessSquare) (PROMOTED cl.pieceIn); + + cl.rfIn = -1; + cl.ffIn = -1; + cl.rtIn = yytext[2+skip] - ONE; + cl.ftIn = yytext[1+skip] - AAA; + cl.promoCharIn = NULLCHAR; + + if(yyleng-skip > 3) /* [HGM] can have Shogi-style promotion */ + cl.promoCharIn = yytext[yyleng-1]; + + if (appData.debugMode) { + fprintf(debugFP, "Parser Qa1: yyleng=%d, %d(%d,%d)-(%d,%d) = %d (%c)\n", + yyleng, + cl.pieceIn,cl.ffIn,cl.rfIn,cl.ftIn,cl.rtIn,cl.promoCharIn,cl.promoCharIn?cl.promoCharIn:' '); + } + + /* [HGM] but do not allow values beyond board size */ + if(cl.rtIn >= BOARD_HEIGHT || + cl.rtIn < 0 || + cl.ftIn >= BOARD_RGHT || + cl.ftIn < BOARD_LEFT ) + return 0; + + Disambiguate(boards[yyboardindex], + PosFlags(yyboardindex), EP_UNKNOWN, &cl); + + currentMoveString[0] = cl.ff + AAA; + currentMoveString[1] = cl.rf + ONE; + currentMoveString[2] = cl.ft + AAA; + currentMoveString[3] = cl.rt + ONE; + currentMoveString[4] = cl.promoChar; + currentMoveString[5] = NULLCHAR; + + return (int) cl.kind; +} + +"+"?[A-Z][a-l0-9][xX:-]?[a-l][0-9]=? { + /* + * piece move with rank or file disambiguator + */ + DisambiguateClosure cl; + int skip = 0, skip2 = 0; int promoted=0; + + if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */ + + if(yytext[0]=='+') promoted = skip = skip2 = 1; + + /* remove the [xX:-] */ + if ((yytext[2+skip] == 'x') || (yytext[2+skip] == 'X') + || (yytext[2+skip] == ':') || (yytext[2+skip] == '-')) skip++; + + if (WhiteOnMove(yyboardindex)) { + cl.pieceIn = CharToPiece(ToUpper(yytext[skip2])); + } else { + cl.pieceIn = CharToPiece(ToLower(yytext[skip2])); + } + if(promoted) cl.pieceIn = (ChessSquare) (PROMOTED cl.pieceIn); + + if (isalpha(yytext[1+skip2])) { + cl.rfIn = -1; + cl.ffIn = yytext[1+skip2] - AAA; + + if(cl.ffIn >= BOARD_RGHT || + cl.ffIn < BOARD_LEFT ) return 0; + } else { + cl.rfIn = yytext[1+skip2] - ONE; + cl.ffIn = -1; + if(cl.rfIn >= BOARD_HEIGHT || + cl.rfIn < 0) return 0; + } + cl.rtIn = yytext[3+skip] - ONE; + cl.ftIn = yytext[2+skip] - AAA; + cl.promoCharIn = NULLCHAR; + + if(yyleng-skip > 4) /* [HGM] can have Shogi-style promotion */ + cl.promoCharIn = yytext[yyleng-1]; + + /* [HGM] do not allow values beyond board size */ + if(cl.rtIn >= BOARD_HEIGHT || + cl.rtIn < 0 || + cl.ftIn >= BOARD_RGHT || + cl.ftIn < BOARD_LEFT ) + return 0; + + Disambiguate(boards[yyboardindex], + PosFlags(yyboardindex), EP_UNKNOWN, &cl); + + currentMoveString[0] = cl.ff + AAA; + currentMoveString[1] = cl.rf + ONE; + currentMoveString[2] = cl.ft + AAA; + currentMoveString[3] = cl.rt + ONE; + currentMoveString[4] = cl.promoChar; + currentMoveString[5] = NULLCHAR; + + return (int) cl.kind; +} + +000|0-0-0|ooo|OOO|o-o-o|O-O-O { + int rf, ff, rt, ft; + + if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */ + + /* [HGM] all squares referenced to board edges in stead of absolute */ + if (WhiteOnMove(yyboardindex)) { + if (boards[yyboardindex][0][(BOARD_WIDTH-1)>>1] == WhiteKing) { + /* ICS wild castling */ + rf = 0; + ff = (BOARD_WIDTH-1)>>1; + rt = 0; + ft = BOARD_RGHT-3; + } else { + rf = 0; + ff = BOARD_WIDTH>>1; + rt = 0; + ft = BOARD_LEFT+2; + } + } else{ + if (boards[yyboardindex][BOARD_HEIGHT-1][(BOARD_WIDTH-1)>>1] == BlackKing) { + /* ICS wild castling */ + rf = BOARD_HEIGHT-1; + ff = (BOARD_WIDTH-1)>>1; + rt = BOARD_HEIGHT-1; + ft = BOARD_RGHT-3; + } else { + rf = BOARD_HEIGHT-1; + ff = BOARD_WIDTH>>1; + rt = BOARD_HEIGHT-1; + ft = BOARD_LEFT+2; + } + } + if(gameInfo.variant == VariantFischeRandom) { + if (WhiteOnMove(yyboardindex)) { + ff = initialRights[2]; + ft = initialRights[1]; + } else { + ff = initialRights[5]; + ft = initialRights[4]; + } + fprintf(debugFP, "Parser FRC long %d %d\n", ff, ft); + if(ff < 0 || ft < 0) return 0; + } + sprintf(currentMoveString, "%c%c%c%c",ff+AAA,rf+ONE,ft+AAA,rt+ONE); + if (appData.debugMode) { + fprintf(debugFP, "long castling %d %d\n", ff, ft); + } + return (int) LegalityTest(boards[yyboardindex], + PosFlags(yyboardindex)&~F_MANDATORY_CAPTURE, // [HGM] losers: e.p.! + EP_UNKNOWN, + castlingRights[yyboardindex], /* [HGM] use true castling rights */ + rf, ff, rt, ft, NULLCHAR); +} + +00|0-0|oo|OO|o-o|O-O { + int rf, ff, rt, ft; + + if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */ + + if (WhiteOnMove(yyboardindex)) { + if (boards[yyboardindex][0][(BOARD_WIDTH-1)>>1] == WhiteKing) { + /* ICS wild castling */ + rf = 0; + ff = (BOARD_WIDTH-1)>>1; + rt = 0; + ft = BOARD_LEFT+1; + } else { + rf = 0; + ff = BOARD_WIDTH>>1; + rt = 0; + ft = BOARD_RGHT-2; + } + } else { + if (boards[yyboardindex][BOARD_HEIGHT-1][(BOARD_WIDTH-1)>>1] == BlackKing) { + /* ICS wild castling */ + rf = BOARD_HEIGHT-1; + ff = (BOARD_WIDTH-1)>>1; + rt = BOARD_HEIGHT-1; + ft = BOARD_LEFT+1; + } else { + rf = BOARD_HEIGHT-1; + ff = BOARD_WIDTH>>1; + rt = BOARD_HEIGHT-1; + ft = BOARD_RGHT-2; + } + } + if(gameInfo.variant == VariantFischeRandom) { + if (WhiteOnMove(yyboardindex)) { + ff = initialRights[2]; + ft = initialRights[0]; + } else { + ff = initialRights[5]; + ft = initialRights[3]; + } + if (appData.debugMode) { + fprintf(debugFP, "Parser FRC short %d %d\n", ff, ft); + } + if(ff < 0 || ft < 0) return 0; + } + sprintf(currentMoveString, "%c%c%c%c",ff+AAA,rf+ONE,ft+AAA,rt+ONE); + if (appData.debugMode) { + fprintf(debugFP, "short castling %d %d\n", ff, ft); + } + + return (int) LegalityTest(boards[yyboardindex], + PosFlags(yyboardindex)&~F_MANDATORY_CAPTURE, // [HGM] losers: e.p.! + EP_UNKNOWN, + castlingRights[yyboardindex], /* [HGM] use true castling rights */ + rf, ff, rt, ft, NULLCHAR); +} + +[A-Z][@*][a-l][0-9] { + /* Bughouse piece drop. No legality checking for now. */ + currentMoveString[1] = '@'; + currentMoveString[2] = yytext[2]; + currentMoveString[3] = yytext[3]; + currentMoveString[4] = NULLCHAR; + + if (appData.debugMode) { + fprintf(debugFP, "Drop: %s\n", currentMoveString); + } + /* [HGM] do not allow values beyond board size */ + if(currentMoveString[3] - ONE >= BOARD_HEIGHT || + currentMoveString[2] - AAA >= BOARD_WIDTH ) + return 0; + + if (WhiteOnMove(yyboardindex)) { + currentMoveString[0] = ToUpper(yytext[0]); + return (int) WhiteDrop; + } else { + currentMoveString[0] = ToLower(yytext[0]); + return (int) BlackDrop; + } +} + +[Rr]esign(s|ed)? { + if (WhiteOnMove(yyboardindex)) + return (int) BlackWins; + else + return (int) WhiteWins; +} + +(([Ww](hite)?)|([Bb](lack)?))" "(([Rr]esign)|([Ff]orfeit))(s|ed)? { + return (int) (ToUpper(yytext[0]) == 'W' ? BlackWins : WhiteWins); +} + +(([Ww](hite)?)|([Bb](lack)?))" "[Dd]isconnect(s|ed) { + return (int) GameUnfinished; +} + +[Ss]talemate { + return (int) GameIsDrawn; +} + +"+-+" { + return (int) GameIsDrawn; +} + +([Cc]heck)?[Mm]ate { + if (WhiteOnMove(yyboardindex)) + return (int) BlackWins; + else + return (int) WhiteWins; +} + +"++" { + if (WhiteOnMove(yyboardindex)) + return (int) BlackWins; + else + return (int) WhiteWins; +} + +[Dd]raw(n)?(" "by)?(" "[Rr]epetition)|(" "[Aa]gree(d|ment)) { + return (int) GameIsDrawn; +} + +[Dd]raw(n)?(" (".*")")? { + return (int) GameIsDrawn; +} + +(([Ww](hite)?)|([Bb](lack)?))" "([Mm]ate(s|ed)?)|([Ww][io]n(s)?.*) { + return (int) (ToUpper(yytext[0]) == 'W' ? WhiteWins : BlackWins); +} + +(([Ww](hite)?)|([Bb](lack)?))" "([Mm]ate(s|ed)?)|([Ll]os[tes]+.*) { + return (int) (ToUpper(yytext[0]) == 'W' ? BlackWins : WhiteWins); +} + +("{"[^\}\n]*"} ")?(1-0|"1 - 0"|"1/0"|"1 / 0"|"1:0"|"1 : 0")(" (".*")"|" {".*"}")? { + return (int) WhiteWins; +} + +("{"[^\}\n]*"} ")?(0-1|"0 - 1"|"0/1"|"0 / 1"|"0:1"|"0 : 1")(" (".*")"|" {".*"}")? { + return (int) BlackWins; +} + +("{"[^\}\n]*"} ")?("1/2"|"1 / 2")(" "?[-:]" "?("1/2"|"1 / 2"))?(" (".*")"|" {".*"}")? { + return (int) GameIsDrawn; +} + +("{"[^\}\n]*"} ")?"*"(" (".*")"|" {".*"}")? { + return (int) GameUnfinished; +} + +[1-9][0-9]*/"."?[ \t\n]*[a-lNnPpRrBQqKACFEWDGHOo] { + /* move numbers */ + if ((yyleng == 1) && (yytext[0] == '1')) + return (int) MoveNumberOne; +} + +\([0-9]+:[0-9][0-9](\.[0-9]+)?\)|\{[0-9]+:[0-9][0-9](\.[0-9]+)?\} { + /* elapsed time indication, e.g. (0:12) or {10:21.071} */ + return (int) ElapsedTime; +} + +"[--"[^\]]*"--]" { + /* position diagram enclosed in [-- --] */ + return (int) PositionDiagram; +} + +^"{--------------"\n[^\}]*\n"--------------}"$ { + /* position diagram enclosed in {-- --} */ + return (int) PositionDiagram; +} + +\[[ \t\n]*[A-Za-z0-9][A-Za-z0-9_+#=-]*[ \t\n]*\"[^"]*\"[ \t\n]*\] { + return (int) PGNTag; +} + +[Gg](nu|NU)" "?[Cc](hess|HESS).*[Gg](ame|AME) { + return (int) GNUChessGame; +} + +^[#;%]" "[^ ]*(" game file"|" position file").*$ { + return (int) XBoardGame; +} + +\$[0-9]+ { /* numeric annotation glyph */ + return (int) NAG; +} + +\{[^\}]*\} { /* anything in {} */ + return (int) Comment; +} + +;.*$ { /* ; to end of line */ + return (int) Comment; +} + +\[[^\]]*\] { /* anything in [] */ + return (int) Comment; +} + +\([^()]*(\([^()]*\)[^()]*)+[^()]*\) { /* nested () */ + return (int) Comment; +} + +\([^)][^)]+\) { /* >=2 chars in () */ + return (int) Comment; +} + +^[-a-zA-Z0-9]+:" ".*(\n[ \t]+.*)* { + /* Skip mail headers */ +} + +[a-zA-Z0-9'-]+ { + /* Skip random words */ +} + +.|\n { + /* Skip everything else */ +} + +%% + + +static char *StringToLex; + +#ifndef FLEX_SCANNER +static FILE *lexFP; + +static int input() +{ + int ret; + + if (StringToLex != NULL) { + ret = *StringToLex; + if (ret == NULLCHAR) + ret = EOF; + else + StringToLex++; + } else if (unputCount > 0) { + ret = unputBuffer[--unputCount]; + } else { + ret = fgetc(lexFP); + } + + if (ret == EOF) + return 0; + else + return ret; +} + +/* + * Return offset of next pattern within current file + */ +int yyoffset() +{ + int offset = ftell(lexFP) - unputCount; + + if (offset < 0) { + offset = 0; + } + return(offset); +} + +static void output(ch) + int ch; +{ + fprintf(stderr, "PARSER BUG: unmatched character '%c' (0%o)\n", + ch, ch); +} + +static void unput(ch) + int ch; +{ + if (ch == 0) return; + if (StringToLex != NULL) { + StringToLex--; + } else { + if (unputCount >= UNPUT_BUF_SIZE) + fprintf(stderr, "PARSER BUG: unput buffer overflow '%c' (0%o)\n", + ch, ch); + unputBuffer[unputCount++] = ch; + } +} + +/* Get ready to lex from a new file. Kludge below sticks + an artificial newline at the front of the file, which the + above grammar ignores, but which makes ^ at start of pattern + match at the real start of the file. +*/ +void yynewfile(f) + FILE *f; +{ + lexFP = f; + StringToLex = NULL; + unputCount = 0; + unput('\n'); /* kludge */ +} + +/* Get ready to lex from a string. ^ at start of pattern WON'T + match at the start of the string! +*/ +void yynewstr(s) + char *s; +{ + lexFP = NULL; + StringToLex = s; + unputCount = 0; +} +#endif /*!FLEX_SCANNER*/ + +#ifdef FLEX_SCANNER +void my_yy_input(buf, result, max_size) + char *buf; + int *result; + int max_size; +{ + int count; + + if (StringToLex != NULL) { + count = 0; + while (*StringToLex != NULLCHAR) { + *buf++ = *StringToLex++; + count++; + } + *result = count; + return; + } else { + count = fread(buf, 1, max_size, yyin); + if (count == 0) { + *result = YY_NULL; + } else { + *result = count; + } + return; + } +} + +static YY_BUFFER_STATE my_file_buffer = NULL; + +/* + Return offset of next pattern in the current file. +*/ +int yyoffset() +{ + int pos = yy_c_buf_p - YY_CURRENT_BUFFER->yy_ch_buf; + + return(ftell(YY_CURRENT_BUFFER->yy_input_file) - + yy_n_chars + pos); +} + + +void yynewstr(s) + char *s; +{ + if (my_file_buffer != NULL) + yy_delete_buffer(my_file_buffer); + StringToLex = s; + my_file_buffer = yy_create_buffer(stdin, YY_BUF_SIZE); + yy_switch_to_buffer(my_file_buffer); +} + +void yynewfile(f) + FILE *f; +{ + if (my_file_buffer != NULL) + yy_delete_buffer(my_file_buffer); + StringToLex = NULL; + my_file_buffer = yy_create_buffer(f, YY_BUF_SIZE); + yy_switch_to_buffer(my_file_buffer); +} +#endif /*FLEX_SCANNER*/ + +int yywrap() +{ + return TRUE; +} + +/* Parse a move from the given string s */ +/* ^ at start of pattern WON'T work here unless using flex */ +ChessMove yylexstr(boardIndex, s) + int boardIndex; + char *s; +{ + ChessMove ret; + char *oldStringToLex; +#ifdef FLEX_SCANNER + YY_BUFFER_STATE buffer, oldBuffer; +#endif + + yyboardindex = boardIndex; + oldStringToLex = StringToLex; + StringToLex = s; +#ifdef FLEX_SCANNER + buffer = yy_create_buffer(stdin, YY_BUF_SIZE); + oldBuffer = YY_CURRENT_BUFFER; + yy_switch_to_buffer(buffer); +#endif /*FLEX_SCANNER*/ + + ret = (ChessMove) yylex(); + +#ifdef FLEX_SCANNER + if (oldBuffer != NULL) + yy_switch_to_buffer(oldBuffer); + yy_delete_buffer(buffer); +#endif /*FLEX_SCANNER*/ + StringToLex = oldStringToLex; + + return ret; +}