Branch libreoffice-5-0-4
[LibreOffice.git] / soltools / cpp / _eval.c
blobf10fa7988bb5b2ebc89b4e10ac347c28441bab08
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 long 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 pri;
47 char arity;
48 char ctype;
49 } priority[] =
53 0, 0, 0
54 }, /* END */
56 0, 0, 0
57 }, /* UNCLASS */
59 0, 0, 0
60 }, /* NAME */
62 0, 0, 0
63 }, /* NUMBER */
65 0, 0, 0
66 }, /* STRING */
68 0, 0, 0
69 }, /* CCON */
71 0, 0, 0
72 }, /* NL */
74 0, 0, 0
75 }, /* WS */
77 0, 0, 0
78 }, /* DSHARP */
80 11, 2, RELAT
81 }, /* EQ */
83 11, 2, RELAT
84 }, /* NEQ */
86 12, 2, RELAT
87 }, /* LEQ */
89 12, 2, RELAT
90 }, /* GEQ */
92 13, 2, SHIFT
93 }, /* LSH */
95 13, 2, SHIFT
96 }, /* RSH */
98 7, 2, LOGIC
99 }, /* LAND */
101 6, 2, LOGIC
102 }, /* LOR */
104 0, 0, 0
105 }, /* PPLUS */
107 0, 0, 0
108 }, /* MMINUS */
110 0, 0, 0
111 }, /* ARROW */
113 0, 0, 0
114 }, /* SBRA */
116 0, 0, 0
117 }, /* SKET */
119 3, 0, 0
120 }, /* LP */
122 3, 0, 0
123 }, /* RP */
125 0, 0, 0
126 }, /* DOT */
128 10, 2, ARITH
129 }, /* AND */
131 15, 2, ARITH
132 }, /* STAR */
134 14, 2, ARITH
135 }, /* PLUS */
137 14, 2, ARITH
138 }, /* MINUS */
140 16, 1, UNARY
141 }, /* TILDE */
143 16, 1, UNARY
144 }, /* NOT */
146 15, 2, ARITH
147 }, /* SLASH */
149 15, 2, ARITH
150 }, /* PCT */
152 12, 2, RELAT
153 }, /* LT */
155 12, 2, RELAT
156 }, /* GT */
158 9, 2, ARITH
159 }, /* CIRC */
161 8, 2, ARITH
162 }, /* OR */
164 5, 2, SPCL
165 }, /* QUEST */
167 5, 2, SPCL
168 }, /* COLON */
170 0, 0, 0
171 }, /* ASGN */
173 4, 2, 0
174 }, /* COMMA */
176 0, 0, 0
177 }, /* SHARP */
179 0, 0, 0
180 }, /* SEMIC */
182 0, 0, 0
183 }, /* CBRA */
185 0, 0, 0
186 }, /* CKET */
188 0, 0, 0
189 }, /* ASPLUS */
191 0, 0, 0
192 }, /* ASMINUS */
194 0, 0, 0
195 }, /* ASSTAR */
197 0, 0, 0
198 }, /* ASSLASH */
200 0, 0, 0
201 }, /* ASPCT */
203 0, 0, 0
204 }, /* ASCIRC */
206 0, 0, 0
207 }, /* ASLSH */
209 0, 0, 0
210 }, /* ASRSH */
212 0, 0, 0
213 }, /* ASOR */
215 0, 0, 0
216 }, /* ASAND */
218 0, 0, 0
219 }, /* ELLIPS */
221 0, 0, 0
222 }, /* DSHARP1 */
224 0, 0, 0
225 }, /* NAME1 */
227 0, 0, 0
228 }, /* NAME2 */
230 16, 1, UNARY
231 }, /* DEFINED */
233 16, 0, UNARY
234 }, /* UMINUS */
236 16, 1, UNARY
237 }, /* ARCHITECTURE */
240 int evalop(struct pri);
241 struct value tokval(Token *);
242 struct value vals[NSTAK], *vp;
243 enum toktype ops[NSTAK], *op;
246 * Evaluate an #if #elif #ifdef #ifndef line. trp->tp points to the keyword.
248 long
249 eval(Tokenrow * trp, int kw)
251 Token *tp;
252 Nlist *np;
253 size_t ntok;
254 int rnd;
256 trp->tp++;
257 if (kw == KIFDEF || kw == KIFNDEF)
259 if (trp->lp - trp->bp != 4 || trp->tp->type != NAME)
261 error(ERROR, "Syntax error in #ifdef/#ifndef");
262 return 0;
264 np = lookup(trp->tp, 0);
265 return (kw == KIFDEF) == (np && np->flag & (ISDEFINED | ISMAC));
267 ntok = trp->tp - trp->bp;
268 kwdefined->val = KDEFINED; /* activate special meaning of
269 * defined */
270 expandrow(trp, "<if>");
271 kwdefined->val = NAME;
272 vp = vals;
273 op = ops;
274 *op++ = END;
275 for (rnd = 0, tp = trp->bp + ntok; tp < trp->lp; tp++)
277 switch (tp->type)
279 case WS:
280 case NL:
281 continue;
283 /* nilary */
284 case NAME:
285 case NAME1:
286 case NAME2:
287 case NUMBER:
288 case CCON:
289 case STRING:
290 if (rnd)
291 goto syntax;
292 *vp++ = tokval(tp);
293 rnd = 1;
294 continue;
296 /* unary */
297 case DEFINED:
298 case TILDE:
299 case NOT:
300 if (rnd)
301 goto syntax;
302 *op++ = tp->type;
303 continue;
305 /* unary-binary */
306 case PLUS:
307 case MINUS:
308 case STAR:
309 case AND:
310 if (rnd == 0)
312 if (tp->type == MINUS)
313 *op++ = UMINUS;
314 if (tp->type == STAR || tp->type == AND)
316 error(ERROR, "Illegal operator * or & in #if/#elif");
317 return 0;
319 continue;
321 /* flow through */
323 /* plain binary */
324 case EQ:
325 case NEQ:
326 case LEQ:
327 case GEQ:
328 case LSH:
329 case RSH:
330 case LAND:
331 case LOR:
332 case SLASH:
333 case PCT:
334 case LT:
335 case GT:
336 case CIRC:
337 case OR:
338 case QUEST:
339 case COLON:
340 case COMMA:
341 if (rnd == 0)
342 goto syntax;
343 if (evalop(priority[tp->type]) != 0)
344 return 0;
345 *op++ = tp->type;
346 rnd = 0;
347 continue;
349 case LP:
350 if (rnd)
351 goto syntax;
352 *op++ = LP;
353 continue;
355 case RP:
356 if (!rnd)
357 goto syntax;
358 if (evalop(priority[RP]) != 0)
359 return 0;
360 if (op <= ops || op[-1] != LP)
362 goto syntax;
364 op--;
365 continue;
367 case SHARP:
368 if ((tp + 1) < trp->lp)
370 np = lookup(tp + 1, 0);
371 if (np && (np->val == KMACHINE))
373 tp++;
374 if (rnd)
375 goto syntax;
376 *op++ = ARCHITECTURE;
377 continue;
380 /* fall through */
382 default:
383 error(ERROR, "Bad operator (%t) in #if/#elif", tp);
384 return 0;
387 if (rnd == 0)
388 goto syntax;
389 if (evalop(priority[END]) != 0)
390 return 0;
391 if (op != &ops[1] || vp != &vals[1])
393 error(ERROR, "Botch in #if/#elif");
394 return 0;
396 if (vals[0].type == UND)
397 error(ERROR, "Undefined expression value");
398 return vals[0].val;
399 syntax:
400 error(ERROR, "Syntax error in #if/#elif");
401 return 0;
405 evalop(struct pri pri)
407 struct value v1;
408 struct value v2 = { 0, UND };
409 long rv1, rv2;
410 int rtype, oper;
412 rv2 = 0;
413 rtype = 0;
414 while (pri.pri < priority[op[-1]].pri)
416 oper = *--op;
417 if (priority[oper].arity == 2)
419 v2 = *--vp;
420 rv2 = v2.val;
422 v1 = *--vp;
423 rv1 = v1.val;
424 /*lint -e574 -e644 */
425 switch (priority[oper].ctype)
427 case 0:
428 default:
429 error(WARNING, "Syntax error in #if/#endif");
430 return 1;
431 case ARITH:
432 case RELAT:
433 if (v1.type == UNS || v2.type == UNS)
434 rtype = UNS;
435 else
436 rtype = SGN;
437 if (v1.type == UND || v2.type == UND)
438 rtype = UND;
439 if (priority[oper].ctype == RELAT && rtype == UNS)
441 oper |= UNSMARK;
442 rtype = SGN;
444 break;
445 case SHIFT:
446 if (v1.type == UND || v2.type == UND)
447 rtype = UND;
448 else
449 rtype = v1.type;
450 if (rtype == UNS)
451 oper |= UNSMARK;
452 break;
453 case UNARY:
454 rtype = v1.type;
455 break;
456 case LOGIC:
457 case SPCL:
458 break;
460 switch (oper)
462 case EQ:
463 case EQ | UNSMARK:
464 rv1 = rv1 == rv2;
465 break;
466 case NEQ:
467 case NEQ | UNSMARK:
468 rv1 = rv1 != rv2;
469 break;
470 case LEQ:
471 rv1 = rv1 <= rv2;
472 break;
473 case GEQ:
474 rv1 = rv1 >= rv2;
475 break;
476 case LT:
477 rv1 = rv1 < rv2;
478 break;
479 case GT:
480 rv1 = rv1 > rv2;
481 break;
482 case LEQ | UNSMARK:
483 rv1 = (unsigned long)rv1 <= (unsigned long)rv2;
484 break;
485 case GEQ | UNSMARK:
486 rv1 = (unsigned long)rv1 >= (unsigned long)rv2;
487 break;
488 case LT | UNSMARK:
489 rv1 = (unsigned long)rv1 < (unsigned long)rv2;
490 break;
491 case GT | UNSMARK:
492 rv1 = (unsigned long)rv1 > (unsigned long)rv2;
493 break;
494 case LSH:
495 rv1 <<= rv2;
496 break;
497 case LSH | UNSMARK:
498 rv1 = (unsigned long) rv1 << rv2;
499 break;
500 case RSH:
501 rv1 >>= rv2;
502 break;
503 case RSH | UNSMARK:
504 rv1 = (unsigned long) rv1 >> rv2;
505 break;
506 case LAND:
507 rtype = UND;
508 if (v1.type == UND)
509 break;
510 if (rv1 != 0)
512 if (v2.type == UND)
513 break;
514 rv1 = rv2 != 0;
516 else
517 rv1 = 0;
518 rtype = SGN;
519 break;
520 case LOR:
521 rtype = UND;
522 if (v1.type == UND)
523 break;
524 if (rv1 == 0)
526 if (v2.type == UND)
527 break;
528 rv1 = rv2 != 0;
530 else
531 rv1 = 1;
532 rtype = SGN;
533 break;
534 case AND:
535 rv1 &= rv2;
536 break;
537 case STAR:
538 rv1 *= rv2;
539 break;
540 case PLUS:
541 rv1 += rv2;
542 break;
543 case MINUS:
544 rv1 -= rv2;
545 break;
546 case UMINUS:
547 if (v1.type == UND)
548 rtype = UND;
549 rv1 = -rv1;
550 break;
551 case OR:
552 rv1 |= rv2;
553 break;
554 case CIRC:
555 rv1 ^= rv2;
556 break;
557 case TILDE:
558 rv1 = ~rv1;
559 break;
560 case NOT:
561 rv1 = !rv1;
562 if (rtype != UND)
563 rtype = SGN;
564 break;
565 case SLASH:
566 if (rv2 == 0)
568 rtype = UND;
569 break;
571 if (rtype == UNS)
572 rv1 /= (unsigned long) rv2;
573 else
574 rv1 /= rv2;
575 break;
576 case PCT:
577 if (rv2 == 0)
579 rtype = UND;
580 break;
582 if (rtype == UNS)
583 rv1 %= (unsigned long) rv2;
584 else
585 rv1 %= rv2;
586 break;
587 case COLON:
588 if (op[-1] != QUEST)
589 error(ERROR, "Bad ?: in #if/endif");
590 else
592 op--;
593 if ((--vp)->val == 0)
594 v1 = v2;
595 rtype = v1.type;
596 rv1 = v1.val;
598 break;
600 case DEFINED:
601 case ARCHITECTURE:
602 break;
604 default:
605 error(ERROR, "Eval botch (unknown operator)");
606 return 1;
608 /*lint +e574 +e644 */
609 v1.val = rv1;
610 v1.type = rtype;
611 *vp++ = v1;
613 return 0;
616 struct value
617 tokval(Token * tp)
619 struct value v;
620 Nlist *np;
621 int i, base;
622 unsigned long n;
623 uchar *p, c;
625 v.type = SGN;
626 v.val = 0;
627 switch (tp->type)
630 case NAME:
631 v.val = 0;
632 break;
634 case NAME1:
635 if ((np = lookup(tp, 0)) != NULL && np->flag & (ISDEFINED | ISMAC))
636 v.val = 1;
637 break;
639 case NAME2:
640 if ((np = lookup(tp, 0)) != NULL && np->flag & (ISARCHITECTURE))
641 v.val = 1;
642 break;
644 case NUMBER:
645 n = 0;
646 base = 10;
647 p = tp->t;
648 c = p[tp->len];
649 p[tp->len] = '\0';
650 if (*p == '0')
652 base = 8;
653 if (p[1] == 'x' || p[1] == 'X')
655 base = 16;
656 p++;
658 p++;
660 for (;; p++)
662 if ((i = digit(*p)) < 0)
663 break;
664 if (i >= base)
665 error(WARNING,
666 "Bad digit in number %t", tp);
667 n *= base;
668 n += i;
670 if (n >= 0x80000000 && base != 10)
671 v.type = UNS;
672 for (; *p; p++)
674 if (*p == 'u' || *p == 'U')
675 v.type = UNS;
676 else
677 if (*p == 'l' || *p == 'L')
679 else
681 error(ERROR,
682 "Bad number %t in #if/#elif", tp);
683 break;
686 v.val = n;
687 tp->t[tp->len] = c;
688 break;
690 case CCON:
691 n = 0;
692 p = tp->t;
693 if (*p == 'L')
695 p += 1;
696 error(WARNING, "Wide char constant value undefined");
698 p += 1;
699 if (*p == '\\')
701 p += 1;
702 if ((i = digit(*p)) >= 0 && i <= 7)
704 n = i;
705 p += 1;
706 if ((i = digit(*p)) >= 0 && i <= 7)
708 p += 1;
709 n <<= 3;
710 n += i;
711 if ((i = digit(*p)) >= 0 && i <= 7)
713 p += 1;
714 n <<= 3;
715 n += i;
719 else
720 if (*p == 'x')
722 p += 1;
723 while ((i = digit(*p)) >= 0 && i <= 15)
725 p += 1;
726 n <<= 4;
727 n += i;
730 else
732 static const char cvcon[] = "b\bf\fn\nr\rt\tv\v''\"\"??\\\\";
733 static size_t cvlen = sizeof(cvcon) - 1;
735 size_t j;
736 for (j = 0; j < cvlen; j += 2)
738 if (*p == cvcon[j])
740 n = cvcon[j + 1];
741 break;
744 p += 1;
745 if (j >= cvlen)
746 error(WARNING,
747 "Undefined escape in character constant");
750 else
751 if (*p == '\'')
752 error(ERROR, "Empty character constant");
753 else
754 n = *p++;
755 if (*p != '\'')
756 error(WARNING, "Multibyte character constant undefined");
757 else
758 if (n > 127)
759 error(WARNING, "Character constant taken as not signed");
760 v.val = n;
761 break;
763 case STRING:
764 error(ERROR, "String in #if/#elif");
765 break;
767 return v;
771 digit(int i)
773 if ('0' <= i && i <= '9')
774 i -= '0';
775 else
776 if ('a' <= i && i <= 'f')
777 i -= 'a' - 10;
778 else
779 if ('A' <= i && i <= 'F')
780 i -= 'A' - 10;
781 else
782 i = -1;
783 return i;
786 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */