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"
37 #include "scanner-utils.h"
40 struct xkb_context *ctx;
41 struct scanner *scanner;
46 #define parser_err(param, fmt, ...) \
47 scanner_err((param)->scanner, fmt, ##__VA_ARGS__)
49 #define parser_warn(param, fmt, ...) \
50 scanner_warn((param)->scanner, fmt, ##__VA_ARGS__)
53 _xkbcommon_error(struct parser_param *param, const char *msg)
55 parser_err(param, "%s", msg);
59 resolve_keysym(const char *name, xkb_keysym_t *sym_rtrn)
63 if (!name || istreq(name, "any") || istreq(name, "nosymbol")) {
64 *sym_rtrn = XKB_KEY_NoSymbol;
68 if (istreq(name, "none") || istreq(name, "voidsymbol")) {
69 *sym_rtrn = XKB_KEY_VoidSymbol;
73 sym = xkb_keysym_from_name(name, XKB_KEYSYM_NO_FLAGS);
74 if (sym != XKB_KEY_NoSymbol) {
82 #define param_scanner param->scanner
86 %lex-param { struct scanner *param_scanner }
87 %parse-param { struct parser_param *param }
165 enum xkb_file_type file_type;
168 enum merge_mode merge;
169 enum xkb_map_flags mapFlags;
179 GroupCompatDef *groupCompat;
183 KeyAliasDef *keyAlias;
188 %type <num> INTEGER FLOAT
189 %type <str> IDENT STRING
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 <sval> 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
222 * An actual file may contain more than one map. However, if we do things
223 * in the normal yacc way, i.e. aggregate all of the maps into a list and
224 * let the caller find the map it wants, we end up scanning and parsing a
225 * lot of unneeded maps (in the end we always just need one).
226 * Instead of doing that, we make yyparse return one map at a time, and
227 * then call it repeatedly until we find the map we need. Once we find it,
228 * we don't need to parse everything that follows in the file.
229 * This does mean that if we e.g. always use the first map, the file may
230 * contain complete garbage after that. But it's worth it.
233 XkbFile : XkbCompositeMap
234 { $$ = param->rtrn = $1; param->more_maps = true; }
236 { $$ = param->rtrn = $1; param->more_maps = true; YYACCEPT; }
238 { $$ = param->rtrn = NULL; param->more_maps = false; }
241 XkbCompositeMap : OptFlags XkbCompositeType OptMapName OBRACE
244 { $$ = XkbFileCreate($2, $3, (ParseCommon *) $5, $1); }
247 XkbCompositeType: XKB_KEYMAP { $$ = FILE_TYPE_KEYMAP; }
248 | XKB_SEMANTICS { $$ = FILE_TYPE_KEYMAP; }
249 | XKB_LAYOUT { $$ = FILE_TYPE_KEYMAP; }
252 XkbMapConfigList : XkbMapConfigList XkbMapConfig
257 $$ = (XkbFile *) AppendStmt((ParseCommon *) $1,
264 XkbMapConfig : OptFlags FileType OptMapName OBRACE
268 if ($2 == FILE_TYPE_GEOMETRY) {
274 $$ = XkbFileCreate($2, $3, $5, $1);
279 FileType : XKB_KEYCODES { $$ = FILE_TYPE_KEYCODES; }
280 | XKB_TYPES { $$ = FILE_TYPE_TYPES; }
281 | XKB_COMPATMAP { $$ = FILE_TYPE_COMPAT; }
282 | XKB_SYMBOLS { $$ = FILE_TYPE_SYMBOLS; }
283 | XKB_GEOMETRY { $$ = FILE_TYPE_GEOMETRY; }
286 OptFlags : Flags { $$ = $1; }
290 Flags : Flags Flag { $$ = ($1 | $2); }
294 Flag : PARTIAL { $$ = MAP_IS_PARTIAL; }
295 | DEFAULT { $$ = MAP_IS_DEFAULT; }
296 | HIDDEN { $$ = MAP_IS_HIDDEN; }
297 | ALPHANUMERIC_KEYS { $$ = MAP_HAS_ALPHANUMERIC; }
298 | MODIFIER_KEYS { $$ = MAP_HAS_MODIFIER; }
299 | KEYPAD_KEYS { $$ = MAP_HAS_KEYPAD; }
300 | FUNCTION_KEYS { $$ = MAP_HAS_FN; }
301 | ALTERNATE_GROUP { $$ = MAP_IS_ALTGR; }
304 DeclList : DeclList Decl
305 { $$ = AppendStmt($1, $2); }
309 Decl : OptMergeMode VarDecl
312 $$ = (ParseCommon *) $2;
314 | OptMergeMode VModDecl
317 $$ = (ParseCommon *) $2;
319 | OptMergeMode InterpretDecl
322 $$ = (ParseCommon *) $2;
324 | OptMergeMode KeyNameDecl
327 $$ = (ParseCommon *) $2;
329 | OptMergeMode KeyAliasDecl
332 $$ = (ParseCommon *) $2;
334 | OptMergeMode KeyTypeDecl
337 $$ = (ParseCommon *) $2;
339 | OptMergeMode SymbolsDecl
342 $$ = (ParseCommon *) $2;
344 | OptMergeMode ModMapDecl
347 $$ = (ParseCommon *) $2;
349 | OptMergeMode GroupCompatDecl
352 $$ = (ParseCommon *) $2;
354 | OptMergeMode LedMapDecl
357 $$ = (ParseCommon *) $2;
359 | OptMergeMode LedNameDecl
362 $$ = (ParseCommon *) $2;
364 | OptMergeMode ShapeDecl { $$ = NULL; }
365 | OptMergeMode SectionDecl { $$ = NULL; }
366 | OptMergeMode DoodadDecl { $$ = NULL; }
369 $$ = (ParseCommon *) IncludeCreate(param->ctx, $2, $1);
374 VarDecl : Lhs EQUALS Expr SEMI
375 { $$ = VarCreate($1, $3); }
377 { $$ = BoolVarCreate($1, true); }
379 { $$ = BoolVarCreate($2, false); }
382 KeyNameDecl : KEYNAME EQUALS KeyCode SEMI
383 { $$ = KeycodeCreate($1, $3); }
386 KeyAliasDecl : ALIAS KEYNAME EQUALS KEYNAME SEMI
387 { $$ = KeyAliasCreate($2, $4); }
390 VModDecl : VIRTUAL_MODS VModDefList SEMI
394 VModDefList : VModDefList COMMA VModDef
395 { $$ = (VModDef *) AppendStmt((ParseCommon *) $1,
396 (ParseCommon *) $3); }
402 { $$ = VModCreate($1, NULL); }
404 { $$ = VModCreate($1, $3); }
407 InterpretDecl : INTERPRET InterpretMatch OBRACE
410 { $2->def = $4; $$ = $2; }
413 InterpretMatch : KeySym PLUS Expr
414 { $$ = InterpCreate($1, $3); }
416 { $$ = InterpCreate($1, NULL); }
419 VarDeclList : VarDeclList VarDecl
420 { $$ = (VarDef *) AppendStmt((ParseCommon *) $1,
421 (ParseCommon *) $2); }
426 KeyTypeDecl : TYPE String OBRACE
429 { $$ = KeyTypeCreate($2, $4); }
432 SymbolsDecl : KEY KEYNAME OBRACE
435 { $$ = SymbolsCreate($2, $4); }
438 SymbolsBody : SymbolsBody COMMA SymbolsVarDecl
439 { $$ = (VarDef *) AppendStmt((ParseCommon *) $1,
440 (ParseCommon *) $3); }
446 SymbolsVarDecl : Lhs EQUALS Expr { $$ = VarCreate($1, $3); }
447 | Lhs EQUALS ArrayInit { $$ = VarCreate($1, $3); }
448 | Ident { $$ = BoolVarCreate($1, true); }
449 | EXCLAM Ident { $$ = BoolVarCreate($2, false); }
450 | ArrayInit { $$ = VarCreate(NULL, $1); }
453 ArrayInit : OBRACKET OptKeySymList CBRACKET
455 | OBRACKET ActionList CBRACKET
456 { $$ = ExprCreateUnary(EXPR_ACTION_LIST, EXPR_TYPE_ACTION, $2); }
459 GroupCompatDecl : GROUP Integer EQUALS Expr SEMI
460 { $$ = GroupCompatCreate($2, $4); }
463 ModMapDecl : MODIFIER_MAP Ident OBRACE ExprList CBRACE SEMI
464 { $$ = ModMapCreate($2, $4); }
467 LedMapDecl: INDICATOR String OBRACE VarDeclList CBRACE SEMI
468 { $$ = LedMapCreate($2, $4); }
471 LedNameDecl: INDICATOR Integer EQUALS Expr SEMI
472 { $$ = LedNameCreate($2, $4, false); }
473 | VIRTUAL INDICATOR Integer EQUALS Expr SEMI
474 { $$ = LedNameCreate($3, $5, true); }
477 ShapeDecl : SHAPE String OBRACE OutlineList CBRACE SEMI
479 | SHAPE String OBRACE CoordList CBRACE SEMI
483 SectionDecl : SECTION String OBRACE SectionBody CBRACE SEMI
487 SectionBody : SectionBody SectionBodyItem { $$ = NULL;}
488 | SectionBodyItem { $$ = NULL; }
491 SectionBodyItem : ROW OBRACE RowBody CBRACE SEMI
494 { FreeStmt((ParseCommon *) $1); $$ = NULL; }
498 { FreeStmt((ParseCommon *) $1); $$ = NULL; }
503 RowBody : RowBody RowBodyItem { $$ = NULL;}
504 | RowBodyItem { $$ = NULL; }
507 RowBodyItem : KEYS OBRACE Keys CBRACE SEMI { $$ = NULL; }
509 { FreeStmt((ParseCommon *) $1); $$ = NULL; }
512 Keys : Keys COMMA Key { $$ = NULL; }
518 | OBRACE ExprList CBRACE
519 { FreeStmt((ParseCommon *) $2); $$ = NULL; }
522 OverlayDecl : OVERLAY String OBRACE OverlayKeyList CBRACE SEMI
526 OverlayKeyList : OverlayKeyList COMMA OverlayKey { $$ = NULL; }
527 | OverlayKey { $$ = NULL; }
530 OverlayKey : KEYNAME EQUALS KEYNAME { $$ = NULL; }
533 OutlineList : OutlineList COMMA OutlineInList
539 OutlineInList : OBRACE CoordList CBRACE
541 | Ident EQUALS OBRACE CoordList CBRACE
544 { FreeStmt((ParseCommon *) $3); $$ = NULL; }
547 CoordList : CoordList COMMA Coord
553 Coord : OBRACKET SignedNumber COMMA SignedNumber CBRACKET
557 DoodadDecl : DoodadType String OBRACE VarDeclList CBRACE SEMI
558 { FreeStmt((ParseCommon *) $4); $$ = NULL; }
561 DoodadType : TEXT { $$ = 0; }
562 | OUTLINE { $$ = 0; }
567 FieldSpec : Ident { $$ = $1; }
568 | Element { $$ = $1; }
572 { $$ = xkb_atom_intern_literal(param->ctx, "action"); }
574 { $$ = xkb_atom_intern_literal(param->ctx, "interpret"); }
576 { $$ = xkb_atom_intern_literal(param->ctx, "type"); }
578 { $$ = xkb_atom_intern_literal(param->ctx, "key"); }
580 { $$ = xkb_atom_intern_literal(param->ctx, "group"); }
582 {$$ = xkb_atom_intern_literal(param->ctx, "modifier_map");}
584 { $$ = xkb_atom_intern_literal(param->ctx, "indicator"); }
586 { $$ = XKB_ATOM_NONE; }
588 { $$ = XKB_ATOM_NONE; }
590 { $$ = XKB_ATOM_NONE; }
592 { $$ = XKB_ATOM_NONE; }
595 OptMergeMode : MergeMode { $$ = $1; }
596 | { $$ = MERGE_DEFAULT; }
599 MergeMode : INCLUDE { $$ = MERGE_DEFAULT; }
600 | AUGMENT { $$ = MERGE_AUGMENT; }
601 | OVERRIDE { $$ = MERGE_OVERRIDE; }
602 | REPLACE { $$ = MERGE_REPLACE; }
606 * This used to be MERGE_ALT_FORM. This functionality was
607 * unused and has been removed.
613 OptExprList : ExprList { $$ = $1; }
617 ExprList : ExprList COMMA Expr
618 { $$ = (ExprDef *) AppendStmt((ParseCommon *) $1,
619 (ParseCommon *) $3); }
624 Expr : Expr DIVIDE Expr
625 { $$ = ExprCreateBinary(EXPR_DIVIDE, $1, $3); }
627 { $$ = ExprCreateBinary(EXPR_ADD, $1, $3); }
629 { $$ = ExprCreateBinary(EXPR_SUBTRACT, $1, $3); }
631 { $$ = ExprCreateBinary(EXPR_MULTIPLY, $1, $3); }
633 { $$ = ExprCreateBinary(EXPR_ASSIGN, $1, $3); }
639 { $$ = ExprCreateUnary(EXPR_NEGATE, $2->expr.value_type, $2); }
641 { $$ = ExprCreateUnary(EXPR_UNARY_PLUS, $2->expr.value_type, $2); }
643 { $$ = ExprCreateUnary(EXPR_NOT, EXPR_TYPE_BOOLEAN, $2); }
645 { $$ = ExprCreateUnary(EXPR_INVERT, $2->expr.value_type, $2); }
648 | FieldSpec OPAREN OptExprList CPAREN %prec OPAREN
649 { $$ = ExprCreateAction($1, $3); }
656 ActionList : ActionList COMMA Action
657 { $$ = (ExprDef *) AppendStmt((ParseCommon *) $1,
658 (ParseCommon *) $3); }
663 Action : FieldSpec OPAREN OptExprList CPAREN
664 { $$ = ExprCreateAction($1, $3); }
668 { $$ = ExprCreateIdent($1); }
669 | FieldSpec DOT FieldSpec
670 { $$ = ExprCreateFieldRef($1, $3); }
671 | FieldSpec OBRACKET Expr CBRACKET
672 { $$ = ExprCreateArrayRef(XKB_ATOM_NONE, $1, $3); }
673 | FieldSpec DOT FieldSpec OBRACKET Expr CBRACKET
674 { $$ = ExprCreateArrayRef($1, $3, $5); }
678 { $$ = ExprCreateString($1); }
680 { $$ = ExprCreateInteger($1); }
684 { $$ = ExprCreateKeyName($1); }
687 OptKeySymList : KeySymList { $$ = $1; }
691 KeySymList : KeySymList COMMA KeySym
692 { $$ = ExprAppendKeysymList($1, $3); }
693 | KeySymList COMMA KeySyms
694 { $$ = ExprAppendMultiKeysymList($1, $3); }
696 { $$ = ExprCreateKeysymList($1); }
698 { $$ = ExprCreateMultiKeysymList($1); }
701 KeySyms : OBRACE KeySymList CBRACE
707 if (!resolve_keysym($1, &$$))
708 parser_warn(param, "unrecognized keysym \"%s\"", $1);
711 | SECTION { $$ = XKB_KEY_section; }
715 parser_warn(param, "unrecognized keysym \"%d\"", $1);
716 $$ = XKB_KEY_NoSymbol;
718 else if ($1 < 10) { /* XKB_KEY_0 .. XKB_KEY_9 */
719 $$ = XKB_KEY_0 + (xkb_keysym_t) $1;
723 snprintf(buf, sizeof(buf), "0x%x", $1);
724 if (!resolve_keysym(buf, &$$)) {
725 parser_warn(param, "unrecognized keysym \"%s\"", buf);
726 $$ = XKB_KEY_NoSymbol;
732 SignedNumber : MINUS Number { $$ = -$2; }
733 | Number { $$ = $1; }
736 Number : FLOAT { $$ = $1; }
737 | INTEGER { $$ = $1; }
740 Float : FLOAT { $$ = 0; }
743 Integer : INTEGER { $$ = $1; }
746 KeyCode : INTEGER { $$ = $1; }
749 Ident : IDENT { $$ = xkb_atom_steal(param->ctx, $1); }
750 | DEFAULT { $$ = xkb_atom_intern_literal(param->ctx, "default"); }
753 String : STRING { $$ = xkb_atom_steal(param->ctx, $1); }
756 OptMapName : MapName { $$ = $1; }
760 MapName : STRING { $$ = $1; }
766 parse(struct xkb_context *ctx, struct scanner *scanner, const char *map)
769 XkbFile *first = NULL;
770 struct parser_param param = {
776 * If we got a specific map, we look for it exclusively and return
777 * immediately upon finding it. Otherwise, we need to get the
778 * default map. If we find a map marked as default, we return it
779 * immediately. If there are no maps marked as default, we return
780 * the first map in the file.
783 while ((ret = yyparse(¶m)) == 0 && param.more_maps) {
785 if (streq_not_null(map, param.rtrn->name))
788 FreeXkbFile(param.rtrn);
791 if (param.rtrn->flags & MAP_IS_DEFAULT) {
799 FreeXkbFile(param.rtrn);