blob: 7dcc46668d2e62e24a526d7a2d72029afd186de9 [file] [log] [blame]
/* parser.y
*
* This file is part of kbd project.
* Copyright (C) 1993 Risto Kankkunen.
* Copyright (C) 1993 Eugene G. Crosser.
* Copyright (C) 1994-2007 Andries E. Brouwer.
* Copyright (C) 2007-2013 Alexey Gladkov <gladkov.alexey@gmail.com>
*
* This file is covered by the GNU General Public License,
* which should be included with kbd as the file COPYING.
*/
%{
#define YY_HEADER_EXPORT_START_CONDITIONS 1
#include "nls.h"
#include "kbd.h"
#include "ksyms.h"
#include "modifiers.h"
#include "parser.h"
#include "analyze.h"
%}
%code requires {
#include "keymap.h"
#ifndef STRDATA_STRUCT
#define STRDATA_STRUCT
#define MAX_PARSER_STRING 512
struct strdata {
unsigned int len;
unsigned char data[MAX_PARSER_STRING];
};
#endif
}
%language "C"
%yacc
%defines
%debug
%error-verbose
/* Pure yylex. */
%define api.pure
%lex-param { yyscan_t scanner }
/* Pure yyparse. */
%parse-param { void *scanner }
%parse-param { struct lk_ctx *ctx }
%token EOL NUMBER LITERAL CHARSET KEYMAPS KEYCODE EQUALS
%token PLAIN SHIFT CONTROL ALT ALTGR SHIFTL SHIFTR CTRLL CTRLR CAPSSHIFT
%token COMMA DASH STRING STRLITERAL COMPOSE TO CCHAR ERROR PLUS
%token UNUMBER ALT_IS_META STRINGS AS USUAL ON FOR
%union {
long long int num;
struct strdata str;
}
%type <str> STRLITERAL
%type <num> CCHAR
%type <num> LITERAL
%type <num> NUMBER
%type <num> UNUMBER
%type <num> compsym
%type <num> rvalue
%{
static int
yyerror(yyscan_t scanner __attribute__ ((unused)),
struct lk_ctx *ctx, const char *s)
{
ERR(ctx, "%s", s);
return 0;
}
static int
strings_as_usual(struct lk_ctx *ctx)
{
/*
* 26 strings, mostly inspired by the VT100 family
*/
char *stringvalues[30] = {
/* F1 .. F20 */
"\033[[A", "\033[[B", "\033[[C", "\033[[D", "\033[[E",
"\033[17~", "\033[18~", "\033[19~", "\033[20~", "\033[21~",
"\033[23~", "\033[24~", "\033[25~", "\033[26~",
"\033[28~", "\033[29~",
"\033[31~", "\033[32~", "\033[33~", "\033[34~",
/* Find, Insert, Remove, Select, Prior */
"\033[1~", "\033[2~", "\033[3~", "\033[4~", "\033[5~",
/* Next, Macro, Help, Do, Pause */
"\033[6~", 0, 0, 0, 0
};
int i;
for (i = 0; i < 30; i++) {
if (stringvalues[i]) {
struct kbsentry ke;
ke.kb_func = i;
strncpy((char *)ke.kb_string, stringvalues[i],
sizeof(ke.kb_string));
ke.kb_string[sizeof(ke.kb_string) - 1] = 0;
if (lk_add_func(ctx, ke) == -1)
return -1;
}
}
return 0;
}
static int
compose_as_usual(struct lk_ctx *ctx, char *charset)
{
if (charset && strcmp(charset, "iso-8859-1")) {
ERR(ctx, _("loadkeys: don't know how to compose for %s"), charset);
return -1;
} else {
struct ccc {
unsigned char c1, c2, c3;
} def_latin1_composes[68] = {
{ '`', 'A', 0300 }, { '`', 'a', 0340 },
{ '\'', 'A', 0301 }, { '\'', 'a', 0341 },
{ '^', 'A', 0302 }, { '^', 'a', 0342 },
{ '~', 'A', 0303 }, { '~', 'a', 0343 },
{ '"', 'A', 0304 }, { '"', 'a', 0344 },
{ 'O', 'A', 0305 }, { 'o', 'a', 0345 },
{ '0', 'A', 0305 }, { '0', 'a', 0345 },
{ 'A', 'A', 0305 }, { 'a', 'a', 0345 },
{ 'A', 'E', 0306 }, { 'a', 'e', 0346 },
{ ',', 'C', 0307 }, { ',', 'c', 0347 },
{ '`', 'E', 0310 }, { '`', 'e', 0350 },
{ '\'', 'E', 0311 }, { '\'', 'e', 0351 },
{ '^', 'E', 0312 }, { '^', 'e', 0352 },
{ '"', 'E', 0313 }, { '"', 'e', 0353 },
{ '`', 'I', 0314 }, { '`', 'i', 0354 },
{ '\'', 'I', 0315 }, { '\'', 'i', 0355 },
{ '^', 'I', 0316 }, { '^', 'i', 0356 },
{ '"', 'I', 0317 }, { '"', 'i', 0357 },
{ '-', 'D', 0320 }, { '-', 'd', 0360 },
{ '~', 'N', 0321 }, { '~', 'n', 0361 },
{ '`', 'O', 0322 }, { '`', 'o', 0362 },
{ '\'', 'O', 0323 }, { '\'', 'o', 0363 },
{ '^', 'O', 0324 }, { '^', 'o', 0364 },
{ '~', 'O', 0325 }, { '~', 'o', 0365 },
{ '"', 'O', 0326 }, { '"', 'o', 0366 },
{ '/', 'O', 0330 }, { '/', 'o', 0370 },
{ '`', 'U', 0331 }, { '`', 'u', 0371 },
{ '\'', 'U', 0332 }, { '\'', 'u', 0372 },
{ '^', 'U', 0333 }, { '^', 'u', 0373 },
{ '"', 'U', 0334 }, { '"', 'u', 0374 },
{ '\'', 'Y', 0335 }, { '\'', 'y', 0375 },
{ 'T', 'H', 0336 }, { 't', 'h', 0376 },
{ 's', 's', 0337 }, { '"', 'y', 0377 },
{ 's', 'z', 0337 }, { 'i', 'j', 0377 }
};
int i;
for (i = 0; i < 68; i++) {
struct ccc ptr = def_latin1_composes[i];
if (lk_add_compose(ctx, ptr.c1, ptr.c2, ptr.c3) == -1)
return -1;
}
}
return 0;
}
%}
%%
keytable :
| keytable line
;
line : EOL
| charsetline
| altismetaline
| usualstringsline
| usualcomposeline
| keymapline
| fullline
| singleline
| strline
| compline
;
charsetline : CHARSET STRLITERAL EOL
{
if (lk_set_charset(ctx, (char *) $2.data)) {
ERR(ctx,
_("unknown charset %s - ignoring charset request\n"),
(char *) $2.data);
YYERROR;
}
ctx->keywords |= LK_KEYWORD_CHARSET;
/* Unicode: The first 256 code points were made
identical to the content of ISO 8859-1 */
if (ctx->flags & LK_FLAG_PREFER_UNICODE &&
!strcasecmp((char *) $2.data, "iso-8859-1"))
ctx->flags ^= LK_FLAG_PREFER_UNICODE;
}
;
altismetaline : ALT_IS_META EOL
{
ctx->keywords |= LK_KEYWORD_ALTISMETA;
}
;
usualstringsline: STRINGS AS USUAL EOL
{
if (strings_as_usual(ctx) == -1)
YYERROR;
ctx->keywords |= LK_KEYWORD_STRASUSUAL;
}
;
usualcomposeline: COMPOSE AS USUAL FOR STRLITERAL EOL
{
if (compose_as_usual(ctx, (char *) $5.data) == -1)
YYERROR;
}
| COMPOSE AS USUAL EOL
{
if (compose_as_usual(ctx, 0) == -1)
YYERROR;
}
;
keymapline : KEYMAPS range EOL
{
ctx->keywords |= LK_KEYWORD_KEYMAPS;
}
;
range : range COMMA range0
| range0
;
range0 : NUMBER DASH NUMBER
{
int i;
for (i = $1; i <= $3; i++) {
if (lk_add_map(ctx, i) == -1)
YYERROR;
}
}
| NUMBER
{
if (lk_add_map(ctx, $1) == -1)
YYERROR;
}
;
strline : STRING LITERAL EQUALS STRLITERAL EOL
{
struct kbsentry ke;
if (KTYP($2) != KT_FN) {
ERR(ctx, _("'%s' is not a function key symbol"),
syms[KTYP($2)].table[KVAL($2)]);
YYERROR;
}
ke.kb_func = KVAL($2);
strncpy((char *) ke.kb_string,
(char *) $4.data,
sizeof(ke.kb_string));
ke.kb_string[sizeof(ke.kb_string) - 1] = 0;
if (lk_add_func(ctx, ke) == -1)
YYERROR;
}
;
compline : COMPOSE compsym compsym TO compsym EOL
{
if (lk_add_compose(ctx, $2, $3, $5) == -1)
YYERROR;
}
| COMPOSE compsym compsym TO rvalue EOL
{
if (lk_add_compose(ctx, $2, $3, $5) == -1)
YYERROR;
}
;
compsym : CCHAR { $$ = $1; }
| UNUMBER { $$ = $1 ^ 0xf000; }
;
singleline : {
ctx->mod = 0;
}
modifiers KEYCODE NUMBER EQUALS rvalue EOL
{
if (lk_add_key(ctx, ctx->mod, $4, $6) < 0)
YYERROR;
}
| PLAIN KEYCODE NUMBER EQUALS rvalue EOL
{
if (lk_add_key(ctx, 0, $3, $5) < 0)
YYERROR;
}
;
modifiers : modifiers modifier
| modifier
;
modifier : SHIFT { ctx->mod |= M_SHIFT; }
| CONTROL { ctx->mod |= M_CTRL; }
| ALT { ctx->mod |= M_ALT; }
| ALTGR { ctx->mod |= M_ALTGR; }
| SHIFTL { ctx->mod |= M_SHIFTL; }
| SHIFTR { ctx->mod |= M_SHIFTR; }
| CTRLL { ctx->mod |= M_CTRLL; }
| CTRLR { ctx->mod |= M_CTRLR; }
| CAPSSHIFT { ctx->mod |= M_CAPSSHIFT; }
;
fullline : KEYCODE NUMBER EQUALS rvalue0 EOL
{
unsigned int j, i, keycode;
int *val;
if (ctx->key_line->count == 1) {
char one = 1;
/* Some files do not have a keymaps line, and
* we have to wait until all input has been read
* before we know which maps to fill. */
lk_array_set(ctx->key_constant, $2, &one);
/* On the other hand, we now have include files,
* and it should be possible to override lines
* from an include file. So, kill old defs. */
for (j = 0; j < ctx->keymap->total; j++) {
if (!lk_map_exists(ctx, j))
continue;
if (lk_del_key(ctx, j, $2) < 0)
YYERROR;
}
}
if (ctx->keywords & LK_KEYWORD_KEYMAPS) {
i = 0;
for (j = 0; j < ctx->keymap->total; j++) {
if (!lk_map_exists(ctx, j))
continue;
if (ctx->key_line->count != 1 || i == 0) {
keycode = K_HOLE;
if (i < ctx->key_line->count) {
val = lk_array_get(ctx->key_line, i);
keycode = *val;
}
if (lk_add_key(ctx, j, $2, keycode) < 0)
YYERROR;
}
i++;
}
if (i < ctx->key_line->count) {
ERR(ctx, _("too many (%d) entries on one line"),
ctx->key_line->count);
YYERROR;
}
} else {
for (i = 0; i < ctx->key_line->count; i++) {
val = lk_array_get(ctx->key_line, i);
if (lk_add_key(ctx, i, $2, *val) < 0)
YYERROR;
}
}
}
;
rvalue0 :
| rvalue1 rvalue0
;
rvalue1 : rvalue
{
int val = $1;
lk_array_append(ctx->key_line, &val);
}
;
rvalue : NUMBER { $$ = convert_code(ctx, $1, TO_AUTO); }
| PLUS NUMBER { $$ = add_capslock(ctx, $2); }
| UNUMBER { $$ = convert_code(ctx, $1^0xf000, TO_AUTO); }
| PLUS UNUMBER { $$ = add_capslock(ctx, $2^0xf000); }
| LITERAL { $$ = $1; }
| PLUS LITERAL { $$ = add_capslock(ctx, $2); }
;
%%
int
lk_parse_keymap(struct lk_ctx *ctx, lkfile_t *f)
{
yyscan_t scanner;
int rc = -1;
yylex_init(&scanner);
yylex_init_extra(ctx, &scanner);
INFO(ctx, _("Loading %s"), f->pathname);
if (stack_push(ctx, f, scanner) == -1)
goto fail;
if (yyparse(scanner, ctx))
goto fail;
rc = 0;
stack_pop(ctx, scanner);
fail: yylex_destroy(scanner);
return rc;
}