%}
%%
-"+"?[A-Z][/]?[a-l][0-9][xX:-]?[a-l][0-9]((=?\(?[A-Z]\)?)|=)? {
+"+"?[A-Z][/]?[a-l][0-9][xX:-]?[a-l][0-9](([=/]?\(?[A-Z]\)?)|[=+])? {
/*
* Fully-qualified algebraic move, possibly with promotion
*/
} else {
c = currentMoveString[4] = ToLower(yytext[yyleng-1]);
}
+ if(c == '+' && gameInfo.variant != VariantShogi) c = currentMoveString[4] = NULLCHAR; // + means check outside Shogi
currentMoveString[5] = NULLCHAR;
- if(c != '=' && c != '+' && CharToPiece(c) == EmptySquare)
- return IllegalMove; /* [HGM] promotion to invalid piece */
}
if (appData.debugMode) {
currentMoveString[2] - AAA,
currentMoveString[4]);
- if (currentMoveString[4] == NULLCHAR &&
- (result == WhitePromotion || result == BlackPromotion)) {
+ 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] = '+';
else
currentMoveString[4] = PieceToChar(BlackQueen);
- currentMoveString[5] = NULLCHAR;
+ } else if(result == WhiteNonPromotion || result == BlackNonPromotion)
+ currentMoveString[4] = '=';
+ currentMoveString[5] = NULLCHAR;
}
return (int) result;
}
-[a-l][0-9][xX:-]?[a-l][0-9]((=?\(?[A-Za-z]\)?)|=)? {
+[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!
} else {
c = currentMoveString[4] = ToLower(yytext[yyleng-1]);
}
+ if(c == '+' && gameInfo.variant != VariantShogi) currentMoveString[4] = NULLCHAR; // + means check outside Shogi
currentMoveString[5] = NULLCHAR;
- if(c != '=' && c != '+' && CharToPiece(c) == EmptySquare)
- return IllegalMove;
}
/* [HGM] do not allow values beyond board size */
currentMoveString[4] = '+'; // Queen might not be defined in mini variants!
else
currentMoveString[4] = PieceToChar(BlackQueen);
- currentMoveString[5] = NULLCHAR;
- }
- } else if(appData.testLegality && // strip off unnecessary and false promo characters
+ } 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;
[A-L][0-9][xX:-]?[A-L][0-9] {
/*
* Simple algebraic move, in capitals
- * [HGM] Engine moves are received in this format, with lower-case promoChar!
+ * [HGM] Some Xiangqi engines use this format ('ICCS notation'). So no promotions!
*/
int skip = 0;
ChessMove result;
currentMoveString[2] - AAA,
currentMoveString[4]);
- if (currentMoveString[4] == NULLCHAR &&
- (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
- currentMoveString[4] = PieceToChar(BlackQueen);
- currentMoveString[5] = NULLCHAR;
- }
-
return (int) result;
}
-[a-l][0-9]((=?\(?[A-Za-z]\)?)|=)? {
+[a-l][0-9]((=?\(?[A-Za-z]\)?)|[=+])? {
/*
* Pawn move, possibly with promotion
*/
DisambiguateClosure cl;
- int skip = 0; char c;
+ int skip = 0;
if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */
cl.ffIn = yytext[0] - AAA;
cl.rtIn = yytext[1] - ONE;
cl.ftIn = yytext[0] - AAA;
- c = cl.promoCharIn = ToLower(yytext[2+skip]);
+ 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.ftIn < BOARD_LEFT )
return ImpossibleMove;
- if(c != '=' && c != '+' && c != NULLCHAR && CharToPiece(c) == EmptySquare)
- return IllegalMove;
-
-
Disambiguate(boards[yyboardindex], PosFlags(yyboardindex), &cl);
currentMoveString[0] = cl.ff + AAA;
* Pawn capture, possibly with promotion, possibly ambiguous
*/
DisambiguateClosure cl;
- int skip1 = 0, skip2 = 0; char c;
+ int skip1 = 0, skip2 = 0;
if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */
cl.ffIn = yytext[0] - AAA;
cl.rtIn = -1;
cl.ftIn = yytext[1+skip1] - AAA;
- c = cl.promoCharIn = yytext[2+skip1+skip2];
+ cl.promoCharIn = yytext[2+skip1+skip2];
+ 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.ftIn < BOARD_LEFT )
return ImpossibleMove;
- if(c != '=' && c != '+' && c != NULLCHAR && CharToPiece(c) == EmptySquare)
- return IllegalMove;
-
Disambiguate(boards[yyboardindex], PosFlags(yyboardindex), &cl);
currentMoveString[0] = cl.ff + AAA;
return (int) cl.kind;
}
-[a-l][xX:]?[a-l][0-9]((=?\(?[A-Z]\)?)|ep|"e.p."|=)? {
+[a-l][xX:]?[a-l][0-9]((=?\(?[A-Z]\)?)|ep|"e.p."|[=+])? {
/*
* unambiguously abbreviated Pawn capture, possibly with promotion
*/
else
c = currentMoveString[4] = ToLower(yytext[yyleng-1]);
currentMoveString[5] = NULLCHAR;
- if(c != '=' && c != '+' && CharToPiece(c) == EmptySquare)
- return IllegalMove;
+ if(c == '+' && gameInfo.variant != VariantShogi) c = currentMoveString[4] = NULLCHAR; // + means check outside Shogi
} else {
currentMoveString[4] = NULLCHAR;
}
currentMoveString[2] - AAA,
currentMoveString[4]);
- if (currentMoveString[4] == NULLCHAR &&
- (result == WhitePromotion || result == BlackPromotion)) {
+ 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);
- currentMoveString[5] = NULLCHAR;
+ if(gameInfo.variant == VariantShogi)
+ currentMoveString[4] = '+';
+ } else if(result == WhiteNonPromotion || result == BlackNonPromotion)
+ currentMoveString[4] = '=';
+ currentMoveString[5] = NULLCHAR;
}
if (result != IllegalMove) return (int) result;
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;
+ }
}
-"+"?[A-Z][xX:-]?[a-l][0-9]=? {
+"+"?[A-Z][xX:-]?[a-l][0-9](([=/]?\(?[A-Z]\)?)|[=+])? {
/*
* piece move, possibly ambiguous
*/
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(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",
return (int) cl.kind;
}
-"+"?[A-Z][a-l0-9][xX:-]?[a-l][0-9]=? {
+"+"?[A-Z][a-l0-9][xX:-]?[a-l][0-9](([=/]?\(?[A-Z]\)?)|[=+])? {
/*
* piece move with rank or file disambiguator
*/
cl.ftIn = yytext[2+skip] - AAA;
cl.promoCharIn = NULLCHAR;
- if(yyleng-skip > 4) /* [HGM] can have Shogi-style promotion */
- cl.promoCharIn = yytext[yyleng-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 ||
rf, ff, rt, ft, NULLCHAR);
}
-[A-Z][@*][a-l][0-9] {
+[A-Za-z][@*][a-l][0-9] {
+
+ if (yyskipmoves) return (int) AmbiguousMove; /* not disambiguated */
+
/* Bughouse piece drop. */
currentMoveString[1] = '@';
currentMoveString[2] = yytext[2];
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-lNnPpRrBQqKACFEWDGHOo] {
+[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]+)?\} {
return (int) Comment;
}
-\([^()]*(\([^()]*(\([^()]*(\([^()]*\)[^()]*)*\)[^()]*)*\)[^()]*)+[^()]*\) { /* very 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 */
}
%%
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;
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;
+}