Simplify parsing of numeric keysyms in parser.y
[platform/upstream/libxkbcommon.git] / src / xkbcomp / parser.y
index 90ac75e..d4f62c0 100644 (file)
 
  ********************************************************/
 
+/*
+ * The parser should work with reasonably recent versions of either
+ * bison or byacc.  So if you make changes, try to make sure it works
+ * in both!
+ */
+
 %{
-#include "xkbcomp-priv.h"
-#include "ast-build.h"
-#include "parser-priv.h"
+#include "config.h"
+
+#include "xkbcomp/xkbcomp-priv.h"
+#include "xkbcomp/ast-build.h"
+#include "xkbcomp/parser-priv.h"
+#include "scanner-utils.h"
+#include "keysym.h"
 
 struct parser_param {
     struct xkb_context *ctx;
-    void *scanner;
+    struct scanner *scanner;
     XkbFile *rtrn;
     bool more_maps;
 };
 
+#define parser_err(param, fmt, ...) \
+    scanner_err((param)->scanner, fmt, ##__VA_ARGS__)
+
+#define parser_warn(param, fmt, ...) \
+    scanner_warn((param)->scanner, fmt, ##__VA_ARGS__)
+
 static void
-_xkbcommon_error(struct YYLTYPE *loc, struct parser_param *param, const char *msg)
+_xkbcommon_error(struct parser_param *param, const char *msg)
 {
-    scanner_error(loc, param->scanner, msg);
+    parser_err(param, "%s", msg);
 }
 
-#define scanner param->scanner
+static bool
+resolve_keysym(const char *name, xkb_keysym_t *sym_rtrn)
+{
+    xkb_keysym_t sym;
+
+    if (!name || istreq(name, "any") || istreq(name, "nosymbol")) {
+        *sym_rtrn = XKB_KEY_NoSymbol;
+        return true;
+    }
+
+    if (istreq(name, "none") || istreq(name, "voidsymbol")) {
+        *sym_rtrn = XKB_KEY_VoidSymbol;
+        return true;
+    }
+
+    sym = xkb_keysym_from_name(name, XKB_KEYSYM_NO_FLAGS);
+    if (sym != XKB_KEY_NoSymbol) {
+        *sym_rtrn = sym;
+        return true;
+    }
+
+    return false;
+}
+
+#define param_scanner param->scanner
 %}
 
-%name-prefix    "_xkbcommon_"
-%define         api.pure
-%locations
-%lex-param      { void *scanner }
+%pure-parser
+%lex-param      { struct scanner *param_scanner }
 %parse-param    { struct parser_param *param }
 
 %token
@@ -125,18 +163,21 @@ _xkbcommon_error(struct YYLTYPE *loc, struct parser_param *param, const char *ms
 %start  XkbFile
 
 %union  {
-        int              ival;
-        unsigned         uval;
         int64_t          num;
         enum xkb_file_type file_type;
         char            *str;
-        xkb_atom_t      sval;
+        xkb_atom_t      atom;
         enum merge_mode merge;
         enum xkb_map_flags mapFlags;
+        xkb_keysym_t    keysym;
         ParseCommon     *any;
+        struct { ParseCommon *head; ParseCommon *last; } anyList;
         ExprDef         *expr;
+        struct { ExprDef *head; ExprDef *last; } exprList;
         VarDef          *var;
+        struct { VarDef *head; VarDef *last; } varList;
         VModDef         *vmod;
+        struct { VModDef *head; VModDef *last; } vmodList;
         InterpDef       *interp;
         KeyTypeDef      *keyType;
         SymbolsDef      *syms;
@@ -148,24 +189,28 @@ _xkbcommon_error(struct YYLTYPE *loc, struct parser_param *param, const char *ms
         KeyAliasDef     *keyAlias;
         void            *geom;
         XkbFile         *file;
+        struct { XkbFile *head; XkbFile *last; } fileList;
 }
 
 %type <num>     INTEGER FLOAT
 %type <str>     IDENT STRING
-%type <sval>    KEYNAME
-%type <num>     KeyCode
-%type <ival>    Number Integer Float SignedNumber
+%type <atom>    KEYNAME
+%type <num>     KeyCode Number Integer Float SignedNumber DoodadType
 %type <merge>   MergeMode OptMergeMode
 %type <file_type> XkbCompositeType FileType
-%type <uval>    DoodadType
 %type <mapFlags> Flag Flags OptFlags
-%type <str>     MapName OptMapName KeySym
-%type <sval>    FieldSpec Ident Element String
-%type <any>     DeclList Decl
-%type <expr>    OptExprList ExprList Expr Term Lhs Terminal ArrayInit KeySyms
-%type <expr>    OptKeySymList KeySymList Action ActionList Coord CoordList
-%type <var>     VarDecl VarDeclList SymbolsBody SymbolsVarDecl
-%type <vmod>    VModDecl VModDefList VModDef
+%type <str>     MapName OptMapName
+%type <atom>    FieldSpec Ident Element String
+%type <keysym>  KeySym
+%type <any>     Decl
+%type <anyList> DeclList
+%type <expr>    Expr Term Lhs Terminal ArrayInit KeySyms
+%type <expr>    OptKeySymList KeySymList Action Coord CoordList
+%type <exprList> OptExprList ExprList ActionList
+%type <var>     VarDecl SymbolsVarDecl
+%type <varList> VarDeclList SymbolsBody
+%type <vmod>    VModDef
+%type <vmodList> VModDefList VModDecl
 %type <interp>  InterpretDecl InterpretMatch
 %type <keyType> KeyTypeDecl
 %type <syms>    SymbolsDecl
@@ -178,9 +223,21 @@ _xkbcommon_error(struct YYLTYPE *loc, struct parser_param *param, const char *ms
 %type <geom>    ShapeDecl SectionDecl SectionBody SectionBodyItem RowBody RowBodyItem
 %type <geom>    Keys Key OverlayDecl OverlayKeyList OverlayKey OutlineList OutlineInList
 %type <geom>    DoodadDecl
-%type <file>    XkbFile XkbMapConfigList XkbMapConfig
+%type <file>    XkbFile XkbMapConfig
+%type <fileList> XkbMapConfigList
 %type <file>    XkbCompositeMap
 
+%destructor { FreeStmt((ParseCommon *) $$); }
+    <any> <expr> <var> <vmod> <interp> <keyType> <syms> <modMask> <groupCompat>
+    <ledMap> <ledName> <keyCode> <keyAlias>
+%destructor { FreeStmt((ParseCommon *) $$.head); }
+    <anyList> <exprList> <varList> <vmodList>
+/* The destructor also runs on the start symbol when the parser *succeeds*.
+ * The `if` here catches this case. */
+%destructor { if (!param->rtrn) FreeXkbFile($$); } <file>
+%destructor { FreeXkbFile($$.head); } <fileList>
+%destructor { free($$); } <str>
+
 %%
 
 /*
@@ -196,9 +253,9 @@ _xkbcommon_error(struct YYLTYPE *loc, struct parser_param *param, const char *ms
  */
 
 XkbFile         :       XkbCompositeMap
-                        { $$ = param->rtrn = $1; param->more_maps = true; }
+                        { $$ = param->rtrn = $1; param->more_maps = !!param->rtrn; }
                 |       XkbMapConfig
-                        { $$ = param->rtrn = $1; param->more_maps = true; YYACCEPT; }
+                        { $$ = param->rtrn = $1; param->more_maps = !!param->rtrn; YYACCEPT; }
                 |       END_OF_FILE
                         { $$ = param->rtrn = NULL; param->more_maps = false; }
                 ;
@@ -206,7 +263,7 @@ XkbFile         :       XkbCompositeMap
 XkbCompositeMap :       OptFlags XkbCompositeType OptMapName OBRACE
                             XkbMapConfigList
                         CBRACE SEMI
-                        { $$ = XkbFileCreate(param->ctx, $2, $3, &$5->common, $1); }
+                        { $$ = XkbFileCreate($2, $3, (ParseCommon *) $5.head, $1); }
                 ;
 
 XkbCompositeType:       XKB_KEYMAP      { $$ = FILE_TYPE_KEYMAP; }
@@ -215,28 +272,16 @@ XkbCompositeType:       XKB_KEYMAP      { $$ = FILE_TYPE_KEYMAP; }
                 ;
 
 XkbMapConfigList :      XkbMapConfigList XkbMapConfig
-                        {
-                            if (!$2)
-                                $$ = $1;
-                            else
-                                $$ = (XkbFile *)AppendStmt(&$1->common, &$2->common);
-                        }
+                        { $$.head = $1.head; $$.last->common.next = &$2->common; $$.last = $2; }
                 |       XkbMapConfig
-                        { $$ = $1; }
+                        { $$.head = $$.last = $1; }
                 ;
 
 XkbMapConfig    :       OptFlags FileType OptMapName OBRACE
                             DeclList
                         CBRACE SEMI
                         {
-                            if ($2 == FILE_TYPE_GEOMETRY) {
-                                free($3);
-                                FreeStmt($5);
-                                $$ = NULL;
-                            }
-                            else {
-                                $$ = XkbFileCreate(param->ctx, $2, $3, $5, $1);
-                            }
+                            $$ = XkbFileCreate($2, $3, $5.head, $1);
                         }
                 ;
 
@@ -266,71 +311,90 @@ Flag            :       PARTIAL                 { $$ = MAP_IS_PARTIAL; }
                 ;
 
 DeclList        :       DeclList Decl
-                        { $$ = AppendStmt($1, $2); }
-                |       { $$ = NULL; }
+                        {
+                            if ($2) {
+                                if ($1.head) {
+                                    $$.head = $1.head; $1.last->next = $2; $$.last = $2;
+                                } else {
+                                    $$.head = $$.last = $2;
+                                }
+                            }
+                        }
+                        /*
+                         * VModDecl is "inlined" directly into DeclList, i.e.
+                         * each VModDef in the VModDecl is a separate Decl in
+                         * the File.
+                         */
+                |       DeclList OptMergeMode VModDecl
+                        {
+                            for (VModDef *vmod = $3.head; vmod; vmod = (VModDef *) vmod->common.next)
+                                vmod->merge = $2;
+                            if ($1.head) {
+                                $$.head = $1.head; $1.last->next = &$3.head->common; $$.last = &$3.last->common;
+                            } else {
+                                $$.head = &$3.head->common; $$.last = &$3.last->common;
+                            }
+                        }
+                |       { $$.head = $$.last = NULL; }
                 ;
 
 Decl            :       OptMergeMode VarDecl
                         {
                             $2->merge = $1;
-                            $$ = &$2->common;
-                        }
-                |       OptMergeMode VModDecl
-                        {
-                            $2->merge = $1;
-                            $$ = &$2->common;
+                            $$ = (ParseCommon *) $2;
                         }
+                /*      OptMergeMode VModDecl - see above. */
                 |       OptMergeMode InterpretDecl
                         {
                             $2->merge = $1;
-                            $$ = &$2->common;
+                            $$ = (ParseCommon *) $2;
                         }
                 |       OptMergeMode KeyNameDecl
                         {
                             $2->merge = $1;
-                            $$ = &$2->common;
+                            $$ = (ParseCommon *) $2;
                         }
                 |       OptMergeMode KeyAliasDecl
                         {
                             $2->merge = $1;
-                            $$ = &$2->common;
+                            $$ = (ParseCommon *) $2;
                         }
                 |       OptMergeMode KeyTypeDecl
                         {
                             $2->merge = $1;
-                            $$ = &$2->common;
+                            $$ = (ParseCommon *) $2;
                         }
                 |       OptMergeMode SymbolsDecl
                         {
                             $2->merge = $1;
-                            $$ = &$2->common;
+                            $$ = (ParseCommon *) $2;
                         }
                 |       OptMergeMode ModMapDecl
                         {
                             $2->merge = $1;
-                            $$ = &$2->common;
+                            $$ = (ParseCommon *) $2;
                         }
                 |       OptMergeMode GroupCompatDecl
                         {
                             $2->merge = $1;
-                            $$ = &$2->common;
+                            $$ = (ParseCommon *) $2;
                         }
                 |       OptMergeMode LedMapDecl
                         {
                             $2->merge = $1;
-                            $$ = &$2->common;
+                            $$ = (ParseCommon *) $2;
                         }
                 |       OptMergeMode LedNameDecl
                         {
                             $2->merge = $1;
-                            $$ = &$2->common;
+                            $$ = (ParseCommon *) $2;
                         }
                 |       OptMergeMode ShapeDecl          { $$ = NULL; }
                 |       OptMergeMode SectionDecl        { $$ = NULL; }
                 |       OptMergeMode DoodadDecl         { $$ = NULL; }
                 |       MergeMode STRING
                         {
-                            $$ = &IncludeCreate(param->ctx, $2, $1)->common;
+                            $$ = (ParseCommon *) IncludeCreate(param->ctx, $2, $1);
                             free($2);
                         }
                 ;
@@ -338,9 +402,9 @@ Decl            :       OptMergeMode VarDecl
 VarDecl         :       Lhs EQUALS Expr SEMI
                         { $$ = VarCreate($1, $3); }
                 |       Ident SEMI
-                        { $$ = BoolVarCreate($1, 1); }
+                        { $$ = BoolVarCreate($1, true); }
                 |       EXCLAM Ident SEMI
-                        { $$ = BoolVarCreate($2, 0); }
+                        { $$ = BoolVarCreate($2, false); }
                 ;
 
 KeyNameDecl     :       KEYNAME EQUALS KeyCode SEMI
@@ -356,9 +420,9 @@ VModDecl        :       VIRTUAL_MODS VModDefList SEMI
                 ;
 
 VModDefList     :       VModDefList COMMA VModDef
-                        { $$ = (VModDef *)AppendStmt(&$1->common, &$3->common); }
+                        { $$.head = $1.head; $$.last->common.next = &$3->common; $$.last = $3; }
                 |       VModDef
-                        { $$ = $1; }
+                        { $$.head = $$.last = $1; }
                 ;
 
 VModDef         :       Ident
@@ -370,7 +434,7 @@ VModDef         :       Ident
 InterpretDecl   :       INTERPRET InterpretMatch OBRACE
                             VarDeclList
                         CBRACE SEMI
-                        { $2->def = $4; $$ = $2; }
+                        { $2->def = $4.head; $$ = $2; }
                 ;
 
 InterpretMatch  :       KeySym PLUS Expr
@@ -380,41 +444,41 @@ InterpretMatch  :       KeySym PLUS Expr
                 ;
 
 VarDeclList     :       VarDeclList VarDecl
-                        { $$ = (VarDef *)AppendStmt(&$1->common, &$2->common); }
+                        { $$.head = $1.head; $$.last->common.next = &$2->common; $$.last = $2; }
                 |       VarDecl
-                        { $$ = $1; }
+                        { $$.head = $$.last = $1; }
                 ;
 
 KeyTypeDecl     :       TYPE String OBRACE
                             VarDeclList
                         CBRACE SEMI
-                        { $$ = KeyTypeCreate($2, $4); }
+                        { $$ = KeyTypeCreate($2, $4.head); }
                 ;
 
 SymbolsDecl     :       KEY KEYNAME OBRACE
                             SymbolsBody
                         CBRACE SEMI
-                        { $$ = SymbolsCreate($2, (ExprDef *)$4); }
+                        { $$ = SymbolsCreate($2, $4.head); }
                 ;
 
 SymbolsBody     :       SymbolsBody COMMA SymbolsVarDecl
-                        { $$ = (VarDef *)AppendStmt(&$1->common, &$3->common); }
+                        { $$.head = $1.head; $$.last->common.next = &$3->common; $$.last = $3; }
                 |       SymbolsVarDecl
-                        { $$ = $1; }
-                |       { $$ = NULL; }
+                        { $$.head = $$.last = $1; }
+                |       { $$.head = $$.last = NULL; }
                 ;
 
 SymbolsVarDecl  :       Lhs EQUALS Expr         { $$ = VarCreate($1, $3); }
                 |       Lhs EQUALS ArrayInit    { $$ = VarCreate($1, $3); }
-                |       Ident                   { $$ = BoolVarCreate($1, 1); }
-                |       EXCLAM Ident            { $$ = BoolVarCreate($2, 0); }
+                |       Ident                   { $$ = BoolVarCreate($1, true); }
+                |       EXCLAM Ident            { $$ = BoolVarCreate($2, false); }
                 |       ArrayInit               { $$ = VarCreate(NULL, $1); }
                 ;
 
 ArrayInit       :       OBRACKET OptKeySymList CBRACKET
                         { $$ = $2; }
                 |       OBRACKET ActionList CBRACKET
-                        { $$ = ExprCreateUnary(EXPR_ACTION_LIST, EXPR_TYPE_ACTION, $2); }
+                        { $$ = ExprCreateActionList($2.head); }
                 ;
 
 GroupCompatDecl :       GROUP Integer EQUALS Expr SEMI
@@ -422,11 +486,11 @@ GroupCompatDecl :       GROUP Integer EQUALS Expr SEMI
                 ;
 
 ModMapDecl      :       MODIFIER_MAP Ident OBRACE ExprList CBRACE SEMI
-                        { $$ = ModMapCreate($2, $4); }
+                        { $$ = ModMapCreate($2, $4.head); }
                 ;
 
 LedMapDecl:             INDICATOR String OBRACE VarDeclList CBRACE SEMI
-                        { $$ = LedMapCreate($2, $4); }
+                        { $$ = LedMapCreate($2, $4.head); }
                 ;
 
 LedNameDecl:            INDICATOR Integer EQUALS Expr SEMI
@@ -438,7 +502,7 @@ LedNameDecl:            INDICATOR Integer EQUALS Expr SEMI
 ShapeDecl       :       SHAPE String OBRACE OutlineList CBRACE SEMI
                         { $$ = NULL; }
                 |       SHAPE String OBRACE CoordList CBRACE SEMI
-                        { $$ = NULL; }
+                        { (void) $4; $$ = NULL; }
                 ;
 
 SectionDecl     :       SECTION String OBRACE SectionBody CBRACE SEMI
@@ -452,11 +516,11 @@ SectionBody     :       SectionBody SectionBodyItem     { $$ = NULL;}
 SectionBodyItem :       ROW OBRACE RowBody CBRACE SEMI
                         { $$ = NULL; }
                 |       VarDecl
-                        { FreeStmt(&$1->common); $$ = NULL; }
+                        { FreeStmt((ParseCommon *) $1); $$ = NULL; }
                 |       DoodadDecl
                         { $$ = NULL; }
                 |       LedMapDecl
-                        { FreeStmt(&$1->common); $$ = NULL; }
+                        { FreeStmt((ParseCommon *) $1); $$ = NULL; }
                 |       OverlayDecl
                         { $$ = NULL; }
                 ;
@@ -467,7 +531,7 @@ RowBody         :       RowBody RowBodyItem     { $$ = NULL;}
 
 RowBodyItem     :       KEYS OBRACE Keys CBRACE SEMI { $$ = NULL; }
                 |       VarDecl
-                        { FreeStmt(&$1->common); $$ = NULL; }
+                        { FreeStmt((ParseCommon *) $1); $$ = NULL; }
                 ;
 
 Keys            :       Keys COMMA Key          { $$ = NULL; }
@@ -477,7 +541,7 @@ Keys            :       Keys COMMA Key          { $$ = NULL; }
 Key             :       KEYNAME
                         { $$ = NULL; }
                 |       OBRACE ExprList CBRACE
-                        { FreeStmt(&$2->common); $$ = NULL; }
+                        { FreeStmt((ParseCommon *) $2.head); $$ = NULL; }
                 ;
 
 OverlayDecl     :       OVERLAY String OBRACE OverlayKeyList CBRACE SEMI
@@ -498,17 +562,17 @@ OutlineList     :       OutlineList COMMA OutlineInList
                 ;
 
 OutlineInList   :       OBRACE CoordList CBRACE
-                        { $$ = NULL; }
+                        { (void) $2; $$ = NULL; }
                 |       Ident EQUALS OBRACE CoordList CBRACE
-                        { $$ = NULL; }
+                        { (void) $4; $$ = NULL; }
                 |       Ident EQUALS Expr
-                        { FreeStmt(&$3->common); $$ = NULL; }
+                        { FreeStmt((ParseCommon *) $3); $$ = NULL; }
                 ;
 
 CoordList       :       CoordList COMMA Coord
-                        { $$ = NULL; }
+                        { (void) $1; (void) $3; $$ = NULL; }
                 |       Coord
-                        { $$ = NULL; }
+                        { (void) $1; $$ = NULL; }
                 ;
 
 Coord           :       OBRACKET SignedNumber COMMA SignedNumber CBRACKET
@@ -516,7 +580,7 @@ Coord           :       OBRACKET SignedNumber COMMA SignedNumber CBRACKET
                 ;
 
 DoodadDecl      :       DoodadType String OBRACE VarDeclList CBRACE SEMI
-                        { FreeStmt(&$4->common); $$ = NULL; }
+                        { FreeStmt((ParseCommon *) $4.head); $$ = NULL; }
                 ;
 
 DoodadType      :       TEXT    { $$ = 0; }
@@ -530,27 +594,27 @@ FieldSpec       :       Ident   { $$ = $1; }
                 ;
 
 Element         :       ACTION_TOK
-                        { $$ = xkb_atom_intern(param->ctx, "action"); }
+                        { $$ = xkb_atom_intern_literal(param->ctx, "action"); }
                 |       INTERPRET
-                        { $$ = xkb_atom_intern(param->ctx, "interpret"); }
+                        { $$ = xkb_atom_intern_literal(param->ctx, "interpret"); }
                 |       TYPE
-                        { $$ = xkb_atom_intern(param->ctx, "type"); }
+                        { $$ = xkb_atom_intern_literal(param->ctx, "type"); }
                 |       KEY
-                        { $$ = xkb_atom_intern(param->ctx, "key"); }
+                        { $$ = xkb_atom_intern_literal(param->ctx, "key"); }
                 |       GROUP
-                        { $$ = xkb_atom_intern(param->ctx, "group"); }
+                        { $$ = xkb_atom_intern_literal(param->ctx, "group"); }
                 |       MODIFIER_MAP
-                        {$$ = xkb_atom_intern(param->ctx, "modifier_map");}
+                        {$$ = xkb_atom_intern_literal(param->ctx, "modifier_map");}
                 |       INDICATOR
-                        { $$ = xkb_atom_intern(param->ctx, "indicator"); }
+                        { $$ = xkb_atom_intern_literal(param->ctx, "indicator"); }
                 |       SHAPE
-                        { $$ = XKB_ATOM_NONE; }
+                        { $$ = xkb_atom_intern_literal(param->ctx, "shape"); }
                 |       ROW
-                        { $$ = XKB_ATOM_NONE; }
+                        { $$ = xkb_atom_intern_literal(param->ctx, "row"); }
                 |       SECTION
-                        { $$ = XKB_ATOM_NONE; }
+                        { $$ = xkb_atom_intern_literal(param->ctx, "section"); }
                 |       TEXT
-                        { $$ = XKB_ATOM_NONE; }
+                        { $$ = xkb_atom_intern_literal(param->ctx, "text"); }
                 ;
 
 OptMergeMode    :       MergeMode       { $$ = $1; }
@@ -572,13 +636,13 @@ MergeMode       :       INCLUDE         { $$ = MERGE_DEFAULT; }
                 ;
 
 OptExprList     :       ExprList        { $$ = $1; }
-                |                       { $$ = NULL; }
+                |                       { $$.head = $$.last = NULL; }
                 ;
 
 ExprList        :       ExprList COMMA Expr
-                        { $$ = (ExprDef *)AppendStmt(&$1->common, &$3->common); }
+                        { $$.head = $1.head; $$.last->common.next = &$3->common; $$.last = $3; }
                 |       Expr
-                        { $$ = $1; }
+                        { $$.head = $$.last = $1; }
                 ;
 
 Expr            :       Expr DIVIDE Expr
@@ -596,17 +660,17 @@ Expr            :       Expr DIVIDE Expr
                 ;
 
 Term            :       MINUS Term
-                        { $$ = ExprCreateUnary(EXPR_NEGATE, $2->value_type, $2); }
+                        { $$ = ExprCreateUnary(EXPR_NEGATE, $2->expr.value_type, $2); }
                 |       PLUS Term
-                        { $$ = ExprCreateUnary(EXPR_UNARY_PLUS, $2->value_type, $2); }
+                        { $$ = ExprCreateUnary(EXPR_UNARY_PLUS, $2->expr.value_type, $2); }
                 |       EXCLAM Term
                         { $$ = ExprCreateUnary(EXPR_NOT, EXPR_TYPE_BOOLEAN, $2); }
                 |       INVERT Term
-                        { $$ = ExprCreateUnary(EXPR_INVERT, $2->value_type, $2); }
+                        { $$ = ExprCreateUnary(EXPR_INVERT, $2->expr.value_type, $2); }
                 |       Lhs
                         { $$ = $1;  }
                 |       FieldSpec OPAREN OptExprList CPAREN %prec OPAREN
-                        { $$ = ActionCreate($1, $3); }
+                        { $$ = ExprCreateAction($1, $3.head); }
                 |       Terminal
                         { $$ = $1;  }
                 |       OPAREN Expr CPAREN
@@ -614,75 +678,33 @@ Term            :       MINUS Term
                 ;
 
 ActionList      :       ActionList COMMA Action
-                        { $$ = (ExprDef *)AppendStmt(&$1->common, &$3->common); }
+                        { $$.head = $1.head; $$.last->common.next = &$3->common; $$.last = $3; }
                 |       Action
-                        { $$ = $1; }
+                        { $$.head = $$.last = $1; }
                 ;
 
 Action          :       FieldSpec OPAREN OptExprList CPAREN
-                        { $$ = ActionCreate($1, $3); }
+                        { $$ = ExprCreateAction($1, $3.head); }
                 ;
 
 Lhs             :       FieldSpec
-                        {
-                            ExprDef *expr;
-                            expr = ExprCreate(EXPR_IDENT, EXPR_TYPE_UNKNOWN);
-                            expr->value.str = $1;
-                            $$ = expr;
-                        }
+                        { $$ = ExprCreateIdent($1); }
                 |       FieldSpec DOT FieldSpec
-                        {
-                            ExprDef *expr;
-                            expr = ExprCreate(EXPR_FIELD_REF, EXPR_TYPE_UNKNOWN);
-                            expr->value.field.element = $1;
-                            expr->value.field.field = $3;
-                            $$ = expr;
-                        }
+                        { $$ = ExprCreateFieldRef($1, $3); }
                 |       FieldSpec OBRACKET Expr CBRACKET
-                        {
-                            ExprDef *expr;
-                            expr = ExprCreate(EXPR_ARRAY_REF, EXPR_TYPE_UNKNOWN);
-                            expr->value.array.element = XKB_ATOM_NONE;
-                            expr->value.array.field = $1;
-                            expr->value.array.entry = $3;
-                            $$ = expr;
-                        }
+                        { $$ = ExprCreateArrayRef(XKB_ATOM_NONE, $1, $3); }
                 |       FieldSpec DOT FieldSpec OBRACKET Expr CBRACKET
-                        {
-                            ExprDef *expr;
-                            expr = ExprCreate(EXPR_ARRAY_REF, EXPR_TYPE_UNKNOWN);
-                            expr->value.array.element = $1;
-                            expr->value.array.field = $3;
-                            expr->value.array.entry = $5;
-                            $$ = expr;
-                        }
+                        { $$ = ExprCreateArrayRef($1, $3, $5); }
                 ;
 
 Terminal        :       String
-                        {
-                            ExprDef *expr;
-                            expr = ExprCreate(EXPR_VALUE, EXPR_TYPE_STRING);
-                            expr->value.str = $1;
-                            $$ = expr;
-                        }
+                        { $$ = ExprCreateString($1); }
                 |       Integer
-                        {
-                            ExprDef *expr;
-                            expr = ExprCreate(EXPR_VALUE, EXPR_TYPE_INT);
-                            expr->value.ival = $1;
-                            $$ = expr;
-                        }
+                        { $$ = ExprCreateInteger($1); }
                 |       Float
-                        {
-                            $$ = NULL;
-                        }
+                        { $$ = ExprCreateFloat(/* Discard $1 */); }
                 |       KEYNAME
-                        {
-                            ExprDef *expr;
-                            expr = ExprCreate(EXPR_VALUE, EXPR_TYPE_KEYNAME);
-                            expr->value.keyName = $1;
-                            $$ = expr;
-                        }
+                        { $$ = ExprCreateKeyName($1); }
                 ;
 
 OptKeySymList   :       KeySymList      { $$ = $1; }
@@ -690,31 +712,45 @@ OptKeySymList   :       KeySymList      { $$ = $1; }
                 ;
 
 KeySymList      :       KeySymList COMMA KeySym
-                        { $$ = AppendKeysymList($1, $3); }
+                        { $$ = ExprAppendKeysymList($1, $3); }
                 |       KeySymList COMMA KeySyms
-                        { $$ = AppendMultiKeysymList($1, $3); }
+                        { $$ = ExprAppendMultiKeysymList($1, $3); }
                 |       KeySym
-                        { $$ = CreateKeysymList($1); }
+                        { $$ = ExprCreateKeysymList($1); }
                 |       KeySyms
-                        { $$ = CreateMultiKeysymList($1); }
+                        { $$ = ExprCreateMultiKeysymList($1); }
                 ;
 
 KeySyms         :       OBRACE KeySymList CBRACE
                         { $$ = $2; }
                 ;
 
-KeySym          :       IDENT   { $$ = $1; }
-                |       SECTION { $$ = strdup("section"); }
+KeySym          :       IDENT
+                        {
+                            if (!resolve_keysym($1, &$$)) {
+                                parser_warn(param, "unrecognized keysym \"%s\"", $1);
+                                $$ = XKB_KEY_NoSymbol;
+                            }
+                            free($1);
+                        }
+                |       SECTION { $$ = XKB_KEY_section; }
                 |       Integer
                         {
-                            if ($1 < 10) {      /* XK_0 .. XK_9 */
-                                $$ = malloc(2);
-                                $$[0] = $1 + '0';
-                                $$[1] = '\0';
+                            if ($1 < XKB_KEYSYM_MIN) {
+                                parser_warn(param, "unrecognized keysym \"%"PRId64"\"", $1);
+                                $$ = XKB_KEY_NoSymbol;
+                            }
+                            /* Special case for digits 0..9 */
+                            else if ($1 < 10) {      /* XKB_KEY_0 .. XKB_KEY_9 */
+                                $$ = XKB_KEY_0 + (xkb_keysym_t) $1;
                             }
                             else {
-                                $$ = malloc(17);
-                                snprintf($$, 17, "0x%x", $1);
+                                if ($1 <= XKB_KEYSYM_MAX) {
+                                    $$ = (xkb_keysym_t) $1;
+                                } else {
+                                    parser_warn(param, "unrecognized keysym \"0x%"PRIx64"\"", $1);
+                                    $$ = XKB_KEY_NoSymbol;
+                                }
                             }
                         }
                 ;
@@ -736,11 +772,11 @@ Integer         :       INTEGER { $$ = $1; }
 KeyCode         :       INTEGER { $$ = $1; }
                 ;
 
-Ident           :       IDENT   { $$ = xkb_atom_steal(param->ctx, $1); }
-                |       DEFAULT { $$ = xkb_atom_intern(param->ctx, "default"); }
+Ident           :       IDENT   { $$ = xkb_atom_intern(param->ctx, $1, strlen($1)); free($1); }
+                |       DEFAULT { $$ = xkb_atom_intern_literal(param->ctx, "default"); }
                 ;
 
-String          :       STRING  { $$ = xkb_atom_steal(param->ctx, $1); }
+String          :       STRING  { $$ = xkb_atom_intern(param->ctx, $1, strlen($1)); free($1); }
                 ;
 
 OptMapName      :       MapName { $$ = $1; }
@@ -752,17 +788,17 @@ MapName         :       STRING  { $$ = $1; }
 
 %%
 
-#undef scanner
-
 XkbFile *
-parse(struct xkb_context *ctx, void *scanner, const char *map)
+parse(struct xkb_context *ctx, struct scanner *scanner, const char *map)
 {
-    struct parser_param param;
     int ret;
     XkbFile *first = NULL;
-
-    param.scanner = scanner;
-    param.ctx = ctx;
+    struct parser_param param = {
+        .scanner = scanner,
+        .ctx = ctx,
+        .rtrn = NULL,
+        .more_maps = false,
+    };
 
     /*
      * If we got a specific map, we look for it exclusively and return
@@ -791,6 +827,7 @@ parse(struct xkb_context *ctx, void *scanner, const char *map)
                 FreeXkbFile(param.rtrn);
             }
         }
+        param.rtrn = NULL;
     }
 
     if (ret != 0) {
@@ -798,5 +835,11 @@ parse(struct xkb_context *ctx, void *scanner, const char *map)
         return NULL;
     }
 
+    if (first)
+        log_vrb(ctx, 5,
+                "No map in include statement, but \"%s\" contains several; "
+                "Using first defined map, \"%s\"\n",
+                scanner->file_name, first->name);
+
     return first;
 }