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