Remove more float support
[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 == 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 (uStrCaseCmp(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     char *str;
213     Bool ret = True;
214
215     if (type != TypeInt)
216         return False;
217     str = XkbcAtomGetString(field);
218     if (str == NULL)
219         return False;
220     if (uStrCaseCmp(str, "all") == 0)
221         val_rtrn->uval = 0xff;
222     else if (uStrCaseCmp(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     free(str);
229     return ret;
230 }
231
232 int
233 ExprResolveBoolean(ExprDef * expr,
234                    ExprResult * val_rtrn)
235 {
236     int ok = 0;
237     const char *bogus = NULL;
238
239     switch (expr->op)
240     {
241     case ExprValue:
242         if (expr->type != TypeBoolean)
243         {
244             ERROR
245                 ("Found constant of type %s where boolean was expected\n",
246                  exprTypeText(expr->type));
247             return False;
248         }
249         val_rtrn->ival = expr->value.ival;
250         return True;
251     case ExprIdent:
252         bogus = XkbcAtomText(expr->value.str);
253         if (bogus)
254         {
255             if ((uStrCaseCmp(bogus, "true") == 0) ||
256                 (uStrCaseCmp(bogus, "yes") == 0) ||
257                 (uStrCaseCmp(bogus, "on") == 0))
258             {
259                 val_rtrn->uval = 1;
260                 return True;
261             }
262             else if ((uStrCaseCmp(bogus, "false") == 0) ||
263                      (uStrCaseCmp(bogus, "no") == 0) ||
264                      (uStrCaseCmp(bogus, "off") == 0))
265             {
266                 val_rtrn->uval = 0;
267                 return True;
268             }
269         }
270         ERROR("Identifier \"%s\" of type int is unknown\n",
271               XkbcAtomText(expr->value.str));
272         return False;
273     case ExprFieldRef:
274         ERROR("Default \"%s.%s\" of type boolean is unknown\n",
275               XkbcAtomText(expr->value.field.element),
276               XkbcAtomText(expr->value.field.field));
277         return False;
278     case OpInvert:
279     case OpNot:
280         ok = ExprResolveBoolean(expr, val_rtrn);
281         if (ok)
282             val_rtrn->uval = !val_rtrn->uval;
283         return ok;
284     case OpAdd:
285         if (bogus == NULL)
286             bogus = "Addition";
287     case OpSubtract:
288         if (bogus == NULL)
289             bogus = "Subtraction";
290     case OpMultiply:
291         if (bogus == NULL)
292             bogus = "Multiplication";
293     case OpDivide:
294         if (bogus == NULL)
295             bogus = "Division";
296     case OpAssign:
297         if (bogus == NULL)
298             bogus = "Assignment";
299     case OpNegate:
300         if (bogus == NULL)
301             bogus = "Negation";
302         ERROR("%s of boolean values not permitted\n", bogus);
303         break;
304     case OpUnaryPlus:
305         ERROR("Unary \"+\" operator not permitted for boolean values\n");
306         break;
307     default:
308         WSGO("Unknown operator %d in ResolveBoolean\n", expr->op);
309         break;
310     }
311     return False;
312 }
313
314 int
315 ExprResolveFloat(ExprDef * expr,
316                  ExprResult * val_rtrn)
317 {
318     int ok = 0;
319     ExprResult leftRtrn, rightRtrn;
320     ExprDef *left, *right;
321
322     switch (expr->op)
323     {
324     case ExprValue:
325         if (expr->type == TypeString)
326         {
327             const char *str;
328             str = XkbcAtomText(expr->value.str);
329             if ((str != NULL) && (strlen(str) == 1))
330             {
331                 val_rtrn->uval = str[0] * XkbGeomPtsPerMM;
332                 return True;
333             }
334         }
335         if (expr->type != TypeInt)
336         {
337             ERROR("Found constant of type %s, expected a number\n",
338                    exprTypeText(expr->type));
339             return False;
340         }
341         val_rtrn->ival = expr->value.ival;
342         if (expr->type == TypeInt)
343             val_rtrn->ival *= XkbGeomPtsPerMM;
344         return True;
345     case ExprIdent:
346         ERROR("Numeric identifier \"%s\" unknown\n",
347               XkbcAtomText(expr->value.str));
348         return ok;
349     case ExprFieldRef:
350         ERROR("Numeric default \"%s.%s\" unknown\n",
351               XkbcAtomText(expr->value.field.element),
352               XkbcAtomText(expr->value.field.field));
353         return False;
354     case OpAdd:
355     case OpSubtract:
356     case OpMultiply:
357     case OpDivide:
358         left = expr->value.binary.left;
359         right = expr->value.binary.right;
360         if (ExprResolveFloat(left, &leftRtrn) &&
361             ExprResolveFloat(right, &rightRtrn))
362         {
363             switch (expr->op)
364             {
365             case OpAdd:
366                 val_rtrn->ival = leftRtrn.ival + rightRtrn.ival;
367                 break;
368             case OpSubtract:
369                 val_rtrn->ival = leftRtrn.ival - rightRtrn.ival;
370                 break;
371             case OpMultiply:
372                 val_rtrn->ival = leftRtrn.ival * rightRtrn.ival;
373                 break;
374             case OpDivide:
375                 val_rtrn->ival = leftRtrn.ival / rightRtrn.ival;
376                 break;
377             }
378             return True;
379         }
380         return False;
381     case OpAssign:
382         WSGO("Assignment operator not implemented yet\n");
383         break;
384     case OpNot:
385         ERROR("The ! operator cannot be applied to a number\n");
386         return False;
387     case OpInvert:
388     case OpNegate:
389         left = expr->value.child;
390         if (ExprResolveFloat(left, &leftRtrn))
391         {
392             if (expr->op == OpNegate)
393                 val_rtrn->ival = -leftRtrn.ival;
394             else
395                 val_rtrn->ival = ~leftRtrn.ival;
396             return True;
397         }
398         return False;
399     case OpUnaryPlus:
400         left = expr->value.child;
401         return ExprResolveFloat(left, val_rtrn);
402     default:
403         WSGO("Unknown operator %d in ResolveFloat\n", expr->op);
404         break;
405     }
406     return False;
407 }
408
409 int
410 ExprResolveKeyCode(ExprDef * expr,
411                    ExprResult * val_rtrn)
412 {
413     ExprResult leftRtrn, rightRtrn;
414     ExprDef *left, *right;
415
416     switch (expr->op)
417     {
418     case ExprValue:
419         if (expr->type != TypeInt)
420         {
421             ERROR
422                 ("Found constant of type %s where an int was expected\n",
423                  exprTypeText(expr->type));
424             return False;
425         }
426         val_rtrn->uval = expr->value.uval;
427         return True;
428     case OpAdd:
429     case OpSubtract:
430     case OpMultiply:
431     case OpDivide:
432         left = expr->value.binary.left;
433         right = expr->value.binary.right;
434         if (ExprResolveKeyCode(left, &leftRtrn) &&
435             ExprResolveKeyCode(right, &rightRtrn))
436         {
437             switch (expr->op)
438             {
439             case OpAdd:
440                 val_rtrn->uval = leftRtrn.uval + rightRtrn.uval;
441                 break;
442             case OpSubtract:
443                 val_rtrn->uval = leftRtrn.uval - rightRtrn.uval;
444                 break;
445             case OpMultiply:
446                 val_rtrn->uval = leftRtrn.uval * rightRtrn.uval;
447                 break;
448             case OpDivide:
449                 val_rtrn->uval = leftRtrn.uval / rightRtrn.uval;
450                 break;
451             }
452             return True;
453         }
454         return False;
455     case OpNegate:
456         left = expr->value.child;
457         if (ExprResolveKeyCode(left, &leftRtrn))
458         {
459             val_rtrn->uval = ~leftRtrn.uval;
460             return True;
461         }
462         return False;
463     case OpUnaryPlus:
464         left = expr->value.child;
465         return ExprResolveKeyCode(left, val_rtrn);
466     default:
467         WSGO("Unknown operator %d in ResolveKeyCode\n", expr->op);
468         break;
469     }
470     return False;
471 }
472
473 /**
474  * This function returns ... something.  It's a bit of a guess, really.
475  *
476  * If a string is given in value context, its first character will be
477  * returned in uval.  If an integer is given in value context, it will be
478  * returned in ival.  If a float is given in value context, it will be
479  * returned as millimetres (rather than points) in ival.
480  *
481  * If an ident or field reference is given, the lookup function (if given)
482  * will be called.  At the moment, only SimpleLookup use this, and they both
483  * return the results in uval.  And don't support field references.
484  *
485  * Cool.
486  */
487 static int
488 ExprResolveIntegerLookup(ExprDef * expr,
489                          ExprResult * val_rtrn,
490                          IdentLookupFunc lookup, const void * lookupPriv)
491 {
492     int ok = 0;
493     ExprResult leftRtrn, rightRtrn;
494     ExprDef *left, *right;
495
496     switch (expr->op)
497     {
498     case ExprValue:
499         if (expr->type == TypeString)
500         {
501             const char *str;
502             str = XkbcAtomText(expr->value.str);
503             if (str != NULL)
504                 switch (strlen(str))
505                 {
506                 case 0:
507                     val_rtrn->uval = 0;
508                     return True;
509                 case 1:
510                     val_rtrn->uval = str[0];
511                     return True;
512                 default:
513                     break;
514                 }
515         }
516         if (expr->type != TypeInt)
517         {
518             ERROR
519                 ("Found constant of type %s where an int was expected\n",
520                  exprTypeText(expr->type));
521             return False;
522         }
523         val_rtrn->ival = expr->value.ival;
524         return True;
525     case ExprIdent:
526         if (lookup)
527         {
528             ok = (*lookup) (lookupPriv, expr->value.str, TypeInt, val_rtrn);
529         }
530         if (!ok)
531             ERROR("Identifier \"%s\" of type int is unknown\n",
532                    XkbcAtomText(expr->value.str));
533         return ok;
534     case ExprFieldRef:
535         ERROR("Default \"%s.%s\" of type int is unknown\n",
536               XkbcAtomText(expr->value.field.element),
537               XkbcAtomText(expr->value.field.field));
538         return False;
539     case OpAdd:
540     case OpSubtract:
541     case OpMultiply:
542     case OpDivide:
543         left = expr->value.binary.left;
544         right = expr->value.binary.right;
545         if (ExprResolveIntegerLookup(left, &leftRtrn, lookup, lookupPriv) &&
546             ExprResolveIntegerLookup(right, &rightRtrn, lookup, lookupPriv))
547         {
548             switch (expr->op)
549             {
550             case OpAdd:
551                 val_rtrn->ival = leftRtrn.ival + rightRtrn.ival;
552                 break;
553             case OpSubtract:
554                 val_rtrn->ival = leftRtrn.ival - rightRtrn.ival;
555                 break;
556             case OpMultiply:
557                 val_rtrn->ival = leftRtrn.ival * rightRtrn.ival;
558                 break;
559             case OpDivide:
560                 val_rtrn->ival = leftRtrn.ival / rightRtrn.ival;
561                 break;
562             }
563             return True;
564         }
565         return False;
566     case OpAssign:
567         WSGO("Assignment operator not implemented yet\n");
568         break;
569     case OpNot:
570         ERROR("The ! operator cannot be applied to an integer\n");
571         return False;
572     case OpInvert:
573     case OpNegate:
574         left = expr->value.child;
575         if (ExprResolveIntegerLookup(left, &leftRtrn, lookup, lookupPriv))
576         {
577             if (expr->op == OpNegate)
578                 val_rtrn->ival = -leftRtrn.ival;
579             else
580                 val_rtrn->ival = ~leftRtrn.ival;
581             return True;
582         }
583         return False;
584     case OpUnaryPlus:
585         left = expr->value.child;
586         return ExprResolveIntegerLookup(left, val_rtrn, lookup, lookupPriv);
587     default:
588         WSGO("Unknown operator %d in ResolveInteger\n", expr->op);
589         break;
590     }
591     return False;
592 }
593
594 int
595 ExprResolveInteger(ExprDef * expr,
596                    ExprResult * val_rtrn)
597 {
598     return ExprResolveIntegerLookup(expr, val_rtrn, NULL, NULL);
599 }
600
601 int
602 ExprResolveGroup(ExprDef * expr,
603                  ExprResult * val_rtrn)
604 {
605     int ret;
606     static const LookupEntry group_names[] = {
607         { "group1", 1 },
608         { "group2", 2 },
609         { "group3", 3 },
610         { "group4", 4 },
611         { "group5", 5 },
612         { "group6", 6 },
613         { "group7", 7 },
614         { "group8", 8 },
615         { NULL, 0 }
616     };
617
618     ret = ExprResolveIntegerLookup(expr, val_rtrn, SimpleLookup, group_names);
619     if (ret == False)
620         return ret;
621
622     if (val_rtrn->uval == 0 || val_rtrn->uval > XkbNumKbdGroups) {
623         ERROR("Group index %d is out of range (1..%d)\n",
624               val_rtrn->uval, XkbNumKbdGroups);
625         return False;
626     }
627
628     return True;
629 }
630
631 int
632 ExprResolveLevel(ExprDef * expr,
633                  ExprResult * val_rtrn)
634 {
635     int ret;
636     static const LookupEntry level_names[] = {
637         { "level1", 1 },
638         { "level2", 2 },
639         { "level3", 3 },
640         { "level4", 4 },
641         { "level5", 5 },
642         { "level6", 6 },
643         { "level7", 7 },
644         { "level8", 8 },
645         { NULL, 0 }
646     };
647
648     ret = ExprResolveIntegerLookup(expr, val_rtrn, SimpleLookup, level_names);
649     if (ret == False)
650         return ret;
651
652     if (val_rtrn->ival < 1 || val_rtrn->ival > XkbMaxShiftLevel) {
653         ERROR("Shift level %d is out of range (1..%d)\n", val_rtrn->ival,
654               XkbMaxShiftLevel);
655         return False;
656     }
657
658     return True;
659 }
660
661 int
662 ExprResolveButton(ExprDef * expr,
663                   ExprResult * val_rtrn)
664 {
665     static const LookupEntry button_names[] = {
666         { "button1", 1 },
667         { "button2", 2 },
668         { "button3", 3 },
669         { "button4", 4 },
670         { "button5", 5 },
671         { "default", 0 },
672         { NULL, 0 }
673     };
674
675     return ExprResolveIntegerLookup(expr, val_rtrn, SimpleLookup,
676                                     button_names);
677 }
678
679 int
680 ExprResolveString(ExprDef * expr,
681                   ExprResult * val_rtrn)
682 {
683     ExprResult leftRtrn, rightRtrn;
684     ExprDef *left;
685     ExprDef *right;
686     const char *bogus = NULL;
687
688     switch (expr->op)
689     {
690     case ExprValue:
691         if (expr->type != TypeString)
692         {
693             ERROR("Found constant of type %s, expected a string\n",
694                    exprTypeText(expr->type));
695             return False;
696         }
697         val_rtrn->str = XkbcAtomGetString(expr->value.str);
698         if (val_rtrn->str == NULL)
699             val_rtrn->str = strdup("");
700         return True;
701     case ExprIdent:
702         ERROR("Identifier \"%s\" of type string not found\n",
703               XkbcAtomText(expr->value.str));
704         return False;
705     case ExprFieldRef:
706         ERROR("Default \"%s.%s\" of type string not found\n",
707               XkbcAtomText(expr->value.field.element),
708               XkbcAtomText(expr->value.field.field));
709         return False;
710     case OpAdd:
711         left = expr->value.binary.left;
712         right = expr->value.binary.right;
713         if (ExprResolveString(left, &leftRtrn) &&
714             ExprResolveString(right, &rightRtrn))
715         {
716             int len;
717             char *new;
718             len = strlen(leftRtrn.str) + strlen(rightRtrn.str) + 1;
719             new = malloc(len);
720             if (new)
721             { sprintf(new, "%s%s", leftRtrn.str, rightRtrn.str);
722                 free(leftRtrn.str);
723                 free(rightRtrn.str);
724                 val_rtrn->str = new;
725                 return True;
726             }
727             free(leftRtrn.str);
728             free(rightRtrn.str);
729         }
730         return False;
731     case OpSubtract:
732         if (bogus == NULL)
733             bogus = "Subtraction";
734     case OpMultiply:
735         if (bogus == NULL)
736             bogus = "Multiplication";
737     case OpDivide:
738         if (bogus == NULL)
739             bogus = "Division";
740     case OpAssign:
741         if (bogus == NULL)
742             bogus = "Assignment";
743     case OpNegate:
744         if (bogus == NULL)
745             bogus = "Negation";
746     case OpInvert:
747         if (bogus == NULL)
748             bogus = "Bitwise complement";
749         ERROR("%s of string values not permitted\n", bogus);
750         return False;
751     case OpNot:
752         ERROR("The ! operator cannot be applied to a string\n");
753         return False;
754     case OpUnaryPlus:
755         ERROR("The + operator cannot be applied to a string\n");
756         return False;
757     default:
758         WSGO("Unknown operator %d in ResolveString\n", expr->op);
759         break;
760     }
761     return False;
762 }
763
764 int
765 ExprResolveKeyName(ExprDef * expr,
766                    ExprResult * val_rtrn)
767 {
768     const char *bogus = NULL;
769
770     switch (expr->op)
771     {
772     case ExprValue:
773         if (expr->type != TypeKeyName)
774         {
775             ERROR("Found constant of type %s, expected a key name\n",
776                    exprTypeText(expr->type));
777             return False;
778         }
779         memcpy(val_rtrn->keyName.name, expr->value.keyName, XkbKeyNameLength);
780         return True;
781     case ExprIdent:
782         ERROR("Identifier \"%s\" of type string not found\n",
783               XkbcAtomText(expr->value.str));
784         return False;
785     case ExprFieldRef:
786         ERROR("Default \"%s.%s\" of type key name not found\n",
787               XkbcAtomText(expr->value.field.element),
788               XkbcAtomText(expr->value.field.field));
789         return False;
790     case OpAdd:
791         if (bogus == NULL)
792             bogus = "Addition";
793     case OpSubtract:
794         if (bogus == NULL)
795             bogus = "Subtraction";
796     case OpMultiply:
797         if (bogus == NULL)
798             bogus = "Multiplication";
799     case OpDivide:
800         if (bogus == NULL)
801             bogus = "Division";
802     case OpAssign:
803         if (bogus == NULL)
804             bogus = "Assignment";
805     case OpNegate:
806         if (bogus == NULL)
807             bogus = "Negation";
808     case OpInvert:
809         if (bogus == NULL)
810             bogus = "Bitwise complement";
811         ERROR("%s of key name values not permitted\n", bogus);
812         return False;
813     case OpNot:
814         ERROR("The ! operator cannot be applied to a key name\n");
815         return False;
816     case OpUnaryPlus:
817         ERROR("The + operator cannot be applied to a key name\n");
818         return False;
819     default:
820         WSGO("Unknown operator %d in ResolveKeyName\n", expr->op);
821         break;
822     }
823     return False;
824 }
825
826 /***====================================================================***/
827
828 int
829 ExprResolveEnum(ExprDef * expr, ExprResult * val_rtrn, const LookupEntry * values)
830 {
831     if (expr->op != ExprIdent)
832     {
833         ERROR("Found a %s where an enumerated value was expected\n",
834                exprOpText(expr->op));
835         return False;
836     }
837     if (!SimpleLookup(values, expr->value.str, TypeInt, val_rtrn))
838     {
839         int nOut = 0;
840         ERROR("Illegal identifier %s (expected one of: ",
841                XkbcAtomText(expr->value.str));
842         while (values && values->name)
843         {
844             if (nOut != 0)
845                 INFO(", %s", values->name);
846             else
847                 INFO("%s", values->name);
848             values++;
849             nOut++;
850         }
851         INFO(")\n");
852         return False;
853     }
854     return True;
855 }
856
857 static int
858 ExprResolveMaskLookup(ExprDef * expr,
859                       ExprResult * val_rtrn,
860                       IdentLookupFunc lookup,
861                       const void * lookupPriv)
862 {
863     int ok = 0;
864     ExprResult leftRtrn, rightRtrn;
865     ExprDef *left, *right;
866     const char *bogus = NULL;
867
868     switch (expr->op)
869     {
870     case ExprValue:
871         if (expr->type != TypeInt)
872         {
873             ERROR
874                 ("Found constant of type %s where a mask was expected\n",
875                  exprTypeText(expr->type));
876             return False;
877         }
878         val_rtrn->ival = expr->value.ival;
879         return True;
880     case ExprIdent:
881         ok = (*lookup) (lookupPriv, expr->value.str, TypeInt, val_rtrn);
882         if (!ok)
883             ERROR("Identifier \"%s\" of type int is unknown\n",
884                    XkbcAtomText(expr->value.str));
885         return ok;
886     case ExprFieldRef:
887         ERROR("Default \"%s.%s\" of type int is unknown\n",
888               XkbcAtomText(expr->value.field.element),
889               XkbcAtomText(expr->value.field.field));
890         return False;
891     case ExprArrayRef:
892         bogus = "array reference";
893     case ExprActionDecl:
894         if (bogus == NULL)
895             bogus = "function use";
896         ERROR("Unexpected %s in mask expression\n", bogus);
897         ACTION("Expression ignored\n");
898         return False;
899     case OpAdd:
900     case OpSubtract:
901     case OpMultiply:
902     case OpDivide:
903         left = expr->value.binary.left;
904         right = expr->value.binary.right;
905         if (ExprResolveMaskLookup(left, &leftRtrn, lookup, lookupPriv) &&
906             ExprResolveMaskLookup(right, &rightRtrn, lookup, lookupPriv))
907         {
908             switch (expr->op)
909             {
910             case OpAdd:
911                 val_rtrn->ival = leftRtrn.ival | rightRtrn.ival;
912                 break;
913             case OpSubtract:
914                 val_rtrn->ival = leftRtrn.ival & (~rightRtrn.ival);
915                 break;
916             case OpMultiply:
917             case OpDivide:
918                 ERROR("Cannot %s masks\n",
919                        expr->op == OpDivide ? "divide" : "multiply");
920                 ACTION("Illegal operation ignored\n");
921                 return False;
922             }
923             return True;
924         }
925         return False;
926     case OpAssign:
927         WSGO("Assignment operator not implemented yet\n");
928         break;
929     case OpInvert:
930         left = expr->value.child;
931         if (ExprResolveIntegerLookup(left, &leftRtrn, lookup, lookupPriv))
932         {
933             val_rtrn->ival = ~leftRtrn.ival;
934             return True;
935         }
936         return False;
937     case OpUnaryPlus:
938     case OpNegate:
939     case OpNot:
940         left = expr->value.child;
941         if (ExprResolveIntegerLookup(left, &leftRtrn, lookup, lookupPriv))
942         {
943             ERROR("The %s operator cannot be used with a mask\n",
944                    (expr->op == OpNegate ? "-" : "!"));
945         }
946         return False;
947     default:
948         WSGO("Unknown operator %d in ResolveMask\n", expr->op);
949         break;
950     }
951     return False;
952 }
953
954 int
955 ExprResolveMask(ExprDef * expr,
956                 ExprResult * val_rtrn,
957                 const LookupEntry * values)
958 {
959     return ExprResolveMaskLookup(expr, val_rtrn, SimpleLookup, values);
960 }
961
962 int
963 ExprResolveModMask(ExprDef * expr,
964                    ExprResult * val_rtrn)
965 {
966     return ExprResolveMaskLookup(expr, val_rtrn, LookupModMask, NULL);
967 }
968
969 int
970 ExprResolveVModMask(ExprDef * expr,
971                     ExprResult * val_rtrn,
972                     struct xkb_desc *xkb)
973 {
974     return ExprResolveMaskLookup(expr, val_rtrn, LookupVModMask, xkb);
975 }
976
977 int
978 ExprResolveKeySym(ExprDef * expr,
979                   ExprResult * val_rtrn)
980 {
981     int ok = 0;
982     xkb_keysym_t sym;
983
984     if (expr->op == ExprIdent)
985     {
986         const char *str;
987         str = XkbcAtomText(expr->value.str);
988         if ((str != NULL) && ((sym = xkb_string_to_keysym(str)) != NoSymbol))
989         {
990             val_rtrn->uval = sym;
991             return True;
992         }
993     }
994     ok = ExprResolveInteger(expr, val_rtrn);
995     if ((ok) && (val_rtrn->uval < 10))
996         val_rtrn->uval += '0';
997     return ok;
998 }