Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / soltools / cpp / _eval.c
blob3d19974da82514e452ea4a112508f8990d707278
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "cpp.h"
22 #define NSTAK 32
23 #define SGN 0
24 #define UNS 1
25 #define UND 2
27 #define UNSMARK 0x1000
29 struct value
31 int val;
32 int type;
35 /* conversion types */
36 #define RELAT 1
37 #define ARITH 2
38 #define LOGIC 3
39 #define SPCL 4
40 #define SHIFT 5
41 #define UNARY 6
43 /* operator priority, arity, and conversion type, indexed by tokentype */
44 struct pri
46 char const pri;
47 char const arity;
48 char const ctype;
51 static const struct pri priority[] =
54 0, 0, 0
55 }, /* END */
57 0, 0, 0
58 }, /* UNCLASS */
60 0, 0, 0
61 }, /* NAME */
63 0, 0, 0
64 }, /* NUMBER */
66 0, 0, 0
67 }, /* STRING */
69 0, 0, 0
70 }, /* CCON */
72 0, 0, 0
73 }, /* NL */
75 0, 0, 0
76 }, /* WS */
78 0, 0, 0
79 }, /* DSHARP */
81 11, 2, RELAT
82 }, /* EQ */
84 11, 2, RELAT
85 }, /* NEQ */
87 12, 2, RELAT
88 }, /* LEQ */
90 12, 2, RELAT
91 }, /* GEQ */
93 13, 2, SHIFT
94 }, /* LSH */
96 13, 2, SHIFT
97 }, /* RSH */
99 7, 2, LOGIC
100 }, /* LAND */
102 6, 2, LOGIC
103 }, /* LOR */
105 0, 0, 0
106 }, /* PPLUS */
108 0, 0, 0
109 }, /* MMINUS */
111 0, 0, 0
112 }, /* ARROW */
114 0, 0, 0
115 }, /* SBRA */
117 0, 0, 0
118 }, /* SKET */
120 3, 0, 0
121 }, /* LP */
123 3, 0, 0
124 }, /* RP */
126 0, 0, 0
127 }, /* DOT */
129 10, 2, ARITH
130 }, /* AND */
132 15, 2, ARITH
133 }, /* STAR */
135 14, 2, ARITH
136 }, /* PLUS */
138 14, 2, ARITH
139 }, /* MINUS */
141 16, 1, UNARY
142 }, /* TILDE */
144 16, 1, UNARY
145 }, /* NOT */
147 15, 2, ARITH
148 }, /* SLASH */
150 15, 2, ARITH
151 }, /* PCT */
153 12, 2, RELAT
154 }, /* LT */
156 12, 2, RELAT
157 }, /* GT */
159 9, 2, ARITH
160 }, /* CIRC */
162 8, 2, ARITH
163 }, /* OR */
165 5, 2, SPCL
166 }, /* QUEST */
168 5, 2, SPCL
169 }, /* COLON */
171 0, 0, 0
172 }, /* ASGN */
174 4, 2, 0
175 }, /* COMMA */
177 0, 0, 0
178 }, /* SHARP */
180 0, 0, 0
181 }, /* SEMIC */
183 0, 0, 0
184 }, /* CBRA */
186 0, 0, 0
187 }, /* CKET */
189 0, 0, 0
190 }, /* ASPLUS */
192 0, 0, 0
193 }, /* ASMINUS */
195 0, 0, 0
196 }, /* ASSTAR */
198 0, 0, 0
199 }, /* ASSLASH */
201 0, 0, 0
202 }, /* ASPCT */
204 0, 0, 0
205 }, /* ASCIRC */
207 0, 0, 0
208 }, /* ASLSH */
210 0, 0, 0
211 }, /* ASRSH */
213 0, 0, 0
214 }, /* ASOR */
216 0, 0, 0
217 }, /* ASAND */
219 0, 0, 0
220 }, /* ELLIPS */
222 0, 0, 0
223 }, /* DSHARP1 */
225 0, 0, 0
226 }, /* NAME1 */
228 0, 0, 0
229 }, /* NAME2 */
231 16, 1, UNARY
232 }, /* DEFINED */
234 16, 0, UNARY
235 }, /* UMINUS */
237 16, 1, UNARY
238 }, /* ARCHITECTURE */
241 static int evalop(struct pri);
242 static struct value tokval(Token *);
243 static struct value vals[NSTAK], *vp;
244 static enum toktype ops[NSTAK], *op;
247 * Evaluate an #if #elif #ifdef #ifndef line. trp->tp points to the keyword.
249 long
250 eval(Tokenrow * trp, int kw)
252 Token *tp;
253 Nlist *np;
254 size_t ntok;
255 int rnd;
257 trp->tp++;
258 if (kw == KIFDEF || kw == KIFNDEF)
260 if (trp->lp - trp->bp != 4 || trp->tp->type != NAME)
262 error(ERROR, "Syntax error in #ifdef/#ifndef");
263 return 0;
265 np = lookup(trp->tp, 0);
266 return (kw == KIFDEF) == (np && np->flag & (ISDEFINED | ISMAC));
268 ntok = trp->tp - trp->bp;
269 kwdefined->val = KDEFINED; /* activate special meaning of
270 * defined */
271 expandrow(trp, "<if>");
272 kwdefined->val = NAME;
273 vp = vals;
274 op = ops;
275 *op++ = END;
276 for (rnd = 0, tp = trp->bp + ntok; tp < trp->lp; tp++)
278 switch (tp->type)
280 case WS:
281 case NL:
282 continue;
284 /* nilary */
285 case NAME:
286 case NAME1:
287 case NAME2:
288 case NUMBER:
289 case CCON:
290 case STRING:
291 if (rnd)
292 goto syntax;
293 *vp++ = tokval(tp);
294 rnd = 1;
295 continue;
297 /* unary */
298 case DEFINED:
299 case TILDE:
300 case NOT:
301 if (rnd)
302 goto syntax;
303 *op++ = tp->type;
304 continue;
306 /* unary-binary */
307 case PLUS:
308 case MINUS:
309 case STAR:
310 case AND:
311 if (rnd == 0)
313 if (tp->type == MINUS)
314 *op++ = UMINUS;
315 if (tp->type == STAR || tp->type == AND)
317 error(ERROR, "Illegal operator * or & in #if/#elif");
318 return 0;
320 continue;
322 /* fall through */
324 /* plain binary */
325 case EQ:
326 case NEQ:
327 case LEQ:
328 case GEQ:
329 case LSH:
330 case RSH:
331 case LAND:
332 case LOR:
333 case SLASH:
334 case PCT:
335 case LT:
336 case GT:
337 case CIRC:
338 case OR:
339 case QUEST:
340 case COLON:
341 case COMMA:
342 if (rnd == 0)
343 goto syntax;
344 if (evalop(priority[tp->type]) != 0)
345 return 0;
346 *op++ = tp->type;
347 rnd = 0;
348 continue;
350 case LP:
351 if (rnd)
352 goto syntax;
353 *op++ = LP;
354 continue;
356 case RP:
357 if (!rnd)
358 goto syntax;
359 if (evalop(priority[RP]) != 0)
360 return 0;
361 if (op <= ops || op[-1] != LP)
363 goto syntax;
365 op--;
366 continue;
368 case SHARP:
369 if ((tp + 1) < trp->lp)
371 np = lookup(tp + 1, 0);
372 if (np && (np->val == KMACHINE))
374 tp++;
375 if (rnd)
376 goto syntax;
377 *op++ = ARCHITECTURE;
378 continue;
381 /* fall through */
383 default:
384 error(ERROR, "Bad operator (%t) in #if/#elif", tp);
385 return 0;
388 if (rnd == 0)
389 goto syntax;
390 if (evalop(priority[END]) != 0)
391 return 0;
392 if (op != &ops[1] || vp != &vals[1])
394 error(ERROR, "Botch in #if/#elif");
395 return 0;
397 if (vals[0].type == UND)
398 error(ERROR, "Undefined expression value");
399 return vals[0].val;
400 syntax:
401 error(ERROR, "Syntax error in #if/#elif");
402 return 0;
406 evalop(struct pri pri)
408 struct value v1;
409 struct value v2 = { 0, UND };
410 int rv1, rv2;
411 int rtype, oper;
413 rv2 = 0;
414 rtype = 0;
415 while (pri.pri < priority[op[-1]].pri)
417 oper = *--op;
418 if (priority[oper].arity == 2)
420 v2 = *--vp;
421 rv2 = v2.val;
423 v1 = *--vp;
424 rv1 = v1.val;
425 /*lint -e574 -e644 */
426 switch (priority[oper].ctype)
428 case 0:
429 default:
430 error(WARNING, "Syntax error in #if/#endif");
431 return 1;
432 case ARITH:
433 case RELAT:
434 if (v1.type == UNS || v2.type == UNS)
435 rtype = UNS;
436 else
437 rtype = SGN;
438 if (v1.type == UND || v2.type == UND)
439 rtype = UND;
440 if (priority[oper].ctype == RELAT && rtype == UNS)
442 oper |= UNSMARK;
443 rtype = SGN;
445 break;
446 case SHIFT:
447 if (v1.type == UND || v2.type == UND)
448 rtype = UND;
449 else
450 rtype = v1.type;
451 if (rtype == UNS)
452 oper |= UNSMARK;
453 break;
454 case UNARY:
455 rtype = v1.type;
456 break;
457 case LOGIC:
458 case SPCL:
459 break;
461 switch (oper)
463 case EQ:
464 case EQ | UNSMARK:
465 rv1 = rv1 == rv2;
466 break;
467 case NEQ:
468 case NEQ | UNSMARK:
469 rv1 = rv1 != rv2;
470 break;
471 case LEQ:
472 rv1 = rv1 <= rv2;
473 break;
474 case GEQ:
475 rv1 = rv1 >= rv2;
476 break;
477 case LT:
478 rv1 = rv1 < rv2;
479 break;
480 case GT:
481 rv1 = rv1 > rv2;
482 break;
483 case LEQ | UNSMARK:
484 rv1 = (unsigned long)rv1 <= (unsigned long)rv2;
485 break;
486 case GEQ | UNSMARK:
487 rv1 = (unsigned long)rv1 >= (unsigned long)rv2;
488 break;
489 case LT | UNSMARK:
490 rv1 = (unsigned long)rv1 < (unsigned long)rv2;
491 break;
492 case GT | UNSMARK:
493 rv1 = (unsigned long)rv1 > (unsigned long)rv2;
494 break;
495 case LSH:
496 rv1 <<= rv2;
497 break;
498 case LSH | UNSMARK:
499 rv1 = (unsigned long) rv1 << rv2;
500 break;
501 case RSH:
502 rv1 >>= rv2;
503 break;
504 case RSH | UNSMARK:
505 rv1 = (unsigned long) rv1 >> rv2;
506 break;
507 case LAND:
508 rtype = UND;
509 if (v1.type == UND)
510 break;
511 if (rv1 != 0)
513 if (v2.type == UND)
514 break;
515 rv1 = rv2 != 0;
517 else
518 rv1 = 0;
519 rtype = SGN;
520 break;
521 case LOR:
522 rtype = UND;
523 if (v1.type == UND)
524 break;
525 if (rv1 == 0)
527 if (v2.type == UND)
528 break;
529 rv1 = rv2 != 0;
531 else
532 rv1 = 1;
533 rtype = SGN;
534 break;
535 case AND:
536 rv1 &= rv2;
537 break;
538 case STAR:
539 rv1 *= rv2;
540 break;
541 case PLUS:
542 rv1 += rv2;
543 break;
544 case MINUS:
545 rv1 -= rv2;
546 break;
547 case UMINUS:
548 if (v1.type == UND)
549 rtype = UND;
550 rv1 = -rv1;
551 break;
552 case OR:
553 rv1 |= rv2;
554 break;
555 case CIRC:
556 rv1 ^= rv2;
557 break;
558 case TILDE:
559 rv1 = ~rv1;
560 break;
561 case NOT:
562 rv1 = !rv1;
563 if (rtype != UND)
564 rtype = SGN;
565 break;
566 case SLASH:
567 if (rv2 == 0)
569 rtype = UND;
570 break;
572 if (rtype == UNS)
573 rv1 /= (unsigned long) rv2;
574 else
575 rv1 /= rv2;
576 break;
577 case PCT:
578 if (rv2 == 0)
580 rtype = UND;
581 break;
583 if (rtype == UNS)
584 rv1 %= (unsigned long) rv2;
585 else
586 rv1 %= rv2;
587 break;
588 case COLON:
589 if (op[-1] != QUEST)
590 error(ERROR, "Bad ?: in #if/endif");
591 else
593 op--;
594 if ((--vp)->val == 0)
595 v1 = v2;
596 rtype = v1.type;
597 rv1 = v1.val;
599 break;
601 case DEFINED:
602 case ARCHITECTURE:
603 break;
605 default:
606 error(ERROR, "Eval botch (unknown operator)");
607 return 1;
609 /*lint +e574 +e644 */
610 v1.val = rv1;
611 v1.type = rtype;
612 *vp++ = v1;
614 return 0;
617 struct value
618 tokval(Token * tp)
620 struct value v;
621 Nlist *np;
622 int i, base;
623 unsigned int n;
624 uchar *p, c;
626 v.type = SGN;
627 v.val = 0;
628 switch (tp->type)
631 case NAME:
632 v.val = 0;
633 break;
635 case NAME1:
636 if ((np = lookup(tp, 0)) != NULL && np->flag & (ISDEFINED | ISMAC))
637 v.val = 1;
638 break;
640 case NAME2:
641 if ((np = lookup(tp, 0)) != NULL && np->flag & (ISARCHITECTURE))
642 v.val = 1;
643 break;
645 case NUMBER:
646 n = 0;
647 base = 10;
648 p = tp->t;
649 c = p[tp->len];
650 p[tp->len] = '\0';
651 if (*p == '0')
653 base = 8;
654 if (p[1] == 'x' || p[1] == 'X')
656 base = 16;
657 p++;
659 p++;
661 for (;; p++)
663 if ((i = digit(*p)) < 0)
664 break;
665 if (i >= base)
666 error(WARNING,
667 "Bad digit in number %t", tp);
668 n *= base;
669 n += i;
671 if (n >= 0x80000000 && base != 10)
672 v.type = UNS;
673 for (; *p; p++)
675 if (*p == 'u' || *p == 'U')
676 v.type = UNS;
677 else
678 if (*p == 'l' || *p == 'L')
680 else
682 error(ERROR,
683 "Bad number %t in #if/#elif", tp);
684 break;
687 v.val = n;
688 tp->t[tp->len] = c;
689 break;
691 case CCON:
692 n = 0;
693 p = tp->t;
694 if (*p == 'L')
696 p += 1;
697 error(WARNING, "Wide char constant value undefined");
699 p += 1;
700 if (*p == '\\')
702 p += 1;
703 if ((i = digit(*p)) >= 0 && i <= 7)
705 n = i;
706 p += 1;
707 if ((i = digit(*p)) >= 0 && i <= 7)
709 p += 1;
710 n <<= 3;
711 n += i;
712 if ((i = digit(*p)) >= 0 && i <= 7)
714 p += 1;
715 n <<= 3;
716 n += i;
720 else
721 if (*p == 'x')
723 p += 1;
724 while ((i = digit(*p)) >= 0 && i <= 15)
726 p += 1;
727 n <<= 4;
728 n += i;
731 else
733 static const char cvcon[] = "b\bf\fn\nr\rt\tv\v''\"\"??\\\\";
734 static size_t cvlen = sizeof(cvcon) - 1;
736 size_t j;
737 for (j = 0; j < cvlen; j += 2)
739 if (*p == cvcon[j])
741 n = cvcon[j + 1];
742 break;
745 p += 1;
746 if (j >= cvlen)
747 error(WARNING,
748 "Undefined escape in character constant");
751 else
752 if (*p == '\'')
753 error(ERROR, "Empty character constant");
754 else
755 n = *p++;
756 if (*p != '\'')
757 error(WARNING, "Multibyte character constant undefined");
758 else
759 if (n > 127)
760 error(WARNING, "Character constant taken as not signed");
761 v.val = n;
762 break;
764 case STRING:
765 error(ERROR, "String in #if/#elif");
766 break;
768 return v;
772 digit(int i)
774 if ('0' <= i && i <= '9')
775 i -= '0';
776 else
777 if ('a' <= i && i <= 'f')
778 i -= 'a' - 10;
779 else
780 if ('A' <= i && i <= 'F')
781 i -= 'A' - 10;
782 else
783 i = -1;
784 return i;
787 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */