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