bff5d64325c5b3199c25baec0d76b8887860ff31
[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 ExprResolveLevel(ExprDef * expr,
662                  ExprResult * val_rtrn)
663 {
664     static LookupEntry level_names[] = {
665         { "level1", 1 },
666         { "level2", 2 },
667         { "level3", 3 },
668         { "level4", 4 },
669         { "level5", 5 },
670         { "level6", 6 },
671         { "level7", 7 },
672         { "level8", 8 },
673         { NULL, 0 }
674     };
675
676     return ExprResolveInteger(expr, val_rtrn, SimpleLookup,
677                               (char *) level_names);
678 }
679
680 int
681 ExprResolveButton(ExprDef * expr,
682                   ExprResult * val_rtrn)
683 {
684     static LookupEntry button_names[] = {
685         { "button1", 1 },
686         { "button2", 2 },
687         { "button3", 3 },
688         { "button4", 4 },
689         { "button5", 5 },
690         { "default", 0 },
691         { NULL, 0 }
692     };
693
694     return ExprResolveInteger(expr, val_rtrn, SimpleLookup,
695                               (char *) button_names);
696 }
697
698 int
699 ExprResolveString(ExprDef * expr,
700                   ExprResult * val_rtrn)
701 {
702     ExprResult leftRtrn, rightRtrn;
703     ExprDef *left;
704     ExprDef *right;
705     char *bogus = NULL;
706
707     switch (expr->op)
708     {
709     case ExprValue:
710         if (expr->type != TypeString)
711         {
712             ERROR("Found constant of type %s, expected a string\n",
713                    exprTypeText(expr->type));
714             return False;
715         }
716         val_rtrn->str = XkbcAtomGetString(expr->value.str);
717         if (val_rtrn->str == NULL)
718             val_rtrn->str = strdup("");
719         return True;
720     case ExprIdent:
721         ERROR("Identifier \"%s\" of type string not found\n",
722               XkbcAtomText(expr->value.str));
723         return False;
724     case ExprFieldRef:
725         ERROR("Default \"%s.%s\" of type string not found\n",
726               XkbcAtomText(expr->value.field.element),
727               XkbcAtomText(expr->value.field.field));
728         return False;
729     case OpAdd:
730         left = expr->value.binary.left;
731         right = expr->value.binary.right;
732         if (ExprResolveString(left, &leftRtrn) &&
733             ExprResolveString(right, &rightRtrn))
734         {
735             int len;
736             char *new;
737             len = strlen(leftRtrn.str) + strlen(rightRtrn.str) + 1;
738             new = (char *) malloc(len);
739             if (new)
740             { sprintf(new, "%s%s", leftRtrn.str, rightRtrn.str);
741                 free(leftRtrn.str);
742                 free(rightRtrn.str);
743                 val_rtrn->str = new;
744                 return True;
745             }
746             free(leftRtrn.str);
747             free(rightRtrn.str);
748         }
749         return False;
750     case OpSubtract:
751         if (bogus == NULL)
752             bogus = "Subtraction";
753     case OpMultiply:
754         if (bogus == NULL)
755             bogus = "Multiplication";
756     case OpDivide:
757         if (bogus == NULL)
758             bogus = "Division";
759     case OpAssign:
760         if (bogus == NULL)
761             bogus = "Assignment";
762     case OpNegate:
763         if (bogus == NULL)
764             bogus = "Negation";
765     case OpInvert:
766         if (bogus == NULL)
767             bogus = "Bitwise complement";
768         ERROR("%s of string values not permitted\n", bogus);
769         return False;
770     case OpNot:
771         ERROR("The ! operator cannot be applied to a string\n");
772         return False;
773     case OpUnaryPlus:
774         ERROR("The + operator cannot be applied to a string\n");
775         return False;
776     default:
777         WSGO("Unknown operator %d in ResolveString\n", expr->op);
778         break;
779     }
780     return False;
781 }
782
783 int
784 ExprResolveKeyName(ExprDef * expr,
785                    ExprResult * val_rtrn)
786 {
787     char *bogus = NULL;
788
789     switch (expr->op)
790     {
791     case ExprValue:
792         if (expr->type != TypeKeyName)
793         {
794             ERROR("Found constant of type %s, expected a key name\n",
795                    exprTypeText(expr->type));
796             return False;
797         }
798         memcpy(val_rtrn->keyName.name, expr->value.keyName, XkbKeyNameLength);
799         return True;
800     case ExprIdent:
801         ERROR("Identifier \"%s\" of type string not found\n",
802               XkbcAtomText(expr->value.str));
803         return False;
804     case ExprFieldRef:
805         ERROR("Default \"%s.%s\" of type key name not found\n",
806               XkbcAtomText(expr->value.field.element),
807               XkbcAtomText(expr->value.field.field));
808         return False;
809     case OpAdd:
810         if (bogus == NULL)
811             bogus = "Addition";
812     case OpSubtract:
813         if (bogus == NULL)
814             bogus = "Subtraction";
815     case OpMultiply:
816         if (bogus == NULL)
817             bogus = "Multiplication";
818     case OpDivide:
819         if (bogus == NULL)
820             bogus = "Division";
821     case OpAssign:
822         if (bogus == NULL)
823             bogus = "Assignment";
824     case OpNegate:
825         if (bogus == NULL)
826             bogus = "Negation";
827     case OpInvert:
828         if (bogus == NULL)
829             bogus = "Bitwise complement";
830         ERROR("%s of key name values not permitted\n", bogus);
831         return False;
832     case OpNot:
833         ERROR("The ! operator cannot be applied to a key name\n");
834         return False;
835     case OpUnaryPlus:
836         ERROR("The + operator cannot be applied to a key name\n");
837         return False;
838     default:
839         WSGO("Unknown operator %d in ResolveKeyName\n", expr->op);
840         break;
841     }
842     return False;
843 }
844
845 /***====================================================================***/
846
847 int
848 ExprResolveEnum(ExprDef * expr, ExprResult * val_rtrn, LookupEntry * values)
849 {
850     if (expr->op != ExprIdent)
851     {
852         ERROR("Found a %s where an enumerated value was expected\n",
853                exprOpText(expr->op));
854         return False;
855     }
856     if (!SimpleLookup((char *) values, (uint32_t) None, expr->value.str,
857                       (unsigned) TypeInt, val_rtrn))
858     {
859         int nOut = 0;
860         ERROR("Illegal identifier %s (expected one of: ",
861                XkbcAtomText(expr->value.str));
862         while (values && values->name)
863         {
864             if (nOut != 0)
865                 INFO(", %s", values->name);
866             else
867                 INFO("%s", values->name);
868             values++;
869             nOut++;
870         }
871         INFO(")\n");
872         return False;
873     }
874     return True;
875 }
876
877 int
878 ExprResolveMask(ExprDef * expr,
879                 ExprResult * val_rtrn,
880                 IdentLookupFunc lookup, char * lookupPriv)
881 {
882     int ok = 0;
883     ExprResult leftRtrn, rightRtrn;
884     ExprDef *left, *right;
885     char *bogus = NULL;
886
887     switch (expr->op)
888     {
889     case ExprValue:
890         if (expr->type != TypeInt)
891         {
892             ERROR
893                 ("Found constant of type %s where a mask was expected\n",
894                  exprTypeText(expr->type));
895             return False;
896         }
897         val_rtrn->ival = expr->value.ival;
898         return True;
899     case ExprIdent:
900         if (lookup)
901         {
902             ok = (*lookup) (lookupPriv,
903                             None, expr->value.str, TypeInt, val_rtrn);
904         }
905         if (!ok)
906             ERROR("Identifier \"%s\" of type int is unknown\n",
907                    XkbcAtomText(expr->value.str));
908         return ok;
909     case ExprFieldRef:
910         if (lookup)
911         {
912             ok = (*lookup) (lookupPriv,
913                             expr->value.field.element,
914                             expr->value.field.field, TypeInt, val_rtrn);
915         }
916         if (!ok)
917             ERROR("Default \"%s.%s\" of type int is unknown\n",
918                    XkbcAtomText(expr->value.field.element),
919                    XkbcAtomText(expr->value.field.field));
920         return ok;
921     case ExprArrayRef:
922         bogus = "array reference";
923     case ExprActionDecl:
924         if (bogus == NULL)
925             bogus = "function use";
926         ERROR("Unexpected %s in mask expression\n", bogus);
927         ACTION("Expression ignored\n");
928         return False;
929     case OpAdd:
930     case OpSubtract:
931     case OpMultiply:
932     case OpDivide:
933         left = expr->value.binary.left;
934         right = expr->value.binary.right;
935         if (ExprResolveMask(left, &leftRtrn, lookup, lookupPriv) &&
936             ExprResolveMask(right, &rightRtrn, lookup, lookupPriv))
937         {
938             switch (expr->op)
939             {
940             case OpAdd:
941                 val_rtrn->ival = leftRtrn.ival | rightRtrn.ival;
942                 break;
943             case OpSubtract:
944                 val_rtrn->ival = leftRtrn.ival & (~rightRtrn.ival);
945                 break;
946             case OpMultiply:
947             case OpDivide:
948                 ERROR("Cannot %s masks\n",
949                        expr->op == OpDivide ? "divide" : "multiply");
950                 ACTION("Illegal operation ignored\n");
951                 return False;
952             }
953             return True;
954         }
955         return False;
956     case OpAssign:
957         WSGO("Assignment operator not implemented yet\n");
958         break;
959     case OpInvert:
960         left = expr->value.child;
961         if (ExprResolveInteger(left, &leftRtrn, lookup, lookupPriv))
962         {
963             val_rtrn->ival = ~leftRtrn.ival;
964             return True;
965         }
966         return False;
967     case OpUnaryPlus:
968     case OpNegate:
969     case OpNot:
970         left = expr->value.child;
971         if (ExprResolveInteger(left, &leftRtrn, lookup, lookupPriv))
972         {
973             ERROR("The %s operator cannot be used with a mask\n",
974                    (expr->op == OpNegate ? "-" : "!"));
975         }
976         return False;
977     default:
978         WSGO("Unknown operator %d in ResolveMask\n", expr->op);
979         break;
980     }
981     return False;
982 }
983
984 int
985 ExprResolveKeySym(ExprDef * expr,
986                   ExprResult * val_rtrn)
987 {
988     int ok = 0;
989     uint32_t sym;
990
991     if (expr->op == ExprIdent)
992     {
993         const char *str;
994         str = XkbcAtomText(expr->value.str);
995         if ((str != NULL) && ((sym = xkb_string_to_keysym(str)) != NoSymbol))
996         {
997             val_rtrn->uval = sym;
998             return True;
999         }
1000     }
1001     ok = ExprResolveInteger(expr, val_rtrn, NULL, NULL);
1002     if ((ok) && (val_rtrn->uval < 10))
1003         val_rtrn->uval += '0';
1004     return ok;
1005 }