1 /************************************************************
2 Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
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.
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.
25 ********************************************************/
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
36 #include "xkbcomp/xkbcomp-priv.h"
37 #include "xkbcomp/ast-build.h"
38 #include "xkbcomp/parser-priv.h"
39 #include "scanner-utils.h"
42 struct xkb_context *ctx;
43 struct scanner *scanner;
48 #define parser_err(param, fmt, ...) \
49 scanner_err((param)->scanner, fmt, ##__VA_ARGS__)
51 #define parser_warn(param, fmt, ...) \
52 scanner_warn((param)->scanner, fmt, ##__VA_ARGS__)
55 _xkbcommon_error(struct parser_param *param, const char *msg)
57 parser_err(param, "%s", msg);
61 resolve_keysym(const char *name, xkb_keysym_t *sym_rtrn)
65 if (!name || istreq(name, "any") || istreq(name, "nosymbol")) {
66 *sym_rtrn = XKB_KEY_NoSymbol;
70 if (istreq(name, "none") || istreq(name, "voidsymbol")) {
71 *sym_rtrn = XKB_KEY_VoidSymbol;
75 sym = xkb_keysym_from_name(name, XKB_KEYSYM_NO_FLAGS);
76 if (sym != XKB_KEY_NoSymbol) {
84 #define param_scanner param->scanner
88 %lex-param { struct scanner *param_scanner }
89 %parse-param { struct parser_param *param }
166 enum xkb_file_type file_type;
169 enum merge_mode merge;
170 enum xkb_map_flags mapFlags;
173 struct { ParseCommon *head; ParseCommon *last; } anyList;
175 struct { ExprDef *head; ExprDef *last; } exprList;
177 struct { VarDef *head; VarDef *last; } varList;
179 struct { VModDef *head; VModDef *last; } vmodList;
184 GroupCompatDef *groupCompat;
188 KeyAliasDef *keyAlias;
191 struct { XkbFile *head; XkbFile *last; } fileList;
194 %type <num> INTEGER FLOAT
195 %type <str> IDENT STRING
197 %type <num> KeyCode Number Integer Float SignedNumber DoodadType
198 %type <merge> MergeMode OptMergeMode
199 %type <file_type> XkbCompositeType FileType
200 %type <mapFlags> Flag Flags OptFlags
201 %type <str> MapName OptMapName
202 %type <atom> FieldSpec Ident Element String
203 %type <keysym> KeySym
205 %type <anyList> DeclList
206 %type <expr> Expr Term Lhs Terminal ArrayInit KeySyms
207 %type <expr> OptKeySymList KeySymList Action Coord CoordList
208 %type <exprList> OptExprList ExprList ActionList
209 %type <var> VarDecl SymbolsVarDecl
210 %type <varList> VarDeclList SymbolsBody
212 %type <vmodList> VModDefList VModDecl
213 %type <interp> InterpretDecl InterpretMatch
214 %type <keyType> KeyTypeDecl
215 %type <syms> SymbolsDecl
216 %type <modMask> ModMapDecl
217 %type <groupCompat> GroupCompatDecl
218 %type <ledMap> LedMapDecl
219 %type <ledName> LedNameDecl
220 %type <keyCode> KeyNameDecl
221 %type <keyAlias> KeyAliasDecl
222 %type <geom> ShapeDecl SectionDecl SectionBody SectionBodyItem RowBody RowBodyItem
223 %type <geom> Keys Key OverlayDecl OverlayKeyList OverlayKey OutlineList OutlineInList
224 %type <geom> DoodadDecl
225 %type <file> XkbFile XkbMapConfig
226 %type <fileList> XkbMapConfigList
227 %type <file> XkbCompositeMap
229 %destructor { FreeStmt((ParseCommon *) $$); }
230 <any> <expr> <var> <vmod> <interp> <keyType> <syms> <modMask> <groupCompat>
231 <ledMap> <ledName> <keyCode> <keyAlias>
232 %destructor { FreeStmt((ParseCommon *) $$.head); }
233 <anyList> <exprList> <varList> <vmodList>
234 /* The destructor also runs on the start symbol when the parser *succeeds*.
235 * The `if` here catches this case. */
236 %destructor { if (!param->rtrn) FreeXkbFile($$); } <file>
237 %destructor { FreeXkbFile($$.head); } <fileList>
238 %destructor { free($$); } <str>
243 * An actual file may contain more than one map. However, if we do things
244 * in the normal yacc way, i.e. aggregate all of the maps into a list and
245 * let the caller find the map it wants, we end up scanning and parsing a
246 * lot of unneeded maps (in the end we always just need one).
247 * Instead of doing that, we make yyparse return one map at a time, and
248 * then call it repeatedly until we find the map we need. Once we find it,
249 * we don't need to parse everything that follows in the file.
250 * This does mean that if we e.g. always use the first map, the file may
251 * contain complete garbage after that. But it's worth it.
254 XkbFile : XkbCompositeMap
255 { $$ = param->rtrn = $1; param->more_maps = !!param->rtrn; }
257 { $$ = param->rtrn = $1; param->more_maps = !!param->rtrn; YYACCEPT; }
259 { $$ = param->rtrn = NULL; param->more_maps = false; }
262 XkbCompositeMap : OptFlags XkbCompositeType OptMapName OBRACE
265 { $$ = XkbFileCreate($2, $3, (ParseCommon *) $5.head, $1); }
268 XkbCompositeType: XKB_KEYMAP { $$ = FILE_TYPE_KEYMAP; }
269 | XKB_SEMANTICS { $$ = FILE_TYPE_KEYMAP; }
270 | XKB_LAYOUT { $$ = FILE_TYPE_KEYMAP; }
273 XkbMapConfigList : XkbMapConfigList XkbMapConfig
274 { $$.head = $1.head; $$.last->common.next = &$2->common; $$.last = $2; }
276 { $$.head = $$.last = $1; }
279 XkbMapConfig : OptFlags FileType OptMapName OBRACE
283 $$ = XkbFileCreate($2, $3, $5.head, $1);
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; }
294 OptFlags : Flags { $$ = $1; }
298 Flags : Flags Flag { $$ = ($1 | $2); }
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; }
312 DeclList : DeclList Decl
316 $$.head = $1.head; $1.last->next = $2; $$.last = $2;
318 $$.head = $$.last = $2;
323 * VModDecl is "inlined" directly into DeclList, i.e.
324 * each VModDef in the VModDecl is a separate Decl in
327 | DeclList OptMergeMode VModDecl
329 for (VModDef *vmod = $3.head; vmod; vmod = (VModDef *) vmod->common.next)
332 $$.head = $1.head; $1.last->next = &$3.head->common; $$.last = &$3.last->common;
334 $$.head = &$3.head->common; $$.last = &$3.last->common;
337 | { $$.head = $$.last = NULL; }
340 Decl : OptMergeMode VarDecl
343 $$ = (ParseCommon *) $2;
345 /* OptMergeMode VModDecl - see above. */
346 | OptMergeMode InterpretDecl
349 $$ = (ParseCommon *) $2;
351 | OptMergeMode KeyNameDecl
354 $$ = (ParseCommon *) $2;
356 | OptMergeMode KeyAliasDecl
359 $$ = (ParseCommon *) $2;
361 | OptMergeMode KeyTypeDecl
364 $$ = (ParseCommon *) $2;
366 | OptMergeMode SymbolsDecl
369 $$ = (ParseCommon *) $2;
371 | OptMergeMode ModMapDecl
374 $$ = (ParseCommon *) $2;
376 | OptMergeMode GroupCompatDecl
379 $$ = (ParseCommon *) $2;
381 | OptMergeMode LedMapDecl
384 $$ = (ParseCommon *) $2;
386 | OptMergeMode LedNameDecl
389 $$ = (ParseCommon *) $2;
391 | OptMergeMode ShapeDecl { $$ = NULL; }
392 | OptMergeMode SectionDecl { $$ = NULL; }
393 | OptMergeMode DoodadDecl { $$ = NULL; }
396 $$ = (ParseCommon *) IncludeCreate(param->ctx, $2, $1);
401 VarDecl : Lhs EQUALS Expr SEMI
402 { $$ = VarCreate($1, $3); }
404 { $$ = BoolVarCreate($1, true); }
406 { $$ = BoolVarCreate($2, false); }
409 KeyNameDecl : KEYNAME EQUALS KeyCode SEMI
410 { $$ = KeycodeCreate($1, $3); }
413 KeyAliasDecl : ALIAS KEYNAME EQUALS KEYNAME SEMI
414 { $$ = KeyAliasCreate($2, $4); }
417 VModDecl : VIRTUAL_MODS VModDefList SEMI
421 VModDefList : VModDefList COMMA VModDef
422 { $$.head = $1.head; $$.last->common.next = &$3->common; $$.last = $3; }
424 { $$.head = $$.last = $1; }
428 { $$ = VModCreate($1, NULL); }
430 { $$ = VModCreate($1, $3); }
433 InterpretDecl : INTERPRET InterpretMatch OBRACE
436 { $2->def = $4.head; $$ = $2; }
439 InterpretMatch : KeySym PLUS Expr
440 { $$ = InterpCreate($1, $3); }
442 { $$ = InterpCreate($1, NULL); }
445 VarDeclList : VarDeclList VarDecl
446 { $$.head = $1.head; $$.last->common.next = &$2->common; $$.last = $2; }
448 { $$.head = $$.last = $1; }
451 KeyTypeDecl : TYPE String OBRACE
454 { $$ = KeyTypeCreate($2, $4.head); }
457 SymbolsDecl : KEY KEYNAME OBRACE
460 { $$ = SymbolsCreate($2, $4.head); }
463 SymbolsBody : SymbolsBody COMMA SymbolsVarDecl
464 { $$.head = $1.head; $$.last->common.next = &$3->common; $$.last = $3; }
466 { $$.head = $$.last = $1; }
467 | { $$.head = $$.last = NULL; }
470 SymbolsVarDecl : Lhs EQUALS Expr { $$ = VarCreate($1, $3); }
471 | Lhs EQUALS ArrayInit { $$ = VarCreate($1, $3); }
472 | Ident { $$ = BoolVarCreate($1, true); }
473 | EXCLAM Ident { $$ = BoolVarCreate($2, false); }
474 | ArrayInit { $$ = VarCreate(NULL, $1); }
477 ArrayInit : OBRACKET OptKeySymList CBRACKET
479 | OBRACKET ActionList CBRACKET
480 { $$ = ExprCreateActionList($2.head); }
483 GroupCompatDecl : GROUP Integer EQUALS Expr SEMI
484 { $$ = GroupCompatCreate($2, $4); }
487 ModMapDecl : MODIFIER_MAP Ident OBRACE ExprList CBRACE SEMI
488 { $$ = ModMapCreate($2, $4.head); }
491 LedMapDecl: INDICATOR String OBRACE VarDeclList CBRACE SEMI
492 { $$ = LedMapCreate($2, $4.head); }
495 LedNameDecl: INDICATOR Integer EQUALS Expr SEMI
496 { $$ = LedNameCreate($2, $4, false); }
497 | VIRTUAL INDICATOR Integer EQUALS Expr SEMI
498 { $$ = LedNameCreate($3, $5, true); }
501 ShapeDecl : SHAPE String OBRACE OutlineList CBRACE SEMI
503 | SHAPE String OBRACE CoordList CBRACE SEMI
504 { (void) $4; $$ = NULL; }
507 SectionDecl : SECTION String OBRACE SectionBody CBRACE SEMI
511 SectionBody : SectionBody SectionBodyItem { $$ = NULL;}
512 | SectionBodyItem { $$ = NULL; }
515 SectionBodyItem : ROW OBRACE RowBody CBRACE SEMI
518 { FreeStmt((ParseCommon *) $1); $$ = NULL; }
522 { FreeStmt((ParseCommon *) $1); $$ = NULL; }
527 RowBody : RowBody RowBodyItem { $$ = NULL;}
528 | RowBodyItem { $$ = NULL; }
531 RowBodyItem : KEYS OBRACE Keys CBRACE SEMI { $$ = NULL; }
533 { FreeStmt((ParseCommon *) $1); $$ = NULL; }
536 Keys : Keys COMMA Key { $$ = NULL; }
542 | OBRACE ExprList CBRACE
543 { FreeStmt((ParseCommon *) $2.head); $$ = NULL; }
546 OverlayDecl : OVERLAY String OBRACE OverlayKeyList CBRACE SEMI
550 OverlayKeyList : OverlayKeyList COMMA OverlayKey { $$ = NULL; }
551 | OverlayKey { $$ = NULL; }
554 OverlayKey : KEYNAME EQUALS KEYNAME { $$ = NULL; }
557 OutlineList : OutlineList COMMA OutlineInList
563 OutlineInList : OBRACE CoordList CBRACE
564 { (void) $2; $$ = NULL; }
565 | Ident EQUALS OBRACE CoordList CBRACE
566 { (void) $4; $$ = NULL; }
568 { FreeStmt((ParseCommon *) $3); $$ = NULL; }
571 CoordList : CoordList COMMA Coord
572 { (void) $1; (void) $3; $$ = NULL; }
574 { (void) $1; $$ = NULL; }
577 Coord : OBRACKET SignedNumber COMMA SignedNumber CBRACKET
581 DoodadDecl : DoodadType String OBRACE VarDeclList CBRACE SEMI
582 { FreeStmt((ParseCommon *) $4.head); $$ = NULL; }
585 DoodadType : TEXT { $$ = 0; }
586 | OUTLINE { $$ = 0; }
591 FieldSpec : Ident { $$ = $1; }
592 | Element { $$ = $1; }
596 { $$ = xkb_atom_intern_literal(param->ctx, "action"); }
598 { $$ = xkb_atom_intern_literal(param->ctx, "interpret"); }
600 { $$ = xkb_atom_intern_literal(param->ctx, "type"); }
602 { $$ = xkb_atom_intern_literal(param->ctx, "key"); }
604 { $$ = xkb_atom_intern_literal(param->ctx, "group"); }
606 {$$ = xkb_atom_intern_literal(param->ctx, "modifier_map");}
608 { $$ = xkb_atom_intern_literal(param->ctx, "indicator"); }
610 { $$ = xkb_atom_intern_literal(param->ctx, "shape"); }
612 { $$ = xkb_atom_intern_literal(param->ctx, "row"); }
614 { $$ = xkb_atom_intern_literal(param->ctx, "section"); }
616 { $$ = xkb_atom_intern_literal(param->ctx, "text"); }
619 OptMergeMode : MergeMode { $$ = $1; }
620 | { $$ = MERGE_DEFAULT; }
623 MergeMode : INCLUDE { $$ = MERGE_DEFAULT; }
624 | AUGMENT { $$ = MERGE_AUGMENT; }
625 | OVERRIDE { $$ = MERGE_OVERRIDE; }
626 | REPLACE { $$ = MERGE_REPLACE; }
630 * This used to be MERGE_ALT_FORM. This functionality was
631 * unused and has been removed.
637 OptExprList : ExprList { $$ = $1; }
638 | { $$.head = $$.last = NULL; }
641 ExprList : ExprList COMMA Expr
642 { $$.head = $1.head; $$.last->common.next = &$3->common; $$.last = $3; }
644 { $$.head = $$.last = $1; }
647 Expr : Expr DIVIDE Expr
648 { $$ = ExprCreateBinary(EXPR_DIVIDE, $1, $3); }
650 { $$ = ExprCreateBinary(EXPR_ADD, $1, $3); }
652 { $$ = ExprCreateBinary(EXPR_SUBTRACT, $1, $3); }
654 { $$ = ExprCreateBinary(EXPR_MULTIPLY, $1, $3); }
656 { $$ = ExprCreateBinary(EXPR_ASSIGN, $1, $3); }
662 { $$ = ExprCreateUnary(EXPR_NEGATE, $2->expr.value_type, $2); }
664 { $$ = ExprCreateUnary(EXPR_UNARY_PLUS, $2->expr.value_type, $2); }
666 { $$ = ExprCreateUnary(EXPR_NOT, EXPR_TYPE_BOOLEAN, $2); }
668 { $$ = ExprCreateUnary(EXPR_INVERT, $2->expr.value_type, $2); }
671 | FieldSpec OPAREN OptExprList CPAREN %prec OPAREN
672 { $$ = ExprCreateAction($1, $3.head); }
679 ActionList : ActionList COMMA Action
680 { $$.head = $1.head; $$.last->common.next = &$3->common; $$.last = $3; }
682 { $$.head = $$.last = $1; }
685 Action : FieldSpec OPAREN OptExprList CPAREN
686 { $$ = ExprCreateAction($1, $3.head); }
690 { $$ = ExprCreateIdent($1); }
691 | FieldSpec DOT FieldSpec
692 { $$ = ExprCreateFieldRef($1, $3); }
693 | FieldSpec OBRACKET Expr CBRACKET
694 { $$ = ExprCreateArrayRef(XKB_ATOM_NONE, $1, $3); }
695 | FieldSpec DOT FieldSpec OBRACKET Expr CBRACKET
696 { $$ = ExprCreateArrayRef($1, $3, $5); }
700 { $$ = ExprCreateString($1); }
702 { $$ = ExprCreateInteger($1); }
704 { $$ = ExprCreateFloat(/* Discard $1 */); }
706 { $$ = ExprCreateKeyName($1); }
709 OptKeySymList : KeySymList { $$ = $1; }
713 KeySymList : KeySymList COMMA KeySym
714 { $$ = ExprAppendKeysymList($1, $3); }
715 | KeySymList COMMA KeySyms
716 { $$ = ExprAppendMultiKeysymList($1, $3); }
718 { $$ = ExprCreateKeysymList($1); }
720 { $$ = ExprCreateMultiKeysymList($1); }
723 KeySyms : OBRACE KeySymList CBRACE
729 if (!resolve_keysym($1, &$$)) {
730 parser_warn(param, "unrecognized keysym \"%s\"", $1);
731 $$ = XKB_KEY_NoSymbol;
735 | SECTION { $$ = XKB_KEY_section; }
739 parser_warn(param, "unrecognized keysym \"%"PRId64"\"", $1);
740 $$ = XKB_KEY_NoSymbol;
742 else if ($1 < 10) { /* XKB_KEY_0 .. XKB_KEY_9 */
743 $$ = XKB_KEY_0 + (xkb_keysym_t) $1;
747 snprintf(buf, sizeof(buf), "0x%"PRIx64, $1);
748 if (!resolve_keysym(buf, &$$)) {
749 parser_warn(param, "unrecognized keysym \"%s\"", buf);
750 $$ = XKB_KEY_NoSymbol;
756 SignedNumber : MINUS Number { $$ = -$2; }
757 | Number { $$ = $1; }
760 Number : FLOAT { $$ = $1; }
761 | INTEGER { $$ = $1; }
764 Float : FLOAT { $$ = 0; }
767 Integer : INTEGER { $$ = $1; }
770 KeyCode : INTEGER { $$ = $1; }
773 Ident : IDENT { $$ = xkb_atom_intern(param->ctx, $1, strlen($1)); free($1); }
774 | DEFAULT { $$ = xkb_atom_intern_literal(param->ctx, "default"); }
777 String : STRING { $$ = xkb_atom_intern(param->ctx, $1, strlen($1)); free($1); }
780 OptMapName : MapName { $$ = $1; }
784 MapName : STRING { $$ = $1; }
790 parse(struct xkb_context *ctx, struct scanner *scanner, const char *map)
793 XkbFile *first = NULL;
794 struct parser_param param = {
802 * If we got a specific map, we look for it exclusively and return
803 * immediately upon finding it. Otherwise, we need to get the
804 * default map. If we find a map marked as default, we return it
805 * immediately. If there are no maps marked as default, we return
806 * the first map in the file.
809 while ((ret = yyparse(¶m)) == 0 && param.more_maps) {
811 if (streq_not_null(map, param.rtrn->name))
814 FreeXkbFile(param.rtrn);
817 if (param.rtrn->flags & MAP_IS_DEFAULT) {
825 FreeXkbFile(param.rtrn);
838 "No map in include statement, but \"%s\" contains several; "
839 "Using first defined map, \"%s\"\n",
840 scanner->file_name, first->name);