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
34 #include "xkbcomp-priv.h"
35 #include "ast-build.h"
36 #include "parser-priv.h"
39 struct xkb_context *ctx;
40 struct scanner *scanner;
45 #define parser_err(param, fmt, ...) \
46 scanner_err((param)->scanner, fmt, ##__VA_ARGS__)
48 #define parser_warn(param, fmt, ...) \
49 scanner_warn((param)->scanner, fmt, ##__VA_ARGS__)
52 _xkbcommon_error(struct parser_param *param, const char *msg)
54 parser_err(param, "%s", msg);
58 resolve_keysym(const char *str, xkb_keysym_t *sym_rtrn)
62 if (!str || istreq(str, "any") || istreq(str, "nosymbol")) {
63 *sym_rtrn = XKB_KEY_NoSymbol;
67 if (istreq(str, "none") || istreq(str, "voidsymbol")) {
68 *sym_rtrn = XKB_KEY_VoidSymbol;
72 sym = xkb_keysym_from_name(str, XKB_KEYSYM_NO_FLAGS);
73 if (sym != XKB_KEY_NoSymbol) {
81 #define param_scanner param->scanner
85 %lex-param { struct scanner *param_scanner }
86 %parse-param { struct parser_param *param }
164 enum xkb_file_type file_type;
167 enum merge_mode merge;
168 enum xkb_map_flags mapFlags;
178 GroupCompatDef *groupCompat;
182 KeyAliasDef *keyAlias;
187 %type <num> INTEGER FLOAT
188 %type <str> IDENT STRING
191 %type <ival> Number Integer Float SignedNumber DoodadType
192 %type <merge> MergeMode OptMergeMode
193 %type <file_type> XkbCompositeType FileType
194 %type <mapFlags> Flag Flags OptFlags
195 %type <str> MapName OptMapName
196 %type <sval> FieldSpec Ident Element String
197 %type <keysym> KeySym
198 %type <any> DeclList Decl
199 %type <expr> OptExprList ExprList Expr Term Lhs Terminal ArrayInit KeySyms
200 %type <expr> OptKeySymList KeySymList Action ActionList Coord CoordList
201 %type <var> VarDecl VarDeclList SymbolsBody SymbolsVarDecl
202 %type <vmod> VModDecl VModDefList VModDef
203 %type <interp> InterpretDecl InterpretMatch
204 %type <keyType> KeyTypeDecl
205 %type <syms> SymbolsDecl
206 %type <modMask> ModMapDecl
207 %type <groupCompat> GroupCompatDecl
208 %type <ledMap> LedMapDecl
209 %type <ledName> LedNameDecl
210 %type <keyCode> KeyNameDecl
211 %type <keyAlias> KeyAliasDecl
212 %type <geom> ShapeDecl SectionDecl SectionBody SectionBodyItem RowBody RowBodyItem
213 %type <geom> Keys Key OverlayDecl OverlayKeyList OverlayKey OutlineList OutlineInList
214 %type <geom> DoodadDecl
215 %type <file> XkbFile XkbMapConfigList XkbMapConfig
216 %type <file> XkbCompositeMap
221 * An actual file may contain more than one map. However, if we do things
222 * in the normal yacc way, i.e. aggregate all of the maps into a list and
223 * let the caller find the map it wants, we end up scanning and parsing a
224 * lot of unneeded maps (in the end we always just need one).
225 * Instead of doing that, we make yyparse return one map at a time, and
226 * then call it repeatedly until we find the map we need. Once we find it,
227 * we don't need to parse everything that follows in the file.
228 * This does mean that if we e.g. always use the first map, the file may
229 * contain complete garbage after that. But it's worth it.
232 XkbFile : XkbCompositeMap
233 { $$ = param->rtrn = $1; param->more_maps = true; }
235 { $$ = param->rtrn = $1; param->more_maps = true; YYACCEPT; }
237 { $$ = param->rtrn = NULL; param->more_maps = false; }
240 XkbCompositeMap : OptFlags XkbCompositeType OptMapName OBRACE
243 { $$ = XkbFileCreate($2, $3, (ParseCommon *) $5, $1); }
246 XkbCompositeType: XKB_KEYMAP { $$ = FILE_TYPE_KEYMAP; }
247 | XKB_SEMANTICS { $$ = FILE_TYPE_KEYMAP; }
248 | XKB_LAYOUT { $$ = FILE_TYPE_KEYMAP; }
251 XkbMapConfigList : XkbMapConfigList XkbMapConfig
256 $$ = (XkbFile *) AppendStmt((ParseCommon *) $1,
263 XkbMapConfig : OptFlags FileType OptMapName OBRACE
267 if ($2 == FILE_TYPE_GEOMETRY) {
273 $$ = XkbFileCreate($2, $3, $5, $1);
278 FileType : XKB_KEYCODES { $$ = FILE_TYPE_KEYCODES; }
279 | XKB_TYPES { $$ = FILE_TYPE_TYPES; }
280 | XKB_COMPATMAP { $$ = FILE_TYPE_COMPAT; }
281 | XKB_SYMBOLS { $$ = FILE_TYPE_SYMBOLS; }
282 | XKB_GEOMETRY { $$ = FILE_TYPE_GEOMETRY; }
285 OptFlags : Flags { $$ = $1; }
289 Flags : Flags Flag { $$ = ($1 | $2); }
293 Flag : PARTIAL { $$ = MAP_IS_PARTIAL; }
294 | DEFAULT { $$ = MAP_IS_DEFAULT; }
295 | HIDDEN { $$ = MAP_IS_HIDDEN; }
296 | ALPHANUMERIC_KEYS { $$ = MAP_HAS_ALPHANUMERIC; }
297 | MODIFIER_KEYS { $$ = MAP_HAS_MODIFIER; }
298 | KEYPAD_KEYS { $$ = MAP_HAS_KEYPAD; }
299 | FUNCTION_KEYS { $$ = MAP_HAS_FN; }
300 | ALTERNATE_GROUP { $$ = MAP_IS_ALTGR; }
303 DeclList : DeclList Decl
304 { $$ = AppendStmt($1, $2); }
308 Decl : OptMergeMode VarDecl
311 $$ = (ParseCommon *) $2;
313 | OptMergeMode VModDecl
316 $$ = (ParseCommon *) $2;
318 | OptMergeMode InterpretDecl
321 $$ = (ParseCommon *) $2;
323 | OptMergeMode KeyNameDecl
326 $$ = (ParseCommon *) $2;
328 | OptMergeMode KeyAliasDecl
331 $$ = (ParseCommon *) $2;
333 | OptMergeMode KeyTypeDecl
336 $$ = (ParseCommon *) $2;
338 | OptMergeMode SymbolsDecl
341 $$ = (ParseCommon *) $2;
343 | OptMergeMode ModMapDecl
346 $$ = (ParseCommon *) $2;
348 | OptMergeMode GroupCompatDecl
351 $$ = (ParseCommon *) $2;
353 | OptMergeMode LedMapDecl
356 $$ = (ParseCommon *) $2;
358 | OptMergeMode LedNameDecl
361 $$ = (ParseCommon *) $2;
363 | OptMergeMode ShapeDecl { $$ = NULL; }
364 | OptMergeMode SectionDecl { $$ = NULL; }
365 | OptMergeMode DoodadDecl { $$ = NULL; }
368 $$ = (ParseCommon *) IncludeCreate(param->ctx, $2, $1);
373 VarDecl : Lhs EQUALS Expr SEMI
374 { $$ = VarCreate($1, $3); }
376 { $$ = BoolVarCreate($1, true); }
378 { $$ = BoolVarCreate($2, false); }
381 KeyNameDecl : KEYNAME EQUALS KeyCode SEMI
382 { $$ = KeycodeCreate($1, $3); }
385 KeyAliasDecl : ALIAS KEYNAME EQUALS KEYNAME SEMI
386 { $$ = KeyAliasCreate($2, $4); }
389 VModDecl : VIRTUAL_MODS VModDefList SEMI
393 VModDefList : VModDefList COMMA VModDef
394 { $$ = (VModDef *) AppendStmt((ParseCommon *) $1,
395 (ParseCommon *) $3); }
401 { $$ = VModCreate($1, NULL); }
403 { $$ = VModCreate($1, $3); }
406 InterpretDecl : INTERPRET InterpretMatch OBRACE
409 { $2->def = $4; $$ = $2; }
412 InterpretMatch : KeySym PLUS Expr
413 { $$ = InterpCreate($1, $3); }
415 { $$ = InterpCreate($1, NULL); }
418 VarDeclList : VarDeclList VarDecl
419 { $$ = (VarDef *) AppendStmt((ParseCommon *) $1,
420 (ParseCommon *) $2); }
425 KeyTypeDecl : TYPE String OBRACE
428 { $$ = KeyTypeCreate($2, $4); }
431 SymbolsDecl : KEY KEYNAME OBRACE
434 { $$ = SymbolsCreate($2, $4); }
437 SymbolsBody : SymbolsBody COMMA SymbolsVarDecl
438 { $$ = (VarDef *) AppendStmt((ParseCommon *) $1,
439 (ParseCommon *) $3); }
445 SymbolsVarDecl : Lhs EQUALS Expr { $$ = VarCreate($1, $3); }
446 | Lhs EQUALS ArrayInit { $$ = VarCreate($1, $3); }
447 | Ident { $$ = BoolVarCreate($1, true); }
448 | EXCLAM Ident { $$ = BoolVarCreate($2, false); }
449 | ArrayInit { $$ = VarCreate(NULL, $1); }
452 ArrayInit : OBRACKET OptKeySymList CBRACKET
454 | OBRACKET ActionList CBRACKET
455 { $$ = ExprCreateUnary(EXPR_ACTION_LIST, EXPR_TYPE_ACTION, $2); }
458 GroupCompatDecl : GROUP Integer EQUALS Expr SEMI
459 { $$ = GroupCompatCreate($2, $4); }
462 ModMapDecl : MODIFIER_MAP Ident OBRACE ExprList CBRACE SEMI
463 { $$ = ModMapCreate($2, $4); }
466 LedMapDecl: INDICATOR String OBRACE VarDeclList CBRACE SEMI
467 { $$ = LedMapCreate($2, $4); }
470 LedNameDecl: INDICATOR Integer EQUALS Expr SEMI
471 { $$ = LedNameCreate($2, $4, false); }
472 | VIRTUAL INDICATOR Integer EQUALS Expr SEMI
473 { $$ = LedNameCreate($3, $5, true); }
476 ShapeDecl : SHAPE String OBRACE OutlineList CBRACE SEMI
478 | SHAPE String OBRACE CoordList CBRACE SEMI
482 SectionDecl : SECTION String OBRACE SectionBody CBRACE SEMI
486 SectionBody : SectionBody SectionBodyItem { $$ = NULL;}
487 | SectionBodyItem { $$ = NULL; }
490 SectionBodyItem : ROW OBRACE RowBody CBRACE SEMI
493 { FreeStmt((ParseCommon *) $1); $$ = NULL; }
497 { FreeStmt((ParseCommon *) $1); $$ = NULL; }
502 RowBody : RowBody RowBodyItem { $$ = NULL;}
503 | RowBodyItem { $$ = NULL; }
506 RowBodyItem : KEYS OBRACE Keys CBRACE SEMI { $$ = NULL; }
508 { FreeStmt((ParseCommon *) $1); $$ = NULL; }
511 Keys : Keys COMMA Key { $$ = NULL; }
517 | OBRACE ExprList CBRACE
518 { FreeStmt((ParseCommon *) $2); $$ = NULL; }
521 OverlayDecl : OVERLAY String OBRACE OverlayKeyList CBRACE SEMI
525 OverlayKeyList : OverlayKeyList COMMA OverlayKey { $$ = NULL; }
526 | OverlayKey { $$ = NULL; }
529 OverlayKey : KEYNAME EQUALS KEYNAME { $$ = NULL; }
532 OutlineList : OutlineList COMMA OutlineInList
538 OutlineInList : OBRACE CoordList CBRACE
540 | Ident EQUALS OBRACE CoordList CBRACE
543 { FreeStmt((ParseCommon *) $3); $$ = NULL; }
546 CoordList : CoordList COMMA Coord
552 Coord : OBRACKET SignedNumber COMMA SignedNumber CBRACKET
556 DoodadDecl : DoodadType String OBRACE VarDeclList CBRACE SEMI
557 { FreeStmt((ParseCommon *) $4); $$ = NULL; }
560 DoodadType : TEXT { $$ = 0; }
561 | OUTLINE { $$ = 0; }
566 FieldSpec : Ident { $$ = $1; }
567 | Element { $$ = $1; }
571 { $$ = xkb_atom_intern_literal(param->ctx, "action"); }
573 { $$ = xkb_atom_intern_literal(param->ctx, "interpret"); }
575 { $$ = xkb_atom_intern_literal(param->ctx, "type"); }
577 { $$ = xkb_atom_intern_literal(param->ctx, "key"); }
579 { $$ = xkb_atom_intern_literal(param->ctx, "group"); }
581 {$$ = xkb_atom_intern_literal(param->ctx, "modifier_map");}
583 { $$ = xkb_atom_intern_literal(param->ctx, "indicator"); }
585 { $$ = XKB_ATOM_NONE; }
587 { $$ = XKB_ATOM_NONE; }
589 { $$ = XKB_ATOM_NONE; }
591 { $$ = XKB_ATOM_NONE; }
594 OptMergeMode : MergeMode { $$ = $1; }
595 | { $$ = MERGE_DEFAULT; }
598 MergeMode : INCLUDE { $$ = MERGE_DEFAULT; }
599 | AUGMENT { $$ = MERGE_AUGMENT; }
600 | OVERRIDE { $$ = MERGE_OVERRIDE; }
601 | REPLACE { $$ = MERGE_REPLACE; }
605 * This used to be MERGE_ALT_FORM. This functionality was
606 * unused and has been removed.
612 OptExprList : ExprList { $$ = $1; }
616 ExprList : ExprList COMMA Expr
617 { $$ = (ExprDef *) AppendStmt((ParseCommon *) $1,
618 (ParseCommon *) $3); }
623 Expr : Expr DIVIDE Expr
624 { $$ = ExprCreateBinary(EXPR_DIVIDE, $1, $3); }
626 { $$ = ExprCreateBinary(EXPR_ADD, $1, $3); }
628 { $$ = ExprCreateBinary(EXPR_SUBTRACT, $1, $3); }
630 { $$ = ExprCreateBinary(EXPR_MULTIPLY, $1, $3); }
632 { $$ = ExprCreateBinary(EXPR_ASSIGN, $1, $3); }
638 { $$ = ExprCreateUnary(EXPR_NEGATE, $2->expr.value_type, $2); }
640 { $$ = ExprCreateUnary(EXPR_UNARY_PLUS, $2->expr.value_type, $2); }
642 { $$ = ExprCreateUnary(EXPR_NOT, EXPR_TYPE_BOOLEAN, $2); }
644 { $$ = ExprCreateUnary(EXPR_INVERT, $2->expr.value_type, $2); }
647 | FieldSpec OPAREN OptExprList CPAREN %prec OPAREN
648 { $$ = ExprCreateAction($1, $3); }
655 ActionList : ActionList COMMA Action
656 { $$ = (ExprDef *) AppendStmt((ParseCommon *) $1,
657 (ParseCommon *) $3); }
662 Action : FieldSpec OPAREN OptExprList CPAREN
663 { $$ = ExprCreateAction($1, $3); }
667 { $$ = ExprCreateIdent($1); }
668 | FieldSpec DOT FieldSpec
669 { $$ = ExprCreateFieldRef($1, $3); }
670 | FieldSpec OBRACKET Expr CBRACKET
671 { $$ = ExprCreateArrayRef(XKB_ATOM_NONE, $1, $3); }
672 | FieldSpec DOT FieldSpec OBRACKET Expr CBRACKET
673 { $$ = ExprCreateArrayRef($1, $3, $5); }
677 { $$ = ExprCreateString($1); }
679 { $$ = ExprCreateInteger($1); }
683 { $$ = ExprCreateKeyName($1); }
686 OptKeySymList : KeySymList { $$ = $1; }
690 KeySymList : KeySymList COMMA KeySym
691 { $$ = ExprAppendKeysymList($1, $3); }
692 | KeySymList COMMA KeySyms
693 { $$ = ExprAppendMultiKeysymList($1, $3); }
695 { $$ = ExprCreateKeysymList($1); }
697 { $$ = ExprCreateMultiKeysymList($1); }
700 KeySyms : OBRACE KeySymList CBRACE
706 if (!resolve_keysym($1, &$$))
707 parser_warn(param, "unrecognized keysym");
710 | SECTION { $$ = XKB_KEY_section; }
714 parser_warn(param, "unrecognized keysym");
715 $$ = XKB_KEY_NoSymbol;
717 else if ($1 < 10) { /* XKB_KEY_0 .. XKB_KEY_9 */
718 $$ = XKB_KEY_0 + (xkb_keysym_t) $1;
722 snprintf(buf, sizeof(buf), "0x%x", $1);
723 if (!resolve_keysym(buf, &$$)) {
724 parser_warn(param, "unrecognized keysym");
725 $$ = XKB_KEY_NoSymbol;
731 SignedNumber : MINUS Number { $$ = -$2; }
732 | Number { $$ = $1; }
735 Number : FLOAT { $$ = $1; }
736 | INTEGER { $$ = $1; }
739 Float : FLOAT { $$ = 0; }
742 Integer : INTEGER { $$ = $1; }
745 KeyCode : INTEGER { $$ = $1; }
748 Ident : IDENT { $$ = xkb_atom_steal(param->ctx, $1); }
749 | DEFAULT { $$ = xkb_atom_intern_literal(param->ctx, "default"); }
752 String : STRING { $$ = xkb_atom_steal(param->ctx, $1); }
755 OptMapName : MapName { $$ = $1; }
759 MapName : STRING { $$ = $1; }
765 parse(struct xkb_context *ctx, struct scanner *scanner, const char *map)
768 XkbFile *first = NULL;
769 struct parser_param param = {
775 * If we got a specific map, we look for it exclusively and return
776 * immediately upon finding it. Otherwise, we need to get the
777 * default map. If we find a map marked as default, we return it
778 * immediately. If there are no maps marked as default, we return
779 * the first map in the file.
782 while ((ret = yyparse(¶m)) == 0 && param.more_maps) {
784 if (streq_not_null(map, param.rtrn->name))
787 FreeXkbFile(param.rtrn);
790 if (param.rtrn->flags & MAP_IS_DEFAULT) {
798 FreeXkbFile(param.rtrn);