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