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