7145c1b566457e5ac807f9be50c4e955e090d89b
[platform/upstream/libxkbcommon.git] / src / xkbcomp / parser.y
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/xkbcomp-priv.h"
35 #include "xkbcomp/ast-build.h"
36 #include "xkbcomp/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
53 _xkbcommon_error(struct parser_param *param, const char *msg)
54 {
55     parser_err(param, "%s", msg);
56 }
57
58 static bool
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 = !!param->rtrn; }
243                 |       XkbMapConfig
244                         { $$ = param->rtrn = $1; param->more_maps = !!param->rtrn; 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                             $$ = XkbFileCreate($2, $3, $5, $1);
277                         }
278                 ;
279
280 FileType        :       XKB_KEYCODES            { $$ = FILE_TYPE_KEYCODES; }
281                 |       XKB_TYPES               { $$ = FILE_TYPE_TYPES; }
282                 |       XKB_COMPATMAP           { $$ = FILE_TYPE_COMPAT; }
283                 |       XKB_SYMBOLS             { $$ = FILE_TYPE_SYMBOLS; }
284                 |       XKB_GEOMETRY            { $$ = FILE_TYPE_GEOMETRY; }
285                 ;
286
287 OptFlags        :       Flags                   { $$ = $1; }
288                 |                               { $$ = 0; }
289                 ;
290
291 Flags           :       Flags Flag              { $$ = ($1 | $2); }
292                 |       Flag                    { $$ = $1; }
293                 ;
294
295 Flag            :       PARTIAL                 { $$ = MAP_IS_PARTIAL; }
296                 |       DEFAULT                 { $$ = MAP_IS_DEFAULT; }
297                 |       HIDDEN                  { $$ = MAP_IS_HIDDEN; }
298                 |       ALPHANUMERIC_KEYS       { $$ = MAP_HAS_ALPHANUMERIC; }
299                 |       MODIFIER_KEYS           { $$ = MAP_HAS_MODIFIER; }
300                 |       KEYPAD_KEYS             { $$ = MAP_HAS_KEYPAD; }
301                 |       FUNCTION_KEYS           { $$ = MAP_HAS_FN; }
302                 |       ALTERNATE_GROUP         { $$ = MAP_IS_ALTGR; }
303                 ;
304
305 DeclList        :       DeclList Decl
306                         { $$ = AppendStmt($1, $2); }
307                 |       { $$ = NULL; }
308                 ;
309
310 Decl            :       OptMergeMode VarDecl
311                         {
312                             $2->merge = $1;
313                             $$ = (ParseCommon *) $2;
314                         }
315                 |       OptMergeMode VModDecl
316                         {
317                             for (VModDef *vmod = $2; vmod; vmod = (VModDef *) vmod->common.next)
318                                 vmod->merge = $1;
319                             $$ = (ParseCommon *) $2;
320                         }
321                 |       OptMergeMode InterpretDecl
322                         {
323                             $2->merge = $1;
324                             $$ = (ParseCommon *) $2;
325                         }
326                 |       OptMergeMode KeyNameDecl
327                         {
328                             $2->merge = $1;
329                             $$ = (ParseCommon *) $2;
330                         }
331                 |       OptMergeMode KeyAliasDecl
332                         {
333                             $2->merge = $1;
334                             $$ = (ParseCommon *) $2;
335                         }
336                 |       OptMergeMode KeyTypeDecl
337                         {
338                             $2->merge = $1;
339                             $$ = (ParseCommon *) $2;
340                         }
341                 |       OptMergeMode SymbolsDecl
342                         {
343                             $2->merge = $1;
344                             $$ = (ParseCommon *) $2;
345                         }
346                 |       OptMergeMode ModMapDecl
347                         {
348                             $2->merge = $1;
349                             $$ = (ParseCommon *) $2;
350                         }
351                 |       OptMergeMode GroupCompatDecl
352                         {
353                             $2->merge = $1;
354                             $$ = (ParseCommon *) $2;
355                         }
356                 |       OptMergeMode LedMapDecl
357                         {
358                             $2->merge = $1;
359                             $$ = (ParseCommon *) $2;
360                         }
361                 |       OptMergeMode LedNameDecl
362                         {
363                             $2->merge = $1;
364                             $$ = (ParseCommon *) $2;
365                         }
366                 |       OptMergeMode ShapeDecl          { $$ = NULL; }
367                 |       OptMergeMode SectionDecl        { $$ = NULL; }
368                 |       OptMergeMode DoodadDecl         { $$ = NULL; }
369                 |       MergeMode STRING
370                         {
371                             $$ = (ParseCommon *) IncludeCreate(param->ctx, $2, $1);
372                             free($2);
373                         }
374                 ;
375
376 VarDecl         :       Lhs EQUALS Expr SEMI
377                         { $$ = VarCreate($1, $3); }
378                 |       Ident SEMI
379                         { $$ = BoolVarCreate($1, true); }
380                 |       EXCLAM Ident SEMI
381                         { $$ = BoolVarCreate($2, false); }
382                 ;
383
384 KeyNameDecl     :       KEYNAME EQUALS KeyCode SEMI
385                         { $$ = KeycodeCreate($1, $3); }
386                 ;
387
388 KeyAliasDecl    :       ALIAS KEYNAME EQUALS KEYNAME SEMI
389                         { $$ = KeyAliasCreate($2, $4); }
390                 ;
391
392 VModDecl        :       VIRTUAL_MODS VModDefList SEMI
393                         { $$ = $2; }
394                 ;
395
396 VModDefList     :       VModDefList COMMA VModDef
397                         { $$ = (VModDef *) AppendStmt((ParseCommon *) $1,
398                                                       (ParseCommon *) $3); }
399                 |       VModDef
400                         { $$ = $1; }
401                 ;
402
403 VModDef         :       Ident
404                         { $$ = VModCreate($1, NULL); }
405                 |       Ident EQUALS Expr
406                         { $$ = VModCreate($1, $3); }
407                 ;
408
409 InterpretDecl   :       INTERPRET InterpretMatch OBRACE
410                             VarDeclList
411                         CBRACE SEMI
412                         { $2->def = $4; $$ = $2; }
413                 ;
414
415 InterpretMatch  :       KeySym PLUS Expr
416                         { $$ = InterpCreate($1, $3); }
417                 |       KeySym
418                         { $$ = InterpCreate($1, NULL); }
419                 ;
420
421 VarDeclList     :       VarDeclList VarDecl
422                         { $$ = (VarDef *) AppendStmt((ParseCommon *) $1,
423                                                      (ParseCommon *) $2); }
424                 |       VarDecl
425                         { $$ = $1; }
426                 ;
427
428 KeyTypeDecl     :       TYPE String OBRACE
429                             VarDeclList
430                         CBRACE SEMI
431                         { $$ = KeyTypeCreate($2, $4); }
432                 ;
433
434 SymbolsDecl     :       KEY KEYNAME OBRACE
435                             SymbolsBody
436                         CBRACE SEMI
437                         { $$ = SymbolsCreate($2, $4); }
438                 ;
439
440 SymbolsBody     :       SymbolsBody COMMA SymbolsVarDecl
441                         { $$ = (VarDef *) AppendStmt((ParseCommon *) $1,
442                                                      (ParseCommon *) $3); }
443                 |       SymbolsVarDecl
444                         { $$ = $1; }
445                 |       { $$ = NULL; }
446                 ;
447
448 SymbolsVarDecl  :       Lhs EQUALS Expr         { $$ = VarCreate($1, $3); }
449                 |       Lhs EQUALS ArrayInit    { $$ = VarCreate($1, $3); }
450                 |       Ident                   { $$ = BoolVarCreate($1, true); }
451                 |       EXCLAM Ident            { $$ = BoolVarCreate($2, false); }
452                 |       ArrayInit               { $$ = VarCreate(NULL, $1); }
453                 ;
454
455 ArrayInit       :       OBRACKET OptKeySymList CBRACKET
456                         { $$ = $2; }
457                 |       OBRACKET ActionList CBRACKET
458                         { $$ = ExprCreateActionList($2); }
459                 ;
460
461 GroupCompatDecl :       GROUP Integer EQUALS Expr SEMI
462                         { $$ = GroupCompatCreate($2, $4); }
463                 ;
464
465 ModMapDecl      :       MODIFIER_MAP Ident OBRACE ExprList CBRACE SEMI
466                         { $$ = ModMapCreate($2, $4); }
467                 ;
468
469 LedMapDecl:             INDICATOR String OBRACE VarDeclList CBRACE SEMI
470                         { $$ = LedMapCreate($2, $4); }
471                 ;
472
473 LedNameDecl:            INDICATOR Integer EQUALS Expr SEMI
474                         { $$ = LedNameCreate($2, $4, false); }
475                 |       VIRTUAL INDICATOR Integer EQUALS Expr SEMI
476                         { $$ = LedNameCreate($3, $5, true); }
477                 ;
478
479 ShapeDecl       :       SHAPE String OBRACE OutlineList CBRACE SEMI
480                         { $$ = NULL; }
481                 |       SHAPE String OBRACE CoordList CBRACE SEMI
482                         { (void) $4; $$ = NULL; }
483                 ;
484
485 SectionDecl     :       SECTION String OBRACE SectionBody CBRACE SEMI
486                         { $$ = NULL; }
487                 ;
488
489 SectionBody     :       SectionBody SectionBodyItem     { $$ = NULL;}
490                 |       SectionBodyItem                 { $$ = NULL; }
491                 ;
492
493 SectionBodyItem :       ROW OBRACE RowBody CBRACE SEMI
494                         { $$ = NULL; }
495                 |       VarDecl
496                         { FreeStmt((ParseCommon *) $1); $$ = NULL; }
497                 |       DoodadDecl
498                         { $$ = NULL; }
499                 |       LedMapDecl
500                         { FreeStmt((ParseCommon *) $1); $$ = NULL; }
501                 |       OverlayDecl
502                         { $$ = NULL; }
503                 ;
504
505 RowBody         :       RowBody RowBodyItem     { $$ = NULL;}
506                 |       RowBodyItem             { $$ = NULL; }
507                 ;
508
509 RowBodyItem     :       KEYS OBRACE Keys CBRACE SEMI { $$ = NULL; }
510                 |       VarDecl
511                         { FreeStmt((ParseCommon *) $1); $$ = NULL; }
512                 ;
513
514 Keys            :       Keys COMMA Key          { $$ = NULL; }
515                 |       Key                     { $$ = NULL; }
516                 ;
517
518 Key             :       KEYNAME
519                         { $$ = NULL; }
520                 |       OBRACE ExprList CBRACE
521                         { FreeStmt((ParseCommon *) $2); $$ = NULL; }
522                 ;
523
524 OverlayDecl     :       OVERLAY String OBRACE OverlayKeyList CBRACE SEMI
525                         { $$ = NULL; }
526                 ;
527
528 OverlayKeyList  :       OverlayKeyList COMMA OverlayKey { $$ = NULL; }
529                 |       OverlayKey                      { $$ = NULL; }
530                 ;
531
532 OverlayKey      :       KEYNAME EQUALS KEYNAME          { $$ = NULL; }
533                 ;
534
535 OutlineList     :       OutlineList COMMA OutlineInList
536                         { $$ = NULL;}
537                 |       OutlineInList
538                         { $$ = NULL; }
539                 ;
540
541 OutlineInList   :       OBRACE CoordList CBRACE
542                         { (void) $2; $$ = NULL; }
543                 |       Ident EQUALS OBRACE CoordList CBRACE
544                         { (void) $4; $$ = NULL; }
545                 |       Ident EQUALS Expr
546                         { FreeStmt((ParseCommon *) $3); $$ = NULL; }
547                 ;
548
549 CoordList       :       CoordList COMMA Coord
550                         { (void) $1; (void) $3; $$ = NULL; }
551                 |       Coord
552                         { (void) $1; $$ = NULL; }
553                 ;
554
555 Coord           :       OBRACKET SignedNumber COMMA SignedNumber CBRACKET
556                         { $$ = NULL; }
557                 ;
558
559 DoodadDecl      :       DoodadType String OBRACE VarDeclList CBRACE SEMI
560                         { FreeStmt((ParseCommon *) $4); $$ = NULL; }
561                 ;
562
563 DoodadType      :       TEXT    { $$ = 0; }
564                 |       OUTLINE { $$ = 0; }
565                 |       SOLID   { $$ = 0; }
566                 |       LOGO    { $$ = 0; }
567                 ;
568
569 FieldSpec       :       Ident   { $$ = $1; }
570                 |       Element { $$ = $1; }
571                 ;
572
573 Element         :       ACTION_TOK
574                         { $$ = xkb_atom_intern_literal(param->ctx, "action"); }
575                 |       INTERPRET
576                         { $$ = xkb_atom_intern_literal(param->ctx, "interpret"); }
577                 |       TYPE
578                         { $$ = xkb_atom_intern_literal(param->ctx, "type"); }
579                 |       KEY
580                         { $$ = xkb_atom_intern_literal(param->ctx, "key"); }
581                 |       GROUP
582                         { $$ = xkb_atom_intern_literal(param->ctx, "group"); }
583                 |       MODIFIER_MAP
584                         {$$ = xkb_atom_intern_literal(param->ctx, "modifier_map");}
585                 |       INDICATOR
586                         { $$ = xkb_atom_intern_literal(param->ctx, "indicator"); }
587                 |       SHAPE
588                         { $$ = xkb_atom_intern_literal(param->ctx, "shape"); }
589                 |       ROW
590                         { $$ = xkb_atom_intern_literal(param->ctx, "row"); }
591                 |       SECTION
592                         { $$ = xkb_atom_intern_literal(param->ctx, "section"); }
593                 |       TEXT
594                         { $$ = xkb_atom_intern_literal(param->ctx, "text"); }
595                 ;
596
597 OptMergeMode    :       MergeMode       { $$ = $1; }
598                 |                       { $$ = MERGE_DEFAULT; }
599                 ;
600
601 MergeMode       :       INCLUDE         { $$ = MERGE_DEFAULT; }
602                 |       AUGMENT         { $$ = MERGE_AUGMENT; }
603                 |       OVERRIDE        { $$ = MERGE_OVERRIDE; }
604                 |       REPLACE         { $$ = MERGE_REPLACE; }
605                 |       ALTERNATE
606                 {
607                     /*
608                      * This used to be MERGE_ALT_FORM. This functionality was
609                      * unused and has been removed.
610                      */
611                     $$ = MERGE_DEFAULT;
612                 }
613                 ;
614
615 OptExprList     :       ExprList        { $$ = $1; }
616                 |                       { $$ = NULL; }
617                 ;
618
619 ExprList        :       ExprList COMMA Expr
620                         { $$ = (ExprDef *) AppendStmt((ParseCommon *) $1,
621                                                       (ParseCommon *) $3); }
622                 |       Expr
623                         { $$ = $1; }
624                 ;
625
626 Expr            :       Expr DIVIDE Expr
627                         { $$ = ExprCreateBinary(EXPR_DIVIDE, $1, $3); }
628                 |       Expr PLUS Expr
629                         { $$ = ExprCreateBinary(EXPR_ADD, $1, $3); }
630                 |       Expr MINUS Expr
631                         { $$ = ExprCreateBinary(EXPR_SUBTRACT, $1, $3); }
632                 |       Expr TIMES Expr
633                         { $$ = ExprCreateBinary(EXPR_MULTIPLY, $1, $3); }
634                 |       Lhs EQUALS Expr
635                         { $$ = ExprCreateBinary(EXPR_ASSIGN, $1, $3); }
636                 |       Term
637                         { $$ = $1; }
638                 ;
639
640 Term            :       MINUS Term
641                         { $$ = ExprCreateUnary(EXPR_NEGATE, $2->expr.value_type, $2); }
642                 |       PLUS Term
643                         { $$ = ExprCreateUnary(EXPR_UNARY_PLUS, $2->expr.value_type, $2); }
644                 |       EXCLAM Term
645                         { $$ = ExprCreateUnary(EXPR_NOT, EXPR_TYPE_BOOLEAN, $2); }
646                 |       INVERT Term
647                         { $$ = ExprCreateUnary(EXPR_INVERT, $2->expr.value_type, $2); }
648                 |       Lhs
649                         { $$ = $1;  }
650                 |       FieldSpec OPAREN OptExprList CPAREN %prec OPAREN
651                         { $$ = ExprCreateAction($1, $3); }
652                 |       Terminal
653                         { $$ = $1;  }
654                 |       OPAREN Expr CPAREN
655                         { $$ = $2;  }
656                 ;
657
658 ActionList      :       ActionList COMMA Action
659                         { $$ = (ExprDef *) AppendStmt((ParseCommon *) $1,
660                                                       (ParseCommon *) $3); }
661                 |       Action
662                         { $$ = $1; }
663                 ;
664
665 Action          :       FieldSpec OPAREN OptExprList CPAREN
666                         { $$ = ExprCreateAction($1, $3); }
667                 ;
668
669 Lhs             :       FieldSpec
670                         { $$ = ExprCreateIdent($1); }
671                 |       FieldSpec DOT FieldSpec
672                         { $$ = ExprCreateFieldRef($1, $3); }
673                 |       FieldSpec OBRACKET Expr CBRACKET
674                         { $$ = ExprCreateArrayRef(XKB_ATOM_NONE, $1, $3); }
675                 |       FieldSpec DOT FieldSpec OBRACKET Expr CBRACKET
676                         { $$ = ExprCreateArrayRef($1, $3, $5); }
677                 ;
678
679 Terminal        :       String
680                         { $$ = ExprCreateString($1); }
681                 |       Integer
682                         { $$ = ExprCreateInteger($1); }
683                 |       Float
684                         { $$ = ExprCreateFloat(/* Discard $1 */); }
685                 |       KEYNAME
686                         { $$ = ExprCreateKeyName($1); }
687                 ;
688
689 OptKeySymList   :       KeySymList      { $$ = $1; }
690                 |                       { $$ = NULL; }
691                 ;
692
693 KeySymList      :       KeySymList COMMA KeySym
694                         { $$ = ExprAppendKeysymList($1, $3); }
695                 |       KeySymList COMMA KeySyms
696                         { $$ = ExprAppendMultiKeysymList($1, $3); }
697                 |       KeySym
698                         { $$ = ExprCreateKeysymList($1); }
699                 |       KeySyms
700                         { $$ = ExprCreateMultiKeysymList($1); }
701                 ;
702
703 KeySyms         :       OBRACE KeySymList CBRACE
704                         { $$ = $2; }
705                 ;
706
707 KeySym          :       IDENT
708                         {
709                             if (!resolve_keysym($1, &$$))
710                                 parser_warn(param, "unrecognized keysym \"%s\"", $1);
711                             free($1);
712                         }
713                 |       SECTION { $$ = XKB_KEY_section; }
714                 |       Integer
715                         {
716                             if ($1 < 0) {
717                                 parser_warn(param, "unrecognized keysym \"%d\"", $1);
718                                 $$ = XKB_KEY_NoSymbol;
719                             }
720                             else if ($1 < 10) {      /* XKB_KEY_0 .. XKB_KEY_9 */
721                                 $$ = XKB_KEY_0 + (xkb_keysym_t) $1;
722                             }
723                             else {
724                                 char buf[17];
725                                 snprintf(buf, sizeof(buf), "0x%x", $1);
726                                 if (!resolve_keysym(buf, &$$)) {
727                                     parser_warn(param, "unrecognized keysym \"%s\"", buf);
728                                     $$ = XKB_KEY_NoSymbol;
729                                 }
730                             }
731                         }
732                 ;
733
734 SignedNumber    :       MINUS Number    { $$ = -$2; }
735                 |       Number          { $$ = $1; }
736                 ;
737
738 Number          :       FLOAT   { $$ = $1; }
739                 |       INTEGER { $$ = $1; }
740                 ;
741
742 Float           :       FLOAT   { $$ = 0; }
743                 ;
744
745 Integer         :       INTEGER { $$ = $1; }
746                 ;
747
748 KeyCode         :       INTEGER { $$ = $1; }
749                 ;
750
751 Ident           :       IDENT   { $$ = xkb_atom_intern(param->ctx, $1, strlen($1)); free($1); }
752                 |       DEFAULT { $$ = xkb_atom_intern_literal(param->ctx, "default"); }
753                 ;
754
755 String          :       STRING  { $$ = xkb_atom_intern(param->ctx, $1, strlen($1)); free($1); }
756                 ;
757
758 OptMapName      :       MapName { $$ = $1; }
759                 |               { $$ = NULL; }
760                 ;
761
762 MapName         :       STRING  { $$ = $1; }
763                 ;
764
765 %%
766
767 XkbFile *
768 parse(struct xkb_context *ctx, struct scanner *scanner, const char *map)
769 {
770     int ret;
771     XkbFile *first = NULL;
772     struct parser_param param = {
773         .scanner = scanner,
774         .ctx = ctx,
775         .rtrn = NULL,
776         .more_maps = false,
777     };
778
779     /*
780      * If we got a specific map, we look for it exclusively and return
781      * immediately upon finding it. Otherwise, we need to get the
782      * default map. If we find a map marked as default, we return it
783      * immediately. If there are no maps marked as default, we return
784      * the first map in the file.
785      */
786
787     while ((ret = yyparse(&param)) == 0 && param.more_maps) {
788         if (map) {
789             if (streq_not_null(map, param.rtrn->name))
790                 return param.rtrn;
791             else
792                 FreeXkbFile(param.rtrn);
793         }
794         else {
795             if (param.rtrn->flags & MAP_IS_DEFAULT) {
796                 FreeXkbFile(first);
797                 return param.rtrn;
798             }
799             else if (!first) {
800                 first = param.rtrn;
801             }
802             else {
803                 FreeXkbFile(param.rtrn);
804             }
805         }
806         param.rtrn = NULL;
807     }
808
809     if (ret != 0) {
810         FreeXkbFile(first);
811         return NULL;
812     }
813
814     if (first)
815         log_vrb(ctx, 5,
816                 "No map in include statement, but \"%s\" contains several; "
817                 "Using first defined map, \"%s\"\n",
818                 scanner->file_name, first->name);
819
820     return first;
821 }