*/
%{
-#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;
bool more_maps;
};
-#define parser_err(param, fmt, ...) \
- scanner_err((param)->scanner, fmt, ##__VA_ARGS__)
+#define parser_err(param, error_id, fmt, ...) \
+ scanner_err_with_code((param)->scanner, error_id, fmt, ##__VA_ARGS__)
-#define parser_warn(param, fmt, ...) \
- scanner_warn((param)->scanner, fmt, ##__VA_ARGS__)
+#define parser_warn(param, warning_id, fmt, ...) \
+ scanner_warn_with_code((param)->scanner, warning_id, fmt, ##__VA_ARGS__)
static void
_xkbcommon_error(struct parser_param *param, const char *msg)
{
- parser_err(param, "%s", msg);
+ parser_err(param, XKB_ERROR_INVALID_SYNTAX, "%s", msg);
}
static bool
-resolve_keysym(const char *str, xkb_keysym_t *sym_rtrn)
+resolve_keysym(const char *name, xkb_keysym_t *sym_rtrn)
{
xkb_keysym_t sym;
- if (!str || istreq(str, "any") || istreq(str, "nosymbol")) {
+ if (!name || istreq(name, "any") || istreq(name, "nosymbol")) {
*sym_rtrn = XKB_KEY_NoSymbol;
return true;
}
- if (istreq(str, "none") || istreq(str, "voidsymbol")) {
+ if (istreq(name, "none") || istreq(name, "voidsymbol")) {
*sym_rtrn = XKB_KEY_VoidSymbol;
return true;
}
- sym = xkb_keysym_from_name(str, XKB_KEYSYM_NO_FLAGS);
+ sym = xkb_keysym_from_name(name, XKB_KEYSYM_NO_FLAGS);
if (sym != XKB_KEY_NoSymbol) {
*sym_rtrn = sym;
return true;
#define param_scanner param->scanner
%}
-%pure-parser
+%define api.pure
%lex-param { struct scanner *param_scanner }
%parse-param { struct parser_param *param }
%start XkbFile
%union {
- int ival;
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;
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 DoodadType
+%type <atom> KEYNAME
+%type <num> KeyCode Number Integer Float SignedNumber DoodadType
%type <merge> MergeMode OptMergeMode
%type <file_type> XkbCompositeType FileType
%type <mapFlags> Flag Flags OptFlags
%type <str> MapName OptMapName
-%type <sval> FieldSpec Ident Element String
+%type <atom> FieldSpec Ident Element String
%type <keysym> KeySym
-%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 <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
%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>
+
%%
/*
*/
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; }
;
XkbCompositeMap : OptFlags XkbCompositeType OptMapName OBRACE
XkbMapConfigList
CBRACE SEMI
- { $$ = XkbFileCreate($2, $3, (ParseCommon *) $5, $1); }
+ { $$ = XkbFileCreate($2, $3, (ParseCommon *) $5.head, $1); }
;
XkbCompositeType: XKB_KEYMAP { $$ = FILE_TYPE_KEYMAP; }
;
XkbMapConfigList : XkbMapConfigList XkbMapConfig
- {
- if (!$2)
- $$ = $1;
- else
- $$ = (XkbFile *) AppendStmt((ParseCommon *) $1,
- (ParseCommon *) $2);
- }
+ { $$.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($2, $3, $5, $1);
- }
+ $$ = XkbFileCreate($2, $3, $5.head, $1);
}
;
;
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;
$$ = (ParseCommon *) $2;
}
- | OptMergeMode VModDecl
- {
- $2->merge = $1;
- $$ = (ParseCommon *) $2;
- }
+ /* OptMergeMode VModDecl - see above. */
| OptMergeMode InterpretDecl
{
$2->merge = $1;
;
VModDefList : VModDefList COMMA VModDef
- { $$ = (VModDef *) AppendStmt((ParseCommon *) $1,
- (ParseCommon *) $3); }
+ { $$.head = $1.head; $$.last->common.next = &$3->common; $$.last = $3; }
| VModDef
- { $$ = $1; }
+ { $$.head = $$.last = $1; }
;
VModDef : Ident
InterpretDecl : INTERPRET InterpretMatch OBRACE
VarDeclList
CBRACE SEMI
- { $2->def = $4; $$ = $2; }
+ { $2->def = $4.head; $$ = $2; }
;
InterpretMatch : KeySym PLUS Expr
;
VarDeclList : VarDeclList VarDecl
- { $$ = (VarDef *) AppendStmt((ParseCommon *) $1,
- (ParseCommon *) $2); }
+ { $$.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, $4); }
+ { $$ = SymbolsCreate($2, $4.head); }
;
SymbolsBody : SymbolsBody COMMA SymbolsVarDecl
- { $$ = (VarDef *) AppendStmt((ParseCommon *) $1,
- (ParseCommon *) $3); }
+ { $$.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); }
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
;
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
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
Key : KEYNAME
{ $$ = NULL; }
| OBRACE ExprList CBRACE
- { FreeStmt((ParseCommon *) $2); $$ = NULL; }
+ { FreeStmt((ParseCommon *) $2.head); $$ = NULL; }
;
OverlayDecl : OVERLAY String OBRACE OverlayKeyList CBRACE SEMI
;
OutlineInList : OBRACE CoordList CBRACE
- { $$ = NULL; }
+ { (void) $2; $$ = NULL; }
| Ident EQUALS OBRACE CoordList CBRACE
- { $$ = NULL; }
+ { (void) $4; $$ = NULL; }
| Ident EQUALS Expr
{ 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
;
DoodadDecl : DoodadType String OBRACE VarDeclList CBRACE SEMI
- { FreeStmt((ParseCommon *) $4); $$ = NULL; }
+ { FreeStmt((ParseCommon *) $4.head); $$ = NULL; }
;
DoodadType : TEXT { $$ = 0; }
| 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; }
;
OptExprList : ExprList { $$ = $1; }
- | { $$ = NULL; }
+ | { $$.head = $$.last = NULL; }
;
ExprList : ExprList COMMA Expr
- { $$ = (ExprDef *) AppendStmt((ParseCommon *) $1,
- (ParseCommon *) $3); }
+ { $$.head = $1.head; $$.last->common.next = &$3->common; $$.last = $3; }
| Expr
- { $$ = $1; }
+ { $$.head = $$.last = $1; }
;
Expr : Expr DIVIDE Expr
| Lhs
{ $$ = $1; }
| FieldSpec OPAREN OptExprList CPAREN %prec OPAREN
- { $$ = ExprCreateAction($1, $3); }
+ { $$ = ExprCreateAction($1, $3.head); }
| Terminal
{ $$ = $1; }
| OPAREN Expr CPAREN
;
ActionList : ActionList COMMA Action
- { $$ = (ExprDef *) AppendStmt((ParseCommon *) $1,
- (ParseCommon *) $3); }
+ { $$.head = $1.head; $$.last->common.next = &$3->common; $$.last = $3; }
| Action
- { $$ = $1; }
+ { $$.head = $$.last = $1; }
;
Action : FieldSpec OPAREN OptExprList CPAREN
- { $$ = ExprCreateAction($1, $3); }
+ { $$ = ExprCreateAction($1, $3.head); }
;
Lhs : FieldSpec
| Integer
{ $$ = ExprCreateInteger($1); }
| Float
- { $$ = NULL; }
+ { $$ = ExprCreateFloat(/* Discard $1 */); }
| KEYNAME
{ $$ = ExprCreateKeyName($1); }
;
KeySym : IDENT
{
- if (!resolve_keysym($1, &$$))
- parser_warn(param, "unrecognized keysym \"%s\"", $1);
+ if (!resolve_keysym($1, &$$)) {
+ parser_warn(
+ param,
+ XKB_WARNING_UNRECOGNIZED_KEYSYM,
+ "unrecognized keysym \"%s\"",
+ $1
+ );
+ $$ = XKB_KEY_NoSymbol;
+ }
free($1);
}
| SECTION { $$ = XKB_KEY_section; }
| Integer
{
- if ($1 < 0) {
- parser_warn(param, "unrecognized keysym \"%d\"", $1);
+ if ($1 < XKB_KEYSYM_MIN) {
+ parser_warn(
+ param,
+ XKB_WARNING_UNRECOGNIZED_KEYSYM,
+ "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 {
- char buf[17];
- snprintf(buf, sizeof(buf), "0x%x", $1);
- if (!resolve_keysym(buf, &$$)) {
- parser_warn(param, "unrecognized keysym \"%s\"", buf);
+ if ($1 <= XKB_KEYSYM_MAX) {
+ $$ = (xkb_keysym_t) $1;
+ } else {
+ parser_warn(
+ param, XKB_WARNING_UNRECOGNIZED_KEYSYM,
+ "unrecognized keysym \"0x%"PRIx64"\" "
+ "(%"PRId64")", $1, $1
+ );
$$ = XKB_KEY_NoSymbol;
}
+ parser_warn(
+ param, XKB_WARNING_NUMERIC_KEYSYM,
+ "numeric keysym \"0x%"PRIx64"\" (%"PRId64")",
+ $1, $1
+ );
}
}
;
KeyCode : INTEGER { $$ = $1; }
;
-Ident : IDENT { $$ = xkb_atom_steal(param->ctx, $1); }
+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; }
struct parser_param param = {
.scanner = scanner,
.ctx = ctx,
+ .rtrn = NULL,
+ .more_maps = false,
};
/*
FreeXkbFile(param.rtrn);
}
}
+ param.rtrn = NULL;
}
if (ret != 0) {
return NULL;
}
+ if (first)
+ log_vrb(ctx, 5,
+ XKB_WARNING_MISSING_DEFAULT_SECTION,
+ "No map in include statement, but \"%s\" contains several; "
+ "Using first defined map, \"%s\"\n",
+ scanner->file_name, first->name);
+
return first;
}