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/xkbcomp-priv.h"
35 #include "xkbcomp/ast-build.h"
36 #include "xkbcomp/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 <atom> 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
219 %destructor { FreeStmt((ParseCommon *) $$); }
220 <any> <expr> <var> <vmod> <interp> <keyType> <syms> <modMask> <groupCompat>
221 <ledMap> <ledName> <keyCode> <keyAlias>
222 /* The destructor also runs on the start symbol when the parser *succeeds*.
223 * The `if` here catches this case. */
224 %destructor { if (!param->rtrn) FreeXkbFile($$); } <file>
225 %destructor { free($$); } <str>
230 * An actual file may contain more than one map. However, if we do things
231 * in the normal yacc way, i.e. aggregate all of the maps into a list and
232 * let the caller find the map it wants, we end up scanning and parsing a
233 * lot of unneeded maps (in the end we always just need one).
234 * Instead of doing that, we make yyparse return one map at a time, and
235 * then call it repeatedly until we find the map we need. Once we find it,
236 * we don't need to parse everything that follows in the file.
237 * This does mean that if we e.g. always use the first map, the file may
238 * contain complete garbage after that. But it's worth it.
241 XkbFile : XkbCompositeMap
242 { $$ = param->rtrn = $1; param->more_maps = !!param->rtrn; }
244 { $$ = param->rtrn = $1; param->more_maps = !!param->rtrn; YYACCEPT; }
246 { $$ = param->rtrn = NULL; param->more_maps = false; }
249 XkbCompositeMap : OptFlags XkbCompositeType OptMapName OBRACE
252 { $$ = XkbFileCreate($2, $3, (ParseCommon *) $5, $1); }
255 XkbCompositeType: XKB_KEYMAP { $$ = FILE_TYPE_KEYMAP; }
256 | XKB_SEMANTICS { $$ = FILE_TYPE_KEYMAP; }
257 | XKB_LAYOUT { $$ = FILE_TYPE_KEYMAP; }
260 XkbMapConfigList : XkbMapConfigList XkbMapConfig
261 { $$ = (XkbFile *) AppendStmt((ParseCommon *) $1,
262 (ParseCommon *) $2); }
267 XkbMapConfig : OptFlags FileType OptMapName OBRACE
271 $$ = XkbFileCreate($2, $3, $5, $1);
275 FileType : XKB_KEYCODES { $$ = FILE_TYPE_KEYCODES; }
276 | XKB_TYPES { $$ = FILE_TYPE_TYPES; }
277 | XKB_COMPATMAP { $$ = FILE_TYPE_COMPAT; }
278 | XKB_SYMBOLS { $$ = FILE_TYPE_SYMBOLS; }
279 | XKB_GEOMETRY { $$ = FILE_TYPE_GEOMETRY; }
282 OptFlags : Flags { $$ = $1; }
286 Flags : Flags Flag { $$ = ($1 | $2); }
290 Flag : PARTIAL { $$ = MAP_IS_PARTIAL; }
291 | DEFAULT { $$ = MAP_IS_DEFAULT; }
292 | HIDDEN { $$ = MAP_IS_HIDDEN; }
293 | ALPHANUMERIC_KEYS { $$ = MAP_HAS_ALPHANUMERIC; }
294 | MODIFIER_KEYS { $$ = MAP_HAS_MODIFIER; }
295 | KEYPAD_KEYS { $$ = MAP_HAS_KEYPAD; }
296 | FUNCTION_KEYS { $$ = MAP_HAS_FN; }
297 | ALTERNATE_GROUP { $$ = MAP_IS_ALTGR; }
300 DeclList : DeclList Decl
301 { $$ = AppendStmt($1, $2); }
305 Decl : OptMergeMode VarDecl
308 $$ = (ParseCommon *) $2;
310 | OptMergeMode VModDecl
312 for (VModDef *vmod = $2; vmod; vmod = (VModDef *) vmod->common.next)
314 $$ = (ParseCommon *) $2;
316 | OptMergeMode InterpretDecl
319 $$ = (ParseCommon *) $2;
321 | OptMergeMode KeyNameDecl
324 $$ = (ParseCommon *) $2;
326 | OptMergeMode KeyAliasDecl
329 $$ = (ParseCommon *) $2;
331 | OptMergeMode KeyTypeDecl
334 $$ = (ParseCommon *) $2;
336 | OptMergeMode SymbolsDecl
339 $$ = (ParseCommon *) $2;
341 | OptMergeMode ModMapDecl
344 $$ = (ParseCommon *) $2;
346 | OptMergeMode GroupCompatDecl
349 $$ = (ParseCommon *) $2;
351 | OptMergeMode LedMapDecl
354 $$ = (ParseCommon *) $2;
356 | OptMergeMode LedNameDecl
359 $$ = (ParseCommon *) $2;
361 | OptMergeMode ShapeDecl { $$ = NULL; }
362 | OptMergeMode SectionDecl { $$ = NULL; }
363 | OptMergeMode DoodadDecl { $$ = NULL; }
366 $$ = (ParseCommon *) IncludeCreate(param->ctx, $2, $1);
371 VarDecl : Lhs EQUALS Expr SEMI
372 { $$ = VarCreate($1, $3); }
374 { $$ = BoolVarCreate($1, true); }
376 { $$ = BoolVarCreate($2, false); }
379 KeyNameDecl : KEYNAME EQUALS KeyCode SEMI
380 { $$ = KeycodeCreate($1, $3); }
383 KeyAliasDecl : ALIAS KEYNAME EQUALS KEYNAME SEMI
384 { $$ = KeyAliasCreate($2, $4); }
387 VModDecl : VIRTUAL_MODS VModDefList SEMI
391 VModDefList : VModDefList COMMA VModDef
392 { $$ = (VModDef *) AppendStmt((ParseCommon *) $1,
393 (ParseCommon *) $3); }
399 { $$ = VModCreate($1, NULL); }
401 { $$ = VModCreate($1, $3); }
404 InterpretDecl : INTERPRET InterpretMatch OBRACE
407 { $2->def = $4; $$ = $2; }
410 InterpretMatch : KeySym PLUS Expr
411 { $$ = InterpCreate($1, $3); }
413 { $$ = InterpCreate($1, NULL); }
416 VarDeclList : VarDeclList VarDecl
417 { $$ = (VarDef *) AppendStmt((ParseCommon *) $1,
418 (ParseCommon *) $2); }
423 KeyTypeDecl : TYPE String OBRACE
426 { $$ = KeyTypeCreate($2, $4); }
429 SymbolsDecl : KEY KEYNAME OBRACE
432 { $$ = SymbolsCreate($2, $4); }
435 SymbolsBody : SymbolsBody COMMA SymbolsVarDecl
436 { $$ = (VarDef *) AppendStmt((ParseCommon *) $1,
437 (ParseCommon *) $3); }
443 SymbolsVarDecl : Lhs EQUALS Expr { $$ = VarCreate($1, $3); }
444 | Lhs EQUALS ArrayInit { $$ = VarCreate($1, $3); }
445 | Ident { $$ = BoolVarCreate($1, true); }
446 | EXCLAM Ident { $$ = BoolVarCreate($2, false); }
447 | ArrayInit { $$ = VarCreate(NULL, $1); }
450 ArrayInit : OBRACKET OptKeySymList CBRACKET
452 | OBRACKET ActionList CBRACKET
453 { $$ = ExprCreateActionList($2); }
456 GroupCompatDecl : GROUP Integer EQUALS Expr SEMI
457 { $$ = GroupCompatCreate($2, $4); }
460 ModMapDecl : MODIFIER_MAP Ident OBRACE ExprList CBRACE SEMI
461 { $$ = ModMapCreate($2, $4); }
464 LedMapDecl: INDICATOR String OBRACE VarDeclList CBRACE SEMI
465 { $$ = LedMapCreate($2, $4); }
468 LedNameDecl: INDICATOR Integer EQUALS Expr SEMI
469 { $$ = LedNameCreate($2, $4, false); }
470 | VIRTUAL INDICATOR Integer EQUALS Expr SEMI
471 { $$ = LedNameCreate($3, $5, true); }
474 ShapeDecl : SHAPE String OBRACE OutlineList CBRACE SEMI
476 | SHAPE String OBRACE CoordList CBRACE SEMI
477 { (void) $4; $$ = NULL; }
480 SectionDecl : SECTION String OBRACE SectionBody CBRACE SEMI
484 SectionBody : SectionBody SectionBodyItem { $$ = NULL;}
485 | SectionBodyItem { $$ = NULL; }
488 SectionBodyItem : ROW OBRACE RowBody CBRACE SEMI
491 { FreeStmt((ParseCommon *) $1); $$ = NULL; }
495 { FreeStmt((ParseCommon *) $1); $$ = NULL; }
500 RowBody : RowBody RowBodyItem { $$ = NULL;}
501 | RowBodyItem { $$ = NULL; }
504 RowBodyItem : KEYS OBRACE Keys CBRACE SEMI { $$ = NULL; }
506 { FreeStmt((ParseCommon *) $1); $$ = NULL; }
509 Keys : Keys COMMA Key { $$ = NULL; }
515 | OBRACE ExprList CBRACE
516 { FreeStmt((ParseCommon *) $2); $$ = NULL; }
519 OverlayDecl : OVERLAY String OBRACE OverlayKeyList CBRACE SEMI
523 OverlayKeyList : OverlayKeyList COMMA OverlayKey { $$ = NULL; }
524 | OverlayKey { $$ = NULL; }
527 OverlayKey : KEYNAME EQUALS KEYNAME { $$ = NULL; }
530 OutlineList : OutlineList COMMA OutlineInList
536 OutlineInList : OBRACE CoordList CBRACE
537 { (void) $2; $$ = NULL; }
538 | Ident EQUALS OBRACE CoordList CBRACE
539 { (void) $4; $$ = NULL; }
541 { FreeStmt((ParseCommon *) $3); $$ = NULL; }
544 CoordList : CoordList COMMA Coord
545 { (void) $1; (void) $3; $$ = NULL; }
547 { (void) $1; $$ = NULL; }
550 Coord : OBRACKET SignedNumber COMMA SignedNumber CBRACKET
554 DoodadDecl : DoodadType String OBRACE VarDeclList CBRACE SEMI
555 { FreeStmt((ParseCommon *) $4); $$ = NULL; }
558 DoodadType : TEXT { $$ = 0; }
559 | OUTLINE { $$ = 0; }
564 FieldSpec : Ident { $$ = $1; }
565 | Element { $$ = $1; }
569 { $$ = xkb_atom_intern_literal(param->ctx, "action"); }
571 { $$ = xkb_atom_intern_literal(param->ctx, "interpret"); }
573 { $$ = xkb_atom_intern_literal(param->ctx, "type"); }
575 { $$ = xkb_atom_intern_literal(param->ctx, "key"); }
577 { $$ = xkb_atom_intern_literal(param->ctx, "group"); }
579 {$$ = xkb_atom_intern_literal(param->ctx, "modifier_map");}
581 { $$ = xkb_atom_intern_literal(param->ctx, "indicator"); }
583 { $$ = xkb_atom_intern_literal(param->ctx, "shape"); }
585 { $$ = xkb_atom_intern_literal(param->ctx, "row"); }
587 { $$ = xkb_atom_intern_literal(param->ctx, "section"); }
589 { $$ = xkb_atom_intern_literal(param->ctx, "text"); }
592 OptMergeMode : MergeMode { $$ = $1; }
593 | { $$ = MERGE_DEFAULT; }
596 MergeMode : INCLUDE { $$ = MERGE_DEFAULT; }
597 | AUGMENT { $$ = MERGE_AUGMENT; }
598 | OVERRIDE { $$ = MERGE_OVERRIDE; }
599 | REPLACE { $$ = MERGE_REPLACE; }
603 * This used to be MERGE_ALT_FORM. This functionality was
604 * unused and has been removed.
610 OptExprList : ExprList { $$ = $1; }
614 ExprList : ExprList COMMA Expr
615 { $$ = (ExprDef *) AppendStmt((ParseCommon *) $1,
616 (ParseCommon *) $3); }
621 Expr : Expr DIVIDE Expr
622 { $$ = ExprCreateBinary(EXPR_DIVIDE, $1, $3); }
624 { $$ = ExprCreateBinary(EXPR_ADD, $1, $3); }
626 { $$ = ExprCreateBinary(EXPR_SUBTRACT, $1, $3); }
628 { $$ = ExprCreateBinary(EXPR_MULTIPLY, $1, $3); }
630 { $$ = ExprCreateBinary(EXPR_ASSIGN, $1, $3); }
636 { $$ = ExprCreateUnary(EXPR_NEGATE, $2->expr.value_type, $2); }
638 { $$ = ExprCreateUnary(EXPR_UNARY_PLUS, $2->expr.value_type, $2); }
640 { $$ = ExprCreateUnary(EXPR_NOT, EXPR_TYPE_BOOLEAN, $2); }
642 { $$ = ExprCreateUnary(EXPR_INVERT, $2->expr.value_type, $2); }
645 | FieldSpec OPAREN OptExprList CPAREN %prec OPAREN
646 { $$ = ExprCreateAction($1, $3); }
653 ActionList : ActionList COMMA Action
654 { $$ = (ExprDef *) AppendStmt((ParseCommon *) $1,
655 (ParseCommon *) $3); }
660 Action : FieldSpec OPAREN OptExprList CPAREN
661 { $$ = ExprCreateAction($1, $3); }
665 { $$ = ExprCreateIdent($1); }
666 | FieldSpec DOT FieldSpec
667 { $$ = ExprCreateFieldRef($1, $3); }
668 | FieldSpec OBRACKET Expr CBRACKET
669 { $$ = ExprCreateArrayRef(XKB_ATOM_NONE, $1, $3); }
670 | FieldSpec DOT FieldSpec OBRACKET Expr CBRACKET
671 { $$ = ExprCreateArrayRef($1, $3, $5); }
675 { $$ = ExprCreateString($1); }
677 { $$ = ExprCreateInteger($1); }
679 { $$ = ExprCreateFloat(/* Discard $1 */); }
681 { $$ = ExprCreateKeyName($1); }
684 OptKeySymList : KeySymList { $$ = $1; }
688 KeySymList : KeySymList COMMA KeySym
689 { $$ = ExprAppendKeysymList($1, $3); }
690 | KeySymList COMMA KeySyms
691 { $$ = ExprAppendMultiKeysymList($1, $3); }
693 { $$ = ExprCreateKeysymList($1); }
695 { $$ = ExprCreateMultiKeysymList($1); }
698 KeySyms : OBRACE KeySymList CBRACE
704 if (!resolve_keysym($1, &$$))
705 parser_warn(param, "unrecognized keysym \"%s\"", $1);
708 | SECTION { $$ = XKB_KEY_section; }
712 parser_warn(param, "unrecognized keysym \"%d\"", $1);
713 $$ = XKB_KEY_NoSymbol;
715 else if ($1 < 10) { /* XKB_KEY_0 .. XKB_KEY_9 */
716 $$ = XKB_KEY_0 + (xkb_keysym_t) $1;
720 snprintf(buf, sizeof(buf), "0x%x", $1);
721 if (!resolve_keysym(buf, &$$)) {
722 parser_warn(param, "unrecognized keysym \"%s\"", buf);
723 $$ = XKB_KEY_NoSymbol;
729 SignedNumber : MINUS Number { $$ = -$2; }
730 | Number { $$ = $1; }
733 Number : FLOAT { $$ = $1; }
734 | INTEGER { $$ = $1; }
737 Float : FLOAT { $$ = 0; }
740 Integer : INTEGER { $$ = $1; }
743 KeyCode : INTEGER { $$ = $1; }
746 Ident : IDENT { $$ = xkb_atom_intern(param->ctx, $1, strlen($1)); free($1); }
747 | DEFAULT { $$ = xkb_atom_intern_literal(param->ctx, "default"); }
750 String : STRING { $$ = xkb_atom_intern(param->ctx, $1, strlen($1)); free($1); }
753 OptMapName : MapName { $$ = $1; }
757 MapName : STRING { $$ = $1; }
763 parse(struct xkb_context *ctx, struct scanner *scanner, const char *map)
766 XkbFile *first = NULL;
767 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);
811 "No map in include statement, but \"%s\" contains several; "
812 "Using first defined map, \"%s\"\n",
813 scanner->file_name, first->name);