1 /*  DreamChess
2 **
3 **  DreamChess is the legal property of its developers, whose names are too
4 **  numerous to list here. Please refer to the AUTHORS.txt file distributed
5 **  with this source distribution.
6 **
7 **  This program is free software: you can redistribute it and/or modify
8 **  it under the terms of the GNU General Public License as published by
9 **  the Free Software Foundation, either version 3 of the License, or
10 **  (at your option) any later version.
11 **
12 **  This program is distributed in the hope that it will be useful,
13 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 **  GNU General Public License for more details.
16 **
17 **  You should have received a copy of the GNU General Public License
18 **  along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 %token CFILE
22 %token CRANK
23 
24 %{
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include "san.h"
29 
30 int yylex(void);
31 int yyerror(const char *s);
32 
33 san_move_t san_move;
34 %}
35 
36 %%
37 
38 input   : san
39 ;
40 
41 san     : mark move
42 ;
43 
44 move    /* Queenside castle. */
45         : 'O' '-' 'O' '-' 'O'     { san_move.type = SAN_QUEENSIDE_CASTLE; }
46         /* Kingside castle. */
47         | 'O' '-' 'O'             { san_move.type = SAN_KINGSIDE_CASTLE; }
48         /* Non-pawn capture without rank. */
49         | dest capt op_file piece
50         /* Non-pawn move without rank. */
51         | dest op_file piece
52         /* Non-pawn move or capture with rank. */
53         | dest op_capt rank op_file piece
54         /* Pawn move with promotion and capture. */
55         | promo '=' dest capt file
56         /* Pawn move with promotion. */
57         | promo '=' dest
58         /* Pawn move with capture. */
59         | dest capt file
60         /* Pawn move without capture or promotion. */
61         | dest
62 ;
63 
64 piece   : 'Q'                     { san_move.piece = SAN_QUEEN; }
65         | 'R'                     { san_move.piece = SAN_ROOK; }
66         | 'B'                     { san_move.piece = SAN_BISHOP; }
67         | 'N'                     { san_move.piece = SAN_KNIGHT; }
68         | 'K'                     { san_move.piece = SAN_KING; }
69 ;
70 
71 op_capt :
72         | capt
73 ;
74 
75 op_file :
76         | file
77 ;
78 
79 file    : CFILE                   { san_move.source_file = $1; }
80 ;
81 
82 rank    : CRANK                   { san_move.source_rank = $1; }
83 ;
84 
85 capt    : 'x'                     { san_move.type = SAN_CAPTURE; }
86 ;
87 
88 dest    : CRANK CFILE             { san_move.destination = 8 * $1 + $2; }
89 ;
90 
91 mark    :
92         | '+'                     { san_move.state = SAN_STATE_CHECK; }
93         | '#'                     { san_move.state = SAN_STATE_CHECKMATE; }
94 ;
95 
96 promo   : 'Q'                     { san_move.promotion_piece = SAN_QUEEN; }
97         | 'R'                     { san_move.promotion_piece = SAN_ROOK; }
98         | 'B'                     { san_move.promotion_piece = SAN_BISHOP; }
99         | 'N'                     { san_move.promotion_piece = SAN_KNIGHT; }
100 ;
101 %%
102 
103 #include <stdio.h>
104 #include <ctype.h>
105 
106 #include "san.h"
107 
108 char* move;
109 int ptr;
110 
san_parse(char * s)111 san_move_t *san_parse(char *s)
112 {
113     move = s;
114     ptr = strlen(move) - 1;
115 
116     san_move.type = SAN_NORMAL;
117     san_move.state = SAN_STATE_NORMAL;
118     san_move.piece = SAN_PAWN;
119     san_move.destination = SAN_NOT_SPECIFIED;
120     san_move.source_rank = SAN_NOT_SPECIFIED;
121     san_move.source_file = SAN_NOT_SPECIFIED;
122     san_move.promotion_piece = SAN_NOT_SPECIFIED;
123 
124     if (!yyparse())
125     {
126         san_move_t *retval = malloc(sizeof(san_move_t));
127         *retval = san_move;
128         return retval;
129     }
130 
131     return NULL;
132 }
133 
add_piece(char * s,int piece)134 static void add_piece(char *s, int piece)
135 {
136     switch(piece)
137     {
138     case SAN_QUEEN:
139         *s = 'Q';
140         break;
141     case SAN_ROOK:
142         *s = 'R';
143         break;
144     case SAN_BISHOP:
145         *s = 'B';
146         break;
147     case SAN_KNIGHT:
148         *s = 'N';
149         break;
150     case SAN_KING:
151         *s = 'K';
152     }
153 }
154 
san_string(san_move_t * move)155 char *san_string(san_move_t *move)
156 {
157     char *s = malloc(8);
158     int i = 0;
159 
160     switch (move->type)
161     {
162     case SAN_NORMAL:
163     case SAN_CAPTURE:
164         {
165             if ((move->piece != SAN_NOT_SPECIFIED) && (move->piece != SAN_PAWN))
166                 add_piece(s + i++, move->piece);
167 
168             if (move->source_file != SAN_NOT_SPECIFIED)
169                 s[i++] = move->source_file + 'a';
170 
171             if (move->source_rank != SAN_NOT_SPECIFIED)
172                 s[i++] = move->source_rank + '1';
173 
174             if (move->type == SAN_CAPTURE)
175                 s[i++] = 'x';
176 
177             s[i++] = move->destination % 8 + 'a';
178             s[i++] = move->destination / 8 + '1';
179 
180             if (move->promotion_piece != SAN_NOT_SPECIFIED)
181             {
182                 s[i++] = '=';
183                 add_piece(s + i++, move->promotion_piece);
184             }
185         }
186         break;
187     case SAN_QUEENSIDE_CASTLE:
188         strcpy(s, "O-O-O");
189         i = 5;
190         break;
191     case SAN_KINGSIDE_CASTLE:
192         strcpy(s, "O-O");
193         i = 3;
194     }
195 
196     if (move->state == SAN_STATE_CHECK)
197         s[i++] = '+';
198     else if (move->state == SAN_STATE_CHECKMATE)
199         s[i++] = '#';
200 
201     s[i] = '\0';
202 
203     return s;
204 }
205 
yyerror(const char * s)206 int yyerror(const char *s)
207 {
208     return 1;
209 }
210 
yylex(void)211 int yylex(void)
212 {
213     int c;
214 
215     if (ptr >= 0)
216     {
217         c = move[ptr--];
218 
219         if ((c >= '1') && (c <= '8'))
220         {
221             yylval = c - '1';
222             return CRANK;
223         }
224 
225         if ((c >= 'a') && (c <= 'h'))
226         {
227             yylval = c - 'a';
228             return CFILE;
229         }
230 
231         return c;
232     }
233 
234     return 0;
235 }
236