1 %{
2 /* rec_parse.y -- Grammar for xstroke recognition control file
3 
4    Copyright 2001 Carl Worth
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2, or (at your option)
9    any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 */
16 
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <errno.h>
21 
22 #include "rec.h"
23 #include "rec_mode.h"
24 #include "gesture.h"
25 #include "action.h"
26 #include "feature.h"
27 #include "option.h"
28 
29 #include "rec_lex.h"
30 
31 #ifdef DMALLOC
32 #include "dmalloc.h"
33 #endif
34 
35 static int yyerror(rec_t *rec, char *err);
36 
37 #define YYERROR_VERBOSE
38 
39 #ifdef REC_PARSE_DEBUG
40 #define YYDEBUG 1
41 #endif
42 
43 static feature_list_t FEATURE_ERROR = { -1, NULL };
44 #define IS_FEATURE_ERROR(f) ( (f).num_features == FEATURE_ERROR.num_features )
45 
46 %}
47 
48 %pure_parser
49 %parse-param { rec_t *rec }
50 
51 %union {
52   int    ival;
53   char  *sval;
54   double dval;
55   rec_mode_t *rec_mode;
56   rec_mode_list_t rec_mode_list;
57   gesture_list_t gesture_list;
58   gesture_t gesture;
59   action_t action;
60   action_item_t action_item;
61   feature_list_t feature_list;
62   feature_t feature;
63   rec_engine_t *rec_engine;
64   option_t option;
65   option_list_t option_list;
66 }
67 
68 %{
69 int yylex(YYSTYPE *lvalp);
70 %}
71 
72 %token <sval> UNKNOWN_CHARACTER
73 
74 %token <ival> KEY
75 %token <ival> BUTTON
76 %token <ival> MODE_SHIFT
77 %token <ival> MODE_LOCK
78 %token <ival> EXEC
79 %token <ival> ORIENTATION_CORRECTION
80 
81 %token <ival> MODE
82 %token <ival> INTEGER
83 %token <sval> IDENTIFIER
84 %token <sval> STRING
85 %token <dval> DOUBLE
86 %token <ival> ENGINE
87 %token <ival> OPTION
88 
89 %type <ival> alphabet
90 %type <ival> definition_list
91 %type <ival> definition
92 %type <rec_mode> mode
93 %type <rec_mode> mode_decl
94 %type <rec_mode_list> mode_id_list
95 %type <rec_mode> mode_id
96 %type <gesture_list> gesture_list
97 %type <gesture> gesture
98 %type <action> action
99 %type <action_item> action_item
100 %type <feature_list> feature_group
101 %type <feature_list> feature_list
102 %type <feature> feature
103 %type <rec_engine> engine
104 %type <option_list> option_list
105 %type <option> option
106 %%
107 
108 alphabet	: /* empty */ { $$ = 0; }
109 		| definition_list
110 		;
111 
112 definition_list		: definition
113 			| definition_list definition
114 			;
115 
116 definition	: mode
117 			{ $$ = 0; }
118 		| gesture
119 			{
120 			  rec_mode_add_gesture(((rec_t *) rec)->global_mode,
121 					       &$1);
122 			}
123 		| engine
124 			{ $$ = 0; }
125 		;
126 
127 mode		: mode_decl '{' '}'
128 			{ $$ = $1; }
129 		| mode_decl '{' gesture_list '}'
130 			{
131 			  $$ = $1;
132 			  rec_mode_add_gestures($$, &$3);
133 			}
134 		;
135 
136 mode_decl	: MODE STRING
137 			{
138 			  $$ = rec_get_mode((rec_t *) rec, $2);
139 			  free($2);
140 			}
141 		| MODE STRING
142 			{
143 			  /* Do this first so the default mode gets set correctly*/
144 			  $<rec_mode>$ = rec_get_mode((rec_t *) rec, $2);
145 			}
146 		  ':' mode_id_list
147 			{
148 			  $$ = rec_get_mode((rec_t *) rec, $2);
149 			  rec_mode_add_parents($$, &$5);
150 			  rec_mode_list_deinit_shallow(&$5);
151 			  free($2);
152 			}
153 		;
154 
155 mode_id_list	: mode_id
156 			{
157 			  rec_mode_list_init(&$$);
158 			  rec_mode_list_append(&$$, $1);
159 			}
160 		| mode_id_list ',' mode_id
161 			{
162 			  $$ = $1;
163 			  rec_mode_list_append(&$$, $3);
164 			}
165 			;
166 
167 mode_id		: STRING
168 			{
169 			  $$ = rec_get_mode((rec_t *) rec, $1);
170 			  free($1);
171 			}
172 			;
173 
174 gesture_list	: gesture
175 			{
176 			  gesture_list_init(&$$);
177 			  gesture_list_append(&$$, &$1);
178 			}
179 		| gesture_list gesture
180 			{
181 			  $$ = $1;
182 			  gesture_list_append(&$$, &$2);
183 			}
184 		;
185 
186 gesture		: action '=' feature_group
187 			{
188 			  if (IS_FEATURE_ERROR($3)) {
189 			    char *loc = rec_lex_location_alloc();
190 			    char *a_str = action_str_alloc(&$1);
191 			    fprintf(stderr, "%s: Not adding stroke for "
192 				    "`%s' to database.\n", loc, a_str);
193 			    free(loc);
194 			    free(a_str);
195 			  } else {
196 			    gesture_init(&$$, $1, $3);
197 			  }
198 			}
199 		;
200 
201 action		: action_item
202 			{
203 			  action_init(&$$);
204 			  action_add_item(&$$, $1);
205 			}
206 		| action ',' action_item
207 			{
208 			  $$ = $1;
209 			  action_add_item(&$$, $3);
210 			}
211 		;
212 
213 action_item	: KEY IDENTIFIER
214 			{
215 			  action_item_key_init(&$$, $2, 1);
216 			  free($2);
217 			}
218 		| KEY INTEGER
219 			{
220 			  char key[2];
221 			  key[0] = '0' + $2;
222 			  key[1] = '\0';
223 			  action_item_key_init(&$$, key, 1);
224 			}
225 		| BUTTON INTEGER
226 			{
227 			  action_item_button_init(&$$, $2);
228 			}
229 		| MODE_SHIFT STRING
230 			{
231 			  action_item_mode_init(&$$,
232 						rec_get_mode((rec_t *) rec, $2),
233 						0);
234 			  free($2);
235 			}
236 		| MODE_LOCK STRING
237 			{
238 			  action_item_mode_init(&$$,
239 						rec_get_mode((rec_t *) rec, $2),
240 						1);
241 			  free($2);
242 			}
243 		| EXEC STRING
244 			{
245 			  action_item_exec_init(&$$, $2);
246 			  free($2);
247 			}
248 		| ORIENTATION_CORRECTION INTEGER
249 			{
250 			  /* Convert from degrees to radians */
251 			  double orientation = (M_PI / 180.0) * $2;
252 			  action_item_orient_init(&$$, orientation);
253 			}
254 		| ORIENTATION_CORRECTION DOUBLE
255 			{
256 			  /* Convert from degrees to radians */
257 			  double orientation = (M_PI / 180.0) * $2;
258 			  action_item_orient_init(&$$, orientation);
259 			}
260 		;
261 
262 feature_group		: feature
263 				{ rec_lex_newlines_wanted(1); }
264 			  '\n'
265 				{
266 				  rec_lex_newlines_wanted(0);
267 				  feature_list_init(&$$);
268 				  feature_list_append(&$$, &$1);
269 				}
270 			| error
271 				{ rec_lex_newlines_wanted(1); }
272 			  '\n'
273 				{
274 				  rec_lex_newlines_wanted(0);
275 				  $$ = FEATURE_ERROR;
276 				  yyerrok;
277 				}
278 			| '{' feature_list '}'
279 				{ $$ = $2; }
280 			| '{' error '}'
281 				{ $$ = FEATURE_ERROR; yyerrok; }
282 			;
283 
284 feature_list		: feature
285 				{
286 				  feature_list_init(&$$);
287 				  feature_list_append(&$$, &$1);
288 				}
289 			| feature_list ';'
290 				{
291 				  $$ = $1;
292 				}
293 			| feature_list feature
294 				{
295 				  $$ = $1;
296 				  feature_list_append(&$$, &$2);
297 				}
298 			;
299 
300 feature			: IDENTIFIER '(' STRING ')'
301 				{
302 				  feature_init(&$$, (rec_t *) rec, $1, $3);
303 				  free($1);
304 				  free($3);
305 				}
306 			;
307 
308 engine		: ENGINE IDENTIFIER '{' '}'
309 			{
310 			  $$ = rec_get_engine((rec_t *) rec, $2);
311 			  free($2);
312 			}
313 		| ENGINE IDENTIFIER '{' option_list '}'
314 			{
315 			  int i;
316 			  $$ = rec_get_engine((rec_t *) rec, $2);
317 			  for (i=0; i < $4.num_options; i++) {
318 			    rec_engine_set_option($$,
319 						  $4.options[i].name,
320 						  $4.options[i].value);
321 			    free($4.options[i].name);
322 			    free($4.options[i].value);
323 			  }
324 			  option_list_deinit(&$4);
325 			  free($2);
326 			}
327 		;
328 
329 option_list	: option
330 			{
331 			  option_list_init(&$$);
332 			  option_list_append(&$$, &$1);
333 			}
334 		| option_list option
335 			{
336 			  $$ = $1;
337 			  option_list_append(&$$, &$2);
338 			}
339 		;
340 
341 option		: OPTION STRING STRING
342 			{ option_init(&$$, $2, $3); }
343 		;
344 
345 %%
346 
347 static int yyerror(rec_t *rec, char *err)
348 {
349     char *loc = rec_lex_location_alloc();
350     fprintf(stderr, "%s: %s\n", loc, err);
351     free(loc);
352     return 0;
353 }
354 
rec_parse(rec_t * rec,char * filename)355 int rec_parse(rec_t *rec, char *filename)
356 {
357     int ret_val;
358 
359 #ifdef REC_PARSE_DEBUG
360     yydebug = 1;
361 #endif
362 
363     rec_lex_initial_file(filename);
364     ret_val = yyparse(rec);
365 
366     return ret_val;
367 }
368