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 }
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
199 %type <ival> Number Integer Float SignedNumber DoodadType
200 %type <merge> MergeMode OptMergeMode
201 %type <file_type> XkbCompositeType FileType
202 %type <mapFlags> Flag Flags OptFlags
203 %type <str> MapName OptMapName
204 %type <atom> FieldSpec Ident Element String
205 %type <keysym> KeySym
207 %type <anyList> DeclList
208 %type <expr> Expr Term Lhs Terminal ArrayInit KeySyms
209 %type <expr> OptKeySymList KeySymList Action Coord CoordList
210 %type <exprList> OptExprList ExprList ActionList
211 %type <var> VarDecl SymbolsVarDecl
212 %type <varList> VarDeclList SymbolsBody
214 %type <vmodList> VModDefList VModDecl
215 %type <interp> InterpretDecl InterpretMatch
216 %type <keyType> KeyTypeDecl
217 %type <syms> SymbolsDecl
218 %type <modMask> ModMapDecl
219 %type <groupCompat> GroupCompatDecl
220 %type <ledMap> LedMapDecl
221 %type <ledName> LedNameDecl
222 %type <keyCode> KeyNameDecl
223 %type <keyAlias> KeyAliasDecl
224 %type <geom> ShapeDecl SectionDecl SectionBody SectionBodyItem RowBody RowBodyItem
225 %type <geom> Keys Key OverlayDecl OverlayKeyList OverlayKey OutlineList OutlineInList
226 %type <geom> DoodadDecl
227 %type <file> XkbFile XkbMapConfig
228 %type <fileList> XkbMapConfigList
229 %type <file> XkbCompositeMap
231 %destructor { FreeStmt((ParseCommon *) $$); }
232 <any> <expr> <var> <vmod> <interp> <keyType> <syms> <modMask> <groupCompat>
233 <ledMap> <ledName> <keyCode> <keyAlias>
234 %destructor { FreeStmt((ParseCommon *) $$.head); }
235 <anyList> <exprList> <varList> <vmodList>
236 /* The destructor also runs on the start symbol when the parser *succeeds*.
237 * The `if` here catches this case. */
238 %destructor { if (!param->rtrn) FreeXkbFile($$); } <file>
239 %destructor { FreeXkbFile($$.head); } <fileList>
240 %destructor { free($$); } <str>
245 * An actual file may contain more than one map. However, if we do things
246 * in the normal yacc way, i.e. aggregate all of the maps into a list and
247 * let the caller find the map it wants, we end up scanning and parsing a
248 * lot of unneeded maps (in the end we always just need one).
249 * Instead of doing that, we make yyparse return one map at a time, and
250 * then call it repeatedly until we find the map we need. Once we find it,
251 * we don't need to parse everything that follows in the file.
252 * This does mean that if we e.g. always use the first map, the file may
253 * contain complete garbage after that. But it's worth it.
256 XkbFile : XkbCompositeMap
257 { $$ = param->rtrn = $1; param->more_maps = !!param->rtrn; }
259 { $$ = param->rtrn = $1; param->more_maps = !!param->rtrn; YYACCEPT; }
261 { $$ = param->rtrn = NULL; param->more_maps = false; }
264 XkbCompositeMap : OptFlags XkbCompositeType OptMapName OBRACE
267 { $$ = XkbFileCreate($2, $3, (ParseCommon *) $5.head, $1); }
270 XkbCompositeType: XKB_KEYMAP { $$ = FILE_TYPE_KEYMAP; }
271 | XKB_SEMANTICS { $$ = FILE_TYPE_KEYMAP; }
272 | XKB_LAYOUT { $$ = FILE_TYPE_KEYMAP; }
275 XkbMapConfigList : XkbMapConfigList XkbMapConfig
276 { $$.head = $1.head; $$.last->common.next = &$2->common; $$.last = $2; }
278 { $$.head = $$.last = $1; }
281 XkbMapConfig : OptFlags FileType OptMapName OBRACE
285 $$ = XkbFileCreate($2, $3, $5.head, $1);
289 FileType : XKB_KEYCODES { $$ = FILE_TYPE_KEYCODES; }
290 | XKB_TYPES { $$ = FILE_TYPE_TYPES; }
291 | XKB_COMPATMAP { $$ = FILE_TYPE_COMPAT; }
292 | XKB_SYMBOLS { $$ = FILE_TYPE_SYMBOLS; }
293 | XKB_GEOMETRY { $$ = FILE_TYPE_GEOMETRY; }
296 OptFlags : Flags { $$ = $1; }
300 Flags : Flags Flag { $$ = ($1 | $2); }
304 Flag : PARTIAL { $$ = MAP_IS_PARTIAL; }
305 | DEFAULT { $$ = MAP_IS_DEFAULT; }
306 | HIDDEN { $$ = MAP_IS_HIDDEN; }
307 | ALPHANUMERIC_KEYS { $$ = MAP_HAS_ALPHANUMERIC; }
308 | MODIFIER_KEYS { $$ = MAP_HAS_MODIFIER; }
309 | KEYPAD_KEYS { $$ = MAP_HAS_KEYPAD; }
310 | FUNCTION_KEYS { $$ = MAP_HAS_FN; }
311 | ALTERNATE_GROUP { $$ = MAP_IS_ALTGR; }
314 DeclList : DeclList Decl
318 $$.head = $1.head; $1.last->next = $2; $$.last = $2;
320 $$.head = $$.last = $2;
325 * VModDecl is "inlined" directly into DeclList, i.e.
326 * each VModDef in the VModDecl is a separate Decl in
329 | DeclList OptMergeMode VModDecl
331 for (VModDef *vmod = $3.head; vmod; vmod = (VModDef *) vmod->common.next)
334 $$.head = $1.head; $1.last->next = &$3.head->common; $$.last = &$3.last->common;
336 $$.head = &$3.head->common; $$.last = &$3.last->common;
339 | { $$.head = $$.last = NULL; }
342 Decl : OptMergeMode VarDecl
345 $$ = (ParseCommon *) $2;
347 /* OptMergeMode VModDecl - see above. */
348 | OptMergeMode InterpretDecl
351 $$ = (ParseCommon *) $2;
353 | OptMergeMode KeyNameDecl
356 $$ = (ParseCommon *) $2;
358 | OptMergeMode KeyAliasDecl
361 $$ = (ParseCommon *) $2;
363 | OptMergeMode KeyTypeDecl
366 $$ = (ParseCommon *) $2;
368 | OptMergeMode SymbolsDecl
371 $$ = (ParseCommon *) $2;
373 | OptMergeMode ModMapDecl
376 $$ = (ParseCommon *) $2;
378 | OptMergeMode GroupCompatDecl
381 $$ = (ParseCommon *) $2;
383 | OptMergeMode LedMapDecl
386 $$ = (ParseCommon *) $2;
388 | OptMergeMode LedNameDecl
391 $$ = (ParseCommon *) $2;
393 | OptMergeMode ShapeDecl { $$ = NULL; }
394 | OptMergeMode SectionDecl { $$ = NULL; }
395 | OptMergeMode DoodadDecl { $$ = NULL; }
398 $$ = (ParseCommon *) IncludeCreate(param->ctx, $2, $1);
403 VarDecl : Lhs EQUALS Expr SEMI
404 { $$ = VarCreate($1, $3); }
406 { $$ = BoolVarCreate($1, true); }
408 { $$ = BoolVarCreate($2, false); }
411 KeyNameDecl : KEYNAME EQUALS KeyCode SEMI
412 { $$ = KeycodeCreate($1, $3); }
415 KeyAliasDecl : ALIAS KEYNAME EQUALS KEYNAME SEMI
416 { $$ = KeyAliasCreate($2, $4); }
419 VModDecl : VIRTUAL_MODS VModDefList SEMI
423 VModDefList : VModDefList COMMA VModDef
424 { $$.head = $1.head; $$.last->common.next = &$3->common; $$.last = $3; }
426 { $$.head = $$.last = $1; }
430 { $$ = VModCreate($1, NULL); }
432 { $$ = VModCreate($1, $3); }
435 InterpretDecl : INTERPRET InterpretMatch OBRACE
438 { $2->def = $4.head; $$ = $2; }
441 InterpretMatch : KeySym PLUS Expr
442 { $$ = InterpCreate($1, $3); }
444 { $$ = InterpCreate($1, NULL); }
447 VarDeclList : VarDeclList VarDecl
448 { $$.head = $1.head; $$.last->common.next = &$2->common; $$.last = $2; }
450 { $$.head = $$.last = $1; }
453 KeyTypeDecl : TYPE String OBRACE
456 { $$ = KeyTypeCreate($2, $4.head); }
459 SymbolsDecl : KEY KEYNAME OBRACE
462 { $$ = SymbolsCreate($2, $4.head); }
465 SymbolsBody : SymbolsBody COMMA SymbolsVarDecl
466 { $$.head = $1.head; $$.last->common.next = &$3->common; $$.last = $3; }
468 { $$.head = $$.last = $1; }
469 | { $$.head = $$.last = NULL; }
472 SymbolsVarDecl : Lhs EQUALS Expr { $$ = VarCreate($1, $3); }
473 | Lhs EQUALS ArrayInit { $$ = VarCreate($1, $3); }
474 | Ident { $$ = BoolVarCreate($1, true); }
475 | EXCLAM Ident { $$ = BoolVarCreate($2, false); }
476 | ArrayInit { $$ = VarCreate(NULL, $1); }
479 ArrayInit : OBRACKET OptKeySymList CBRACKET
481 | OBRACKET ActionList CBRACKET
482 { $$ = ExprCreateActionList($2.head); }
485 GroupCompatDecl : GROUP Integer EQUALS Expr SEMI
486 { $$ = GroupCompatCreate($2, $4); }
489 ModMapDecl : MODIFIER_MAP Ident OBRACE ExprList CBRACE SEMI
490 { $$ = ModMapCreate($2, $4.head); }
493 LedMapDecl: INDICATOR String OBRACE VarDeclList CBRACE SEMI
494 { $$ = LedMapCreate($2, $4.head); }
497 LedNameDecl: INDICATOR Integer EQUALS Expr SEMI
498 { $$ = LedNameCreate($2, $4, false); }
499 | VIRTUAL INDICATOR Integer EQUALS Expr SEMI
500 { $$ = LedNameCreate($3, $5, true); }
503 ShapeDecl : SHAPE String OBRACE OutlineList CBRACE SEMI
505 | SHAPE String OBRACE CoordList CBRACE SEMI
506 { (void) $4; $$ = NULL; }
509 SectionDecl : SECTION String OBRACE SectionBody CBRACE SEMI
513 SectionBody : SectionBody SectionBodyItem { $$ = NULL;}
514 | SectionBodyItem { $$ = NULL; }
517 SectionBodyItem : ROW OBRACE RowBody CBRACE SEMI
520 { FreeStmt((ParseCommon *) $1); $$ = NULL; }
524 { FreeStmt((ParseCommon *) $1); $$ = NULL; }
529 RowBody : RowBody RowBodyItem { $$ = NULL;}
530 | RowBodyItem { $$ = NULL; }
533 RowBodyItem : KEYS OBRACE Keys CBRACE SEMI { $$ = NULL; }
535 { FreeStmt((ParseCommon *) $1); $$ = NULL; }
538 Keys : Keys COMMA Key { $$ = NULL; }
544 | OBRACE ExprList CBRACE
545 { FreeStmt((ParseCommon *) $2.head); $$ = NULL; }
548 OverlayDecl : OVERLAY String OBRACE OverlayKeyList CBRACE SEMI
552 OverlayKeyList : OverlayKeyList COMMA OverlayKey { $$ = NULL; }
553 | OverlayKey { $$ = NULL; }
556 OverlayKey : KEYNAME EQUALS KEYNAME { $$ = NULL; }
559 OutlineList : OutlineList COMMA OutlineInList
565 OutlineInList : OBRACE CoordList CBRACE
566 { (void) $2; $$ = NULL; }
567 | Ident EQUALS OBRACE CoordList CBRACE
568 { (void) $4; $$ = NULL; }
570 { FreeStmt((ParseCommon *) $3); $$ = NULL; }
573 CoordList : CoordList COMMA Coord
574 { (void) $1; (void) $3; $$ = NULL; }
576 { (void) $1; $$ = NULL; }
579 Coord : OBRACKET SignedNumber COMMA SignedNumber CBRACKET
583 DoodadDecl : DoodadType String OBRACE VarDeclList CBRACE SEMI
584 { FreeStmt((ParseCommon *) $4.head); $$ = NULL; }
587 DoodadType : TEXT { $$ = 0; }
588 | OUTLINE { $$ = 0; }
593 FieldSpec : Ident { $$ = $1; }
594 | Element { $$ = $1; }
598 { $$ = xkb_atom_intern_literal(param->ctx, "action"); }
600 { $$ = xkb_atom_intern_literal(param->ctx, "interpret"); }
602 { $$ = xkb_atom_intern_literal(param->ctx, "type"); }
604 { $$ = xkb_atom_intern_literal(param->ctx, "key"); }
606 { $$ = xkb_atom_intern_literal(param->ctx, "group"); }
608 {$$ = xkb_atom_intern_literal(param->ctx, "modifier_map");}
610 { $$ = xkb_atom_intern_literal(param->ctx, "indicator"); }
612 { $$ = xkb_atom_intern_literal(param->ctx, "shape"); }
614 { $$ = xkb_atom_intern_literal(param->ctx, "row"); }
616 { $$ = xkb_atom_intern_literal(param->ctx, "section"); }
618 { $$ = xkb_atom_intern_literal(param->ctx, "text"); }
621 OptMergeMode : MergeMode { $$ = $1; }
622 | { $$ = MERGE_DEFAULT; }
625 MergeMode : INCLUDE { $$ = MERGE_DEFAULT; }
626 | AUGMENT { $$ = MERGE_AUGMENT; }
627 | OVERRIDE { $$ = MERGE_OVERRIDE; }
628 | REPLACE { $$ = MERGE_REPLACE; }
632 * This used to be MERGE_ALT_FORM. This functionality was
633 * unused and has been removed.
639 OptExprList : ExprList { $$ = $1; }
640 | { $$.head = $$.last = NULL; }
643 ExprList : ExprList COMMA Expr
644 { $$.head = $1.head; $$.last->common.next = &$3->common; $$.last = $3; }
646 { $$.head = $$.last = $1; }
649 Expr : Expr DIVIDE Expr
650 { $$ = ExprCreateBinary(EXPR_DIVIDE, $1, $3); }
652 { $$ = ExprCreateBinary(EXPR_ADD, $1, $3); }
654 { $$ = ExprCreateBinary(EXPR_SUBTRACT, $1, $3); }
656 { $$ = ExprCreateBinary(EXPR_MULTIPLY, $1, $3); }
658 { $$ = ExprCreateBinary(EXPR_ASSIGN, $1, $3); }
664 { $$ = ExprCreateUnary(EXPR_NEGATE, $2->expr.value_type, $2); }
666 { $$ = ExprCreateUnary(EXPR_UNARY_PLUS, $2->expr.value_type, $2); }
668 { $$ = ExprCreateUnary(EXPR_NOT, EXPR_TYPE_BOOLEAN, $2); }
670 { $$ = ExprCreateUnary(EXPR_INVERT, $2->expr.value_type, $2); }
673 | FieldSpec OPAREN OptExprList CPAREN %prec OPAREN
674 { $$ = ExprCreateAction($1, $3.head); }
681 ActionList : ActionList COMMA Action
682 { $$.head = $1.head; $$.last->common.next = &$3->common; $$.last = $3; }
684 { $$.head = $$.last = $1; }
687 Action : FieldSpec OPAREN OptExprList CPAREN
688 { $$ = ExprCreateAction($1, $3.head); }
692 { $$ = ExprCreateIdent($1); }
693 | FieldSpec DOT FieldSpec
694 { $$ = ExprCreateFieldRef($1, $3); }
695 | FieldSpec OBRACKET Expr CBRACKET
696 { $$ = ExprCreateArrayRef(XKB_ATOM_NONE, $1, $3); }
697 | FieldSpec DOT FieldSpec OBRACKET Expr CBRACKET
698 { $$ = ExprCreateArrayRef($1, $3, $5); }
702 { $$ = ExprCreateString($1); }
704 { $$ = ExprCreateInteger($1); }
706 { $$ = ExprCreateFloat(/* Discard $1 */); }
708 { $$ = ExprCreateKeyName($1); }
711 OptKeySymList : KeySymList { $$ = $1; }
715 KeySymList : KeySymList COMMA KeySym
716 { $$ = ExprAppendKeysymList($1, $3); }
717 | KeySymList COMMA KeySyms
718 { $$ = ExprAppendMultiKeysymList($1, $3); }
720 { $$ = ExprCreateKeysymList($1); }
722 { $$ = ExprCreateMultiKeysymList($1); }
725 KeySyms : OBRACE KeySymList CBRACE
731 if (!resolve_keysym($1, &$$))
732 parser_warn(param, "unrecognized keysym \"%s\"", $1);
735 | SECTION { $$ = XKB_KEY_section; }
739 parser_warn(param, "unrecognized keysym \"%d\"", $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%x", $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);