Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include "cpp.h"
21 :
22 : #define NSTAK 32
23 : #define SGN 0
24 : #define UNS 1
25 : #define UND 2
26 :
27 : #define UNSMARK 0x1000
28 :
29 : struct value
30 : {
31 : long val;
32 : int type;
33 : };
34 :
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
42 :
43 : /* operator priority, arity, and conversion type, indexed by tokentype */
44 : struct pri
45 : {
46 : char pri;
47 : char arity;
48 : char ctype;
49 : } priority[] =
50 :
51 : {
52 : {
53 : 0, 0, 0
54 : }, /* END */
55 : {
56 : 0, 0, 0
57 : }, /* UNCLASS */
58 : {
59 : 0, 0, 0
60 : }, /* NAME */
61 : {
62 : 0, 0, 0
63 : }, /* NUMBER */
64 : {
65 : 0, 0, 0
66 : }, /* STRING */
67 : {
68 : 0, 0, 0
69 : }, /* CCON */
70 : {
71 : 0, 0, 0
72 : }, /* NL */
73 : {
74 : 0, 0, 0
75 : }, /* WS */
76 : {
77 : 0, 0, 0
78 : }, /* DSHARP */
79 : {
80 : 11, 2, RELAT
81 : }, /* EQ */
82 : {
83 : 11, 2, RELAT
84 : }, /* NEQ */
85 : {
86 : 12, 2, RELAT
87 : }, /* LEQ */
88 : {
89 : 12, 2, RELAT
90 : }, /* GEQ */
91 : {
92 : 13, 2, SHIFT
93 : }, /* LSH */
94 : {
95 : 13, 2, SHIFT
96 : }, /* RSH */
97 : {
98 : 7, 2, LOGIC
99 : }, /* LAND */
100 : {
101 : 6, 2, LOGIC
102 : }, /* LOR */
103 : {
104 : 0, 0, 0
105 : }, /* PPLUS */
106 : {
107 : 0, 0, 0
108 : }, /* MMINUS */
109 : {
110 : 0, 0, 0
111 : }, /* ARROW */
112 : {
113 : 0, 0, 0
114 : }, /* SBRA */
115 : {
116 : 0, 0, 0
117 : }, /* SKET */
118 : {
119 : 3, 0, 0
120 : }, /* LP */
121 : {
122 : 3, 0, 0
123 : }, /* RP */
124 : {
125 : 0, 0, 0
126 : }, /* DOT */
127 : {
128 : 10, 2, ARITH
129 : }, /* AND */
130 : {
131 : 15, 2, ARITH
132 : }, /* STAR */
133 : {
134 : 14, 2, ARITH
135 : }, /* PLUS */
136 : {
137 : 14, 2, ARITH
138 : }, /* MINUS */
139 : {
140 : 16, 1, UNARY
141 : }, /* TILDE */
142 : {
143 : 16, 1, UNARY
144 : }, /* NOT */
145 : {
146 : 15, 2, ARITH
147 : }, /* SLASH */
148 : {
149 : 15, 2, ARITH
150 : }, /* PCT */
151 : {
152 : 12, 2, RELAT
153 : }, /* LT */
154 : {
155 : 12, 2, RELAT
156 : }, /* GT */
157 : {
158 : 9, 2, ARITH
159 : }, /* CIRC */
160 : {
161 : 8, 2, ARITH
162 : }, /* OR */
163 : {
164 : 5, 2, SPCL
165 : }, /* QUEST */
166 : {
167 : 5, 2, SPCL
168 : }, /* COLON */
169 : {
170 : 0, 0, 0
171 : }, /* ASGN */
172 : {
173 : 4, 2, 0
174 : }, /* COMMA */
175 : {
176 : 0, 0, 0
177 : }, /* SHARP */
178 : {
179 : 0, 0, 0
180 : }, /* SEMIC */
181 : {
182 : 0, 0, 0
183 : }, /* CBRA */
184 : {
185 : 0, 0, 0
186 : }, /* CKET */
187 : {
188 : 0, 0, 0
189 : }, /* ASPLUS */
190 : {
191 : 0, 0, 0
192 : }, /* ASMINUS */
193 : {
194 : 0, 0, 0
195 : }, /* ASSTAR */
196 : {
197 : 0, 0, 0
198 : }, /* ASSLASH */
199 : {
200 : 0, 0, 0
201 : }, /* ASPCT */
202 : {
203 : 0, 0, 0
204 : }, /* ASCIRC */
205 : {
206 : 0, 0, 0
207 : }, /* ASLSH */
208 : {
209 : 0, 0, 0
210 : }, /* ASRSH */
211 : {
212 : 0, 0, 0
213 : }, /* ASOR */
214 : {
215 : 0, 0, 0
216 : }, /* ASAND */
217 : {
218 : 0, 0, 0
219 : }, /* ELLIPS */
220 : {
221 : 0, 0, 0
222 : }, /* DSHARP1 */
223 : {
224 : 0, 0, 0
225 : }, /* NAME1 */
226 : {
227 : 0, 0, 0
228 : }, /* NAME2 */
229 : {
230 : 16, 1, UNARY
231 : }, /* DEFINED */
232 : {
233 : 16, 0, UNARY
234 : }, /* UMINUS */
235 : {
236 : 16, 1, UNARY
237 : }, /* ARCHITECTURE */
238 : };
239 :
240 : int evalop(struct pri);
241 : struct value tokval(Token *);
242 : struct value vals[NSTAK], *vp;
243 : enum toktype ops[NSTAK], *op;
244 :
245 : /*
246 : * Evaluate an #if #elif #ifdef #ifndef line. trp->tp points to the keyword.
247 : */
248 : long
249 1170 : eval(Tokenrow * trp, int kw)
250 : {
251 : Token *tp;
252 : Nlist *np;
253 : size_t ntok;
254 : int rnd;
255 :
256 1170 : trp->tp++;
257 1170 : if (kw == KIFDEF || kw == KIFNDEF)
258 : {
259 790 : if (trp->lp - trp->bp != 4 || trp->tp->type != NAME)
260 : {
261 0 : error(ERROR, "Syntax error in #ifdef/#ifndef");
262 0 : return 0;
263 : }
264 790 : np = lookup(trp->tp, 0);
265 790 : return (kw == KIFDEF) == (np && np->flag & (ISDEFINED | ISMAC));
266 : }
267 380 : ntok = trp->tp - trp->bp;
268 380 : kwdefined->val = KDEFINED; /* activate special meaning of
269 : * defined */
270 380 : expandrow(trp, "<if>");
271 380 : kwdefined->val = NAME;
272 380 : vp = vals;
273 380 : op = ops;
274 380 : *op++ = END;
275 1800 : for (rnd = 0, tp = trp->bp + ntok; tp < trp->lp; tp++)
276 : {
277 1420 : switch (tp->type)
278 : {
279 : case WS:
280 : case NL:
281 380 : continue;
282 :
283 : /* nilary */
284 : case NAME:
285 : case NAME1:
286 : case NAME2:
287 : case NUMBER:
288 : case CCON:
289 : case STRING:
290 415 : if (rnd)
291 0 : goto syntax;
292 415 : *vp++ = tokval(tp);
293 415 : rnd = 1;
294 415 : continue;
295 :
296 : /* unary */
297 : case DEFINED:
298 : case TILDE:
299 : case NOT:
300 442 : if (rnd)
301 0 : goto syntax;
302 442 : *op++ = tp->type;
303 442 : continue;
304 :
305 : /* unary-binary */
306 : case PLUS:
307 : case MINUS:
308 : case STAR:
309 : case AND:
310 0 : if (rnd == 0)
311 : {
312 0 : if (tp->type == MINUS)
313 0 : *op++ = UMINUS;
314 0 : if (tp->type == STAR || tp->type == AND)
315 : {
316 0 : error(ERROR, "Illegal operator * or & in #if/#elif");
317 0 : return 0;
318 : }
319 0 : continue;
320 : }
321 : /* flow through */
322 :
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 35 : if (rnd == 0)
342 0 : goto syntax;
343 35 : if (evalop(priority[tp->type]) != 0)
344 0 : return 0;
345 35 : *op++ = tp->type;
346 35 : rnd = 0;
347 35 : continue;
348 :
349 : case LP:
350 74 : if (rnd)
351 0 : goto syntax;
352 74 : *op++ = LP;
353 74 : continue;
354 :
355 : case RP:
356 74 : if (!rnd)
357 0 : goto syntax;
358 74 : if (evalop(priority[RP]) != 0)
359 0 : return 0;
360 74 : if (op <= ops || op[-1] != LP)
361 : {
362 : goto syntax;
363 : }
364 74 : op--;
365 74 : continue;
366 :
367 : case SHARP:
368 0 : if ((tp + 1) < trp->lp)
369 : {
370 0 : np = lookup(tp + 1, 0);
371 0 : if (np && (np->val == KMACHINE))
372 : {
373 0 : tp++;
374 0 : if (rnd)
375 0 : goto syntax;
376 0 : *op++ = ARCHITECTURE;
377 0 : continue;
378 : }
379 : }
380 : /* fall through */
381 :
382 : default:
383 0 : error(ERROR, "Bad operator (%t) in #if/#elif", tp);
384 0 : return 0;
385 : }
386 : }
387 380 : if (rnd == 0)
388 0 : goto syntax;
389 380 : if (evalop(priority[END]) != 0)
390 0 : return 0;
391 380 : if (op != &ops[1] || vp != &vals[1])
392 : {
393 0 : error(ERROR, "Botch in #if/#elif");
394 0 : return 0;
395 : }
396 380 : if (vals[0].type == UND)
397 0 : error(ERROR, "Undefined expression value");
398 380 : return vals[0].val;
399 : syntax:
400 0 : error(ERROR, "Syntax error in #if/#elif");
401 0 : return 0;
402 : }
403 :
404 : int
405 489 : evalop(struct pri pri)
406 : {
407 : struct value v1;
408 489 : struct value v2 = { 0, UND };
409 : long rv1, rv2;
410 : int rtype, oper;
411 :
412 489 : rv2 = 0;
413 489 : rtype = 0;
414 1455 : while (pri.pri < priority[op[-1]].pri)
415 : {
416 477 : oper = *--op;
417 477 : if (priority[oper].arity == 2)
418 : {
419 35 : v2 = *--vp;
420 35 : rv2 = v2.val;
421 : }
422 477 : v1 = *--vp;
423 477 : rv1 = v1.val;
424 : /*lint -e574 -e644 */
425 477 : switch (priority[oper].ctype)
426 : {
427 : case 0:
428 : default:
429 0 : error(WARNING, "Syntax error in #if/#endif");
430 0 : return 1;
431 : case ARITH:
432 : case RELAT:
433 0 : if (v1.type == UNS || v2.type == UNS)
434 0 : rtype = UNS;
435 : else
436 0 : rtype = SGN;
437 0 : if (v1.type == UND || v2.type == UND)
438 0 : rtype = UND;
439 0 : if (priority[oper].ctype == RELAT && rtype == UNS)
440 : {
441 0 : oper |= UNSMARK;
442 0 : rtype = SGN;
443 : }
444 0 : break;
445 : case SHIFT:
446 0 : if (v1.type == UND || v2.type == UND)
447 0 : rtype = UND;
448 : else
449 0 : rtype = v1.type;
450 0 : if (rtype == UNS)
451 0 : oper |= UNSMARK;
452 0 : break;
453 : case UNARY:
454 442 : rtype = v1.type;
455 442 : break;
456 : case LOGIC:
457 : case SPCL:
458 35 : break;
459 : }
460 477 : switch (oper)
461 : {
462 : case EQ:
463 : case EQ | UNSMARK:
464 0 : rv1 = rv1 == rv2;
465 0 : break;
466 : case NEQ:
467 : case NEQ | UNSMARK:
468 0 : rv1 = rv1 != rv2;
469 0 : break;
470 : case LEQ:
471 0 : rv1 = rv1 <= rv2;
472 0 : break;
473 : case GEQ:
474 0 : rv1 = rv1 >= rv2;
475 0 : break;
476 : case LT:
477 0 : rv1 = rv1 < rv2;
478 0 : break;
479 : case GT:
480 0 : rv1 = rv1 > rv2;
481 0 : break;
482 : case LEQ | UNSMARK:
483 0 : rv1 = (unsigned long)rv1 <= (unsigned long)rv2;
484 0 : break;
485 : case GEQ | UNSMARK:
486 0 : rv1 = (unsigned long)rv1 >= (unsigned long)rv2;
487 0 : break;
488 : case LT | UNSMARK:
489 0 : rv1 = (unsigned long)rv1 < (unsigned long)rv2;
490 0 : break;
491 : case GT | UNSMARK:
492 0 : rv1 = (unsigned long)rv1 > (unsigned long)rv2;
493 0 : break;
494 : case LSH:
495 0 : rv1 <<= rv2;
496 0 : break;
497 : case LSH | UNSMARK:
498 0 : rv1 = (unsigned long) rv1 << rv2;
499 0 : break;
500 : case RSH:
501 0 : rv1 >>= rv2;
502 0 : break;
503 : case RSH | UNSMARK:
504 0 : rv1 = (unsigned long) rv1 >> rv2;
505 0 : break;
506 : case LAND:
507 28 : rtype = UND;
508 28 : if (v1.type == UND)
509 0 : break;
510 28 : if (rv1 != 0)
511 : {
512 21 : if (v2.type == UND)
513 0 : break;
514 21 : rv1 = rv2 != 0;
515 : }
516 : else
517 7 : rv1 = 0;
518 28 : rtype = SGN;
519 28 : break;
520 : case LOR:
521 7 : rtype = UND;
522 7 : if (v1.type == UND)
523 0 : break;
524 7 : if (rv1 == 0)
525 : {
526 5 : if (v2.type == UND)
527 0 : break;
528 5 : rv1 = rv2 != 0;
529 : }
530 : else
531 2 : rv1 = 1;
532 7 : rtype = SGN;
533 7 : break;
534 : case AND:
535 0 : rv1 &= rv2;
536 0 : break;
537 : case STAR:
538 0 : rv1 *= rv2;
539 0 : break;
540 : case PLUS:
541 0 : rv1 += rv2;
542 0 : break;
543 : case MINUS:
544 0 : rv1 -= rv2;
545 0 : break;
546 : case UMINUS:
547 0 : if (v1.type == UND)
548 0 : rtype = UND;
549 0 : rv1 = -rv1;
550 0 : break;
551 : case OR:
552 0 : rv1 |= rv2;
553 0 : break;
554 : case CIRC:
555 0 : rv1 ^= rv2;
556 0 : break;
557 : case TILDE:
558 0 : rv1 = ~rv1;
559 0 : break;
560 : case NOT:
561 27 : rv1 = !rv1;
562 27 : if (rtype != UND)
563 27 : rtype = SGN;
564 27 : break;
565 : case SLASH:
566 0 : if (rv2 == 0)
567 : {
568 0 : rtype = UND;
569 0 : break;
570 : }
571 0 : if (rtype == UNS)
572 0 : rv1 /= (unsigned long) rv2;
573 : else
574 0 : rv1 /= rv2;
575 0 : break;
576 : case PCT:
577 0 : if (rv2 == 0)
578 : {
579 0 : rtype = UND;
580 0 : break;
581 : }
582 0 : if (rtype == UNS)
583 0 : rv1 %= (unsigned long) rv2;
584 : else
585 0 : rv1 %= rv2;
586 0 : break;
587 : case COLON:
588 0 : if (op[-1] != QUEST)
589 0 : error(ERROR, "Bad ?: in #if/endif");
590 : else
591 : {
592 0 : op--;
593 0 : if ((--vp)->val == 0)
594 0 : v1 = v2;
595 0 : rtype = v1.type;
596 0 : rv1 = v1.val;
597 : }
598 0 : break;
599 :
600 : case DEFINED:
601 : case ARCHITECTURE:
602 415 : break;
603 :
604 : default:
605 0 : error(ERROR, "Eval botch (unknown operator)");
606 0 : return 1;
607 : }
608 : /*lint +e574 +e644 */
609 477 : v1.val = rv1;
610 477 : v1.type = rtype;
611 477 : *vp++ = v1;
612 : }
613 489 : return 0;
614 : }
615 :
616 : struct value
617 415 : tokval(Token * tp)
618 : {
619 : struct value v;
620 : Nlist *np;
621 : int i, base;
622 : unsigned long n;
623 : uchar *p, c;
624 :
625 415 : v.type = SGN;
626 415 : v.val = 0;
627 415 : switch (tp->type)
628 : {
629 :
630 : case NAME:
631 0 : v.val = 0;
632 0 : break;
633 :
634 : case NAME1:
635 415 : if ((np = lookup(tp, 0)) != NULL && np->flag & (ISDEFINED | ISMAC))
636 32 : v.val = 1;
637 415 : break;
638 :
639 : case NAME2:
640 0 : if ((np = lookup(tp, 0)) != NULL && np->flag & (ISARCHITECTURE))
641 0 : v.val = 1;
642 0 : break;
643 :
644 : case NUMBER:
645 0 : n = 0;
646 0 : base = 10;
647 0 : p = tp->t;
648 0 : c = p[tp->len];
649 0 : p[tp->len] = '\0';
650 0 : if (*p == '0')
651 : {
652 0 : base = 8;
653 0 : if (p[1] == 'x' || p[1] == 'X')
654 : {
655 0 : base = 16;
656 0 : p++;
657 : }
658 0 : p++;
659 : }
660 0 : for (;; p++)
661 : {
662 0 : if ((i = digit(*p)) < 0)
663 0 : break;
664 0 : if (i >= base)
665 0 : error(WARNING,
666 : "Bad digit in number %t", tp);
667 0 : n *= base;
668 0 : n += i;
669 0 : }
670 0 : if (n >= 0x80000000 && base != 10)
671 0 : v.type = UNS;
672 0 : for (; *p; p++)
673 : {
674 0 : if (*p == 'u' || *p == 'U')
675 0 : v.type = UNS;
676 : else
677 0 : if (*p == 'l' || *p == 'L')
678 : ;
679 : else
680 : {
681 0 : error(ERROR,
682 : "Bad number %t in #if/#elif", tp);
683 0 : break;
684 : }
685 : }
686 0 : v.val = n;
687 0 : tp->t[tp->len] = c;
688 0 : break;
689 :
690 : case CCON:
691 0 : n = 0;
692 0 : p = tp->t;
693 0 : if (*p == 'L')
694 : {
695 0 : p += 1;
696 0 : error(WARNING, "Wide char constant value undefined");
697 : }
698 0 : p += 1;
699 0 : if (*p == '\\')
700 : {
701 0 : p += 1;
702 0 : if ((i = digit(*p)) >= 0 && i <= 7)
703 : {
704 0 : n = i;
705 0 : p += 1;
706 0 : if ((i = digit(*p)) >= 0 && i <= 7)
707 : {
708 0 : p += 1;
709 0 : n <<= 3;
710 0 : n += i;
711 0 : if ((i = digit(*p)) >= 0 && i <= 7)
712 : {
713 0 : p += 1;
714 0 : n <<= 3;
715 0 : n += i;
716 : }
717 : }
718 : }
719 : else
720 0 : if (*p == 'x')
721 : {
722 0 : p += 1;
723 0 : while ((i = digit(*p)) >= 0 && i <= 15)
724 : {
725 0 : p += 1;
726 0 : n <<= 4;
727 0 : n += i;
728 : }
729 : }
730 : else
731 : {
732 : static const char cvcon[] = "b\bf\fn\nr\rt\tv\v''\"\"??\\\\";
733 : static size_t cvlen = sizeof(cvcon) - 1;
734 :
735 : size_t j;
736 0 : for (j = 0; j < cvlen; j += 2)
737 : {
738 0 : if (*p == cvcon[j])
739 : {
740 0 : n = cvcon[j + 1];
741 0 : break;
742 : }
743 : }
744 0 : p += 1;
745 0 : if (j >= cvlen)
746 0 : error(WARNING,
747 : "Undefined escape in character constant");
748 : }
749 : }
750 : else
751 0 : if (*p == '\'')
752 0 : error(ERROR, "Empty character constant");
753 : else
754 0 : n = *p++;
755 0 : if (*p != '\'')
756 0 : error(WARNING, "Multibyte character constant undefined");
757 : else
758 0 : if (n > 127)
759 0 : error(WARNING, "Character constant taken as not signed");
760 0 : v.val = n;
761 0 : break;
762 :
763 : case STRING:
764 0 : error(ERROR, "String in #if/#elif");
765 0 : break;
766 : }
767 415 : return v;
768 : }
769 :
770 : int
771 0 : digit(int i)
772 : {
773 0 : if ('0' <= i && i <= '9')
774 0 : i -= '0';
775 : else
776 0 : if ('a' <= i && i <= 'f')
777 0 : i -= 'a' - 10;
778 : else
779 0 : if ('A' <= i && i <= 'F')
780 0 : i -= 'A' - 10;
781 : else
782 0 : i = -1;
783 0 : return i;
784 : }
785 :
786 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|