Define our own NoSymbol value and use it
[platform/upstream/libxkbcommon.git] / src / xkbcomp / expr.c
1 /************************************************************
2  Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
3
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.
15
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.
24
25  ********************************************************/
26
27 #include "xkbcomp.h"
28 #include "xkbmisc.h"
29 #include "expr.h"
30 #include "vmod.h"
31
32 #include <ctype.h>
33
34 /***====================================================================***/
35
36 typedef Bool(*IdentLookupFunc) (const void * /* priv */ ,
37                                 xkb_atom_t /* field */ ,
38                                 unsigned /* type */ ,
39                                 ExprResult *    /* val_rtrn */
40     );
41
42 /***====================================================================***/
43
44 const char *
45 exprOpText(unsigned type)
46 {
47     static char buf[32];
48
49     switch (type)
50     {
51     case ExprValue:
52         strcpy(buf, "literal");
53         break;
54     case ExprIdent:
55         strcpy(buf, "identifier");
56         break;
57     case ExprActionDecl:
58         strcpy(buf, "action declaration");
59         break;
60     case ExprFieldRef:
61         strcpy(buf, "field reference");
62         break;
63     case ExprArrayRef:
64         strcpy(buf, "array reference");
65         break;
66     case ExprKeysymList:
67         strcpy(buf, "list of keysyms");
68         break;
69     case ExprActionList:
70         strcpy(buf, "list of actions");
71         break;
72     case OpAdd:
73         strcpy(buf, "addition");
74         break;
75     case OpSubtract:
76         strcpy(buf, "subtraction");
77         break;
78     case OpMultiply:
79         strcpy(buf, "multiplication");
80         break;
81     case OpDivide:
82         strcpy(buf, "division");
83         break;
84     case OpAssign:
85         strcpy(buf, "assignment");
86         break;
87     case OpNot:
88         strcpy(buf, "logical not");
89         break;
90     case OpNegate:
91         strcpy(buf, "arithmetic negation");
92         break;
93     case OpInvert:
94         strcpy(buf, "bitwise inversion");
95         break;
96     case OpUnaryPlus:
97         strcpy(buf, "plus sign");
98         break;
99     default:
100         snprintf(buf, sizeof(buf), "illegal(%d)", type);
101         break;
102     }
103     return buf;
104 }
105
106 static const char *
107 exprTypeText(unsigned type)
108 {
109     static char buf[20];
110
111     switch (type)
112     {
113     case TypeUnknown:
114         strcpy(buf, "unknown");
115         break;
116     case TypeBoolean:
117         strcpy(buf, "boolean");
118         break;
119     case TypeInt:
120         strcpy(buf, "int");
121         break;
122     case TypeString:
123         strcpy(buf, "string");
124         break;
125     case TypeAction:
126         strcpy(buf, "action");
127         break;
128     case TypeKeyName:
129         strcpy(buf, "keyname");
130         break;
131     default:
132         snprintf(buf, sizeof(buf), "illegal(%d)", type);
133         break;
134     }
135     return buf;
136 }
137
138 int
139 ExprResolveLhs(ExprDef * expr,
140                ExprResult * elem_rtrn,
141                ExprResult * field_rtrn, ExprDef ** index_rtrn)
142 {
143     switch (expr->op)
144     {
145     case ExprIdent:
146         elem_rtrn->str = NULL;
147         field_rtrn->str = XkbcAtomGetString(expr->value.str);
148         *index_rtrn = NULL;
149         return True;
150     case ExprFieldRef:
151         elem_rtrn->str = XkbcAtomGetString(expr->value.field.element);
152         field_rtrn->str = XkbcAtomGetString(expr->value.field.field);
153         *index_rtrn = NULL;
154         return True;
155     case ExprArrayRef:
156         elem_rtrn->str = XkbcAtomGetString(expr->value.array.element);
157         field_rtrn->str = XkbcAtomGetString(expr->value.array.field);
158         *index_rtrn = expr->value.array.entry;
159         return True;
160     }
161     WSGO("Unexpected operator %d in ResolveLhs\n", expr->op);
162     return False;
163 }
164
165 static Bool
166 SimpleLookup(const void * priv, xkb_atom_t field, unsigned type,
167              ExprResult * val_rtrn)
168 {
169     const LookupEntry *entry;
170     const char *str;
171
172     if ((priv == NULL) || (field == XKB_ATOM_NONE) || (type != TypeInt))
173     {
174         return False;
175     }
176     str = XkbcAtomText(field);
177     for (entry = priv; (entry != NULL) && (entry->name != NULL); entry++)
178     {
179         if (strcasecmp(str, entry->name) == 0)
180         {
181             val_rtrn->uval = entry->result;
182             return True;
183         }
184     }
185     return False;
186 }
187
188 static const LookupEntry modIndexNames[] = {
189     {"shift", ShiftMapIndex},
190     {"control", ControlMapIndex},
191     {"lock", LockMapIndex},
192     {"mod1", Mod1MapIndex},
193     {"mod2", Mod2MapIndex},
194     {"mod3", Mod3MapIndex},
195     {"mod4", Mod4MapIndex},
196     {"mod5", Mod5MapIndex},
197     {"none", XkbNoModifier},
198     {NULL, 0}
199 };
200
201 int
202 LookupModIndex(const void * priv, xkb_atom_t field, unsigned type,
203                ExprResult * val_rtrn)
204 {
205     return SimpleLookup(modIndexNames, field, type, val_rtrn);
206 }
207
208 int
209 LookupModMask(const void * priv, xkb_atom_t field, unsigned type,
210               ExprResult * val_rtrn)
211 {
212     const char *str;
213     Bool ret = True;
214
215     if (type != TypeInt)
216         return False;
217     str = XkbcAtomText(field);
218     if (str == NULL)
219         return False;
220     if (strcasecmp(str, "all") == 0)
221         val_rtrn->uval = 0xff;
222     else if (strcasecmp(str, "none") == 0)
223         val_rtrn->uval = 0;
224     else if (LookupModIndex(priv, field, type, val_rtrn))
225         val_rtrn->uval = (1 << val_rtrn->uval);
226     else
227         ret = False;
228     return ret;
229 }
230
231 int
232 ExprResolveBoolean(ExprDef * expr,
233                    ExprResult * val_rtrn)
234 {
235     int ok = 0;
236     const char *bogus = NULL;
237
238     switch (expr->op)
239     {
240     case ExprValue:
241         if (expr->type != TypeBoolean)
242         {
243             ERROR
244                 ("Found constant of type %s where boolean was expected\n",
245                  exprTypeText(expr->type));
246             return False;
247         }
248         val_rtrn->ival = expr->value.ival;
249         return True;
250     case ExprIdent:
251         bogus = XkbcAtomText(expr->value.str);
252         if (bogus)
253         {
254             if ((strcasecmp(bogus, "true") == 0) ||
255                 (strcasecmp(bogus, "yes") == 0) ||
256                 (strcasecmp(bogus, "on") == 0))
257             {
258                 val_rtrn->uval = 1;
259                 return True;
260             }
261             else if ((strcasecmp(bogus, "false") == 0) ||
262                      (strcasecmp(bogus, "no") == 0) ||
263                      (strcasecmp(bogus, "off") == 0))
264             {
265                 val_rtrn->uval = 0;
266                 return True;
267             }
268         }
269         ERROR("Identifier \"%s\" of type int is unknown\n",
270               XkbcAtomText(expr->value.str));
271         return False;
272     case ExprFieldRef:
273         ERROR("Default \"%s.%s\" of type boolean is unknown\n",
274               XkbcAtomText(expr->value.field.element),
275               XkbcAtomText(expr->value.field.field));
276         return False;
277     case OpInvert:
278     case OpNot:
279         ok = ExprResolveBoolean(expr, val_rtrn);
280         if (ok)
281             val_rtrn->uval = !val_rtrn->uval;
282         return ok;
283     case OpAdd:
284         if (bogus == NULL)
285             bogus = "Addition";
286     case OpSubtract:
287         if (bogus == NULL)
288             bogus = "Subtraction";
289     case OpMultiply:
290         if (bogus == NULL)
291             bogus = "Multiplication";
292     case OpDivide:
293         if (bogus == NULL)
294             bogus = "Division";
295     case OpAssign:
296         if (bogus == NULL)
297             bogus = "Assignment";
298     case OpNegate:
299         if (bogus == NULL)
300             bogus = "Negation";
301         ERROR("%s of boolean values not permitted\n", bogus);
302         break;
303     case OpUnaryPlus:
304         ERROR("Unary \"+\" operator not permitted for boolean values\n");
305         break;
306     default:
307         WSGO("Unknown operator %d in ResolveBoolean\n", expr->op);
308         break;
309     }
310     return False;
311 }
312
313 int
314 ExprResolveFloat(ExprDef * expr,
315                  ExprResult * val_rtrn)
316 {
317     int ok = 0;
318     ExprResult leftRtrn, rightRtrn;
319     ExprDef *left, *right;
320
321     switch (expr->op)
322     {
323     case ExprValue:
324         if (expr->type == TypeString)
325         {
326             const char *str;
327             str = XkbcAtomText(expr->value.str);
328             if ((str != NULL) && (strlen(str) == 1))
329             {
330                 val_rtrn->uval = str[0] * XkbGeomPtsPerMM;
331                 return True;
332             }
333         }
334         if (expr->type != TypeInt)
335         {
336             ERROR("Found constant of type %s, expected a number\n",
337                    exprTypeText(expr->type));
338             return False;
339         }
340         val_rtrn->ival = expr->value.ival;
341         if (expr->type == TypeInt)
342             val_rtrn->ival *= XkbGeomPtsPerMM;
343         return True;
344     case ExprIdent:
345         ERROR("Numeric identifier \"%s\" unknown\n",
346               XkbcAtomText(expr->value.str));
347         return ok;
348     case ExprFieldRef:
349         ERROR("Numeric default \"%s.%s\" unknown\n",
350               XkbcAtomText(expr->value.field.element),
351               XkbcAtomText(expr->value.field.field));
352         return False;
353     case OpAdd:
354     case OpSubtract:
355     case OpMultiply:
356     case OpDivide:
357         left = expr->value.binary.left;
358         right = expr->value.binary.right;
359         if (ExprResolveFloat(left, &leftRtrn) &&
360             ExprResolveFloat(right, &rightRtrn))
361         {
362             switch (expr->op)
363             {
364             case OpAdd:
365                 val_rtrn->ival = leftRtrn.ival + rightRtrn.ival;
366                 break;
367             case OpSubtract:
368                 val_rtrn->ival = leftRtrn.ival - rightRtrn.ival;
369                 break;
370             case OpMultiply:
371                 val_rtrn->ival = leftRtrn.ival * rightRtrn.ival;
372                 break;
373             case OpDivide:
374                 val_rtrn->ival = leftRtrn.ival / rightRtrn.ival;
375                 break;
376             }
377             return True;
378         }
379         return False;
380     case OpAssign:
381         WSGO("Assignment operator not implemented yet\n");
382         break;
383     case OpNot:
384         ERROR("The ! operator cannot be applied to a number\n");
385         return False;
386     case OpInvert:
387     case OpNegate:
388         left = expr->value.child;
389         if (ExprResolveFloat(left, &leftRtrn))
390         {
391             if (expr->op == OpNegate)
392                 val_rtrn->ival = -leftRtrn.ival;
393             else
394                 val_rtrn->ival = ~leftRtrn.ival;
395             return True;
396         }
397         return False;
398     case OpUnaryPlus:
399         left = expr->value.child;
400         return ExprResolveFloat(left, val_rtrn);
401     default:
402         WSGO("Unknown operator %d in ResolveFloat\n", expr->op);
403         break;
404     }
405     return False;
406 }
407
408 int
409 ExprResolveKeyCode(ExprDef * expr,
410                    ExprResult * val_rtrn)
411 {
412     ExprResult leftRtrn, rightRtrn;
413     ExprDef *left, *right;
414
415     switch (expr->op)
416     {
417     case ExprValue:
418         if (expr->type != TypeInt)
419         {
420             ERROR
421                 ("Found constant of type %s where an int was expected\n",
422                  exprTypeText(expr->type));
423             return False;
424         }
425         val_rtrn->uval = expr->value.uval;
426         return True;
427     case OpAdd:
428     case OpSubtract:
429     case OpMultiply:
430     case OpDivide:
431         left = expr->value.binary.left;
432         right = expr->value.binary.right;
433         if (ExprResolveKeyCode(left, &leftRtrn) &&
434             ExprResolveKeyCode(right, &rightRtrn))
435         {
436             switch (expr->op)
437             {
438             case OpAdd:
439                 val_rtrn->uval = leftRtrn.uval + rightRtrn.uval;
440                 break;
441             case OpSubtract:
442                 val_rtrn->uval = leftRtrn.uval - rightRtrn.uval;
443                 break;
444             case OpMultiply:
445                 val_rtrn->uval = leftRtrn.uval * rightRtrn.uval;
446                 break;
447             case OpDivide:
448                 val_rtrn->uval = leftRtrn.uval / rightRtrn.uval;
449                 break;
450             }
451             return True;
452         }
453         return False;
454     case OpNegate:
455         left = expr->value.child;
456         if (ExprResolveKeyCode(left, &leftRtrn))
457         {
458             val_rtrn->uval = ~leftRtrn.uval;
459             return True;
460         }
461         return False;
462     case OpUnaryPlus:
463         left = expr->value.child;
464         return ExprResolveKeyCode(left, val_rtrn);
465     default:
466         WSGO("Unknown operator %d in ResolveKeyCode\n", expr->op);
467         break;
468     }
469     return False;
470 }
471
472 /**
473  * This function returns ... something.  It's a bit of a guess, really.
474  *
475  * If a string is given in value context, its first character will be
476  * returned in uval.  If an integer is given in value context, it will be
477  * returned in ival.  If a float is given in value context, it will be
478  * returned as millimetres (rather than points) in ival.
479  *
480  * If an ident or field reference is given, the lookup function (if given)
481  * will be called.  At the moment, only SimpleLookup use this, and they both
482  * return the results in uval.  And don't support field references.
483  *
484  * Cool.
485  */
486 static int
487 ExprResolveIntegerLookup(ExprDef * expr,
488                          ExprResult * val_rtrn,
489                          IdentLookupFunc lookup, const void * lookupPriv)
490 {
491     int ok = 0;
492     ExprResult leftRtrn, rightRtrn;
493     ExprDef *left, *right;
494
495     switch (expr->op)
496     {
497     case ExprValue:
498         if (expr->type == TypeString)
499         {
500             const char *str;
501             str = XkbcAtomText(expr->value.str);
502             if (str != NULL)
503                 switch (strlen(str))
504                 {
505                 case 0:
506                     val_rtrn->uval = 0;
507                     return True;
508                 case 1:
509                     val_rtrn->uval = str[0];
510                     return True;
511                 default:
512                     break;
513                 }
514         }
515         if (expr->type != TypeInt)
516         {
517             ERROR
518                 ("Found constant of type %s where an int was expected\n",
519                  exprTypeText(expr->type));
520             return False;
521         }
522         val_rtrn->ival = expr->value.ival;
523         return True;
524     case ExprIdent:
525         if (lookup)
526         {
527             ok = (*lookup) (lookupPriv, expr->value.str, TypeInt, val_rtrn);
528         }
529         if (!ok)
530             ERROR("Identifier \"%s\" of type int is unknown\n",
531                    XkbcAtomText(expr->value.str));
532         return ok;
533     case ExprFieldRef:
534         ERROR("Default \"%s.%s\" of type int is unknown\n",
535               XkbcAtomText(expr->value.field.element),
536               XkbcAtomText(expr->value.field.field));
537         return False;
538     case OpAdd:
539     case OpSubtract:
540     case OpMultiply:
541     case OpDivide:
542         left = expr->value.binary.left;
543         right = expr->value.binary.right;
544         if (ExprResolveIntegerLookup(left, &leftRtrn, lookup, lookupPriv) &&
545             ExprResolveIntegerLookup(right, &rightRtrn, lookup, lookupPriv))
546         {
547             switch (expr->op)
548             {
549             case OpAdd:
550                 val_rtrn->ival = leftRtrn.ival + rightRtrn.ival;
551                 break;
552             case OpSubtract:
553                 val_rtrn->ival = leftRtrn.ival - rightRtrn.ival;
554                 break;
555             case OpMultiply:
556                 val_rtrn->ival = leftRtrn.ival * rightRtrn.ival;
557                 break;
558             case OpDivide:
559                 val_rtrn->ival = leftRtrn.ival / rightRtrn.ival;
560                 break;
561             }
562             return True;
563         }
564         return False;
565     case OpAssign:
566         WSGO("Assignment operator not implemented yet\n");
567         break;
568     case OpNot:
569         ERROR("The ! operator cannot be applied to an integer\n");
570         return False;
571     case OpInvert:
572     case OpNegate:
573         left = expr->value.child;
574         if (ExprResolveIntegerLookup(left, &leftRtrn, lookup, lookupPriv))
575         {
576             if (expr->op == OpNegate)
577                 val_rtrn->ival = -leftRtrn.ival;
578             else
579                 val_rtrn->ival = ~leftRtrn.ival;
580             return True;
581         }
582         return False;
583     case OpUnaryPlus:
584         left = expr->value.child;
585         return ExprResolveIntegerLookup(left, val_rtrn, lookup, lookupPriv);
586     default:
587         WSGO("Unknown operator %d in ResolveInteger\n", expr->op);
588         break;
589     }
590     return False;
591 }
592
593 int
594 ExprResolveInteger(ExprDef * expr,
595                    ExprResult * val_rtrn)
596 {
597     return ExprResolveIntegerLookup(expr, val_rtrn, NULL, NULL);
598 }
599
600 int
601 ExprResolveGroup(ExprDef * expr,
602                  ExprResult * val_rtrn)
603 {
604     int ret;
605     static const LookupEntry group_names[] = {
606         { "group1", 1 },
607         { "group2", 2 },
608         { "group3", 3 },
609         { "group4", 4 },
610         { "group5", 5 },
611         { "group6", 6 },
612         { "group7", 7 },
613         { "group8", 8 },
614         { NULL, 0 }
615     };
616
617     ret = ExprResolveIntegerLookup(expr, val_rtrn, SimpleLookup, group_names);
618     if (ret == False)
619         return ret;
620
621     if (val_rtrn->uval == 0 || val_rtrn->uval > XkbNumKbdGroups) {
622         ERROR("Group index %d is out of range (1..%d)\n",
623               val_rtrn->uval, XkbNumKbdGroups);
624         return False;
625     }
626
627     return True;
628 }
629
630 int
631 ExprResolveLevel(ExprDef * expr,
632                  ExprResult * val_rtrn)
633 {
634     int ret;
635     static const LookupEntry level_names[] = {
636         { "level1", 1 },
637         { "level2", 2 },
638         { "level3", 3 },
639         { "level4", 4 },
640         { "level5", 5 },
641         { "level6", 6 },
642         { "level7", 7 },
643         { "level8", 8 },
644         { NULL, 0 }
645     };
646
647     ret = ExprResolveIntegerLookup(expr, val_rtrn, SimpleLookup, level_names);
648     if (ret == False)
649         return ret;
650
651     if (val_rtrn->ival < 1 || val_rtrn->ival > XkbMaxShiftLevel) {
652         ERROR("Shift level %d is out of range (1..%d)\n", val_rtrn->ival,
653               XkbMaxShiftLevel);
654         return False;
655     }
656
657     return True;
658 }
659
660 int
661 ExprResolveButton(ExprDef * expr,
662                   ExprResult * val_rtrn)
663 {
664     static const LookupEntry button_names[] = {
665         { "button1", 1 },
666         { "button2", 2 },
667         { "button3", 3 },
668         { "button4", 4 },
669         { "button5", 5 },
670         { "default", 0 },
671         { NULL, 0 }
672     };
673
674     return ExprResolveIntegerLookup(expr, val_rtrn, SimpleLookup,
675                                     button_names);
676 }
677
678 int
679 ExprResolveString(ExprDef * expr,
680                   ExprResult * val_rtrn)
681 {
682     ExprResult leftRtrn, rightRtrn;
683     ExprDef *left;
684     ExprDef *right;
685     const char *bogus = NULL;
686
687     switch (expr->op)
688     {
689     case ExprValue:
690         if (expr->type != TypeString)
691         {
692             ERROR("Found constant of type %s, expected a string\n",
693                    exprTypeText(expr->type));
694             return False;
695         }
696         val_rtrn->str = XkbcAtomGetString(expr->value.str);
697         if (val_rtrn->str == NULL)
698             val_rtrn->str = strdup("");
699         return True;
700     case ExprIdent:
701         ERROR("Identifier \"%s\" of type string not found\n",
702               XkbcAtomText(expr->value.str));
703         return False;
704     case ExprFieldRef:
705         ERROR("Default \"%s.%s\" of type string not found\n",
706               XkbcAtomText(expr->value.field.element),
707               XkbcAtomText(expr->value.field.field));
708         return False;
709     case OpAdd:
710         left = expr->value.binary.left;
711         right = expr->value.binary.right;
712         if (ExprResolveString(left, &leftRtrn) &&
713             ExprResolveString(right, &rightRtrn))
714         {
715             int len;
716             char *new;
717             len = strlen(leftRtrn.str) + strlen(rightRtrn.str) + 1;
718             new = malloc(len);
719             if (new)
720             { sprintf(new, "%s%s", leftRtrn.str, rightRtrn.str);
721                 free(leftRtrn.str);
722                 free(rightRtrn.str);
723                 val_rtrn->str = new;
724                 return True;
725             }
726             free(leftRtrn.str);
727             free(rightRtrn.str);
728         }
729         return False;
730     case OpSubtract:
731         if (bogus == NULL)
732             bogus = "Subtraction";
733     case OpMultiply:
734         if (bogus == NULL)
735             bogus = "Multiplication";
736     case OpDivide:
737         if (bogus == NULL)
738             bogus = "Division";
739     case OpAssign:
740         if (bogus == NULL)
741             bogus = "Assignment";
742     case OpNegate:
743         if (bogus == NULL)
744             bogus = "Negation";
745     case OpInvert:
746         if (bogus == NULL)
747             bogus = "Bitwise complement";
748         ERROR("%s of string values not permitted\n", bogus);
749         return False;
750     case OpNot:
751         ERROR("The ! operator cannot be applied to a string\n");
752         return False;
753     case OpUnaryPlus:
754         ERROR("The + operator cannot be applied to a string\n");
755         return False;
756     default:
757         WSGO("Unknown operator %d in ResolveString\n", expr->op);
758         break;
759     }
760     return False;
761 }
762
763 int
764 ExprResolveKeyName(ExprDef * expr,
765                    ExprResult * val_rtrn)
766 {
767     const char *bogus = NULL;
768
769     switch (expr->op)
770     {
771     case ExprValue:
772         if (expr->type != TypeKeyName)
773         {
774             ERROR("Found constant of type %s, expected a key name\n",
775                    exprTypeText(expr->type));
776             return False;
777         }
778         memcpy(val_rtrn->keyName.name, expr->value.keyName, XkbKeyNameLength);
779         return True;
780     case ExprIdent:
781         ERROR("Identifier \"%s\" of type string not found\n",
782               XkbcAtomText(expr->value.str));
783         return False;
784     case ExprFieldRef:
785         ERROR("Default \"%s.%s\" of type key name not found\n",
786               XkbcAtomText(expr->value.field.element),
787               XkbcAtomText(expr->value.field.field));
788         return False;
789     case OpAdd:
790         if (bogus == NULL)
791             bogus = "Addition";
792     case OpSubtract:
793         if (bogus == NULL)
794             bogus = "Subtraction";
795     case OpMultiply:
796         if (bogus == NULL)
797             bogus = "Multiplication";
798     case OpDivide:
799         if (bogus == NULL)
800             bogus = "Division";
801     case OpAssign:
802         if (bogus == NULL)
803             bogus = "Assignment";
804     case OpNegate:
805         if (bogus == NULL)
806             bogus = "Negation";
807     case OpInvert:
808         if (bogus == NULL)
809             bogus = "Bitwise complement";
810         ERROR("%s of key name values not permitted\n", bogus);
811         return False;
812     case OpNot:
813         ERROR("The ! operator cannot be applied to a key name\n");
814         return False;
815     case OpUnaryPlus:
816         ERROR("The + operator cannot be applied to a key name\n");
817         return False;
818     default:
819         WSGO("Unknown operator %d in ResolveKeyName\n", expr->op);
820         break;
821     }
822     return False;
823 }
824
825 /***====================================================================***/
826
827 int
828 ExprResolveEnum(ExprDef * expr, ExprResult * val_rtrn, const LookupEntry * values)
829 {
830     if (expr->op != ExprIdent)
831     {
832         ERROR("Found a %s where an enumerated value was expected\n",
833                exprOpText(expr->op));
834         return False;
835     }
836     if (!SimpleLookup(values, expr->value.str, TypeInt, val_rtrn))
837     {
838         int nOut = 0;
839         ERROR("Illegal identifier %s (expected one of: ",
840                XkbcAtomText(expr->value.str));
841         while (values && values->name)
842         {
843             if (nOut != 0)
844                 INFO(", %s", values->name);
845             else
846                 INFO("%s", values->name);
847             values++;
848             nOut++;
849         }
850         INFO(")\n");
851         return False;
852     }
853     return True;
854 }
855
856 static int
857 ExprResolveMaskLookup(ExprDef * expr,
858                       ExprResult * val_rtrn,
859                       IdentLookupFunc lookup,
860                       const void * lookupPriv)
861 {
862     int ok = 0;
863     ExprResult leftRtrn, rightRtrn;
864     ExprDef *left, *right;
865     const char *bogus = NULL;
866
867     switch (expr->op)
868     {
869     case ExprValue:
870         if (expr->type != TypeInt)
871         {
872             ERROR
873                 ("Found constant of type %s where a mask was expected\n",
874                  exprTypeText(expr->type));
875             return False;
876         }
877         val_rtrn->ival = expr->value.ival;
878         return True;
879     case ExprIdent:
880         ok = (*lookup) (lookupPriv, expr->value.str, TypeInt, val_rtrn);
881         if (!ok)
882             ERROR("Identifier \"%s\" of type int is unknown\n",
883                    XkbcAtomText(expr->value.str));
884         return ok;
885     case ExprFieldRef:
886         ERROR("Default \"%s.%s\" of type int is unknown\n",
887               XkbcAtomText(expr->value.field.element),
888               XkbcAtomText(expr->value.field.field));
889         return False;
890     case ExprArrayRef:
891         bogus = "array reference";
892     case ExprActionDecl:
893         if (bogus == NULL)
894             bogus = "function use";
895         ERROR("Unexpected %s in mask expression\n", bogus);
896         ACTION("Expression ignored\n");
897         return False;
898     case OpAdd:
899     case OpSubtract:
900     case OpMultiply:
901     case OpDivide:
902         left = expr->value.binary.left;
903         right = expr->value.binary.right;
904         if (ExprResolveMaskLookup(left, &leftRtrn, lookup, lookupPriv) &&
905             ExprResolveMaskLookup(right, &rightRtrn, lookup, lookupPriv))
906         {
907             switch (expr->op)
908             {
909             case OpAdd:
910                 val_rtrn->ival = leftRtrn.ival | rightRtrn.ival;
911                 break;
912             case OpSubtract:
913                 val_rtrn->ival = leftRtrn.ival & (~rightRtrn.ival);
914                 break;
915             case OpMultiply:
916             case OpDivide:
917                 ERROR("Cannot %s masks\n",
918                        expr->op == OpDivide ? "divide" : "multiply");
919                 ACTION("Illegal operation ignored\n");
920                 return False;
921             }
922             return True;
923         }
924         return False;
925     case OpAssign:
926         WSGO("Assignment operator not implemented yet\n");
927         break;
928     case OpInvert:
929         left = expr->value.child;
930         if (ExprResolveIntegerLookup(left, &leftRtrn, lookup, lookupPriv))
931         {
932             val_rtrn->ival = ~leftRtrn.ival;
933             return True;
934         }
935         return False;
936     case OpUnaryPlus:
937     case OpNegate:
938     case OpNot:
939         left = expr->value.child;
940         if (ExprResolveIntegerLookup(left, &leftRtrn, lookup, lookupPriv))
941         {
942             ERROR("The %s operator cannot be used with a mask\n",
943                    (expr->op == OpNegate ? "-" : "!"));
944         }
945         return False;
946     default:
947         WSGO("Unknown operator %d in ResolveMask\n", expr->op);
948         break;
949     }
950     return False;
951 }
952
953 int
954 ExprResolveMask(ExprDef * expr,
955                 ExprResult * val_rtrn,
956                 const LookupEntry * values)
957 {
958     return ExprResolveMaskLookup(expr, val_rtrn, SimpleLookup, values);
959 }
960
961 int
962 ExprResolveModMask(ExprDef * expr,
963                    ExprResult * val_rtrn)
964 {
965     return ExprResolveMaskLookup(expr, val_rtrn, LookupModMask, NULL);
966 }
967
968 int
969 ExprResolveVModMask(ExprDef * expr,
970                     ExprResult * val_rtrn,
971                     struct xkb_desc *xkb)
972 {
973     return ExprResolveMaskLookup(expr, val_rtrn, LookupVModMask, xkb);
974 }
975
976 int
977 ExprResolveKeySym(ExprDef * expr,
978                   ExprResult * val_rtrn)
979 {
980     int ok = 0;
981     xkb_keysym_t sym;
982
983     if (expr->op == ExprIdent)
984     {
985         const char *str;
986         str = XkbcAtomText(expr->value.str);
987         if (str) {
988             sym = xkb_string_to_keysym(str);
989             if (sym != XKB_KEYSYM_NO_SYMBOL) {
990                 val_rtrn->uval = sym;
991                 return True;
992             }
993         }
994     }
995     ok = ExprResolveInteger(expr, val_rtrn);
996     if ((ok) && (val_rtrn->uval < 10))
997         val_rtrn->uval += '0';
998     return ok;
999 }