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