1 /************************************************************
2 Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
3
4 Permission to use, copy, modify, and distribute this
5 software and its documentation for any purpose and without
6 fee is hereby granted, provided that the above copyright
7 notice appear in all copies and that both that copyright
8 notice and this permission notice appear in supporting
9 documentation, and that the name of Silicon Graphics not be
10 used in advertising or publicity pertaining to distribution
11 of the software without specific prior written permission.
12 Silicon Graphics makes no representation about the suitability
13 of this software for any purpose. It is provided "as is"
14 without any express or implied warranty.
15
16 SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18 AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19 GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21 DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
23 THE USE OR PERFORMANCE OF THIS SOFTWARE.
24
25 ********************************************************/
26
27 /*
28 * The parser should work with reasonably recent versions of either
29 * bison or byacc. So if you make changes, try to make sure it works
30 * in both!
31 */
32
33 %{
34 #include "xkbcomp-priv.h"
35 #include "ast-build.h"
36 #include "parser-priv.h"
37 #include "scanner-utils.h"
38
39 struct parser_param {
40 struct xkb_context *ctx;
41 struct scanner *scanner;
42 XkbFile *rtrn;
43 bool more_maps;
44 };
45
46 #define parser_err(param, fmt, ...) \
47 scanner_err((param)->scanner, fmt, ##__VA_ARGS__)
48
49 #define parser_warn(param, fmt, ...) \
50 scanner_warn((param)->scanner, fmt, ##__VA_ARGS__)
51
52 static void
_xkbcommon_error(struct parser_param * param,const char * msg)53 _xkbcommon_error(struct parser_param *param, const char *msg)
54 {
55 parser_err(param, "%s", msg);
56 }
57
58 static bool
resolve_keysym(const char * name,xkb_keysym_t * sym_rtrn)59 resolve_keysym(const char *name, xkb_keysym_t *sym_rtrn)
60 {
61 xkb_keysym_t sym;
62
63 if (!name || istreq(name, "any") || istreq(name, "nosymbol")) {
64 *sym_rtrn = XKB_KEY_NoSymbol;
65 return true;
66 }
67
68 if (istreq(name, "none") || istreq(name, "voidsymbol")) {
69 *sym_rtrn = XKB_KEY_VoidSymbol;
70 return true;
71 }
72
73 sym = xkb_keysym_from_name(name, XKB_KEYSYM_NO_FLAGS);
74 if (sym != XKB_KEY_NoSymbol) {
75 *sym_rtrn = sym;
76 return true;
77 }
78
79 return false;
80 }
81
82 #define param_scanner param->scanner
83 %}
84
85 %pure-parser
86 %lex-param { struct scanner *param_scanner }
87 %parse-param { struct parser_param *param }
88
89 %token
90 END_OF_FILE 0
91 ERROR_TOK 255
92 XKB_KEYMAP 1
93 XKB_KEYCODES 2
94 XKB_TYPES 3
95 XKB_SYMBOLS 4
96 XKB_COMPATMAP 5
97 XKB_GEOMETRY 6
98 XKB_SEMANTICS 7
99 XKB_LAYOUT 8
100 INCLUDE 10
101 OVERRIDE 11
102 AUGMENT 12
103 REPLACE 13
104 ALTERNATE 14
105 VIRTUAL_MODS 20
106 TYPE 21
107 INTERPRET 22
108 ACTION_TOK 23
109 KEY 24
110 ALIAS 25
111 GROUP 26
112 MODIFIER_MAP 27
113 INDICATOR 28
114 SHAPE 29
115 KEYS 30
116 ROW 31
117 SECTION 32
118 OVERLAY 33
119 TEXT 34
120 OUTLINE 35
121 SOLID 36
122 LOGO 37
123 VIRTUAL 38
124 EQUALS 40
125 PLUS 41
126 MINUS 42
127 DIVIDE 43
128 TIMES 44
129 OBRACE 45
130 CBRACE 46
131 OPAREN 47
132 CPAREN 48
133 OBRACKET 49
134 CBRACKET 50
135 DOT 51
136 COMMA 52
137 SEMI 53
138 EXCLAM 54
139 INVERT 55
140 STRING 60
141 INTEGER 61
142 FLOAT 62
143 IDENT 63
144 KEYNAME 64
145 PARTIAL 70
146 DEFAULT 71
147 HIDDEN 72
148 ALPHANUMERIC_KEYS 73
149 MODIFIER_KEYS 74
150 KEYPAD_KEYS 75
151 FUNCTION_KEYS 76
152 ALTERNATE_GROUP 77
153
154 %right EQUALS
155 %left PLUS MINUS
156 %left TIMES DIVIDE
157 %left EXCLAM INVERT
158 %left OPAREN
159
160 %start XkbFile
161
162 %union {
163 int ival;
164 int64_t num;
165 enum xkb_file_type file_type;
166 char *str;
167 xkb_atom_t atom;
168 enum merge_mode merge;
169 enum xkb_map_flags mapFlags;
170 xkb_keysym_t keysym;
171 ParseCommon *any;
172 ExprDef *expr;
173 VarDef *var;
174 VModDef *vmod;
175 InterpDef *interp;
176 KeyTypeDef *keyType;
177 SymbolsDef *syms;
178 ModMapDef *modMask;
179 GroupCompatDef *groupCompat;
180 LedMapDef *ledMap;
181 LedNameDef *ledName;
182 KeycodeDef *keyCode;
183 KeyAliasDef *keyAlias;
184 void *geom;
185 XkbFile *file;
186 }
187
188 %type <num> INTEGER FLOAT
189 %type <str> IDENT STRING
190 %type <atom> KEYNAME
191 %type <num> KeyCode
192 %type <ival> Number Integer Float SignedNumber DoodadType
193 %type <merge> MergeMode OptMergeMode
194 %type <file_type> XkbCompositeType FileType
195 %type <mapFlags> Flag Flags OptFlags
196 %type <str> MapName OptMapName
197 %type <atom> FieldSpec Ident Element String
198 %type <keysym> KeySym
199 %type <any> DeclList Decl
200 %type <expr> OptExprList ExprList Expr Term Lhs Terminal ArrayInit KeySyms
201 %type <expr> OptKeySymList KeySymList Action ActionList Coord CoordList
202 %type <var> VarDecl VarDeclList SymbolsBody SymbolsVarDecl
203 %type <vmod> VModDecl VModDefList VModDef
204 %type <interp> InterpretDecl InterpretMatch
205 %type <keyType> KeyTypeDecl
206 %type <syms> SymbolsDecl
207 %type <modMask> ModMapDecl
208 %type <groupCompat> GroupCompatDecl
209 %type <ledMap> LedMapDecl
210 %type <ledName> LedNameDecl
211 %type <keyCode> KeyNameDecl
212 %type <keyAlias> KeyAliasDecl
213 %type <geom> ShapeDecl SectionDecl SectionBody SectionBodyItem RowBody RowBodyItem
214 %type <geom> Keys Key OverlayDecl OverlayKeyList OverlayKey OutlineList OutlineInList
215 %type <geom> DoodadDecl
216 %type <file> XkbFile XkbMapConfigList XkbMapConfig
217 %type <file> XkbCompositeMap
218
219 %destructor { FreeStmt((ParseCommon *) $$); }
220 <any> <expr> <var> <vmod> <interp> <keyType> <syms> <modMask> <groupCompat>
221 <ledMap> <ledName> <keyCode> <keyAlias>
222 /* The destructor also runs on the start symbol when the parser *succeeds*.
223 * The `if` here catches this case. */
224 %destructor { if (!param->rtrn) FreeXkbFile($$); } <file>
225 %destructor { free($$); } <str>
226
227 %%
228
229 /*
230 * An actual file may contain more than one map. However, if we do things
231 * in the normal yacc way, i.e. aggregate all of the maps into a list and
232 * let the caller find the map it wants, we end up scanning and parsing a
233 * lot of unneeded maps (in the end we always just need one).
234 * Instead of doing that, we make yyparse return one map at a time, and
235 * then call it repeatedly until we find the map we need. Once we find it,
236 * we don't need to parse everything that follows in the file.
237 * This does mean that if we e.g. always use the first map, the file may
238 * contain complete garbage after that. But it's worth it.
239 */
240
241 XkbFile : XkbCompositeMap
242 { $$ = param->rtrn = $1; param->more_maps = true; }
243 | XkbMapConfig
244 { $$ = param->rtrn = $1; param->more_maps = true; YYACCEPT; }
245 | END_OF_FILE
246 { $$ = param->rtrn = NULL; param->more_maps = false; }
247 ;
248
249 XkbCompositeMap : OptFlags XkbCompositeType OptMapName OBRACE
250 XkbMapConfigList
251 CBRACE SEMI
252 { $$ = XkbFileCreate($2, $3, (ParseCommon *) $5, $1); }
253 ;
254
255 XkbCompositeType: XKB_KEYMAP { $$ = FILE_TYPE_KEYMAP; }
256 | XKB_SEMANTICS { $$ = FILE_TYPE_KEYMAP; }
257 | XKB_LAYOUT { $$ = FILE_TYPE_KEYMAP; }
258 ;
259
260 XkbMapConfigList : XkbMapConfigList XkbMapConfig
261 {
262 if (!$2)
263 $$ = $1;
264 else
265 $$ = (XkbFile *) AppendStmt((ParseCommon *) $1,
266 (ParseCommon *) $2);
267 }
268 | XkbMapConfig
269 { $$ = $1; }
270 ;
271
272 XkbMapConfig : OptFlags FileType OptMapName OBRACE
273 DeclList
274 CBRACE SEMI
275 {
276 if ($2 == FILE_TYPE_GEOMETRY) {
277 free($3);
278 FreeStmt($5);
279 $$ = NULL;
280 }
281 else {
282 $$ = XkbFileCreate($2, $3, $5, $1);
283 }
284 }
285 ;
286
287 FileType : XKB_KEYCODES { $$ = FILE_TYPE_KEYCODES; }
288 | XKB_TYPES { $$ = FILE_TYPE_TYPES; }
289 | XKB_COMPATMAP { $$ = FILE_TYPE_COMPAT; }
290 | XKB_SYMBOLS { $$ = FILE_TYPE_SYMBOLS; }
291 | XKB_GEOMETRY { $$ = FILE_TYPE_GEOMETRY; }
292 ;
293
294 OptFlags : Flags { $$ = $1; }
295 | { $$ = 0; }
296 ;
297
298 Flags : Flags Flag { $$ = ($1 | $2); }
299 | Flag { $$ = $1; }
300 ;
301
302 Flag : PARTIAL { $$ = MAP_IS_PARTIAL; }
303 | DEFAULT { $$ = MAP_IS_DEFAULT; }
304 | HIDDEN { $$ = MAP_IS_HIDDEN; }
305 | ALPHANUMERIC_KEYS { $$ = MAP_HAS_ALPHANUMERIC; }
306 | MODIFIER_KEYS { $$ = MAP_HAS_MODIFIER; }
307 | KEYPAD_KEYS { $$ = MAP_HAS_KEYPAD; }
308 | FUNCTION_KEYS { $$ = MAP_HAS_FN; }
309 | ALTERNATE_GROUP { $$ = MAP_IS_ALTGR; }
310 ;
311
312 DeclList : DeclList Decl
313 { $$ = AppendStmt($1, $2); }
314 | { $$ = NULL; }
315 ;
316
317 Decl : OptMergeMode VarDecl
318 {
319 $2->merge = $1;
320 $$ = (ParseCommon *) $2;
321 }
322 | OptMergeMode VModDecl
323 {
324 $2->merge = $1;
325 $$ = (ParseCommon *) $2;
326 }
327 | OptMergeMode InterpretDecl
328 {
329 $2->merge = $1;
330 $$ = (ParseCommon *) $2;
331 }
332 | OptMergeMode KeyNameDecl
333 {
334 $2->merge = $1;
335 $$ = (ParseCommon *) $2;
336 }
337 | OptMergeMode KeyAliasDecl
338 {
339 $2->merge = $1;
340 $$ = (ParseCommon *) $2;
341 }
342 | OptMergeMode KeyTypeDecl
343 {
344 $2->merge = $1;
345 $$ = (ParseCommon *) $2;
346 }
347 | OptMergeMode SymbolsDecl
348 {
349 $2->merge = $1;
350 $$ = (ParseCommon *) $2;
351 }
352 | OptMergeMode ModMapDecl
353 {
354 $2->merge = $1;
355 $$ = (ParseCommon *) $2;
356 }
357 | OptMergeMode GroupCompatDecl
358 {
359 $2->merge = $1;
360 $$ = (ParseCommon *) $2;
361 }
362 | OptMergeMode LedMapDecl
363 {
364 $2->merge = $1;
365 $$ = (ParseCommon *) $2;
366 }
367 | OptMergeMode LedNameDecl
368 {
369 $2->merge = $1;
370 $$ = (ParseCommon *) $2;
371 }
372 | OptMergeMode ShapeDecl { $$ = NULL; }
373 | OptMergeMode SectionDecl { $$ = NULL; }
374 | OptMergeMode DoodadDecl { $$ = NULL; }
375 | MergeMode STRING
376 {
377 $$ = (ParseCommon *) IncludeCreate(param->ctx, $2, $1);
378 free($2);
379 }
380 ;
381
382 VarDecl : Lhs EQUALS Expr SEMI
383 { $$ = VarCreate($1, $3); }
384 | Ident SEMI
385 { $$ = BoolVarCreate($1, true); }
386 | EXCLAM Ident SEMI
387 { $$ = BoolVarCreate($2, false); }
388 ;
389
390 KeyNameDecl : KEYNAME EQUALS KeyCode SEMI
391 { $$ = KeycodeCreate($1, $3); }
392 ;
393
394 KeyAliasDecl : ALIAS KEYNAME EQUALS KEYNAME SEMI
395 { $$ = KeyAliasCreate($2, $4); }
396 ;
397
398 VModDecl : VIRTUAL_MODS VModDefList SEMI
399 { $$ = $2; }
400 ;
401
402 VModDefList : VModDefList COMMA VModDef
403 { $$ = (VModDef *) AppendStmt((ParseCommon *) $1,
404 (ParseCommon *) $3); }
405 | VModDef
406 { $$ = $1; }
407 ;
408
409 VModDef : Ident
410 { $$ = VModCreate($1, NULL); }
411 | Ident EQUALS Expr
412 { $$ = VModCreate($1, $3); }
413 ;
414
415 InterpretDecl : INTERPRET InterpretMatch OBRACE
416 VarDeclList
417 CBRACE SEMI
418 { $2->def = $4; $$ = $2; }
419 ;
420
421 InterpretMatch : KeySym PLUS Expr
422 { $$ = InterpCreate($1, $3); }
423 | KeySym
424 { $$ = InterpCreate($1, NULL); }
425 ;
426
427 VarDeclList : VarDeclList VarDecl
428 { $$ = (VarDef *) AppendStmt((ParseCommon *) $1,
429 (ParseCommon *) $2); }
430 | VarDecl
431 { $$ = $1; }
432 ;
433
434 KeyTypeDecl : TYPE String OBRACE
435 VarDeclList
436 CBRACE SEMI
437 { $$ = KeyTypeCreate($2, $4); }
438 ;
439
440 SymbolsDecl : KEY KEYNAME OBRACE
441 SymbolsBody
442 CBRACE SEMI
443 { $$ = SymbolsCreate($2, $4); }
444 ;
445
446 SymbolsBody : SymbolsBody COMMA SymbolsVarDecl
447 { $$ = (VarDef *) AppendStmt((ParseCommon *) $1,
448 (ParseCommon *) $3); }
449 | SymbolsVarDecl
450 { $$ = $1; }
451 | { $$ = NULL; }
452 ;
453
454 SymbolsVarDecl : Lhs EQUALS Expr { $$ = VarCreate($1, $3); }
455 | Lhs EQUALS ArrayInit { $$ = VarCreate($1, $3); }
456 | Ident { $$ = BoolVarCreate($1, true); }
457 | EXCLAM Ident { $$ = BoolVarCreate($2, false); }
458 | ArrayInit { $$ = VarCreate(NULL, $1); }
459 ;
460
461 ArrayInit : OBRACKET OptKeySymList CBRACKET
462 { $$ = $2; }
463 | OBRACKET ActionList CBRACKET
464 { $$ = ExprCreateUnary(EXPR_ACTION_LIST, EXPR_TYPE_ACTION, $2); }
465 ;
466
467 GroupCompatDecl : GROUP Integer EQUALS Expr SEMI
468 { $$ = GroupCompatCreate($2, $4); }
469 ;
470
471 ModMapDecl : MODIFIER_MAP Ident OBRACE ExprList CBRACE SEMI
472 { $$ = ModMapCreate($2, $4); }
473 ;
474
475 LedMapDecl: INDICATOR String OBRACE VarDeclList CBRACE SEMI
476 { $$ = LedMapCreate($2, $4); }
477 ;
478
479 LedNameDecl: INDICATOR Integer EQUALS Expr SEMI
480 { $$ = LedNameCreate($2, $4, false); }
481 | VIRTUAL INDICATOR Integer EQUALS Expr SEMI
482 { $$ = LedNameCreate($3, $5, true); }
483 ;
484
485 ShapeDecl : SHAPE String OBRACE OutlineList CBRACE SEMI
486 { $$ = NULL; }
487 | SHAPE String OBRACE CoordList CBRACE SEMI
488 { (void) $4; $$ = NULL; }
489 ;
490
491 SectionDecl : SECTION String OBRACE SectionBody CBRACE SEMI
492 { $$ = NULL; }
493 ;
494
495 SectionBody : SectionBody SectionBodyItem { $$ = NULL;}
496 | SectionBodyItem { $$ = NULL; }
497 ;
498
499 SectionBodyItem : ROW OBRACE RowBody CBRACE SEMI
500 { $$ = NULL; }
501 | VarDecl
502 { FreeStmt((ParseCommon *) $1); $$ = NULL; }
503 | DoodadDecl
504 { $$ = NULL; }
505 | LedMapDecl
506 { FreeStmt((ParseCommon *) $1); $$ = NULL; }
507 | OverlayDecl
508 { $$ = NULL; }
509 ;
510
511 RowBody : RowBody RowBodyItem { $$ = NULL;}
512 | RowBodyItem { $$ = NULL; }
513 ;
514
515 RowBodyItem : KEYS OBRACE Keys CBRACE SEMI { $$ = NULL; }
516 | VarDecl
517 { FreeStmt((ParseCommon *) $1); $$ = NULL; }
518 ;
519
520 Keys : Keys COMMA Key { $$ = NULL; }
521 | Key { $$ = NULL; }
522 ;
523
524 Key : KEYNAME
525 { $$ = NULL; }
526 | OBRACE ExprList CBRACE
527 { FreeStmt((ParseCommon *) $2); $$ = NULL; }
528 ;
529
530 OverlayDecl : OVERLAY String OBRACE OverlayKeyList CBRACE SEMI
531 { $$ = NULL; }
532 ;
533
534 OverlayKeyList : OverlayKeyList COMMA OverlayKey { $$ = NULL; }
535 | OverlayKey { $$ = NULL; }
536 ;
537
538 OverlayKey : KEYNAME EQUALS KEYNAME { $$ = NULL; }
539 ;
540
541 OutlineList : OutlineList COMMA OutlineInList
542 { $$ = NULL;}
543 | OutlineInList
544 { $$ = NULL; }
545 ;
546
547 OutlineInList : OBRACE CoordList CBRACE
548 { (void) $2; $$ = NULL; }
549 | Ident EQUALS OBRACE CoordList CBRACE
550 { (void) $4; $$ = NULL; }
551 | Ident EQUALS Expr
552 { FreeStmt((ParseCommon *) $3); $$ = NULL; }
553 ;
554
555 CoordList : CoordList COMMA Coord
556 { (void) $1; (void) $3; $$ = NULL; }
557 | Coord
558 { (void) $1; $$ = NULL; }
559 ;
560
561 Coord : OBRACKET SignedNumber COMMA SignedNumber CBRACKET
562 { $$ = NULL; }
563 ;
564
565 DoodadDecl : DoodadType String OBRACE VarDeclList CBRACE SEMI
566 { FreeStmt((ParseCommon *) $4); $$ = NULL; }
567 ;
568
569 DoodadType : TEXT { $$ = 0; }
570 | OUTLINE { $$ = 0; }
571 | SOLID { $$ = 0; }
572 | LOGO { $$ = 0; }
573 ;
574
575 FieldSpec : Ident { $$ = $1; }
576 | Element { $$ = $1; }
577 ;
578
579 Element : ACTION_TOK
580 { $$ = xkb_atom_intern_literal(param->ctx, "action"); }
581 | INTERPRET
582 { $$ = xkb_atom_intern_literal(param->ctx, "interpret"); }
583 | TYPE
584 { $$ = xkb_atom_intern_literal(param->ctx, "type"); }
585 | KEY
586 { $$ = xkb_atom_intern_literal(param->ctx, "key"); }
587 | GROUP
588 { $$ = xkb_atom_intern_literal(param->ctx, "group"); }
589 | MODIFIER_MAP
590 {$$ = xkb_atom_intern_literal(param->ctx, "modifier_map");}
591 | INDICATOR
592 { $$ = xkb_atom_intern_literal(param->ctx, "indicator"); }
593 | SHAPE
594 { $$ = XKB_ATOM_NONE; }
595 | ROW
596 { $$ = XKB_ATOM_NONE; }
597 | SECTION
598 { $$ = XKB_ATOM_NONE; }
599 | TEXT
600 { $$ = XKB_ATOM_NONE; }
601 ;
602
603 OptMergeMode : MergeMode { $$ = $1; }
604 | { $$ = MERGE_DEFAULT; }
605 ;
606
607 MergeMode : INCLUDE { $$ = MERGE_DEFAULT; }
608 | AUGMENT { $$ = MERGE_AUGMENT; }
609 | OVERRIDE { $$ = MERGE_OVERRIDE; }
610 | REPLACE { $$ = MERGE_REPLACE; }
611 | ALTERNATE
612 {
613 /*
614 * This used to be MERGE_ALT_FORM. This functionality was
615 * unused and has been removed.
616 */
617 $$ = MERGE_DEFAULT;
618 }
619 ;
620
621 OptExprList : ExprList { $$ = $1; }
622 | { $$ = NULL; }
623 ;
624
625 ExprList : ExprList COMMA Expr
626 { $$ = (ExprDef *) AppendStmt((ParseCommon *) $1,
627 (ParseCommon *) $3); }
628 | Expr
629 { $$ = $1; }
630 ;
631
632 Expr : Expr DIVIDE Expr
633 { $$ = ExprCreateBinary(EXPR_DIVIDE, $1, $3); }
634 | Expr PLUS Expr
635 { $$ = ExprCreateBinary(EXPR_ADD, $1, $3); }
636 | Expr MINUS Expr
637 { $$ = ExprCreateBinary(EXPR_SUBTRACT, $1, $3); }
638 | Expr TIMES Expr
639 { $$ = ExprCreateBinary(EXPR_MULTIPLY, $1, $3); }
640 | Lhs EQUALS Expr
641 { $$ = ExprCreateBinary(EXPR_ASSIGN, $1, $3); }
642 | Term
643 { $$ = $1; }
644 ;
645
646 Term : MINUS Term
647 { $$ = ExprCreateUnary(EXPR_NEGATE, $2->expr.value_type, $2); }
648 | PLUS Term
649 { $$ = ExprCreateUnary(EXPR_UNARY_PLUS, $2->expr.value_type, $2); }
650 | EXCLAM Term
651 { $$ = ExprCreateUnary(EXPR_NOT, EXPR_TYPE_BOOLEAN, $2); }
652 | INVERT Term
653 { $$ = ExprCreateUnary(EXPR_INVERT, $2->expr.value_type, $2); }
654 | Lhs
655 { $$ = $1; }
656 | FieldSpec OPAREN OptExprList CPAREN %prec OPAREN
657 { $$ = ExprCreateAction($1, $3); }
658 | Terminal
659 { $$ = $1; }
660 | OPAREN Expr CPAREN
661 { $$ = $2; }
662 ;
663
664 ActionList : ActionList COMMA Action
665 { $$ = (ExprDef *) AppendStmt((ParseCommon *) $1,
666 (ParseCommon *) $3); }
667 | Action
668 { $$ = $1; }
669 ;
670
671 Action : FieldSpec OPAREN OptExprList CPAREN
672 { $$ = ExprCreateAction($1, $3); }
673 ;
674
675 Lhs : FieldSpec
676 { $$ = ExprCreateIdent($1); }
677 | FieldSpec DOT FieldSpec
678 { $$ = ExprCreateFieldRef($1, $3); }
679 | FieldSpec OBRACKET Expr CBRACKET
680 { $$ = ExprCreateArrayRef(XKB_ATOM_NONE, $1, $3); }
681 | FieldSpec DOT FieldSpec OBRACKET Expr CBRACKET
682 { $$ = ExprCreateArrayRef($1, $3, $5); }
683 ;
684
685 Terminal : String
686 { $$ = ExprCreateString($1); }
687 | Integer
688 { $$ = ExprCreateInteger($1); }
689 | Float
690 { $$ = NULL; }
691 | KEYNAME
692 { $$ = ExprCreateKeyName($1); }
693 ;
694
695 OptKeySymList : KeySymList { $$ = $1; }
696 | { $$ = NULL; }
697 ;
698
699 KeySymList : KeySymList COMMA KeySym
700 { $$ = ExprAppendKeysymList($1, $3); }
701 | KeySymList COMMA KeySyms
702 { $$ = ExprAppendMultiKeysymList($1, $3); }
703 | KeySym
704 { $$ = ExprCreateKeysymList($1); }
705 | KeySyms
706 { $$ = ExprCreateMultiKeysymList($1); }
707 ;
708
709 KeySyms : OBRACE KeySymList CBRACE
710 { $$ = $2; }
711 ;
712
713 KeySym : IDENT
714 {
715 if (!resolve_keysym($1, &$$))
716 parser_warn(param, "unrecognized keysym \"%s\"", $1);
717 free($1);
718 }
719 | SECTION { $$ = XKB_KEY_section; }
720 | Integer
721 {
722 if ($1 < 0) {
723 parser_warn(param, "unrecognized keysym \"%d\"", $1);
724 $$ = XKB_KEY_NoSymbol;
725 }
726 else if ($1 < 10) { /* XKB_KEY_0 .. XKB_KEY_9 */
727 $$ = XKB_KEY_0 + (xkb_keysym_t) $1;
728 }
729 else {
730 char buf[17];
731 snprintf(buf, sizeof(buf), "0x%x", $1);
732 if (!resolve_keysym(buf, &$$)) {
733 parser_warn(param, "unrecognized keysym \"%s\"", buf);
734 $$ = XKB_KEY_NoSymbol;
735 }
736 }
737 }
738 ;
739
740 SignedNumber : MINUS Number { $$ = -$2; }
741 | Number { $$ = $1; }
742 ;
743
744 Number : FLOAT { $$ = $1; }
745 | INTEGER { $$ = $1; }
746 ;
747
748 Float : FLOAT { $$ = 0; }
749 ;
750
751 Integer : INTEGER { $$ = $1; }
752 ;
753
754 KeyCode : INTEGER { $$ = $1; }
755 ;
756
757 Ident : IDENT { $$ = xkb_atom_steal(param->ctx, $1); }
758 | DEFAULT { $$ = xkb_atom_intern_literal(param->ctx, "default"); }
759 ;
760
761 String : STRING { $$ = xkb_atom_steal(param->ctx, $1); }
762 ;
763
764 OptMapName : MapName { $$ = $1; }
765 | { $$ = NULL; }
766 ;
767
768 MapName : STRING { $$ = $1; }
769 ;
770
771 %%
772
773 XkbFile *
774 parse(struct xkb_context *ctx, struct scanner *scanner, const char *map)
775 {
776 int ret;
777 XkbFile *first = NULL;
778 struct parser_param param = {
779 .scanner = scanner,
780 .ctx = ctx,
781 .rtrn = NULL,
782 };
783
784 /*
785 * If we got a specific map, we look for it exclusively and return
786 * immediately upon finding it. Otherwise, we need to get the
787 * default map. If we find a map marked as default, we return it
788 * immediately. If there are no maps marked as default, we return
789 * the first map in the file.
790 */
791
792 while ((ret = yyparse(¶m)) == 0 && param.more_maps) {
793 if (map) {
794 if (streq_not_null(map, param.rtrn->name))
795 return param.rtrn;
796 else
797 FreeXkbFile(param.rtrn);
798 }
799 else {
800 if (param.rtrn->flags & MAP_IS_DEFAULT) {
801 FreeXkbFile(first);
802 return param.rtrn;
803 }
804 else if (!first) {
805 first = param.rtrn;
806 }
807 else {
808 FreeXkbFile(param.rtrn);
809 }
810 }
811 param.rtrn = NULL;
812 }
813
814 if (ret != 0) {
815 FreeXkbFile(first);
816 return NULL;
817 }
818
819 if (first)
820 log_vrb(ctx, 5,
821 "No map in include statement, but \"%s\" contains several; "
822 "Using first defined map, \"%s\"\n",
823 scanner->file_name, first->name);
824
825 return first;
826 }
827