]> andersk Git - splint.git/blob - src/cppexp.c
Fixed state clauses. Added obvious loop exec checking.
[splint.git] / src / cppexp.c
1 /*
2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2002 University of Virginia,
4 **         Massachusetts Institute of Technology
5 **
6 ** This program is free software; you can redistribute it and/or modify it
7 ** under the terms of the GNU General Public License as published by the
8 ** Free Software Foundation; either version 2 of the License, or (at your
9 ** option) any later version.
10 ** 
11 ** This program is distributed in the hope that it will be useful, but
12 ** WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 ** General Public License for more details.
15 ** 
16 ** The GNU General Public License is available from http://www.gnu.org/ or
17 ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18 ** MA 02111-1307, USA.
19 **
20 ** For information on lclint: lclint-request@cs.virginia.edu
21 ** To report a bug: lclint-bug@cs.virginia.edu
22 ** For more information: http://www.splint.org
23 */
24 /*
25 ** cppexp.c
26 */
27 /* Parse C expressions for CCCP.
28    Copyright (C) 1987, 1992, 1994, 1995, 1997 Free Software Foundation.
29
30 This program is free software; you can redistribute it and/or modify it
31 under the terms of the GNU General Public License as published by the
32 Free Software Foundation; either version 2, or (at your option) any
33 later version.
34
35 This program is distributed in the hope that it will be useful,
36 but WITHOUT ANY WARRANTY; without even the implied warranty of
37 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
38 GNU General Public License for more details.
39
40 You should have received a copy of the GNU General Public License
41 along with this program; if not, write to the Free Software
42 Foundation, 59 Temple Place - Suite 330,
43 Boston, MA 02111-1307, USA.
44
45  In other words, you are welcome to use, share and improve this program.
46  You are forbidden to forbid anyone else to use, share and improve
47  what you give them.   Help stamp out software-hoarding!
48
49 Written by Per Bothner 1994.  */
50
51 /* Parse a C expression from text in a string  */
52
53 /*@+charint@*/
54 /*@+ignorequals@*/
55 /*@+ignoresigns@*/
56 /*@+matchanyintegral@*/
57 /*@-shiftsigned@*/
58
59 # include <string.h> 
60 # include "lclintMacros.nf"
61 # include "llbasic.h"
62 # include "cpplib.h"
63 # include "cpphash.h"
64 # include "cppexp.h"
65 # include "cpperror.h"
66
67 /* Yield nonzero if adding two numbers with A's and B's signs can yield a
68    number with SUM's sign, where A, B, and SUM are all C integers.  */
69
70 /*@function static bool possibleSumSign (sef int, int, int) 
71       modifies nothing ; @*/
72
73 #define possibleSumSign(a, b, sum) ((((a) ^ (b)) | ~ ((a) ^ (sum))) < 0)
74
75 /* these are guesses! */ 
76
77 /*@constant int BITS_PER_UNIT@*/
78 # define BITS_PER_UNIT 8
79
80 /*@constant size_t BITS_PER_CHAR@*/
81 # define BITS_PER_CHAR 8
82
83 /*@constant size_t BITS_PER_WORD@*/
84 # define BITS_PER_WORD 32
85
86 /*@constant size_t HOST_BITS_PER_INT@*/
87 # define HOST_BITS_PER_INT 32
88
89 /*@constant size_t HOST_BITS_PER_LONG@*/
90 # define HOST_BITS_PER_LONG 32
91
92 /*@constant char TARGET_BELL@*/
93 # define TARGET_BELL (char) 6 
94
95 /*@constant char TARGET_BS@*/
96 # define TARGET_BS   (char) 7
97
98 /*@constant char TARGET_FF@*/
99 # define TARGET_FF   (char) 8
100
101 /*@constant char TARGET_NEWLINE@*/
102 # define TARGET_NEWLINE '\n' 
103
104 /*@constant char TARGET_CR@*/
105 # define TARGET_CR '\n'
106
107 /*@constant char TARGET_TAB@*/
108 # define TARGET_TAB '\t'
109
110 /*@constant char TARGET_VT@*/
111 # define TARGET_VT '\v'
112
113 #ifdef MULTIBYTE_CHARS
114 #include <stdlib.h>
115 #include <locale.h>
116 #endif
117
118 #include <stdio.h>
119
120 #ifndef INT_TYPE_SIZE
121 /*@constant size_t INT_TYPE_SIZE@*/
122 #define INT_TYPE_SIZE BITS_PER_WORD
123 #endif
124
125 #ifndef LONG_TYPE_SIZE
126 /*@constant size_t LONG_TYPE_SIZE@*/
127 #define LONG_TYPE_SIZE BITS_PER_WORD
128 #endif
129
130 #ifndef WCHAR_TYPE_SIZE
131 /*@constant size_t WCHAR_TYPE_SIZE@*/
132 #define WCHAR_TYPE_SIZE INT_TYPE_SIZE
133 #endif
134
135 # ifndef CHAR_TYPE_SIZE
136 /*@constant size_t CHAR_TYPE_SIZE@*/
137 # define CHAR_TYPE_SIZE BITS_PER_CHAR
138 # endif
139
140 #ifndef MAX_CHAR_TYPE_SIZE
141 /*@constant size_t MAX_CHAR_TYPE_SIZE@*/
142 #define MAX_CHAR_TYPE_SIZE CHAR_TYPE_SIZE
143 #endif
144
145 #ifndef MAX_LONG_TYPE_SIZE
146 /*@constant size_t MAX_LONG_TYPE_SIZE@*/
147 #define MAX_LONG_TYPE_SIZE LONG_TYPE_SIZE
148 #endif
149
150 #ifndef MAX_WCHAR_TYPE_SIZE
151 /*@constant size_t MAX_WCHAR_TYPE_SIZE@*/
152 #define MAX_WCHAR_TYPE_SIZE WCHAR_TYPE_SIZE
153 #endif
154
155 static struct operation cppexp_lex (cppReader *);
156 static void integer_overflow (cppReader *);
157 static long left_shift (cppReader *, long, bool p_unsignedp, size_t);
158 static long right_shift (long, bool p_unsignedp, unsigned long);
159
160 /*@constant short CPPREADER_ERRORTOK@*/
161 #define CPPREADER_ERRORTOK 299
162
163 /*@constant int OROR@*/
164 #define OROR 300
165
166 /*@constant int ANDAND@*/
167 #define ANDAND 301
168
169 /*@constant int CPP_EQUALTOK@*/
170 #define CPP_EQUALTOK 302
171
172 /*@constant int NOTEQUAL@*/
173 #define NOTEQUAL 303
174
175 /*@constant int LEQ@*/
176 #define LEQ 304
177
178 /*@constant int GEQ@*/
179 #define GEQ 305
180
181 /*@constant int LSH@*/
182 #define LSH 306
183
184 /*@constant int RSH@*/
185 #define RSH 307
186
187 /*@constant int NAME@*/
188 #define NAME 308
189
190 /*@constant short CPPEXP_INT@*/
191 #define CPPEXP_INT 309
192
193 /*@constant short CPPEXP_CHAR@*/
194 #define CPPEXP_CHAR 310
195
196 /*@constant int LEFT_OPERAND_REQUIRED@*/
197 #define LEFT_OPERAND_REQUIRED 1
198
199 /*@constant int RIGHT_OPERAND_REQUIRED@*/
200 #define RIGHT_OPERAND_REQUIRED 2
201
202 /*@constant int HAVE_VALUE@*/
203 #define HAVE_VALUE 4
204
205 #ifndef HOST_BITS_PER_WIDE_INT
206
207 #if HOST_BITS_PER_LONG > HOST_BITS_PER_INT
208 /*@constant int HOST_BITS_PER_WIDE_INT@*/
209 #define HOST_BITS_PER_WIDE_INT HOST_BITS_PER_LONG
210 /*@notfunction@*/
211 #define HOST_WIDE_INT long
212 #else
213 /*@constant int HOST_BITS_PER_WIDE_INT@*/
214 #define HOST_BITS_PER_WIDE_INT HOST_BITS_PER_INT
215 /*@notfunction@*/
216 #define HOST_WIDE_INT long
217 #endif
218
219 #endif
220
221 struct operation {
222   short op;
223
224   /* Priority of op (relative to it right operand).  */
225   /*@reldef@*/ char rprio;
226
227   /*@reldef@*/ char flags;
228
229   /* true if value should be treated as unsigned */
230   /*@reldef@*/ bool unsignedp;
231
232   /* The value logically "right" of op.  */
233   /*@reldef@*/ HOST_WIDE_INT value;
234 } ;
235
236 /* Take care of parsing a number (anything that starts with a digit).
237    LEN is the number of characters in it.  */
238
239 /* maybe needs to actually deal with floating point numbers */
240
241 struct operation
242 cppReader_parseNumber (cppReader *pfile, char *start, int olen)
243 {
244   struct operation op;
245   char *p = start;
246   char c;
247   int i;
248   long n = 0;
249   unsigned long nd, ULONG_MAX_over_base;
250   int base = 10;
251   int len = olen;
252   bool overflow = FALSE;
253   int digit, largest_digit = 0;
254   bool spec_long = FALSE;
255
256   op.unsignedp = FALSE;
257
258   for (i = 0; i < len; i++)
259     {
260       if (p[i] == '.') {
261         /* It's a float since it contains a point.  */
262         cppReader_errorLit
263           (pfile,
264            cstring_makeLiteralTemp
265            ("Floating point numbers not allowed in #if expressions"));
266         op.op = CPPREADER_ERRORTOK;
267         return op;
268       }
269     }
270       
271   if (len >= 3 && (mstring_equalPrefix (p, "0x") 
272                    || mstring_equalPrefix (p, "0X")))
273     {
274       p += 2;
275       base = 16;
276       len -= 2;
277     }
278   else if (*p == '0')
279     {
280       base = 8;
281     }
282   else
283     {
284       ;
285     }
286
287   /* Some buggy compilers (e.g. MPW C) seem to need both casts.  */
288   ULONG_MAX_over_base = ((unsigned long) -1) / ((unsigned long) base);
289
290   for (; len > 0; len--) {
291     c = *p++;
292
293     if (c >= '0' && c <= '9')
294       {
295         digit = (int) (c - '0');
296       }
297     else if (base == 16 && c >= 'a' && c <= 'f')
298       {
299         digit = (int) (c - 'a') + 10;
300       }
301     else if (base == 16 && c >= 'A' && c <= 'F')
302       {
303         digit = (int) (c - 'A') + 10;
304       }
305     else 
306       {
307         /* `l' means long, and `u' means unsigned.  */
308         while (TRUE)
309           {
310             if (c == 'l' || c == 'L')
311               {
312                 if (spec_long)
313                   cppReader_errorLit (pfile,
314                                       cstring_makeLiteralTemp ("two `l's in integer constant"));
315                 spec_long = TRUE;
316               }
317             else if (c == 'u' || c == 'U')
318               {
319                 if (op.unsignedp)
320                   cppReader_errorLit (pfile, 
321                                       cstring_makeLiteralTemp ("two `u's in integer constant"));
322                 op.unsignedp = TRUE;
323               }
324             else
325               {
326                 /*@innerbreak@*/ break;
327               }
328             
329             if (--len == 0)
330               {
331                 /*@innerbreak@*/ break;
332               }
333
334             c = *p++;
335           }
336         /* Don't look for any more digits after the suffixes.  */
337         break;
338       }
339     
340     if (largest_digit < digit)
341       {
342         largest_digit = digit;
343       }
344     
345     nd = (long unsigned) (n * base + digit);
346     overflow |= (ULONG_MAX_over_base < (unsigned long) n) 
347       | (nd < (unsigned long) n);
348     n = (long) nd;
349   }
350
351   if (len != 0)
352     {
353       cppReader_errorLit 
354         (pfile, 
355          cstring_makeLiteralTemp ("Invalid number in #if expression"));
356       op.op = CPPREADER_ERRORTOK;
357       return op;
358     }
359   
360   if (base <= largest_digit)
361     {
362       cppReader_pedwarnLit 
363         (pfile, 
364          cstring_makeLiteralTemp 
365          ("Integer constant contains digits beyond the radix"));
366     }
367   
368   if (overflow)
369     {
370       /*@i23 add flags for all these...*/
371       cppReader_pedwarnLit
372         (pfile, 
373          cstring_makeLiteralTemp ("Integer constant out of range"));
374     }
375
376   /* If too big to be signed, consider it unsigned.  */
377   if ((long) n < 0 && ! op.unsignedp)
378     {
379       if (base == 10)
380         {
381           cppReader_warningLit
382             (pfile,
383              cstring_makeLiteralTemp ("Integer constant is so large that it is unsigned"));
384         }
385          
386       op.unsignedp = TRUE;
387     }
388   
389   op.value = n;
390   op.op = CPPEXP_INT;
391   DPRINTF (("Parse number: %d", op.value));
392   return op;
393 }
394
395 struct token {
396   /*@null@*/ /*@observer@*/ char *operator;
397   int token;
398 };
399
400 static struct token tokentab2[] = {
401   { "&&", ANDAND },
402   { "||", OROR },
403   { "<<", LSH },
404   { ">>", RSH },
405   { "==", CPP_EQUALTOK },
406   { "!=", NOTEQUAL },
407   { "<=", LEQ },
408   { ">=", GEQ },
409   { "++", CPPREADER_ERRORTOK },
410   { "--", CPPREADER_ERRORTOK },
411   { NULL, CPPREADER_ERRORTOK }
412 } ;
413
414 /* Read one token.  */
415
416 struct operation cppexp_lex (cppReader *pfile)
417 {
418   int ic;
419   char c;
420   register struct token *toktab;
421   enum cpp_token token;
422   struct operation op;
423   char *tok_start, *tok_end;
424   int old_written;
425
426  retry:
427   
428   old_written = size_toInt (cpplib_getWritten (pfile));
429   cppSkipHspace (pfile);
430   ic = cpplib_bufPeek (cppReader_getBufferSafe (pfile));
431
432   c = (char) ic;
433   llassert (c != '#');
434   DPRINTF (("Read: %c", c));
435
436   if (c == '\n')
437     {
438       op.op = 0;
439       return op;
440     }
441
442   token = cpplib_getTokenForceExpand (pfile);
443
444   tok_start = pfile->token_buffer + old_written;
445   tok_end = cpplib_getPWritten (pfile);
446
447   DPRINTF (("Token: %s < %s", tok_start, tok_end));
448
449   pfile->limit = tok_start;
450
451   switch (token)
452     {
453     case CPP_EOF: /* Should not happen ...  */
454     case CPP_VSPACE:
455       op.op = 0;
456       return op;
457     case CPP_POP:
458       if (cstring_isDefined (cppReader_getBufferSafe (pfile)->fname))
459         {
460           op.op = 0;
461           return op;
462         }
463       (void) cppReader_popBuffer (pfile);
464       goto retry;
465     case CPP_HSPACE:   case CPP_COMMENT: 
466       goto retry;
467     case CPP_NUMBER:
468       return cppReader_parseNumber (pfile, tok_start, tok_end - tok_start);
469     case CPP_STRING:
470       cppReader_errorLit (pfile, 
471                           cstring_makeLiteralTemp ("string constants not allowed in #if expressions"));
472       op.op = CPPREADER_ERRORTOK;
473       return op;
474     case CPP_CHAR:
475       /* This code for reading a character constant
476          handles multicharacter constants and wide characters.
477          It is mostly copied from c-lex.c.  */
478       {
479         int result = 0;
480         int num_chars = 0;
481         size_t width = MAX_CHAR_TYPE_SIZE;
482         int wide_flag = 0;
483         int max_chars;
484         char *ptr = tok_start;
485 #ifdef MULTIBYTE_CHARS
486         char token_buffer[MAX_LONG_TYPE_SIZE/MAX_CHAR_TYPE_SIZE + MB_CUR_MAX];
487 #else
488         char token_buffer[MAX_LONG_TYPE_SIZE/MAX_CHAR_TYPE_SIZE + 1];
489 #endif
490         
491         if (*ptr == 'L')
492           {
493             ptr++;
494             wide_flag = 1;
495             width = MAX_WCHAR_TYPE_SIZE;
496 #ifdef MULTIBYTE_CHARS
497             max_chars = MB_CUR_MAX;
498 #else
499             max_chars = 1;
500 #endif
501           }
502         else
503           {
504             max_chars = size_toInt (MAX_LONG_TYPE_SIZE / width);
505           }
506         
507         ++ptr;
508         while (ptr < tok_end && ((c = *ptr++) != '\''))
509           {
510             if (c == '\\')
511               {
512                 c = cppReader_parseEscape (pfile, &ptr);
513                 if (width < HOST_BITS_PER_INT && c >= (1 << width))
514                   {
515                     cppReader_pedwarnLit 
516                       (pfile,
517                        cstring_makeLiteralTemp ("Escape sequence out of range for character"));
518                   }
519               }
520                 
521             num_chars++;
522             
523             /* Merge character into result; ignore excess chars.  */
524             if (num_chars < max_chars + 1)
525               {
526                 if (width < HOST_BITS_PER_INT)
527                   {
528                     result = (int) ((unsigned) result << width) | (c & ((1 << width) - 1));
529                   }
530                 else
531                   {
532                     result = c;
533                   }
534
535                 token_buffer[num_chars - 1] = c;
536               }
537           }
538
539         token_buffer[num_chars] = 0;
540
541         if (c != '\'')
542           cppReader_errorLit (pfile,
543                         cstring_makeLiteralTemp ("malformatted character constant"));
544         else if (num_chars == 0)
545           cppReader_errorLit (pfile, 
546                         cstring_makeLiteralTemp ("empty character constant"));
547         else if (num_chars > max_chars)
548           {
549             num_chars = max_chars;
550             cppReader_errorLit (pfile, 
551                           cstring_makeLiteralTemp ("character constant too long"));
552           }
553         else if (num_chars != 1 && ! cppReader_isTraditional (pfile))
554           {
555             cppReader_warningLit (pfile, 
556                             cstring_makeLiteralTemp ("multi-character character constant"));
557           }
558         else
559           {
560             ;
561           }
562
563         /* If char type is signed, sign-extend the constant.  */
564         if (wide_flag == 0)
565           {
566             int num_bits = num_chars * width;
567
568             if ((cpphash_lookup ("__CHAR_UNSIGNED__",
569                              sizeof ("__CHAR_UNSIGNED__") - 1, -1) != NULL)
570                 || (((unsigned) result >> (num_bits - 1)) & 1) == 0)
571               {
572                 op.value
573                   = result & ((unsigned long) ~0 >> (HOST_BITS_PER_LONG - num_bits));
574               }
575             else
576               {
577                 op.value
578                   = result | ~((unsigned long) ~0 >> (HOST_BITS_PER_LONG - num_bits));
579               }
580           }
581         else
582           {
583 #ifdef MULTIBYTE_CHARS
584             /* Set the initial shift state and convert the next sequence.  */
585               result = 0;
586               /* In all locales L'\0' is zero and mbtowc will return zero,
587                  so don't use it.  */
588               if (num_chars > 1
589                   || (num_chars == 1 && token_buffer[0] != '\0'))
590                 {
591                   wchar_t wc;
592                   (void) mbtowc (NULL, NULL, 0);
593                   if (mbtowc (& wc, token_buffer, num_chars) == num_chars)
594                     result = wc;
595                   else
596                     cppReader_pedwarn (pfile,"Ignoring invalid multibyte character");
597                 }
598 #endif
599               op.value = result;
600             }
601         }
602
603       /* This is always a signed type.  */
604       op.unsignedp = FALSE;
605       op.op = CPPEXP_CHAR;
606     
607       return op;
608
609     case CPP_NAME:
610       DPRINTF (("Name!"));
611       return cppReader_parseNumber (pfile, "0", 0);
612
613     case CPP_OTHER:
614       /* See if it is a special token of length 2.  */
615       if (tok_start + 2 == tok_end)
616         {
617           for (toktab = tokentab2; toktab->operator != NULL; toktab++)
618             {
619               if (tok_start[0] == toktab->operator[0]
620                   && tok_start[1] == toktab->operator[1])
621                 {
622                   /*@loopbreak@*/ break;
623                 }
624             }
625
626           if (toktab->token == CPPREADER_ERRORTOK)
627             {
628               cppReader_error (pfile, message ("`%s' not allowed in operand of `#if'", cstring_fromChars (tok_start)));
629             }
630
631           op.op = toktab->token; 
632           return op;
633         }
634       /*@fallthrough@*/ 
635     default:
636       op.op = *tok_start;
637       return op;
638   }
639
640   BADEXIT;
641   /*@notreached@*/ 
642 }
643
644
645 /* Parse a C escape sequence.  STRING_PTR points to a variable
646    containing a pointer to the string to parse.  That pointer
647    is updated past the characters we use.  The value of the
648    escape sequence is returned.
649
650    A negative value means the sequence \ newline was seen,
651    which is supposed to be equivalent to nothing at all.
652
653    If \ is followed by a null character, we return a negative
654    value and leave the string pointer pointing at the null character.
655
656    If \ is followed by 000, we return 0 and leave the string pointer
657    after the zeros.  A value of 0 does not mean end of string.  */
658
659 int
660 cppReader_parseEscape (cppReader *pfile, char **string_ptr)
661 {
662   char c = *(*string_ptr)++;
663
664   switch (c)
665     {
666     case 'a':
667       return TARGET_BELL;
668     case 'b':
669       return TARGET_BS;
670     case 'e':
671     case 'E':
672       if (cppReader_isPedantic (pfile))
673         {
674           cppReader_pedwarn (pfile, 
675                        message ("non-ANSI-standard escape sequence, `\\%c'", c));
676         }
677       return (char) 033;
678     case 'f':
679       return TARGET_FF;
680     case 'n':
681       return TARGET_NEWLINE;
682     case 'r':
683       return TARGET_CR;
684     case 't':
685       return TARGET_TAB;
686     case 'v':
687       return TARGET_VT;
688     case '\n':
689       return -2;
690     case 0:
691       (*string_ptr)--;
692       return 0;
693       
694     case '0':
695     case '1':
696     case '2':
697     case '3':
698     case '4':
699     case '5':
700     case '6':
701     case '7':
702       {
703         int i = (int) c - '0';
704         int count = 0;
705
706         while (++count < 3)
707           {
708             c = *(*string_ptr)++;
709             if (c >= '0' && c <= '7')
710               {
711                 i = ((unsigned) i << 3) + c - '0';
712               }
713
714             else
715               {
716                 (*string_ptr)--;
717                 /*@loopbreak@*/ break;
718               }
719           }
720         if ((i & ~((1 << MAX_CHAR_TYPE_SIZE) - 1)) != 0)
721           {
722             i &= (1 << MAX_CHAR_TYPE_SIZE) - 1;
723             cppReader_pedwarnLit (pfile,
724                             cstring_makeLiteralTemp ("octal character constant does not fit in a byte"));
725           }
726         return i;
727       }
728     case 'x':
729       {
730         register unsigned i = 0, overflow = 0, digits_found = 0, digit;
731         for (;;)
732           {
733             c = *(*string_ptr)++;
734
735             if (c >= '0' && c <= '9')
736               {
737                 digit = (unsigned int) (c - '0');
738               }
739             else if (c >= 'a' && c <= 'f')
740               {
741                 digit = (unsigned int) (c - 'a') + 10;
742               }
743             else if (c >= 'A' && c <= 'F')
744               {
745                 digit = (unsigned int) (c - 'A') + 10;
746               }
747             else
748               {
749                 (*string_ptr)--;
750                 /*@loopbreak@*/ break;
751               }
752             overflow |= i ^ (i << 4 >> 4);
753             i = (i << 4) + digit;
754             digits_found = 1;
755           }
756         
757         if (digits_found == 0)
758           {
759             cppReader_errorLit (pfile,
760                                 cstring_makeLiteralTemp ("\\x used with no following hex digits"));
761           }
762
763         if ((overflow | (i & ~((1 << BITS_PER_UNIT) - 1))) != 0)
764           {
765             i &= (1 << BITS_PER_UNIT) - 1;
766             cppReader_pedwarnLit (pfile,
767                             cstring_makeLiteralTemp ("hex character constant does not fit in a byte"));
768           }
769
770         return i;
771       }
772     default:
773       return c;
774     }
775 }
776
777 static void
778 integer_overflow (cppReader *pfile)
779 {
780   if (cppReader_isPedantic (pfile))
781     cppReader_pedwarnLit (pfile, 
782                     cstring_makeLiteralTemp ("integer overflow in preprocessor expression"));
783 }
784
785 static long
786 left_shift (cppReader *pfile, long a, bool unsignedp, size_t b)
787 {
788   if (b >= HOST_BITS_PER_LONG)
789     {
790       if (!unsignedp && a != 0)
791         {
792           integer_overflow (pfile);
793         }
794
795       return 0;
796     }
797   else if (unsignedp)
798     {
799       return (unsigned long) a << b;
800     }
801   else
802     {
803       long l = a << b;
804       
805       if (l >> b != a)
806         {
807           integer_overflow (pfile);
808         }
809
810       return l;
811     }
812 }
813
814 static long
815 right_shift (long a, bool unsignedp, unsigned long b)
816 {
817   if (b >= HOST_BITS_PER_LONG)
818     return (unsignedp ? 0 : a >> (HOST_BITS_PER_LONG - 1));
819   else if (unsignedp)
820     return (unsigned long) a >> b;
821   else
822     return a >> b;
823 }
824
825 /* These priorities are all even, so we can handle associatively.  */
826
827 /*@constant int PAREN_INNER_PRIO@*/
828 #define PAREN_INNER_PRIO 0
829
830 /*@constant int COMMA_PRIO@*/
831 #define COMMA_PRIO 4
832
833 /*@constant int COND_PRIO@*/
834 #define COND_PRIO (COMMA_PRIO+2)
835
836 /*@constant int OROR_PRIO@*/
837 #define OROR_PRIO (COND_PRIO+2)
838
839 /*@constant int ANDAND_PRIO@*/
840 #define ANDAND_PRIO (OROR_PRIO+2)
841
842 /*@constant int OR_PRIO@*/
843 #define OR_PRIO (ANDAND_PRIO+2)
844
845 /*@constant int XOR_PRIO@*/
846 #define XOR_PRIO (OR_PRIO+2)
847
848 /*@constant int AND_PRIO@*/
849 #define AND_PRIO (XOR_PRIO+2)
850
851 /*@constant int CPP_EQUAL_PRIO@*/
852 #define CPP_EQUAL_PRIO (AND_PRIO+2)
853
854 /*@constant int LESS_PRIO@*/
855 #define LESS_PRIO (CPP_EQUAL_PRIO+2)
856
857 /*@constant int SHIFT_PRIO@*/
858 #define SHIFT_PRIO (LESS_PRIO+2)
859
860 /*@constant int PLUS_PRIO@*/
861 #define PLUS_PRIO (SHIFT_PRIO+2)
862
863 /*@constant int MUL_PRIO@*/
864 #define MUL_PRIO (PLUS_PRIO+2)
865
866 /*@constant int UNARY_PRIO@*/
867 #define UNARY_PRIO (MUL_PRIO+2)
868
869 /*@constant int PAREN_OUTER_PRIO@*/
870 #define PAREN_OUTER_PRIO (UNARY_PRIO+2)
871
872 /*@notfunction@*/
873 #define COMPARE(OP) \
874   top->unsignedp = FALSE;\
875   top->value = ((unsigned1 || unsigned2) \
876                  ? (unsigned long) v1 OP (unsigned long) v2 \
877                  : ((long) v1 OP (long) v2)) ? 1 : 0
878
879 /* Parse and evaluate a C expression, reading from PFILE.
880    Returns the value of the expression.  */
881
882 /*@constant int INIT_STACK_SIZE@*/
883 # define INIT_STACK_SIZE 20
884
885 HOST_WIDE_INT
886 cppReader_parseExpression (cppReader *pfile)
887 {
888   /* The implementation is an operator precedence parser,
889      i.e. a bottom-up parser, using a stack for not-yet-reduced tokens.
890
891      The stack base is 'stack', and the current stack pointer is 'top'.
892      There is a stack element for each operator (only),
893      and the most recently pushed operator is 'top->op'.
894      An operand (value) is stored in the 'value' field of the stack
895      element of the operator that precedes it.
896      In that case the 'flags' field has the HAVE_VALUE flag set.  */
897
898   struct operation init_stack[INIT_STACK_SIZE];
899   struct operation *stack = init_stack;
900   struct operation *limit = stack + INIT_STACK_SIZE;
901   register struct operation *top = stack;
902   int lprio, rprio = 0;
903   int skip_evaluation = 0;
904
905   top->rprio = 0;
906   top->flags = 0;
907
908   for (;;)
909     {
910       struct operation op;
911       int flags = 0;
912
913       /* Read a token */
914       op = cppexp_lex (pfile);
915
916       /* See if the token is an operand, in which case go to set_value.
917          If the token is an operator, figure out its left and right
918          priorities, and then goto maybe_reduce.  */
919
920       switch (op.op)
921         {
922         case NAME:
923           top->value = 0, top->unsignedp = FALSE;
924           goto set_value;
925         case CPPEXP_INT:
926         case CPPEXP_CHAR:
927           top->value = op.value;
928           top->unsignedp = op.unsignedp;
929           goto set_value;
930         case 0:
931           lprio = 0;  goto maybe_reduce;
932         case '+':  case '-':
933           /* Is this correct if unary ? FIXME */
934           flags = RIGHT_OPERAND_REQUIRED;
935           lprio = PLUS_PRIO;  rprio = lprio + 1;  goto maybe_reduce;
936         case '!':  case '~':
937           flags = RIGHT_OPERAND_REQUIRED;
938           rprio = UNARY_PRIO;  lprio = rprio + 1;  goto maybe_reduce;
939         case '*':  case '/':  case '%':
940           lprio = MUL_PRIO;  goto binop;
941         case '<':  case '>':  case LEQ:  case GEQ:
942           lprio = LESS_PRIO;  goto binop;
943         case CPP_EQUALTOK:  case NOTEQUAL:
944           lprio = CPP_EQUAL_PRIO;  goto binop;
945         case LSH:  case RSH:
946           lprio = SHIFT_PRIO;  goto binop;
947         case '&':  lprio = AND_PRIO;  goto binop;
948         case '^':  lprio = XOR_PRIO;  goto binop;
949         case '|':  lprio = OR_PRIO;  goto binop;
950         case ANDAND:  lprio = ANDAND_PRIO;  goto binop;
951         case OROR:  lprio = OROR_PRIO;  goto binop;
952         case ',':
953           lprio = COMMA_PRIO;  goto binop;
954         case '(':
955           lprio = PAREN_OUTER_PRIO;  rprio = PAREN_INNER_PRIO;
956           goto maybe_reduce;
957         case ')':
958           lprio = PAREN_INNER_PRIO;  rprio = PAREN_OUTER_PRIO;
959           goto maybe_reduce;
960         case ':':
961           lprio = COND_PRIO;  rprio = COND_PRIO;
962           goto maybe_reduce;
963         case '?':
964           lprio = COND_PRIO + 1;  rprio = COND_PRIO;
965           goto maybe_reduce;
966         binop:
967           flags = LEFT_OPERAND_REQUIRED | RIGHT_OPERAND_REQUIRED;
968           rprio = lprio + 1;
969           goto maybe_reduce;
970         default:
971           cppReader_error 
972             (pfile, 
973              message ("Invalid character in #if: %c", 
974                       (char) op.op));
975           goto syntax_error;
976         }
977
978     set_value:
979       /* Push a value onto the stack.  */
980       if ((top->flags & HAVE_VALUE) != 0)
981         {
982           cppReader_errorLit (pfile, 
983                         cstring_makeLiteralTemp ("syntax error in #if"));
984           goto syntax_error;
985         }
986       top->flags |= HAVE_VALUE;
987       continue;
988
989     maybe_reduce:
990       /* Push an operator, and check if we can reduce now.  */
991       while (top->rprio > lprio)
992         {
993           /*@-usedef@*/
994           long v1 = top[-1].value, v2 = top[0].value;
995           bool unsigned1 = top[-1].unsignedp;
996           bool unsigned2 = top[0].unsignedp;
997
998           top--;
999
1000           if (((top[1].flags & LEFT_OPERAND_REQUIRED) != 0)
1001               && ((top[0].flags & HAVE_VALUE) == 0))
1002             {
1003               cppReader_errorLit (pfile, 
1004                             cstring_makeLiteralTemp ("syntax error - missing left operand"));
1005               goto syntax_error;
1006             }
1007           if (((top[1].flags & RIGHT_OPERAND_REQUIRED) != 0)
1008               && ((top[1].flags & HAVE_VALUE) == 0))
1009             {
1010               cppReader_errorLit (pfile, 
1011                             cstring_makeLiteralTemp ("syntax error - missing right operand"));
1012               goto syntax_error;
1013             }
1014           /* top[0].value = (top[1].op)(v1, v2);*/
1015           switch (top[1].op)
1016             {
1017             case '+':
1018               if ((top->flags & HAVE_VALUE) == 0)
1019                 { /* Unary '+' */
1020                   top->value = v2;
1021                   top->unsignedp = unsigned2;
1022                   top->flags |= HAVE_VALUE;
1023                 }
1024               else
1025                 {
1026                   top->value = v1 + v2;
1027                   top->unsignedp = unsigned1 || unsigned2;
1028                   if (!top->unsignedp && (skip_evaluation == 0)
1029                       && ! possibleSumSign (v1, v2, top->value))
1030                     integer_overflow (pfile);
1031                 }
1032               /*@switchbreak@*/ break;
1033             case '-':
1034               if ((top->flags & HAVE_VALUE) == 0)
1035                 { /* Unary '-' */
1036                   top->value = - v2;
1037                   if ((skip_evaluation == 0) 
1038                       && (top->value & v2) < 0 && !unsigned2)
1039                     integer_overflow (pfile);
1040                   top->unsignedp = unsigned2;
1041                   top->flags |= HAVE_VALUE;
1042                 }
1043               else
1044                 { /* Binary '-' */
1045                   top->value = v1 - v2;
1046                   top->unsignedp = unsigned1 || unsigned2;
1047                   if (!top->unsignedp && (skip_evaluation == 0)
1048                       && !possibleSumSign (top->value, v2, v1))
1049                     {
1050                       integer_overflow (pfile);
1051                     }
1052                 }
1053               /*@switchbreak@*/ break;
1054             case '*':
1055               top->unsignedp = unsigned1 || unsigned2;
1056
1057               if (top->unsignedp)
1058                 {
1059                   top->value = (unsigned long) v1 * v2;
1060                 }
1061               else if (skip_evaluation == 0)
1062                 {
1063                   top->value = v1 * v2;
1064                   if ((v1 != 0)
1065                       && (top->value / v1 != v2
1066                           || (top->value & v1 & v2) < 0))
1067                     {
1068                       integer_overflow (pfile);
1069                     }
1070                 }
1071               else
1072                 {
1073                   ;
1074                 }
1075
1076               /*@switchbreak@*/ break;
1077             case '/':
1078               if (skip_evaluation != 0)
1079                 /*@switchbreak@*/ break;
1080               if (v2 == 0)
1081                 {
1082                   cppReader_errorLit (pfile, 
1083                                 cstring_makeLiteralTemp ("Division by zero in #if"));
1084                   v2 = 1;
1085                 }
1086               top->unsignedp = unsigned1 || unsigned2;
1087               if (top->unsignedp)
1088                 top->value = (unsigned long) v1 / v2;
1089               else
1090                 {
1091                   top->value = v1 / v2;
1092                   if ((top->value & v1 & v2) < 0)
1093                     integer_overflow (pfile);
1094                 }
1095               /*@switchbreak@*/ break;
1096             case '%':
1097               if (skip_evaluation != 0)
1098                 /*@switchbreak@*/ break;
1099               if (v2 == 0)
1100                 {
1101                   cppReader_errorLit (pfile, 
1102                                 cstring_makeLiteralTemp ("Division by zero in #if"));
1103                   v2 = 1;
1104                 }
1105               top->unsignedp = unsigned1 || unsigned2;
1106               if (top->unsignedp)
1107                 top->value = (unsigned long) v1 % v2;
1108               else
1109                 top->value = v1 % v2;
1110               /*@switchbreak@*/ break;
1111             case '!':
1112               if ((top->flags & HAVE_VALUE) != 0)
1113                 {
1114                   cppReader_errorLit (pfile, 
1115                                       cstring_makeLiteralTemp ("Syntax error"));
1116                   goto syntax_error;
1117                 }
1118
1119               top->value = (v2 == 0) ? 1 : 0;
1120               top->unsignedp = FALSE;
1121               top->flags |= HAVE_VALUE;
1122               /*@switchbreak@*/ break;
1123             case '~':
1124               if ((top->flags & HAVE_VALUE) != 0)
1125                 {
1126                   cppReader_errorLit (pfile, 
1127                                 cstring_makeLiteralTemp ("syntax error"));
1128                   goto syntax_error;
1129                 }
1130               top->value = ~ v2;
1131               top->unsignedp = unsigned2;
1132               top->flags |= HAVE_VALUE;
1133               /*@switchbreak@*/ break;
1134             case '<':  COMPARE(<);  /*@switchbreak@*/ break;
1135             case '>':  COMPARE(>);  /*@switchbreak@*/ break;
1136             case LEQ:  COMPARE(<=); /*@switchbreak@*/ break;
1137             case GEQ:  COMPARE(>=); /*@switchbreak@*/ break;
1138             case CPP_EQUALTOK:
1139               top->value = (v1 == v2) ? 1 : 0;
1140               top->unsignedp = FALSE;
1141               /*@switchbreak@*/ break;
1142             case NOTEQUAL:
1143               top->value = (v1 != v2) ? 1 : 0;
1144               top->unsignedp = FALSE;
1145               /*@switchbreak@*/ break;
1146             case LSH:
1147               if (skip_evaluation != 0)
1148                 {
1149                   /*@switchbreak@*/ break;
1150                 }
1151
1152               top->unsignedp = unsigned1;
1153               if (v2 < 0 && ! unsigned2)
1154                 top->value = right_shift (v1, unsigned1, -v2);
1155               else
1156                 top->value = left_shift (pfile, v1, unsigned1, v2);
1157               /*@switchbreak@*/ break;
1158             case RSH:
1159               if (skip_evaluation != 0)
1160                 {
1161                   /*@switchbreak@*/ break;
1162                 }
1163               top->unsignedp = unsigned1;
1164               if (v2 < 0 && ! unsigned2)
1165                 top->value = left_shift (pfile, v1, unsigned1, -v2);
1166               else
1167                 top->value = right_shift (v1, unsigned1, v2);
1168               /*@switchbreak@*/ break;
1169
1170 /*@notfunction@*/
1171 #define LOGICAL(OP) \
1172               top->value = v1 OP v2;\
1173               top->unsignedp = unsigned1 || unsigned2;
1174
1175             case '&':  LOGICAL(&); /*@switchbreak@*/ break;
1176             case '^':  LOGICAL(^); /*@switchbreak@*/ break;
1177             case '|':  LOGICAL(|); /*@switchbreak@*/ break;
1178             case ANDAND:
1179               top->value = ((v1 != 0) && (v2 != 0)) ? 1 : 0;
1180               top->unsignedp = FALSE;
1181
1182               if (v1 == 0)
1183                 {
1184                   skip_evaluation--;
1185                 }
1186               /*@switchbreak@*/ break;
1187             case OROR:
1188               top->value = ((v1 != 0) || (v2 != 0)) ? 1 : 0;
1189               top->unsignedp = FALSE;
1190               if (v1 != 0)
1191                 {
1192                   skip_evaluation--;
1193                 }
1194               /*@switchbreak@*/ break;
1195             case ',':
1196               if (cppReader_isPedantic (pfile))
1197                 cppReader_pedwarnLit (pfile, 
1198                                 cstring_makeLiteralTemp ("comma operator in operand of `#if'"));
1199               top->value = v2;
1200               top->unsignedp = unsigned2;
1201               /*@switchbreak@*/ break;
1202             case '(':  case '?':
1203               cppReader_errorLit (pfile, 
1204                             cstring_makeLiteralTemp ("syntax error in #if"));
1205               goto syntax_error;
1206             case ':':
1207               if (top[0].op != '?')
1208                 {
1209                   cppReader_errorLit (pfile,
1210                                 cstring_makeLiteralTemp ("syntax error ':' without preceding '?'"));
1211                   goto syntax_error;
1212                 }
1213               else if (((top[1].flags & HAVE_VALUE) == 0)
1214                        || ((top[-1].flags & HAVE_VALUE) == 0)
1215                        || ((top[0].flags & HAVE_VALUE) == 0))
1216                 {
1217                   cppReader_errorLit (pfile, 
1218                                 cstring_makeLiteralTemp ("bad syntax for ?: operator"));
1219                   goto syntax_error;
1220                 }
1221               else
1222                 {
1223                   top--;
1224                   if (top->value != 0)
1225                     {
1226                       skip_evaluation--;
1227                     }
1228
1229                   top->value = (top->value != 0) ? v1 : v2;
1230                   top->unsignedp = unsigned1 || unsigned2;
1231                 }
1232               /*@switchbreak@*/ break;
1233             case ')':
1234               if (((top[1].flags & HAVE_VALUE) != 0)
1235                   || ((top[0].flags & HAVE_VALUE) == 0)
1236                   || top[0].op != '('
1237                   || ((top[-1].flags & HAVE_VALUE) != 0))
1238                 {
1239                   cppReader_errorLit (pfile, 
1240                                 cstring_makeLiteralTemp ("mismatched parentheses in #if"));
1241                   goto syntax_error;
1242                 }
1243               else
1244                 {
1245                   top--;
1246                   top->value = v1;
1247                   top->unsignedp = unsigned1;
1248                   top->flags |= HAVE_VALUE;
1249                 }
1250               /*@switchbreak@*/ break;
1251             default:
1252               /*@-formatconst@*/
1253               fprintf (stderr,
1254                        top[1].op >= ' ' && top[1].op <= '~'
1255                        ? "unimplemented operator '%c'\n"
1256                        : "unimplemented operator '\\%03o'\n",
1257                        top[1].op);
1258               /*@=formatconst@*/
1259             }
1260         }
1261       if (op.op == 0)
1262         {
1263           long val;
1264
1265           if (top != stack)
1266             {
1267               cppReader_errorLit (pfile, 
1268                             cstring_makeLiteralTemp ("internal error in #if expression"));
1269             }
1270
1271           val = top->value;
1272
1273           if (stack != init_stack)
1274             {
1275               sfree (stack);
1276               /*@-branchstate@*/
1277             } /*@=branchstate@*/
1278
1279           return val;
1280         }
1281       top++;
1282       
1283       /* Check for and handle stack overflow.  */
1284       if (top == limit)
1285         {
1286           struct operation *new_stack;
1287           int old_size = (char *) limit - (char *) stack;
1288           size_t new_size = size_fromInt (2 * old_size);
1289
1290           if (stack != init_stack)
1291             {
1292               new_stack = (struct operation *) drealloc ((char *) stack,
1293                                                          new_size);
1294             }
1295           else
1296             {
1297               new_stack = (struct operation *) dmalloc (new_size);
1298
1299               /* Bug: the parameters were in the wrong order! */
1300               memcpy ((char *) new_stack, (char *) stack, old_size);
1301               /*@-branchstate@*/
1302             } /*@=branchstate@*/
1303
1304           stack = new_stack;
1305           top = (struct operation *) ((char *) new_stack + old_size);
1306           limit = (struct operation *) ((char *) new_stack + new_size);
1307           /*@-branchstate@*/ 
1308         } /*@=branchstate@*/ 
1309       
1310       top->flags = flags;
1311       top->rprio = rprio;
1312       top->op = op.op;
1313       if ((op.op == OROR && (top[-1].value != 0))
1314           || (op.op == ANDAND && (top[-1].value == 0))
1315           || (op.op == '?' && (top[-1].value == 0)))
1316         {
1317           skip_evaluation++;
1318         }
1319       else if (op.op == ':')
1320         {
1321           if (top[-2].value != 0) /* Was condition true? */
1322             {
1323               skip_evaluation++;
1324             }
1325           else
1326             {
1327               skip_evaluation--;
1328             }
1329         }
1330       else
1331         {
1332           ;
1333         }
1334     }
1335  syntax_error:
1336   /*@-usereleased@*/
1337   if (stack != init_stack)
1338     {
1339       sfree (stack);
1340       /*@-branchstate@*/
1341     } /*@=branchstate@*/
1342   /*@=usereleased@*/
1343
1344   cppReader_skipRestOfLine (pfile);
1345   return 0;
1346 }
This page took 0.144476 seconds and 5 git commands to generate.