X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=parser.l;h=e78c23c0902977e6f2f1f5e0f653c1e3b8acbfb2;hb=c29f3526dee9ab2774d7a6e9958ce145c2cd1187;hp=39264f518da237a0d3147c71f4508ce0a035e3b1;hpb=05bc30b15e31c427ce208495a889e9ff36e6642b;p=xboard.git diff --git a/parser.l b/parser.l index 39264f5..e78c23c 100644 --- a/parser.l +++ b/parser.l @@ -7,10 +7,12 @@ %{ /* * 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. + * 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: @@ -34,28 +36,39 @@ * SOFTWARE. * ------------------------------------------------------------------------ * - * The following terms apply to the enhanced version of XBoard distributed - * by the Free Software Foundation: + * 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 + * + * 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 2 of the License, or - * (at your option) any later version. + * the Free Software Foundation, either version 3 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. + * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * ------------------------------------------------------------------------ - */ + * 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" @@ -77,6 +90,16 @@ char *yy_text = (char *) yytext; #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 @@ -155,22 +178,25 @@ extern void CopyBoard P((Board to, Board from)); %} %% -[RrBbNnQqKkPp][/]?[a-h][1-8][xX:-]?[a-h][1-8](=?\(?[RrBbNnQqKk]\)?)? { +"+"?[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; + 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 = 1; + 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; + (yytext[3+skip1] == '-') || (yytext[3+skip1] == ':')) skip2 = 1; currentMoveString[0] = yytext[1+skip1]; currentMoveString[1] = yytext[2+skip1]; @@ -178,40 +204,74 @@ extern void CopyBoard P((Board to, Board from)); currentMoveString[3] = yytext[4+skip1+skip2]; currentMoveString[4] = NULLCHAR; - if (yyleng-skip1-skip2 > 5) { - if (yytext[yyleng-1] == ')') { - currentMoveString[4] = ToLower(yytext[yyleng-2]); + 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 { - currentMoveString[4] = ToLower(yytext[yyleng-1]); + c = currentMoveString[4] = ToLower(yytext[yyleng-1]); } + if(c == '+' && gameInfo.variant != VariantShogi) c = currentMoveString[4] = NULLCHAR; // + means check outside Shogi currentMoveString[5] = NULLCHAR; } + 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 ImpossibleMove; + piece = boards[yyboardindex] - [currentMoveString[1] - '1'][currentMoveString[0] - 'a']; - if (ToLower(yytext[0]) != ToLower(PieceToChar(piece))) + [currentMoveString[1] - ONE][currentMoveString[0] - AAA]; + if(PieceToChar(piece) == '+' && appData.icsActive) promoted = 1, yytext[skip3] = PieceToChar(DEMOTED piece); // trust ICS + 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), EP_UNKNOWN, - currentMoveString[1] - '1', - currentMoveString[0] - 'a', - currentMoveString[3] - '1', - currentMoveString[2] - 'a', + PosFlags(yyboardindex)&~F_MANDATORY_CAPTURE, // [HGM] losers: might think we can e.p.! + currentMoveString[1] - ONE, + currentMoveString[0] - AAA, + currentMoveString[3] - ONE, + currentMoveString[2] - AAA, currentMoveString[4]); - if (currentMoveString[4] == NULLCHAR && - (result == WhitePromotionQueen || result == BlackPromotionQueen)) { - currentMoveString[4] = 'q'; - currentMoveString[5] = NULLCHAR; + if (currentMoveString[4] == NULLCHAR) { + if(result == WhitePromotion || result == BlackPromotion) { + if(gameInfo.variant == VariantCourier || gameInfo.variant == VariantShatranj) + currentMoveString[4] = PieceToChar(BlackFerz); + else if(gameInfo.variant == VariantGreat) + currentMoveString[4] = PieceToChar(BlackMan); + else if(gameInfo.variant == VariantShogi) + currentMoveString[4] = '+'; + else + currentMoveString[4] = PieceToChar(BlackQueen); + } else if(result == WhiteNonPromotion || result == BlackNonPromotion) + currentMoveString[4] = '='; + currentMoveString[5] = NULLCHAR; } return (int) result; } -[a-h][1-8][xX:-]?[a-h][1-8](=?\(?[RrBbNnQqKk]\)?)? { +[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; @@ -228,33 +288,98 @@ extern void CopyBoard P((Board to, Board from)); currentMoveString[3] = yytext[3+skip]; currentMoveString[4] = NULLCHAR; - if (yyleng-skip > 4) { + if (yyleng-skip > 4) { char c; if (yytext[yyleng-1] == ')') { - currentMoveString[4] = ToLower(yytext[yyleng-2]); + c = currentMoveString[4] = ToLower(yytext[yyleng-2]); } else { - currentMoveString[4] = ToLower(yytext[yyleng-1]); + c = currentMoveString[4] = ToLower(yytext[yyleng-1]); } + if(c == '+' && gameInfo.variant != VariantShogi) currentMoveString[4] = NULLCHAR; // + means check outside Shogi currentMoveString[5] = NULLCHAR; } + /* [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 ImpossibleMove; + result = LegalityTest(boards[yyboardindex], - PosFlags(yyboardindex), EP_UNKNOWN, - currentMoveString[1] - '1', - currentMoveString[0] - 'a', - currentMoveString[3] - '1', - currentMoveString[2] - 'a', + PosFlags(yyboardindex)&~F_MANDATORY_CAPTURE, // [HGM] losers: might think we can e.p.! + currentMoveString[1] - ONE, + currentMoveString[0] - AAA, + currentMoveString[3] - ONE, + currentMoveString[2] - AAA, currentMoveString[4]); - if (currentMoveString[4] == NULLCHAR && - (result == WhitePromotionQueen || result == BlackPromotionQueen)) { - currentMoveString[4] = 'q'; - currentMoveString[5] = NULLCHAR; - } + if (currentMoveString[4] == NULLCHAR) { + if(result == WhitePromotion || result == BlackPromotion) { + if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier || gameInfo.variant == VariantMakruk) + currentMoveString[4] = PieceToChar(BlackFerz); + else if(gameInfo.variant == VariantGreat) + currentMoveString[4] = PieceToChar(BlackMan); + else if(gameInfo.variant == VariantShogi) + currentMoveString[4] = '+'; // Queen might not be defined in mini variants! + else + currentMoveString[4] = PieceToChar(BlackQueen); + } else if(result == WhiteNonPromotion || result == BlackNonPromotion) + currentMoveString[4] = '='; + currentMoveString[5] = NULLCHAR; + } else if(appData.testLegality && gameInfo.variant != VariantSChess && // strip off unnecessary and false promo characters + !(result == WhitePromotion || result == BlackPromotion || + result == WhiteNonPromotion || result == BlackNonPromotion)) currentMoveString[4] = NULLCHAR; return (int) result; } -[a-h][1-8](=?\(?[RrBbNnQqKk]\)?)? { +[A-L][0-9][xX:-]?[A-L][0-9] { + /* + * Simple algebraic move, in capitals + * [HGM] Some Xiangqi engines use this format ('ICCS notation'). So no promotions! + */ + 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]+32; + currentMoveString[1] = yytext[1]; + currentMoveString[2] = yytext[2+skip]+32; + currentMoveString[3] = yytext[3+skip]; + currentMoveString[4] = NULLCHAR; + + /* [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 ImpossibleMove; + + result = LegalityTest(boards[yyboardindex], + PosFlags(yyboardindex)&~F_MANDATORY_CAPTURE, // [HGM] losers: might think we can e.p.! + currentMoveString[1] - ONE, + currentMoveString[0] - AAA, + currentMoveString[3] - ONE, + currentMoveString[2] - AAA, + currentMoveString[4]); + + return (int) result; +} + +[a-l][0-9]((=?\(?[A-Za-z]\)?)|[=+])? { /* * Pawn move, possibly with promotion */ @@ -264,22 +389,30 @@ extern void CopyBoard P((Board to, Board from)); if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */ /* remove the =() */ - if (yytext[2] == '=') skip++; + 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] - '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'; + cl.ffIn = yytext[0] - AAA; + cl.rtIn = yytext[1] - ONE; + cl.ftIn = yytext[0] - AAA; + cl.promoCharIn = ToLower(yytext[2+skip]); + if(cl.promoCharIn == '+' && gameInfo.variant != VariantShogi) cl.promoCharIn = NULLCHAR; // + means check outside Shogi + + /* [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 ImpossibleMove; + + Disambiguate(boards[yyboardindex], PosFlags(yyboardindex), &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; @@ -287,7 +420,7 @@ extern void CopyBoard P((Board to, Board from)); } -(ab|bc|cd|de|ef|fg|gh|hg|gf|fe|ed|dc|cb|ba|([a-h][xX:-][a-h]))(=?\(?[RrBbNnQqKk]\)?)?(ep|"e.p.")? { +(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 */ @@ -308,34 +441,42 @@ extern void CopyBoard P((Board to, Board from)); /* 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] == '=' && yytext[3+skip1] != NULLCHAR) skip2++; if (yytext[2+skip1+skip2] == '(') skip2++; cl.pieceIn = WhiteOnMove(yyboardindex) ? WhitePawn : BlackPawn; cl.rfIn = -1; - cl.ffIn = yytext[0] - 'a'; + cl.ffIn = yytext[0] - AAA; cl.rtIn = -1; - cl.ftIn = yytext[1+skip1] - 'a'; + cl.ftIn = yytext[1+skip1] - AAA; cl.promoCharIn = yytext[2+skip1+skip2]; - Disambiguate(boards[yyboardindex], - PosFlags(yyboardindex), EP_UNKNOWN, &cl); + if(cl.promoCharIn == '+' && gameInfo.variant != VariantShogi) cl.promoCharIn = NULLCHAR; // + means check outside Shogi + + /* [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 ImpossibleMove; + + Disambiguate(boards[yyboardindex], PosFlags(yyboardindex), &cl); - currentMoveString[0] = cl.ff + 'a'; - currentMoveString[1] = cl.rf + '1'; - currentMoveString[2] = cl.ft + 'a'; - currentMoveString[3] = cl.rt + '1'; + 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-h][xX:]?[a-h][1-8](=?\(?[RrBbNnQqKk]\)?)?(ep|"e.p.")? { +[a-l][xX:]?[a-l][0-9]((=?\(?[A-Z]\)?)|ep|"e.p."|[=+])? { /* * unambiguously abbreviated Pawn capture, possibly with promotion */ int skip = 0; - ChessMove result; + ChessMove result; char c; if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */ @@ -355,35 +496,63 @@ extern void CopyBoard P((Board to, Board from)); 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 ImpossibleMove; + + 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] == '1') return (int) ImpossibleMove; + 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 { - if (yytext[2+skip] == '8') return (int) ImpossibleMove; - currentMoveString[1] = yytext[2+skip] + 1; + 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] == ')') - currentMoveString[4] = ToLower(yytext[yyleng-2]); + c = currentMoveString[4] = ToLower(yytext[yyleng-2]); else - currentMoveString[4] = ToLower(yytext[yyleng-1]); + c = currentMoveString[4] = ToLower(yytext[yyleng-1]); currentMoveString[5] = NULLCHAR; + if(c == '+' && gameInfo.variant != VariantShogi) c = currentMoveString[4] = NULLCHAR; // + means check outside Shogi } else { currentMoveString[4] = NULLCHAR; } result = LegalityTest(boards[yyboardindex], - PosFlags(yyboardindex), EP_UNKNOWN, - currentMoveString[1] - '1', - currentMoveString[0] - 'a', - currentMoveString[3] - '1', - currentMoveString[2] - 'a', + PosFlags(yyboardindex)&~F_MANDATORY_CAPTURE, // [HGM] losers: might think we can e.p.! + currentMoveString[1] - ONE, + currentMoveString[0] - AAA, + currentMoveString[3] - ONE, + currentMoveString[2] - AAA, currentMoveString[4]); - if (currentMoveString[4] == NULLCHAR && - (result == WhitePromotionQueen || result == BlackPromotionQueen)) { - currentMoveString[4] = 'q'; - currentMoveString[5] = NULLCHAR; + if (currentMoveString[4] == NULLCHAR) { + if(result == WhitePromotion || result == BlackPromotion) { + currentMoveString[4] = PieceToChar(BlackQueen); + // [HGM] shatranj: take care of variants without Queen + if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier || gameInfo.variant == VariantMakruk) + currentMoveString[4] = PieceToChar(BlackFerz); + if(gameInfo.variant == VariantGreat) + currentMoveString[4] = PieceToChar(BlackMan); + if(gameInfo.variant == VariantShogi) + currentMoveString[4] = '+'; + } else if(result == WhiteNonPromotion || result == BlackNonPromotion) + currentMoveString[4] = '='; + currentMoveString[5] = NULLCHAR; } if (result != IllegalMove) return (int) result; @@ -406,90 +575,135 @@ extern void CopyBoard P((Board to, Board from)); } result = LegalityTest(boards[yyboardindex], - PosFlags(yyboardindex), EP_UNKNOWN, - currentMoveString[1] - '1', - currentMoveString[0] - 'a', - currentMoveString[3] - '1', - currentMoveString[2] - 'a', + PosFlags(yyboardindex)&~F_MANDATORY_CAPTURE, // [HGM] losers: might think we can e.p.! + currentMoveString[1] - ONE, + currentMoveString[0] - AAA, + currentMoveString[3] - ONE, + currentMoveString[2] - AAA, currentMoveString[4]); if (result == WhiteCapturesEnPassant || result == BlackCapturesEnPassant) return (int) result; - else + else { // [HGM] all very nice, but this messed up the input move that we might want to accept with legality testing off... + if (WhiteOnMove(yyboardindex)) // undo the damage + currentMoveString[1]--, currentMoveString[3]--; + else currentMoveString[1]++, currentMoveString[3]++; return (int) IllegalMove; + } } -[RrBbNnQqKk][xX:-]?[a-h][1-8] { +"+"?[A-Z][xX:-]?[a-l][0-9](([=/]?\(?[A-Z]\)?)|[=+])? { /* * piece move, possibly ambiguous */ DisambiguateClosure cl; - int skip = 0; + 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] == 'x') || (yytext[1] == 'X') - || (yytext[1] == ':') || (yytext[1] == '-')) skip = 1; + if ((yytext[1+skip] == 'x') || (yytext[1+skip] == 'X') + || (yytext[1+skip] == ':') || (yytext[1+skip] == '-')) skip++; if (WhiteOnMove(yyboardindex)) { - cl.pieceIn = CharToPiece(ToUpper(yytext[0])); + cl.pieceIn = CharToPiece(ToUpper(yytext[skip2])); } else { - cl.pieceIn = CharToPiece(ToLower(yytext[0])); + 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] - '1'; - cl.ftIn = yytext[1+skip] - 'a'; + cl.rtIn = yytext[2+skip] - ONE; + cl.ftIn = yytext[1+skip] - AAA; 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'; + if(yyleng-skip > 3 && (gameInfo.variant == VariantShogi || gameInfo.variant == VariantSChess)) /* [HGM] can have Shogi-style promotion */ + cl.promoCharIn = yytext[yyleng-1-(yytext[yyleng-1]==')')]; + if(cl.promoCharIn == '+' && gameInfo.variant != VariantShogi) cl.promoCharIn = NULLCHAR; // + means check outside Shogi + + 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 ImpossibleMove; + + Disambiguate(boards[yyboardindex], PosFlags(yyboardindex), &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; } -[RrBbNnQqKk][a-h1-8][xX:-]?[a-h][1-8] { +"+"?[A-Z][a-l0-9][xX:-]?[a-l][0-9](([=/]?\(?[A-Z]\)?)|[=+])? { /* * piece move with rank or file disambiguator */ DisambiguateClosure cl; - int skip = 0; + 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] == 'x') || (yytext[2] == 'X') - || (yytext[2] == ':') || (yytext[2] == '-')) skip = 1; + if ((yytext[2+skip] == 'x') || (yytext[2+skip] == 'X') + || (yytext[2+skip] == ':') || (yytext[2+skip] == '-')) skip++; if (WhiteOnMove(yyboardindex)) { - cl.pieceIn = CharToPiece(ToUpper(yytext[0])); + cl.pieceIn = CharToPiece(ToUpper(yytext[skip2])); } else { - cl.pieceIn = CharToPiece(ToLower(yytext[0])); + cl.pieceIn = CharToPiece(ToLower(yytext[skip2])); } - if (isalpha(yytext[1])) { + if(promoted) cl.pieceIn = (ChessSquare) (PROMOTED cl.pieceIn); + + if (isalpha(yytext[1+skip2])) { cl.rfIn = -1; - cl.ffIn = yytext[1] - 'a'; + cl.ffIn = yytext[1+skip2] - AAA; + + if(cl.ffIn >= BOARD_RGHT || + cl.ffIn < BOARD_LEFT ) return 0; } else { - cl.rfIn = yytext[1] - '1'; + cl.rfIn = yytext[1+skip2] - ONE; cl.ffIn = -1; + if(cl.rfIn >= BOARD_HEIGHT || + cl.rfIn < 0) return 0; } - cl.rtIn = yytext[3+skip] - '1'; - cl.ftIn = yytext[2+skip] - 'a'; + cl.rtIn = yytext[3+skip] - ONE; + cl.ftIn = yytext[2+skip] - AAA; 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'; + if(yyleng-skip > 4 && (gameInfo.variant == VariantShogi || gameInfo.variant == VariantSChess)) /* [HGM] can have Shogi-style promotion */ + cl.promoCharIn = yytext[yyleng-1-(yytext[yyleng-1]==')')]; + if(cl.promoCharIn == '+' && gameInfo.variant != VariantShogi) cl.promoCharIn = NULLCHAR; // + means check outside Shogi + + /* [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 ImpossibleMove; + + Disambiguate(boards[yyboardindex], PosFlags(yyboardindex), &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; @@ -501,39 +715,55 @@ extern void CopyBoard P((Board to, Board from)); 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][3] == WhiteKing) { + if (boards[yyboardindex][0][(BOARD_WIDTH-1)>>1] == WhiteKing) { /* ICS wild castling */ - strcpy(currentMoveString, "d1f1"); rf = 0; - ff = 3; + ff = (BOARD_WIDTH-1)>>1; rt = 0; - ft = 5; + ft = BOARD_RGHT-3; } else { - strcpy(currentMoveString, "e1c1"); rf = 0; - ff = 4; + ff = BOARD_WIDTH>>1; rt = 0; - ft = 2; + ft = BOARD_LEFT+2; } } else{ - if (boards[yyboardindex][7][3] == BlackKing) { + if (boards[yyboardindex][BOARD_HEIGHT-1][(BOARD_WIDTH-1)>>1] == BlackKing) { /* ICS wild castling */ - strcpy(currentMoveString, "d8f8"); - rf = 7; - ff = 3; - rt = 7; - ft = 5; + rf = BOARD_HEIGHT-1; + ff = (BOARD_WIDTH-1)>>1; + rt = BOARD_HEIGHT-1; + ft = BOARD_RGHT-3; } else { - strcpy(currentMoveString, "e8c8"); - rf = 7; - ff = 4; - rt = 7; - ft = 2; + rf = BOARD_HEIGHT-1; + ff = BOARD_WIDTH>>1; + rt = BOARD_HEIGHT-1; + ft = BOARD_LEFT+2; } } + if(PosFlags(0) & F_FRC_TYPE_CASTLING) { + + if (WhiteOnMove(yyboardindex)) { + ff = initialRights[2]; + ft = initialRights[1]; + } else { + ff = initialRights[5]; + ft = initialRights[4]; + } + if (appData.debugMode) + { + 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), EP_UNKNOWN, + PosFlags(yyboardindex)&~F_MANDATORY_CAPTURE, // [HGM] losers: e.p.! rf, ff, rt, ft, NULLCHAR); } @@ -543,54 +773,80 @@ extern void CopyBoard P((Board to, Board from)); if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */ if (WhiteOnMove(yyboardindex)) { - if (boards[yyboardindex][0][3] == WhiteKing) { + if (boards[yyboardindex][0][(BOARD_WIDTH-1)>>1] == WhiteKing) { /* ICS wild castling */ - strcpy(currentMoveString, "d1b1"); rf = 0; - ff = 3; + ff = (BOARD_WIDTH-1)>>1; rt = 0; - ft = 1; + ft = BOARD_LEFT+1; } else { - strcpy(currentMoveString, "e1g1"); rf = 0; - ff = 4; + ff = BOARD_WIDTH>>1; rt = 0; - ft = 6; + ft = BOARD_RGHT-2; } } else { - if (boards[yyboardindex][7][3] == BlackKing) { + if (boards[yyboardindex][BOARD_HEIGHT-1][(BOARD_WIDTH-1)>>1] == BlackKing) { /* ICS wild castling */ - strcpy(currentMoveString, "d8b8"); - rf = 7; - ff = 3; - rt = 7; - ft = 1; + rf = BOARD_HEIGHT-1; + ff = (BOARD_WIDTH-1)>>1; + rt = BOARD_HEIGHT-1; + ft = BOARD_LEFT+1; } else { - strcpy(currentMoveString, "e8g8"); - rf = 7; - ff = 4; - rt = 7; - ft = 6; + rf = BOARD_HEIGHT-1; + ff = BOARD_WIDTH>>1; + rt = BOARD_HEIGHT-1; + ft = BOARD_RGHT-2; } } + if(PosFlags(0) & F_FRC_TYPE_CASTLING) { + 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), EP_UNKNOWN, + PosFlags(yyboardindex)&~F_MANDATORY_CAPTURE, // [HGM] losers: e.p.! rf, ff, rt, ft, NULLCHAR); } -[PpNnBbRrQq]@[a-h][1-8] { - /* Bughouse piece drop. No legality checking for now. */ +[A-Za-z][@*][a-l][0-9] { + + if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */ + + /* Bughouse piece drop. */ 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 ImpossibleMove; + if (WhiteOnMove(yyboardindex)) { currentMoveString[0] = ToUpper(yytext[0]); - return (int) WhiteDrop; } else { currentMoveString[0] = ToLower(yytext[0]); - return (int) BlackDrop; } + return LegalityTest(boards[yyboardindex], PosFlags(yyboardindex), DROP_RANK, // [HGM] does drops now too + CharToPiece(currentMoveString[0]), currentMoveString[3] - ONE, currentMoveString[2] - AAA, NULLCHAR); } [Rr]esign(s|ed)? { @@ -638,34 +894,35 @@ extern void CopyBoard P((Board to, Board from)); return (int) GameIsDrawn; } -(([Ww](hite)?)|([Bb](lack)?))" "([Mm]ate(s|ed)?)|([Ww][io]n(s)?.*) { +(([Ww](hite)?)|([Bb](lack)?))" "(([Mm]ates)|([Ww][io]n(s)?)) { return (int) (ToUpper(yytext[0]) == 'W' ? WhiteWins : BlackWins); } -(([Ww](hite)?)|([Bb](lack)?))" "([Mm]ate(s|ed)?)|([Ll]os[tes]+.*) { +(([Ww](hite)?)|([Bb](lack)?))" "(([Mm]ated)|([Ll]os[tes]+)) { return (int) (ToUpper(yytext[0]) == 'W' ? BlackWins : WhiteWins); } -("{"[^\}\n]*"} ")?(1-0|"1 - 0"|"1/0"|"1 / 0"|"1:0"|"1 : 0")(" (".*")"|" {".*"}")? { +("{"[^\}]*"}"[ \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")(" (".*")"|" {".*"}")? { +("{"[^\}]*"}"[ \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"))?(" (".*")"|" {".*"}")? { +("{"[^\}]*"}"[ \n])?("1/2"|"1 / 2")(" "?[-:]" "?("1/2"|"1 / 2"))?(" (".*")"|" {".*"}")? { return (int) GameIsDrawn; } -("{"[^\}\n]*"} ")?"*"(" (".*")"|" {".*"}")? { +("{"[^\}]*"}"[ \n])?"*"(" (".*")"|" {".*"}")? { return (int) GameUnfinished; } -[1-9][0-9]*/"."?[ \t\n]*[a-hNnPpRrBQqKkOo] { +[1-9][0-9]*/"."?[ \t\n]*[a-lnprqoA-Z+] { /* move numbers */ if ((yyleng == 1) && (yytext[0] == '1')) return (int) MoveNumberOne; + else return (int) Nothing; // [HGM] make sure something is returned, for gathering parsed text } \([0-9]+:[0-9][0-9](\.[0-9]+)?\)|\{[0-9]+:[0-9][0-9](\.[0-9]+)?\} { @@ -711,24 +968,24 @@ extern void CopyBoard P((Board to, Board from)); return (int) Comment; } -\([^()]*(\([^()]*\)[^()]*)+[^()]*\) { /* nested () */ - return (int) Comment; +\( { /* Opening parentheses */ + return (int) Open; } -\([^)][^)]+\) { /* >=2 chars in () */ - return (int) Comment; +\) { /* closing parentheses */ + return (int) Close; } ^[-a-zA-Z0-9]+:" ".*(\n[ \t]+.*)* { - /* Skip mail headers */ + return (int) Nothing; /* Skip mail headers */ } [a-zA-Z0-9'-]+ { - /* Skip random words */ + return (int) Nothing; /* Skip random words */ } .|\n { - /* Skip everything else */ + return (int) Nothing; /* Skip everything else */ } %% @@ -777,7 +1034,7 @@ int yyoffset() static void output(ch) int ch; { - fprintf(stderr, "PARSER BUG: unmatched character '%c' (0%o)\n", + if(appData.debugMode) fprintf(debugFP, "PARSER BUG: unmatched character '%c' (0%o)\n", ch, ch); } @@ -789,7 +1046,7 @@ static void unput(ch) StringToLex--; } else { if (unputCount >= UNPUT_BUF_SIZE) - fprintf(stderr, "PARSER BUG: unput buffer overflow '%c' (0%o)\n", + if(appData.debugMode) fprintf(debugFP, "PARSER BUG: unput buffer overflow '%c' (0%o)\n", ch, ch); unputBuffer[unputCount++] = ch; } @@ -855,9 +1112,9 @@ static YY_BUFFER_STATE my_file_buffer = NULL; */ int yyoffset() { - int pos = yy_c_buf_p - yy_current_buffer->yy_ch_buf; + int pos = yy_c_buf_p - YY_CURRENT_BUFFER->yy_ch_buf; - return(ftell(yy_current_buffer->yy_input_file) - + return(ftell(YY_CURRENT_BUFFER->yy_input_file) - yy_n_chars + pos); } @@ -890,9 +1147,9 @@ int yywrap() /* 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 yylexstr(boardIndex, s, text, len) + int boardIndex, len; + char *s, *text; { ChessMove ret; char *oldStringToLex; @@ -909,7 +1166,9 @@ ChessMove yylexstr(boardIndex, s) yy_switch_to_buffer(buffer); #endif /*FLEX_SCANNER*/ - ret = (ChessMove) yylex(); + ret = (ChessMove) Myylex(); + strncpy(text, yy_text, len-1); // [HGM] vari: yy_text is not available to caller after buffer switch ?!? + text[len-1] = NULLCHAR; #ifdef FLEX_SCANNER if (oldBuffer != NULL) @@ -920,3 +1179,23 @@ ChessMove yylexstr(boardIndex, s) return ret; } + +int Myylex() +{ // [HGM] wrapper for yylex, which treats nesting of parentheses + int symbol, nestingLevel = 0, i=0; + char *p; + static char buf[256*MSG_SIZ]; + buf[0] = NULLCHAR; + do { // eat away anything not at level 0 + symbol = yylex(); + if(symbol == Open) nestingLevel++; + if(nestingLevel) { // save all parsed text between (and including) the () + for(p=yytext; *p && i<256*MSG_SIZ-2;) buf[i++] = *p++; + buf[i] = NULLCHAR; + } + if(symbol == 0) break; // ran into EOF + if(symbol == Close) symbol = Comment, nestingLevel--; + } while(nestingLevel || symbol == Nothing); + yy_text = buf[0] ? buf : (char*)yytext; + return symbol; +}