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"
43 struct xkb_context *ctx;
44 struct scanner *scanner;
49 #define parser_err(param, error_id, fmt, ...) \
50 scanner_err_with_code((param)->scanner, error_id, fmt, ##__VA_ARGS__)
52 #define parser_warn(param, warning_id, fmt, ...) \
53 scanner_warn_with_code((param)->scanner, warning_id, fmt, ##__VA_ARGS__)
56 _xkbcommon_error(struct parser_param *param, const char *msg)
58 parser_err(param, XKB_ERROR_INVALID_SYNTAX, "%s", msg);
62 resolve_keysym(const char *name, xkb_keysym_t *sym_rtrn)
66 if (!name || istreq(name, "any") || istreq(name, "nosymbol")) {
67 *sym_rtrn = XKB_KEY_NoSymbol;
71 if (istreq(name, "none") || istreq(name, "voidsymbol")) {
72 *sym_rtrn = XKB_KEY_VoidSymbol;
76 sym = xkb_keysym_from_name(name, XKB_KEYSYM_NO_FLAGS);
77 if (sym != XKB_KEY_NoSymbol) {
85 #define param_scanner param->scanner
89 %lex-param { struct scanner *param_scanner }
90 %parse-param { struct parser_param *param }
167 enum xkb_file_type file_type;
170 enum merge_mode merge;
171 enum xkb_map_flags mapFlags;
174 struct { ParseCommon *head; ParseCommon *last; } anyList;
176 struct { ExprDef *head; ExprDef *last; } exprList;
178 struct { VarDef *head; VarDef *last; } varList;
180 struct { VModDef *head; VModDef *last; } vmodList;
185 GroupCompatDef *groupCompat;
189 KeyAliasDef *keyAlias;
192 struct { XkbFile *head; XkbFile *last; } fileList;
195 %type <num> INTEGER FLOAT
196 %type <str> IDENT STRING
198 %type <num> KeyCode Number Integer Float SignedNumber DoodadType
199 %type <merge> MergeMode OptMergeMode
200 %type <file_type> XkbCompositeType FileType
201 %type <mapFlags> Flag Flags OptFlags
202 %type <str> MapName OptMapName
203 %type <atom> FieldSpec Ident Element String
204 %type <keysym> KeySym
206 %type <anyList> DeclList
207 %type <expr> Expr Term Lhs Terminal ArrayInit KeySyms
208 %type <expr> OptKeySymList KeySymList Action Coord CoordList
209 %type <exprList> OptExprList ExprList ActionList
210 %type <var> VarDecl SymbolsVarDecl
211 %type <varList> VarDeclList SymbolsBody
213 %type <vmodList> VModDefList VModDecl
214 %type <interp> InterpretDecl InterpretMatch
215 %type <keyType> KeyTypeDecl
216 %type <syms> SymbolsDecl
217 %type <modMask> ModMapDecl
218 %type <groupCompat> GroupCompatDecl
219 %type <ledMap> LedMapDecl
220 %type <ledName> LedNameDecl
221 %type <keyCode> KeyNameDecl
222 %type <keyAlias> KeyAliasDecl
223 %type <geom> ShapeDecl SectionDecl SectionBody SectionBodyItem RowBody RowBodyItem
224 %type <geom> Keys Key OverlayDecl OverlayKeyList OverlayKey OutlineList OutlineInList
225 %type <geom> DoodadDecl
226 %type <file> XkbFile XkbMapConfig
227 %type <fileList> XkbMapConfigList
228 %type <file> XkbCompositeMap
230 %destructor { FreeStmt((ParseCommon *) $$); }
231 <any> <expr> <var> <vmod> <interp> <keyType> <syms> <modMask> <groupCompat>
232 <ledMap> <ledName> <keyCode> <keyAlias>
233 %destructor { FreeStmt((ParseCommon *) $$.head); }
234 <anyList> <exprList> <varList> <vmodList>
235 /* The destructor also runs on the start symbol when the parser *succeeds*.
236 * The `if` here catches this case. */
237 %destructor { if (!param->rtrn) FreeXkbFile($$); } <file>
238 %destructor { FreeXkbFile($$.head); } <fileList>
239 %destructor { free($$); } <str>
244 * An actual file may contain more than one map. However, if we do things
245 * in the normal yacc way, i.e. aggregate all of the maps into a list and
246 * let the caller find the map it wants, we end up scanning and parsing a
247 * lot of unneeded maps (in the end we always just need one).
248 * Instead of doing that, we make yyparse return one map at a time, and
249 * then call it repeatedly until we find the map we need. Once we find it,
250 * we don't need to parse everything that follows in the file.
251 * This does mean that if we e.g. always use the first map, the file may
252 * contain complete garbage after that. But it's worth it.
255 XkbFile : XkbCompositeMap
256 { $$ = param->rtrn = $1; param->more_maps = !!param->rtrn; }
258 { $$ = param->rtrn = $1; param->more_maps = !!param->rtrn; YYACCEPT; }
260 { $$ = param->rtrn = NULL; param->more_maps = false; }
263 XkbCompositeMap : OptFlags XkbCompositeType OptMapName OBRACE
266 { $$ = XkbFileCreate($2, $3, (ParseCommon *) $5.head, $1); }
269 XkbCompositeType: XKB_KEYMAP { $$ = FILE_TYPE_KEYMAP; }
270 | XKB_SEMANTICS { $$ = FILE_TYPE_KEYMAP; }
271 | XKB_LAYOUT { $$ = FILE_TYPE_KEYMAP; }
274 XkbMapConfigList : XkbMapConfigList XkbMapConfig
275 { $$.head = $1.head; $$.last->common.next = &$2->common; $$.last = $2; }
277 { $$.head = $$.last = $1; }
280 XkbMapConfig : OptFlags FileType OptMapName OBRACE
284 $$ = XkbFileCreate($2, $3, $5.head, $1);
288 FileType : XKB_KEYCODES { $$ = FILE_TYPE_KEYCODES; }
289 | XKB_TYPES { $$ = FILE_TYPE_TYPES; }
290 | XKB_COMPATMAP { $$ = FILE_TYPE_COMPAT; }
291 | XKB_SYMBOLS { $$ = FILE_TYPE_SYMBOLS; }
292 | XKB_GEOMETRY { $$ = FILE_TYPE_GEOMETRY; }
295 OptFlags : Flags { $$ = $1; }
299 Flags : Flags Flag { $$ = ($1 | $2); }
303 Flag : PARTIAL { $$ = MAP_IS_PARTIAL; }
304 | DEFAULT { $$ = MAP_IS_DEFAULT; }
305 | HIDDEN { $$ = MAP_IS_HIDDEN; }
306 | ALPHANUMERIC_KEYS { $$ = MAP_HAS_ALPHANUMERIC; }
307 | MODIFIER_KEYS { $$ = MAP_HAS_MODIFIER; }
308 | KEYPAD_KEYS { $$ = MAP_HAS_KEYPAD; }
309 | FUNCTION_KEYS { $$ = MAP_HAS_FN; }
310 | ALTERNATE_GROUP { $$ = MAP_IS_ALTGR; }
313 DeclList : DeclList Decl
317 $$.head = $1.head; $1.last->next = $2; $$.last = $2;
319 $$.head = $$.last = $2;
324 * VModDecl is "inlined" directly into DeclList, i.e.
325 * each VModDef in the VModDecl is a separate Decl in
328 | DeclList OptMergeMode VModDecl
330 for (VModDef *vmod = $3.head; vmod; vmod = (VModDef *) vmod->common.next)
333 $$.head = $1.head; $1.last->next = &$3.head->common; $$.last = &$3.last->common;
335 $$.head = &$3.head->common; $$.last = &$3.last->common;
338 | { $$.head = $$.last = NULL; }
341 Decl : OptMergeMode VarDecl
344 $$ = (ParseCommon *) $2;
346 /* OptMergeMode VModDecl - see above. */
347 | OptMergeMode InterpretDecl
350 $$ = (ParseCommon *) $2;
352 | OptMergeMode KeyNameDecl
355 $$ = (ParseCommon *) $2;
357 | OptMergeMode KeyAliasDecl
360 $$ = (ParseCommon *) $2;
362 | OptMergeMode KeyTypeDecl
365 $$ = (ParseCommon *) $2;
367 | OptMergeMode SymbolsDecl
370 $$ = (ParseCommon *) $2;
372 | OptMergeMode ModMapDecl
375 $$ = (ParseCommon *) $2;
377 | OptMergeMode GroupCompatDecl
380 $$ = (ParseCommon *) $2;
382 | OptMergeMode LedMapDecl
385 $$ = (ParseCommon *) $2;
387 | OptMergeMode LedNameDecl
390 $$ = (ParseCommon *) $2;
392 | OptMergeMode ShapeDecl { $$ = NULL; }
393 | OptMergeMode SectionDecl { $$ = NULL; }
394 | OptMergeMode DoodadDecl { $$ = NULL; }
397 $$ = (ParseCommon *) IncludeCreate(param->ctx, $2, $1);
402 VarDecl : Lhs EQUALS Expr SEMI
403 { $$ = VarCreate($1, $3); }
405 { $$ = BoolVarCreate($1, true); }
407 { $$ = BoolVarCreate($2, false); }
410 KeyNameDecl : KEYNAME EQUALS KeyCode SEMI
411 { $$ = KeycodeCreate($1, $3); }
414 KeyAliasDecl : ALIAS KEYNAME EQUALS KEYNAME SEMI
415 { $$ = KeyAliasCreate($2, $4); }
418 VModDecl : VIRTUAL_MODS VModDefList SEMI
422 VModDefList : VModDefList COMMA VModDef
423 { $$.head = $1.head; $$.last->common.next = &$3->common; $$.last = $3; }
425 { $$.head = $$.last = $1; }
429 { $$ = VModCreate($1, NULL); }
431 { $$ = VModCreate($1, $3); }
434 InterpretDecl : INTERPRET InterpretMatch OBRACE
437 { $2->def = $4.head; $$ = $2; }
440 InterpretMatch : KeySym PLUS Expr
441 { $$ = InterpCreate($1, $3); }
443 { $$ = InterpCreate($1, NULL); }
446 VarDeclList : VarDeclList VarDecl
447 { $$.head = $1.head; $$.last->common.next = &$2->common; $$.last = $2; }
449 { $$.head = $$.last = $1; }
452 KeyTypeDecl : TYPE String OBRACE
455 { $$ = KeyTypeCreate($2, $4.head); }
458 SymbolsDecl : KEY KEYNAME OBRACE
461 { $$ = SymbolsCreate($2, $4.head); }
464 SymbolsBody : SymbolsBody COMMA SymbolsVarDecl
465 { $$.head = $1.head; $$.last->common.next = &$3->common; $$.last = $3; }
467 { $$.head = $$.last = $1; }
468 | { $$.head = $$.last = NULL; }
471 SymbolsVarDecl : Lhs EQUALS Expr { $$ = VarCreate($1, $3); }
472 | Lhs EQUALS ArrayInit { $$ = VarCreate($1, $3); }
473 | Ident { $$ = BoolVarCreate($1, true); }
474 | EXCLAM Ident { $$ = BoolVarCreate($2, false); }
475 | ArrayInit { $$ = VarCreate(NULL, $1); }
478 ArrayInit : OBRACKET OptKeySymList CBRACKET
480 | OBRACKET ActionList CBRACKET
481 { $$ = ExprCreateActionList($2.head); }
484 GroupCompatDecl : GROUP Integer EQUALS Expr SEMI
485 { $$ = GroupCompatCreate($2, $4); }
488 ModMapDecl : MODIFIER_MAP Ident OBRACE ExprList CBRACE SEMI
489 { $$ = ModMapCreate($2, $4.head); }
492 LedMapDecl: INDICATOR String OBRACE VarDeclList CBRACE SEMI
493 { $$ = LedMapCreate($2, $4.head); }
496 LedNameDecl: INDICATOR Integer EQUALS Expr SEMI
497 { $$ = LedNameCreate($2, $4, false); }
498 | VIRTUAL INDICATOR Integer EQUALS Expr SEMI
499 { $$ = LedNameCreate($3, $5, true); }
502 ShapeDecl : SHAPE String OBRACE OutlineList CBRACE SEMI
504 | SHAPE String OBRACE CoordList CBRACE SEMI
505 { (void) $4; $$ = NULL; }
508 SectionDecl : SECTION String OBRACE SectionBody CBRACE SEMI
512 SectionBody : SectionBody SectionBodyItem { $$ = NULL;}
513 | SectionBodyItem { $$ = NULL; }
516 SectionBodyItem : ROW OBRACE RowBody CBRACE SEMI
519 { FreeStmt((ParseCommon *) $1); $$ = NULL; }
523 { FreeStmt((ParseCommon *) $1); $$ = NULL; }
528 RowBody : RowBody RowBodyItem { $$ = NULL;}
529 | RowBodyItem { $$ = NULL; }
532 RowBodyItem : KEYS OBRACE Keys CBRACE SEMI { $$ = NULL; }
534 { FreeStmt((ParseCommon *) $1); $$ = NULL; }
537 Keys : Keys COMMA Key { $$ = NULL; }
543 | OBRACE ExprList CBRACE
544 { FreeStmt((ParseCommon *) $2.head); $$ = NULL; }
547 OverlayDecl : OVERLAY String OBRACE OverlayKeyList CBRACE SEMI
551 OverlayKeyList : OverlayKeyList COMMA OverlayKey { $$ = NULL; }
552 | OverlayKey { $$ = NULL; }
555 OverlayKey : KEYNAME EQUALS KEYNAME { $$ = NULL; }
558 OutlineList : OutlineList COMMA OutlineInList
564 OutlineInList : OBRACE CoordList CBRACE
565 { (void) $2; $$ = NULL; }
566 | Ident EQUALS OBRACE CoordList CBRACE
567 { (void) $4; $$ = NULL; }
569 { FreeStmt((ParseCommon *) $3); $$ = NULL; }
572 CoordList : CoordList COMMA Coord
573 { (void) $1; (void) $3; $$ = NULL; }
575 { (void) $1; $$ = NULL; }
578 Coord : OBRACKET SignedNumber COMMA SignedNumber CBRACKET
582 DoodadDecl : DoodadType String OBRACE VarDeclList CBRACE SEMI
583 { FreeStmt((ParseCommon *) $4.head); $$ = NULL; }
586 DoodadType : TEXT { $$ = 0; }
587 | OUTLINE { $$ = 0; }
592 FieldSpec : Ident { $$ = $1; }
593 | Element { $$ = $1; }
597 { $$ = xkb_atom_intern_literal(param->ctx, "action"); }
599 { $$ = xkb_atom_intern_literal(param->ctx, "interpret"); }
601 { $$ = xkb_atom_intern_literal(param->ctx, "type"); }
603 { $$ = xkb_atom_intern_literal(param->ctx, "key"); }
605 { $$ = xkb_atom_intern_literal(param->ctx, "group"); }
607 {$$ = xkb_atom_intern_literal(param->ctx, "modifier_map");}
609 { $$ = xkb_atom_intern_literal(param->ctx, "indicator"); }
611 { $$ = xkb_atom_intern_literal(param->ctx, "shape"); }
613 { $$ = xkb_atom_intern_literal(param->ctx, "row"); }
615 { $$ = xkb_atom_intern_literal(param->ctx, "section"); }
617 { $$ = xkb_atom_intern_literal(param->ctx, "text"); }
620 OptMergeMode : MergeMode { $$ = $1; }
621 | { $$ = MERGE_DEFAULT; }
624 MergeMode : INCLUDE { $$ = MERGE_DEFAULT; }
625 | AUGMENT { $$ = MERGE_AUGMENT; }
626 | OVERRIDE { $$ = MERGE_OVERRIDE; }
627 | REPLACE { $$ = MERGE_REPLACE; }
631 * This used to be MERGE_ALT_FORM. This functionality was
632 * unused and has been removed.
638 OptExprList : ExprList { $$ = $1; }
639 | { $$.head = $$.last = NULL; }
642 ExprList : ExprList COMMA Expr
643 { $$.head = $1.head; $$.last->common.next = &$3->common; $$.last = $3; }
645 { $$.head = $$.last = $1; }
648 Expr : Expr DIVIDE Expr
649 { $$ = ExprCreateBinary(EXPR_DIVIDE, $1, $3); }
651 { $$ = ExprCreateBinary(EXPR_ADD, $1, $3); }
653 { $$ = ExprCreateBinary(EXPR_SUBTRACT, $1, $3); }
655 { $$ = ExprCreateBinary(EXPR_MULTIPLY, $1, $3); }
657 { $$ = ExprCreateBinary(EXPR_ASSIGN, $1, $3); }
663 { $$ = ExprCreateUnary(EXPR_NEGATE, $2->expr.value_type, $2); }
665 { $$ = ExprCreateUnary(EXPR_UNARY_PLUS, $2->expr.value_type, $2); }
667 { $$ = ExprCreateUnary(EXPR_NOT, EXPR_TYPE_BOOLEAN, $2); }
669 { $$ = ExprCreateUnary(EXPR_INVERT, $2->expr.value_type, $2); }
672 | FieldSpec OPAREN OptExprList CPAREN %prec OPAREN
673 { $$ = ExprCreateAction($1, $3.head); }
680 ActionList : ActionList COMMA Action
681 { $$.head = $1.head; $$.last->common.next = &$3->common; $$.last = $3; }
683 { $$.head = $$.last = $1; }
686 Action : FieldSpec OPAREN OptExprList CPAREN
687 { $$ = ExprCreateAction($1, $3.head); }
691 { $$ = ExprCreateIdent($1); }
692 | FieldSpec DOT FieldSpec
693 { $$ = ExprCreateFieldRef($1, $3); }
694 | FieldSpec OBRACKET Expr CBRACKET
695 { $$ = ExprCreateArrayRef(XKB_ATOM_NONE, $1, $3); }
696 | FieldSpec DOT FieldSpec OBRACKET Expr CBRACKET
697 { $$ = ExprCreateArrayRef($1, $3, $5); }
701 { $$ = ExprCreateString($1); }
703 { $$ = ExprCreateInteger($1); }
705 { $$ = ExprCreateFloat(/* Discard $1 */); }
707 { $$ = ExprCreateKeyName($1); }
710 OptKeySymList : KeySymList { $$ = $1; }
714 KeySymList : KeySymList COMMA KeySym
715 { $$ = ExprAppendKeysymList($1, $3); }
716 | KeySymList COMMA KeySyms
717 { $$ = ExprAppendMultiKeysymList($1, $3); }
719 { $$ = ExprCreateKeysymList($1); }
721 { $$ = ExprCreateMultiKeysymList($1); }
724 KeySyms : OBRACE KeySymList CBRACE
730 if (!resolve_keysym($1, &$$)) {
733 XKB_WARNING_UNRECOGNIZED_KEYSYM,
734 "unrecognized keysym \"%s\"",
737 $$ = XKB_KEY_NoSymbol;
741 | SECTION { $$ = XKB_KEY_section; }
744 if ($1 < XKB_KEYSYM_MIN) {
747 XKB_WARNING_UNRECOGNIZED_KEYSYM,
748 "unrecognized keysym \"%"PRId64"\"",
751 $$ = XKB_KEY_NoSymbol;
753 /* Special case for digits 0..9 */
754 else if ($1 < 10) { /* XKB_KEY_0 .. XKB_KEY_9 */
755 $$ = XKB_KEY_0 + (xkb_keysym_t) $1;
758 if ($1 <= XKB_KEYSYM_MAX) {
759 $$ = (xkb_keysym_t) $1;
762 param, XKB_WARNING_UNRECOGNIZED_KEYSYM,
763 "unrecognized keysym \"0x%"PRIx64"\" "
764 "(%"PRId64")", $1, $1
766 $$ = XKB_KEY_NoSymbol;
769 param, XKB_WARNING_NUMERIC_KEYSYM,
770 "numeric keysym \"0x%"PRIx64"\" (%"PRId64")",
777 SignedNumber : MINUS Number { $$ = -$2; }
778 | Number { $$ = $1; }
781 Number : FLOAT { $$ = $1; }
782 | INTEGER { $$ = $1; }
785 Float : FLOAT { $$ = 0; }
788 Integer : INTEGER { $$ = $1; }
791 KeyCode : INTEGER { $$ = $1; }
794 Ident : IDENT { $$ = xkb_atom_intern(param->ctx, $1, strlen($1)); free($1); }
795 | DEFAULT { $$ = xkb_atom_intern_literal(param->ctx, "default"); }
798 String : STRING { $$ = xkb_atom_intern(param->ctx, $1, strlen($1)); free($1); }
801 OptMapName : MapName { $$ = $1; }
805 MapName : STRING { $$ = $1; }
811 parse(struct xkb_context *ctx, struct scanner *scanner, const char *map)
814 XkbFile *first = NULL;
815 struct parser_param param = {
823 * If we got a specific map, we look for it exclusively and return
824 * immediately upon finding it. Otherwise, we need to get the
825 * default map. If we find a map marked as default, we return it
826 * immediately. If there are no maps marked as default, we return
827 * the first map in the file.
830 while ((ret = yyparse(¶m)) == 0 && param.more_maps) {
832 if (streq_not_null(map, param.rtrn->name))
835 FreeXkbFile(param.rtrn);
838 if (param.rtrn->flags & MAP_IS_DEFAULT) {
846 FreeXkbFile(param.rtrn);
859 XKB_WARNING_MISSING_DEFAULT_SECTION,
860 "No map in include statement, but \"%s\" contains several; "
861 "Using first defined map, \"%s\"\n",
862 scanner->file_name, first->name);