Main Page   Alphabetical List   Compound List   File List   Compound Members   File Members  

cppexp.c

Go to the documentation of this file.
00001 /*
00002 ** LCLint - annotation-assisted static program checker
00003 ** Copyright (C) 1994-2000 University of Virginia,
00004 **         Massachusetts Institute of Technology
00005 **
00006 ** This program is free software; you can redistribute it and/or modify it
00007 ** under the terms of the GNU General Public License as published by the
00008 ** Free Software Foundation; either version 2 of the License, or (at your
00009 ** option) any later version.
00010 ** 
00011 ** This program is distributed in the hope that it will be useful, but
00012 ** WITHOUT ANY WARRANTY; without even the implied warranty of
00013 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014 ** General Public License for more details.
00015 ** 
00016 ** The GNU General Public License is available from http://www.gnu.org/ or
00017 ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00018 ** MA 02111-1307, USA.
00019 **
00020 ** For information on lclint: lclint-request@cs.virginia.edu
00021 ** To report a bug: lclint-bug@cs.virginia.edu
00022 ** For more information: http://lclint.cs.virginia.edu
00023 */
00024 /*
00025 ** cppexp.c
00026 */
00027 /* Parse C expressions for CCCP.
00028    Copyright (C) 1987, 1992, 1994, 1995, 1997 Free Software Foundation.
00029 
00030 This program is free software; you can redistribute it and/or modify it
00031 under the terms of the GNU General Public License as published by the
00032 Free Software Foundation; either version 2, or (at your option) any
00033 later version.
00034 
00035 This program is distributed in the hope that it will be useful,
00036 but WITHOUT ANY WARRANTY; without even the implied warranty of
00037 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00038 GNU General Public License for more details.
00039 
00040 You should have received a copy of the GNU General Public License
00041 along with this program; if not, write to the Free Software
00042 Foundation, 59 Temple Place - Suite 330,
00043 Boston, MA 02111-1307, USA.
00044 
00045  In other words, you are welcome to use, share and improve this program.
00046  You are forbidden to forbid anyone else to use, share and improve
00047  what you give them.   Help stamp out software-hoarding!
00048 
00049 Written by Per Bothner 1994.  */
00050 
00051 /* Parse a C expression from text in a string  */
00052 
00053 /*@+charint@*/
00054 /*@+ignorequals@*/
00055 /*@+ignoresigns@*/
00056 /*@+matchanyintegral@*/
00057 /*@-shiftsigned@*/
00058 
00059 # include <string.h> 
00060 # include "lclintMacros.nf"
00061 # include "llbasic.h"
00062 # include "cpp.h"
00063 # include "cpplib.h"
00064 # include "cpphash.h"
00065 # include "cppexp.h"
00066 # include "cpperror.h"
00067 
00068 /* Yield nonzero if adding two numbers with A's and B's signs can yield a
00069    number with SUM's sign, where A, B, and SUM are all C integers.  */
00070 
00071 /*@function static bool possibleSumSign (sef int, int, int) 
00072       modifies nothing ; @*/
00073 
00074 #define possibleSumSign(a, b, sum) ((((a) ^ (b)) | ~ ((a) ^ (sum))) < 0)
00075 
00076 /* these are guesses! */ 
00077 
00078 /*@constant int BITS_PER_UNIT@*/
00079 # define BITS_PER_UNIT 8
00080 
00081 /*@constant size_t BITS_PER_CHAR@*/
00082 # define BITS_PER_CHAR 8
00083 
00084 /*@constant size_t BITS_PER_WORD@*/
00085 # define BITS_PER_WORD 32
00086 
00087 /*@constant size_t HOST_BITS_PER_INT@*/
00088 # define HOST_BITS_PER_INT 32
00089 
00090 /*@constant size_t HOST_BITS_PER_LONG@*/
00091 # define HOST_BITS_PER_LONG 32
00092 
00093 /*@constant char TARGET_BELL@*/
00094 # define TARGET_BELL (char) 6 
00095 
00096 /*@constant char TARGET_BS@*/
00097 # define TARGET_BS   (char) 7
00098 
00099 /*@constant char TARGET_FF@*/
00100 # define TARGET_FF   (char) 8
00101 
00102 /*@constant char TARGET_NEWLINE@*/
00103 # define TARGET_NEWLINE '\n' 
00104 
00105 /*@constant char TARGET_CR@*/
00106 # define TARGET_CR '\n'
00107 
00108 /*@constant char TARGET_TAB@*/
00109 # define TARGET_TAB '\t'
00110 
00111 /*@constant char TARGET_VT@*/
00112 # define TARGET_VT '\v'
00113 
00114 #ifdef MULTIBYTE_CHARS
00115 #include <stdlib.h>
00116 #include <locale.h>
00117 #endif
00118 
00119 #include <stdio.h>
00120 
00121 #ifndef INT_TYPE_SIZE
00122 /*@constant size_t INT_TYPE_SIZE@*/
00123 #define INT_TYPE_SIZE BITS_PER_WORD
00124 #endif
00125 
00126 #ifndef LONG_TYPE_SIZE
00127 /*@constant size_t LONG_TYPE_SIZE@*/
00128 #define LONG_TYPE_SIZE BITS_PER_WORD
00129 #endif
00130 
00131 #ifndef WCHAR_TYPE_SIZE
00132 /*@constant size_t WCHAR_TYPE_SIZE@*/
00133 #define WCHAR_TYPE_SIZE INT_TYPE_SIZE
00134 #endif
00135 
00136 # ifndef CHAR_TYPE_SIZE
00137 /*@constant size_t CHAR_TYPE_SIZE@*/
00138 # define CHAR_TYPE_SIZE BITS_PER_CHAR
00139 # endif
00140 
00141 #ifndef MAX_CHAR_TYPE_SIZE
00142 /*@constant size_t MAX_CHAR_TYPE_SIZE@*/
00143 #define MAX_CHAR_TYPE_SIZE CHAR_TYPE_SIZE
00144 #endif
00145 
00146 #ifndef MAX_LONG_TYPE_SIZE
00147 /*@constant size_t MAX_LONG_TYPE_SIZE@*/
00148 #define MAX_LONG_TYPE_SIZE LONG_TYPE_SIZE
00149 #endif
00150 
00151 #ifndef MAX_WCHAR_TYPE_SIZE
00152 /*@constant size_t MAX_WCHAR_TYPE_SIZE@*/
00153 #define MAX_WCHAR_TYPE_SIZE WCHAR_TYPE_SIZE
00154 #endif
00155 
00156 static struct operation cppReader_lex (cppReader *);
00157 static void integer_overflow (cppReader *);
00158 static long left_shift (cppReader *, long, bool p_unsignedp, size_t);
00159 static long right_shift (long, bool p_unsignedp, unsigned long);
00160 
00161 /*@constant short CPPREADER_ERRORTOK@*/
00162 #define CPPREADER_ERRORTOK 299
00163 
00164 /*@constant int OROR@*/
00165 #define OROR 300
00166 
00167 /*@constant int ANDAND@*/
00168 #define ANDAND 301
00169 
00170 /*@constant int CPP_EQUALTOK@*/
00171 #define CPP_EQUALTOK 302
00172 
00173 /*@constant int NOTEQUAL@*/
00174 #define NOTEQUAL 303
00175 
00176 /*@constant int LEQ@*/
00177 #define LEQ 304
00178 
00179 /*@constant int GEQ@*/
00180 #define GEQ 305
00181 
00182 /*@constant int LSH@*/
00183 #define LSH 306
00184 
00185 /*@constant int RSH@*/
00186 #define RSH 307
00187 
00188 /*@constant int NAME@*/
00189 #define NAME 308
00190 
00191 /*@constant short CPPEXP_INT@*/
00192 #define CPPEXP_INT 309
00193 
00194 /*@constant short CPPEXP_CHAR@*/
00195 #define CPPEXP_CHAR 310
00196 
00197 /*@constant int LEFT_OPERAND_REQUIRED@*/
00198 #define LEFT_OPERAND_REQUIRED 1
00199 
00200 /*@constant int RIGHT_OPERAND_REQUIRED@*/
00201 #define RIGHT_OPERAND_REQUIRED 2
00202 
00203 /*@constant int HAVE_VALUE@*/
00204 #define HAVE_VALUE 4
00205 
00206 #ifndef HOST_BITS_PER_WIDE_INT
00207 
00208 #if HOST_BITS_PER_LONG > HOST_BITS_PER_INT
00209 /*@constant int HOST_BITS_PER_WIDE_INT@*/
00210 #define HOST_BITS_PER_WIDE_INT HOST_BITS_PER_LONG
00211 /*@notfunction@*/
00212 #define HOST_WIDE_INT long
00213 #else
00214 /*@constant int HOST_BITS_PER_WIDE_INT@*/
00215 #define HOST_BITS_PER_WIDE_INT HOST_BITS_PER_INT
00216 /*@notfunction@*/
00217 #define HOST_WIDE_INT long
00218 #endif
00219 
00220 #endif
00221 
00222 struct operation {
00223   short op;
00224 
00225   /* Priority of op (relative to it right operand).  */
00226   /*@reldef@*/ char rprio;
00227 
00228   /*@reldef@*/ char flags;
00229 
00230   /* true if value should be treated as unsigned */
00231   /*@reldef@*/ bool unsignedp;
00232 
00233   /* The value logically "right" of op.  */
00234   /*@reldef@*/ HOST_WIDE_INT value;
00235 } ;
00236 
00237 /* Take care of parsing a number (anything that starts with a digit).
00238    LEN is the number of characters in it.  */
00239 
00240 /* maybe needs to actually deal with floating point numbers */
00241 
00242 struct operation
00243 cppReader_parseNumber (cppReader *pfile, char *start, int olen)
00244 {
00245   struct operation op;
00246   char *p = start;
00247   char c;
00248   int i;
00249   long n = 0;
00250   unsigned long nd, ULONG_MAX_over_base;
00251   int base = 10;
00252   int len = olen;
00253   bool overflow = FALSE;
00254   int digit, largest_digit = 0;
00255   bool spec_long = FALSE;
00256 
00257   op.unsignedp = FALSE;
00258 
00259   for (i = 0; i < len; i++)
00260     {
00261       if (p[i] == '.') {
00262         /* It's a float since it contains a point.  */
00263         cppReader_errorLit
00264           (pfile,
00265            cstring_makeLiteralTemp
00266            ("Floating point numbers not allowed in #if expressions"));
00267         op.op = CPPREADER_ERRORTOK;
00268         return op;
00269       }
00270     }
00271       
00272   if (len >= 3 && (mstring_equalPrefix (p, "0x") 
00273                    || mstring_equalPrefix (p, "0X")))
00274     {
00275       p += 2;
00276       base = 16;
00277       len -= 2;
00278     }
00279   else if (*p == '0')
00280     {
00281       base = 8;
00282     }
00283   else
00284     {
00285       ;
00286     }
00287 
00288   /* Some buggy compilers (e.g. MPW C) seem to need both casts.  */
00289   ULONG_MAX_over_base = ((unsigned long) -1) / ((unsigned long) base);
00290 
00291   for (; len > 0; len--) {
00292     c = *p++;
00293 
00294     if (c >= '0' && c <= '9')
00295       {
00296         digit = (int) (c - '0');
00297       }
00298     else if (base == 16 && c >= 'a' && c <= 'f')
00299       {
00300         digit = (int) (c - 'a') + 10;
00301       }
00302     else if (base == 16 && c >= 'A' && c <= 'F')
00303       {
00304         digit = (int) (c - 'A') + 10;
00305       }
00306     else 
00307       {
00308         /* `l' means long, and `u' means unsigned.  */
00309         while (TRUE)
00310           {
00311             if (c == 'l' || c == 'L')
00312               {
00313                 if (spec_long)
00314                   cppReader_errorLit (pfile,
00315                                       cstring_makeLiteralTemp ("two `l's in integer constant"));
00316                 spec_long = TRUE;
00317               }
00318             else if (c == 'u' || c == 'U')
00319               {
00320                 if (op.unsignedp)
00321                   cppReader_errorLit (pfile, 
00322                                       cstring_makeLiteralTemp ("two `u's in integer constant"));
00323                 op.unsignedp = TRUE;
00324               }
00325             else
00326               {
00327                 /*@innerbreak@*/ break;
00328               }
00329             
00330             if (--len == 0)
00331               {
00332                 /*@innerbreak@*/ break;
00333               }
00334 
00335             c = *p++;
00336           }
00337         /* Don't look for any more digits after the suffixes.  */
00338         break;
00339       }
00340     
00341     if (largest_digit < digit)
00342       {
00343         largest_digit = digit;
00344       }
00345     
00346     nd = (long unsigned) (n * base + digit);
00347     overflow |= (ULONG_MAX_over_base < (unsigned long) n) 
00348       | (nd < (unsigned long) n);
00349     n = (long) nd;
00350   }
00351 
00352   if (len != 0)
00353     {
00354       cppReader_errorLit 
00355         (pfile, 
00356          cstring_makeLiteralTemp ("Invalid number in #if expression"));
00357       op.op = CPPREADER_ERRORTOK;
00358       return op;
00359     }
00360   
00361   if (base <= largest_digit)
00362     {
00363       cppReader_pedwarnLit 
00364         (pfile, 
00365          cstring_makeLiteralTemp 
00366          ("Integer constant contains digits beyond the radix"));
00367     }
00368   
00369   if (overflow)
00370     {
00371       cppReader_pedwarnLit
00372         (pfile, 
00373          cstring_makeLiteralTemp ("Integer constant out of range"));
00374     }
00375 
00376   /* If too big to be signed, consider it unsigned.  */
00377   if ((long) n < 0 && ! op.unsignedp)
00378     {
00379       if (base == 10)
00380         {
00381           cppReader_warningLit
00382             (pfile,
00383              cstring_makeLiteralTemp ("Integer constant is so large that it is unsigned"));
00384         }
00385          
00386       op.unsignedp = TRUE;
00387     }
00388   
00389   op.value = n;
00390   op.op = CPPEXP_INT;
00391   return op;
00392 }
00393 
00394 struct token {
00395   /*@null@*/ /*@observer@*/ char *operator;
00396   int token;
00397 };
00398 
00399 static struct token tokentab2[] = {
00400   { "&&", ANDAND },
00401   { "||", OROR },
00402   { "<<", LSH },
00403   { ">>", RSH },
00404   { "==", CPP_EQUALTOK },
00405   { "!=", NOTEQUAL },
00406   { "<=", LEQ },
00407   { ">=", GEQ },
00408   { "++", CPPREADER_ERRORTOK },
00409   { "--", CPPREADER_ERRORTOK },
00410   { NULL, CPPREADER_ERRORTOK }
00411 } ;
00412 
00413 /* Read one token.  */
00414 
00415 struct operation cppReader_lex (cppReader *pfile)
00416 {
00417   int ic;
00418   char c;
00419   register struct token *toktab;
00420   enum cpp_token token;
00421   struct operation op;
00422   char *tok_start, *tok_end;
00423   int old_written;
00424 
00425  retry:
00426 
00427   old_written = size_toInt (cppReader_getWritten (pfile));
00428   cppSkipHspace (pfile);
00429   ic = cppBufPeek (cppReader_getBufferSafe (pfile));
00430 
00431   c = (char) ic;
00432   llassert (c != '#');
00433   
00434   if (c == '\n')
00435     {
00436       op.op = 0;
00437       return op;
00438     }
00439 
00440   token = cppGetToken (pfile);
00441   tok_start = pfile->token_buffer + old_written;
00442   tok_end = cppReader_getPWritten (pfile);
00443   pfile->limit = tok_start;
00444 
00445   switch (token)
00446   {
00447     case CPP_EOF: /* Should not happen ...  */
00448     case CPP_VSPACE:
00449       op.op = 0;
00450       return op;
00451     case CPP_POP:
00452       if (cstring_isDefined (cppReader_getBufferSafe (pfile)->fname))
00453         {
00454           op.op = 0;
00455           return op;
00456         }
00457       (void) cppReader_popBuffer (pfile);
00458       goto retry;
00459     case CPP_HSPACE:   case CPP_COMMENT: 
00460       goto retry;
00461     case CPP_NUMBER:
00462       return cppReader_parseNumber (pfile, tok_start, tok_end - tok_start);
00463     case CPP_STRING:
00464       cppReader_errorLit (pfile, 
00465                     cstring_makeLiteralTemp ("string constants not allowed in #if expressions"));
00466       op.op = CPPREADER_ERRORTOK;
00467       return op;
00468     case CPP_CHAR:
00469       /* This code for reading a character constant
00470          handles multicharacter constants and wide characters.
00471          It is mostly copied from c-lex.c.  */
00472       {
00473         int result = 0;
00474         int num_chars = 0;
00475         size_t width = MAX_CHAR_TYPE_SIZE;
00476         int wide_flag = 0;
00477         int max_chars;
00478         char *ptr = tok_start;
00479 #ifdef MULTIBYTE_CHARS
00480         char token_buffer[MAX_LONG_TYPE_SIZE/MAX_CHAR_TYPE_SIZE + MB_CUR_MAX];
00481 #else
00482         char token_buffer[MAX_LONG_TYPE_SIZE/MAX_CHAR_TYPE_SIZE + 1];
00483 #endif
00484 
00485         if (*ptr == 'L')
00486           {
00487             ptr++;
00488             wide_flag = 1;
00489             width = MAX_WCHAR_TYPE_SIZE;
00490 #ifdef MULTIBYTE_CHARS
00491             max_chars = MB_CUR_MAX;
00492 #else
00493             max_chars = 1;
00494 #endif
00495           }
00496         else
00497           {
00498             max_chars = size_toInt (MAX_LONG_TYPE_SIZE / width);
00499           }
00500 
00501         ++ptr;
00502         while (ptr < tok_end && ((c = *ptr++) != '\''))
00503           {
00504             if (c == '\\')
00505               {
00506                 c = cppReader_parseEscape (pfile, &ptr);
00507                 if (width < HOST_BITS_PER_INT && c >= (1 << width))
00508                   {
00509                     cppReader_pedwarnLit 
00510                       (pfile,
00511                        cstring_makeLiteralTemp ("Escape sequence out of range for character"));
00512                   }
00513               }
00514                 
00515             num_chars++;
00516             
00517             /* Merge character into result; ignore excess chars.  */
00518             if (num_chars < max_chars + 1)
00519               {
00520                 if (width < HOST_BITS_PER_INT)
00521                   {
00522                     result = (int) ((unsigned) result << width) | (c & ((1 << width) - 1));
00523                   }
00524                 else
00525                   {
00526                     result = c;
00527                   }
00528 
00529                 token_buffer[num_chars - 1] = c;
00530               }
00531           }
00532 
00533         token_buffer[num_chars] = 0;
00534 
00535         if (c != '\'')
00536           cppReader_errorLit (pfile,
00537                         cstring_makeLiteralTemp ("malformatted character constant"));
00538         else if (num_chars == 0)
00539           cppReader_errorLit (pfile, 
00540                         cstring_makeLiteralTemp ("empty character constant"));
00541         else if (num_chars > max_chars)
00542           {
00543             num_chars = max_chars;
00544             cppReader_errorLit (pfile, 
00545                           cstring_makeLiteralTemp ("character constant too long"));
00546           }
00547         else if (num_chars != 1 && ! cppReader_isTraditional (pfile))
00548           {
00549             cppReader_warningLit (pfile, 
00550                             cstring_makeLiteralTemp ("multi-character character constant"));
00551           }
00552         else
00553           {
00554             ;
00555           }
00556 
00557         /* If char type is signed, sign-extend the constant.  */
00558         if (wide_flag == 0)
00559           {
00560             int num_bits = num_chars * width;
00561 
00562             if ((cppReader_lookup ("__CHAR_UNSIGNED__",
00563                              sizeof ("__CHAR_UNSIGNED__") - 1, -1) != NULL)
00564                 || (((unsigned) result >> (num_bits - 1)) & 1) == 0)
00565               {
00566                 op.value
00567                   = result & ((unsigned long) ~0 >> (HOST_BITS_PER_LONG - num_bits));
00568               }
00569             else
00570               {
00571                 op.value
00572                   = result | ~((unsigned long) ~0 >> (HOST_BITS_PER_LONG - num_bits));
00573               }
00574           }
00575         else
00576           {
00577 #ifdef MULTIBYTE_CHARS
00578             /* Set the initial shift state and convert the next sequence.  */
00579               result = 0;
00580               /* In all locales L'\0' is zero and mbtowc will return zero,
00581                  so don't use it.  */
00582               if (num_chars > 1
00583                   || (num_chars == 1 && token_buffer[0] != '\0'))
00584                 {
00585                   wchar_t wc;
00586                   (void) mbtowc (NULL, NULL, 0);
00587                   if (mbtowc (& wc, token_buffer, num_chars) == num_chars)
00588                     result = wc;
00589                   else
00590                     cppReader_pedwarn (pfile,"Ignoring invalid multibyte character");
00591                 }
00592 #endif
00593               op.value = result;
00594             }
00595         }
00596 
00597       /* This is always a signed type.  */
00598       op.unsignedp = FALSE;
00599       op.op = CPPEXP_CHAR;
00600     
00601       return op;
00602 
00603     case CPP_NAME:
00604       return cppReader_parseNumber (pfile, "0", 0);
00605 
00606     case CPP_OTHER:
00607       /* See if it is a special token of length 2.  */
00608       if (tok_start + 2 == tok_end)
00609         {
00610           for (toktab = tokentab2; toktab->operator != NULL; toktab++)
00611             {
00612               if (tok_start[0] == toktab->operator[0]
00613                   && tok_start[1] == toktab->operator[1])
00614                 {
00615                   /*@loopbreak@*/ break;
00616                 }
00617             }
00618 
00619           if (toktab->token == CPPREADER_ERRORTOK)
00620             {
00621               cppReader_error (pfile, message ("`%s' not allowed in operand of `#if'", cstring_fromChars (tok_start)));
00622             }
00623 
00624           op.op = toktab->token; 
00625           return op;
00626         }
00627       /*@fallthrough@*/ 
00628     default:
00629       op.op = *tok_start;
00630       return op;
00631   }
00632 
00633   BADEXIT;
00634   /*@notreached@*/ 
00635 }
00636 
00637 
00638 /* Parse a C escape sequence.  STRING_PTR points to a variable
00639    containing a pointer to the string to parse.  That pointer
00640    is updated past the characters we use.  The value of the
00641    escape sequence is returned.
00642 
00643    A negative value means the sequence \ newline was seen,
00644    which is supposed to be equivalent to nothing at all.
00645 
00646    If \ is followed by a null character, we return a negative
00647    value and leave the string pointer pointing at the null character.
00648 
00649    If \ is followed by 000, we return 0 and leave the string pointer
00650    after the zeros.  A value of 0 does not mean end of string.  */
00651 
00652 int
00653 cppReader_parseEscape (cppReader *pfile, char **string_ptr)
00654 {
00655   char c = *(*string_ptr)++;
00656 
00657   switch (c)
00658     {
00659     case 'a':
00660       return TARGET_BELL;
00661     case 'b':
00662       return TARGET_BS;
00663     case 'e':
00664     case 'E':
00665       if (cppReader_isPedantic (pfile))
00666         {
00667           cppReader_pedwarn (pfile, 
00668                        message ("non-ANSI-standard escape sequence, `\\%c'", c));
00669         }
00670       return (char) 033;
00671     case 'f':
00672       return TARGET_FF;
00673     case 'n':
00674       return TARGET_NEWLINE;
00675     case 'r':
00676       return TARGET_CR;
00677     case 't':
00678       return TARGET_TAB;
00679     case 'v':
00680       return TARGET_VT;
00681     case '\n':
00682       return -2;
00683     case 0:
00684       (*string_ptr)--;
00685       return 0;
00686       
00687     case '0':
00688     case '1':
00689     case '2':
00690     case '3':
00691     case '4':
00692     case '5':
00693     case '6':
00694     case '7':
00695       {
00696         int i = (int) c - '0';
00697         int count = 0;
00698 
00699         while (++count < 3)
00700           {
00701             c = *(*string_ptr)++;
00702             if (c >= '0' && c <= '7')
00703               {
00704                 i = ((unsigned) i << 3) + c - '0';
00705               }
00706 
00707             else
00708               {
00709                 (*string_ptr)--;
00710                 /*@loopbreak@*/ break;
00711               }
00712           }
00713         if ((i & ~((1 << MAX_CHAR_TYPE_SIZE) - 1)) != 0)
00714           {
00715             i &= (1 << MAX_CHAR_TYPE_SIZE) - 1;
00716             cppReader_pedwarnLit (pfile,
00717                             cstring_makeLiteralTemp ("octal character constant does not fit in a byte"));
00718           }
00719         return i;
00720       }
00721     case 'x':
00722       {
00723         register unsigned i = 0, overflow = 0, digits_found = 0, digit;
00724         for (;;)
00725           {
00726             c = *(*string_ptr)++;
00727 
00728             if (c >= '0' && c <= '9')
00729               {
00730                 digit = (unsigned int) (c - '0');
00731               }
00732             else if (c >= 'a' && c <= 'f')
00733               {
00734                 digit = (unsigned int) (c - 'a') + 10;
00735               }
00736             else if (c >= 'A' && c <= 'F')
00737               {
00738                 digit = (unsigned int) (c - 'A') + 10;
00739               }
00740             else
00741               {
00742                 (*string_ptr)--;
00743                 /*@loopbreak@*/ break;
00744               }
00745             overflow |= i ^ (i << 4 >> 4);
00746             i = (i << 4) + digit;
00747             digits_found = 1;
00748           }
00749         
00750         if (digits_found == 0)
00751           {
00752             cppReader_errorLit (pfile,
00753                                 cstring_makeLiteralTemp ("\\x used with no following hex digits"));
00754           }
00755 
00756         if ((overflow | (i & ~((1 << BITS_PER_UNIT) - 1))) != 0)
00757           {
00758             i &= (1 << BITS_PER_UNIT) - 1;
00759             cppReader_pedwarnLit (pfile,
00760                             cstring_makeLiteralTemp ("hex character constant does not fit in a byte"));
00761           }
00762 
00763         return i;
00764       }
00765     default:
00766       return c;
00767     }
00768 }
00769 
00770 static void
00771 integer_overflow (cppReader *pfile)
00772 {
00773   if (cppReader_isPedantic (pfile))
00774     cppReader_pedwarnLit (pfile, 
00775                     cstring_makeLiteralTemp ("integer overflow in preprocessor expression"));
00776 }
00777 
00778 static long
00779 left_shift (cppReader *pfile, long a, bool unsignedp, size_t b)
00780 {
00781   if (b >= HOST_BITS_PER_LONG)
00782     {
00783       if (!unsignedp && a != 0)
00784         {
00785           integer_overflow (pfile);
00786         }
00787 
00788       return 0;
00789     }
00790   else if (unsignedp)
00791     {
00792       return (unsigned long) a << b;
00793     }
00794   else
00795     {
00796       long l = a << b;
00797       
00798       if (l >> b != a)
00799         {
00800           integer_overflow (pfile);
00801         }
00802 
00803       return l;
00804     }
00805 }
00806 
00807 static long
00808 right_shift (long a, bool unsignedp, unsigned long b)
00809 {
00810   if (b >= HOST_BITS_PER_LONG)
00811     return (unsignedp ? 0 : a >> (HOST_BITS_PER_LONG - 1));
00812   else if (unsignedp)
00813     return (unsigned long) a >> b;
00814   else
00815     return a >> b;
00816 }
00817 
00818 /* These priorities are all even, so we can handle associatively.  */
00819 
00820 /*@constant int PAREN_INNER_PRIO@*/
00821 #define PAREN_INNER_PRIO 0
00822 
00823 /*@constant int COMMA_PRIO@*/
00824 #define COMMA_PRIO 4
00825 
00826 /*@constant int COND_PRIO@*/
00827 #define COND_PRIO (COMMA_PRIO+2)
00828 
00829 /*@constant int OROR_PRIO@*/
00830 #define OROR_PRIO (COND_PRIO+2)
00831 
00832 /*@constant int ANDAND_PRIO@*/
00833 #define ANDAND_PRIO (OROR_PRIO+2)
00834 
00835 /*@constant int OR_PRIO@*/
00836 #define OR_PRIO (ANDAND_PRIO+2)
00837 
00838 /*@constant int XOR_PRIO@*/
00839 #define XOR_PRIO (OR_PRIO+2)
00840 
00841 /*@constant int AND_PRIO@*/
00842 #define AND_PRIO (XOR_PRIO+2)
00843 
00844 /*@constant int CPP_EQUAL_PRIO@*/
00845 #define CPP_EQUAL_PRIO (AND_PRIO+2)
00846 
00847 /*@constant int LESS_PRIO@*/
00848 #define LESS_PRIO (CPP_EQUAL_PRIO+2)
00849 
00850 /*@constant int SHIFT_PRIO@*/
00851 #define SHIFT_PRIO (LESS_PRIO+2)
00852 
00853 /*@constant int PLUS_PRIO@*/
00854 #define PLUS_PRIO (SHIFT_PRIO+2)
00855 
00856 /*@constant int MUL_PRIO@*/
00857 #define MUL_PRIO (PLUS_PRIO+2)
00858 
00859 /*@constant int UNARY_PRIO@*/
00860 #define UNARY_PRIO (MUL_PRIO+2)
00861 
00862 /*@constant int PAREN_OUTER_PRIO@*/
00863 #define PAREN_OUTER_PRIO (UNARY_PRIO+2)
00864 
00865 /*@notfunction@*/
00866 #define COMPARE(OP) \
00867   top->unsignedp = FALSE;\
00868   top->value = ((unsigned1 || unsigned2) \
00869                  ? (unsigned long) v1 OP (unsigned long) v2 \
00870                  : ((long) v1 OP (long) v2)) ? 1 : 0
00871 
00872 /* Parse and evaluate a C expression, reading from PFILE.
00873    Returns the value of the expression.  */
00874 
00875 /*@constant int INIT_STACK_SIZE@*/
00876 # define INIT_STACK_SIZE 20
00877 
00878 HOST_WIDE_INT
00879 cppReader_parseExpression (cppReader *pfile)
00880 {
00881   /* The implementation is an operator precedence parser,
00882      i.e. a bottom-up parser, using a stack for not-yet-reduced tokens.
00883 
00884      The stack base is 'stack', and the current stack pointer is 'top'.
00885      There is a stack element for each operator (only),
00886      and the most recently pushed operator is 'top->op'.
00887      An operand (value) is stored in the 'value' field of the stack
00888      element of the operator that precedes it.
00889      In that case the 'flags' field has the HAVE_VALUE flag set.  */
00890 
00891   struct operation init_stack[INIT_STACK_SIZE];
00892   struct operation *stack = init_stack;
00893   struct operation *limit = stack + INIT_STACK_SIZE;
00894   register struct operation *top = stack;
00895   int lprio, rprio = 0;
00896   int skip_evaluation = 0;
00897 
00898   top->rprio = 0;
00899   top->flags = 0;
00900 
00901   for (;;)
00902     {
00903       struct operation op;
00904       int flags = 0;
00905 
00906       /* Read a token */
00907       op =  cppReader_lex (pfile);
00908 
00909       /* See if the token is an operand, in which case go to set_value.
00910          If the token is an operator, figure out its left and right
00911          priorities, and then goto maybe_reduce.  */
00912 
00913       switch (op.op)
00914         {
00915         case NAME:
00916           top->value = 0, top->unsignedp = FALSE;
00917           goto set_value;
00918         case CPPEXP_INT:
00919         case CPPEXP_CHAR:
00920           top->value = op.value;
00921           top->unsignedp = op.unsignedp;
00922           goto set_value;
00923         case 0:
00924           lprio = 0;  goto maybe_reduce;
00925         case '+':  case '-':
00926           /* Is this correct if unary ? FIXME */
00927           flags = RIGHT_OPERAND_REQUIRED;
00928           lprio = PLUS_PRIO;  rprio = lprio + 1;  goto maybe_reduce;
00929         case '!':  case '~':
00930           flags = RIGHT_OPERAND_REQUIRED;
00931           rprio = UNARY_PRIO;  lprio = rprio + 1;  goto maybe_reduce;
00932         case '*':  case '/':  case '%':
00933           lprio = MUL_PRIO;  goto binop;
00934         case '<':  case '>':  case LEQ:  case GEQ:
00935           lprio = LESS_PRIO;  goto binop;
00936         case CPP_EQUALTOK:  case NOTEQUAL:
00937           lprio = CPP_EQUAL_PRIO;  goto binop;
00938         case LSH:  case RSH:
00939           lprio = SHIFT_PRIO;  goto binop;
00940         case '&':  lprio = AND_PRIO;  goto binop;
00941         case '^':  lprio = XOR_PRIO;  goto binop;
00942         case '|':  lprio = OR_PRIO;  goto binop;
00943         case ANDAND:  lprio = ANDAND_PRIO;  goto binop;
00944         case OROR:  lprio = OROR_PRIO;  goto binop;
00945         case ',':
00946           lprio = COMMA_PRIO;  goto binop;
00947         case '(':
00948           lprio = PAREN_OUTER_PRIO;  rprio = PAREN_INNER_PRIO;
00949           goto maybe_reduce;
00950         case ')':
00951           lprio = PAREN_INNER_PRIO;  rprio = PAREN_OUTER_PRIO;
00952           goto maybe_reduce;
00953         case ':':
00954           lprio = COND_PRIO;  rprio = COND_PRIO;
00955           goto maybe_reduce;
00956         case '?':
00957           lprio = COND_PRIO + 1;  rprio = COND_PRIO;
00958           goto maybe_reduce;
00959         binop:
00960           flags = LEFT_OPERAND_REQUIRED | RIGHT_OPERAND_REQUIRED;
00961           rprio = lprio + 1;
00962           goto maybe_reduce;
00963         default:
00964           cppReader_error 
00965             (pfile, 
00966              message ("Invalid character in #if: %c", 
00967                       (char) op.op));
00968           goto syntax_error;
00969         }
00970 
00971     set_value:
00972       /* Push a value onto the stack.  */
00973       if ((top->flags & HAVE_VALUE) != 0)
00974         {
00975           cppReader_errorLit (pfile, 
00976                         cstring_makeLiteralTemp ("syntax error in #if"));
00977           goto syntax_error;
00978         }
00979       top->flags |= HAVE_VALUE;
00980       continue;
00981 
00982     maybe_reduce:
00983       /* Push an operator, and check if we can reduce now.  */
00984       while (top->rprio > lprio)
00985         {
00986           /*@-usedef@*/
00987           long v1 = top[-1].value, v2 = top[0].value;
00988           bool unsigned1 = top[-1].unsignedp;
00989           bool unsigned2 = top[0].unsignedp;
00990 
00991           top--;
00992 
00993           if (((top[1].flags & LEFT_OPERAND_REQUIRED) != 0)
00994               && ((top[0].flags & HAVE_VALUE) == 0))
00995             {
00996               cppReader_errorLit (pfile, 
00997                             cstring_makeLiteralTemp ("syntax error - missing left operand"));
00998               goto syntax_error;
00999             }
01000           if (((top[1].flags & RIGHT_OPERAND_REQUIRED) != 0)
01001               && ((top[1].flags & HAVE_VALUE) == 0))
01002             {
01003               cppReader_errorLit (pfile, 
01004                             cstring_makeLiteralTemp ("syntax error - missing right operand"));
01005               goto syntax_error;
01006             }
01007           /* top[0].value = (top[1].op)(v1, v2);*/
01008           switch (top[1].op)
01009             {
01010             case '+':
01011               if ((top->flags & HAVE_VALUE) == 0)
01012                 { /* Unary '+' */
01013                   top->value = v2;
01014                   top->unsignedp = unsigned2;
01015                   top->flags |= HAVE_VALUE;
01016                 }
01017               else
01018                 {
01019                   top->value = v1 + v2;
01020                   top->unsignedp = unsigned1 || unsigned2;
01021                   if (!top->unsignedp && (skip_evaluation == 0)
01022                       && ! possibleSumSign (v1, v2, top->value))
01023                     integer_overflow (pfile);
01024                 }
01025               /*@switchbreak@*/ break;
01026             case '-':
01027               if ((top->flags & HAVE_VALUE) == 0)
01028                 { /* Unary '-' */
01029                   top->value = - v2;
01030                   if ((skip_evaluation == 0) 
01031                       && (top->value & v2) < 0 && !unsigned2)
01032                     integer_overflow (pfile);
01033                   top->unsignedp = unsigned2;
01034                   top->flags |= HAVE_VALUE;
01035                 }
01036               else
01037                 { /* Binary '-' */
01038                   top->value = v1 - v2;
01039                   top->unsignedp = unsigned1 || unsigned2;
01040                   if (!top->unsignedp && (skip_evaluation == 0)
01041                       && !possibleSumSign (top->value, v2, v1))
01042                     {
01043                       integer_overflow (pfile);
01044                     }
01045                 }
01046               /*@switchbreak@*/ break;
01047             case '*':
01048               top->unsignedp = unsigned1 || unsigned2;
01049 
01050               if (top->unsignedp)
01051                 {
01052                   top->value = (unsigned long) v1 * v2;
01053                 }
01054               else if (skip_evaluation == 0)
01055                 {
01056                   top->value = v1 * v2;
01057                   if ((v1 != 0)
01058                       && (top->value / v1 != v2
01059                           || (top->value & v1 & v2) < 0))
01060                     {
01061                       integer_overflow (pfile);
01062                     }
01063                 }
01064               else
01065                 {
01066                   ;
01067                 }
01068 
01069               /*@switchbreak@*/ break;
01070             case '/':
01071               if (skip_evaluation != 0)
01072                 /*@switchbreak@*/ break;
01073               if (v2 == 0)
01074                 {
01075                   cppReader_errorLit (pfile, 
01076                                 cstring_makeLiteralTemp ("Division by zero in #if"));
01077                   v2 = 1;
01078                 }
01079               top->unsignedp = unsigned1 || unsigned2;
01080               if (top->unsignedp)
01081                 top->value = (unsigned long) v1 / v2;
01082               else
01083                 {
01084                   top->value = v1 / v2;
01085                   if ((top->value & v1 & v2) < 0)
01086                     integer_overflow (pfile);
01087                 }
01088               /*@switchbreak@*/ break;
01089             case '%':
01090               if (skip_evaluation != 0)
01091                 /*@switchbreak@*/ break;
01092               if (v2 == 0)
01093                 {
01094                   cppReader_errorLit (pfile, 
01095                                 cstring_makeLiteralTemp ("Division by zero in #if"));
01096                   v2 = 1;
01097                 }
01098               top->unsignedp = unsigned1 || unsigned2;
01099               if (top->unsignedp)
01100                 top->value = (unsigned long) v1 % v2;
01101               else
01102                 top->value = v1 % v2;
01103               /*@switchbreak@*/ break;
01104             case '!':
01105               if ((top->flags & HAVE_VALUE) != 0)
01106                 {
01107                   cppReader_errorLit (pfile, 
01108                                       cstring_makeLiteralTemp ("Syntax error"));
01109                   goto syntax_error;
01110                 }
01111 
01112               top->value = (v2 == 0) ? 1 : 0;
01113               top->unsignedp = FALSE;
01114               top->flags |= HAVE_VALUE;
01115               /*@switchbreak@*/ break;
01116             case '~':
01117               if ((top->flags & HAVE_VALUE) != 0)
01118                 {
01119                   cppReader_errorLit (pfile, 
01120                                 cstring_makeLiteralTemp ("syntax error"));
01121                   goto syntax_error;
01122                 }
01123               top->value = ~ v2;
01124               top->unsignedp = unsigned2;
01125               top->flags |= HAVE_VALUE;
01126               /*@switchbreak@*/ break;
01127             case '<':  COMPARE(<);  /*@switchbreak@*/ break;
01128             case '>':  COMPARE(>);  /*@switchbreak@*/ break;
01129             case LEQ:  COMPARE(<=); /*@switchbreak@*/ break;
01130             case GEQ:  COMPARE(>=); /*@switchbreak@*/ break;
01131             case CPP_EQUALTOK:
01132               top->value = (v1 == v2) ? 1 : 0;
01133               top->unsignedp = FALSE;
01134               /*@switchbreak@*/ break;
01135             case NOTEQUAL:
01136               top->value = (v1 != v2) ? 1 : 0;
01137               top->unsignedp = FALSE;
01138               /*@switchbreak@*/ break;
01139             case LSH:
01140               if (skip_evaluation != 0)
01141                 {
01142                   /*@switchbreak@*/ break;
01143                 }
01144 
01145               top->unsignedp = unsigned1;
01146               if (v2 < 0 && ! unsigned2)
01147                 top->value = right_shift (v1, unsigned1, -v2);
01148               else
01149                 top->value = left_shift (pfile, v1, unsigned1, v2);
01150               /*@switchbreak@*/ break;
01151             case RSH:
01152               if (skip_evaluation != 0)
01153                 {
01154                   /*@switchbreak@*/ break;
01155                 }
01156               top->unsignedp = unsigned1;
01157               if (v2 < 0 && ! unsigned2)
01158                 top->value = left_shift (pfile, v1, unsigned1, -v2);
01159               else
01160                 top->value = right_shift (v1, unsigned1, v2);
01161               /*@switchbreak@*/ break;
01162 
01163 /*@notfunction@*/
01164 #define LOGICAL(OP) \
01165               top->value = v1 OP v2;\
01166               top->unsignedp = unsigned1 || unsigned2;
01167 
01168             case '&':  LOGICAL(&); /*@switchbreak@*/ break;
01169             case '^':  LOGICAL(^); /*@switchbreak@*/ break;
01170             case '|':  LOGICAL(|); /*@switchbreak@*/ break;
01171             case ANDAND:
01172               top->value = ((v1 != 0) && (v2 != 0)) ? 1 : 0;
01173               top->unsignedp = FALSE;
01174 
01175               if (v1 == 0)
01176                 {
01177                   skip_evaluation--;
01178                 }
01179               /*@switchbreak@*/ break;
01180             case OROR:
01181               top->value = ((v1 != 0) || (v2 != 0)) ? 1 : 0;
01182               top->unsignedp = FALSE;
01183               if (v1 != 0)
01184                 {
01185                   skip_evaluation--;
01186                 }
01187               /*@switchbreak@*/ break;
01188             case ',':
01189               if (cppReader_isPedantic (pfile))
01190                 cppReader_pedwarnLit (pfile, 
01191                                 cstring_makeLiteralTemp ("comma operator in operand of `#if'"));
01192               top->value = v2;
01193               top->unsignedp = unsigned2;
01194               /*@switchbreak@*/ break;
01195             case '(':  case '?':
01196               cppReader_errorLit (pfile, 
01197                             cstring_makeLiteralTemp ("syntax error in #if"));
01198               goto syntax_error;
01199             case ':':
01200               if (top[0].op != '?')
01201                 {
01202                   cppReader_errorLit (pfile,
01203                                 cstring_makeLiteralTemp ("syntax error ':' without preceding '?'"));
01204                   goto syntax_error;
01205                 }
01206               else if (((top[1].flags & HAVE_VALUE) == 0)
01207                        || ((top[-1].flags & HAVE_VALUE) == 0)
01208                        || ((top[0].flags & HAVE_VALUE) == 0))
01209                 {
01210                   cppReader_errorLit (pfile, 
01211                                 cstring_makeLiteralTemp ("bad syntax for ?: operator"));
01212                   goto syntax_error;
01213                 }
01214               else
01215                 {
01216                   top--;
01217                   if (top->value != 0)
01218                     {
01219                       skip_evaluation--;
01220                     }
01221 
01222                   top->value = (top->value != 0) ? v1 : v2;
01223                   top->unsignedp = unsigned1 || unsigned2;
01224                 }
01225               /*@switchbreak@*/ break;
01226             case ')':
01227               if (((top[1].flags & HAVE_VALUE) != 0)
01228                   || ((top[0].flags & HAVE_VALUE) == 0)
01229                   || top[0].op != '('
01230                   || ((top[-1].flags & HAVE_VALUE) != 0))
01231                 {
01232                   cppReader_errorLit (pfile, 
01233                                 cstring_makeLiteralTemp ("mismatched parentheses in #if"));
01234                   goto syntax_error;
01235                 }
01236               else
01237                 {
01238                   top--;
01239                   top->value = v1;
01240                   top->unsignedp = unsigned1;
01241                   top->flags |= HAVE_VALUE;
01242                 }
01243               /*@switchbreak@*/ break;
01244             default:
01245               fprintf (stderr,
01246                        top[1].op >= ' ' && top[1].op <= '~'
01247                        ? "unimplemented operator '%c'\n"
01248                        : "unimplemented operator '\\%03o'\n",
01249                        top[1].op);
01250             }
01251         }
01252       if (op.op == 0)
01253         {
01254           long val;
01255 
01256           if (top != stack)
01257             {
01258               cppReader_errorLit (pfile, 
01259                             cstring_makeLiteralTemp ("internal error in #if expression"));
01260             }
01261 
01262           val = top->value;
01263 
01264           if (stack != init_stack)
01265             {
01266               sfree (stack);
01267               /*@-branchstate@*/
01268             } /*@=branchstate@*/
01269 
01270           return val;
01271         }
01272       top++;
01273       
01274       /* Check for and handle stack overflow.  */
01275       if (top == limit)
01276         {
01277           struct operation *new_stack;
01278           int old_size = (char *) limit - (char *) stack;
01279           size_t new_size = size_fromInt (2 * old_size);
01280 
01281           if (stack != init_stack)
01282             {
01283               new_stack = (struct operation *) drealloc ((char *) stack,
01284                                                          new_size);
01285             }
01286           else
01287             {
01288               new_stack = (struct operation *) dmalloc (new_size);
01289 
01290               /* Bug: the parameters were in the wrong order! */
01291               memcpy ((char *) new_stack, (char *) stack, old_size);
01292               /*@-branchstate@*/
01293             } /*@=branchstate@*/
01294 
01295           stack = new_stack;
01296           top = (struct operation *) ((char *) new_stack + old_size);
01297           limit = (struct operation *) ((char *) new_stack + new_size);
01298           /*@-branchstate@*/ 
01299         } /*@=branchstate@*/ 
01300       
01301       top->flags = flags;
01302       top->rprio = rprio;
01303       top->op = op.op;
01304       if ((op.op == OROR && (top[-1].value != 0))
01305           || (op.op == ANDAND && (top[-1].value == 0))
01306           || (op.op == '?' && (top[-1].value == 0)))
01307         {
01308           skip_evaluation++;
01309         }
01310       else if (op.op == ':')
01311         {
01312           if (top[-2].value != 0) /* Was condition true? */
01313             {
01314               skip_evaluation++;
01315             }
01316           else
01317             {
01318               skip_evaluation--;
01319             }
01320         }
01321       else
01322         {
01323           ;
01324         }
01325     }
01326  syntax_error:
01327   /*@-usereleased@*/
01328   if (stack != init_stack)
01329     {
01330       sfree (stack);
01331       /*@-branchstate@*/
01332     } /*@=branchstate@*/
01333   /*@=usereleased@*/
01334 
01335   cppReader_skipRestOfLine (pfile);
01336   return 0;
01337 }

Generated at Fri Nov 3 18:57:39 2000 for LCLint by doxygen1.2.3 written by Dimitri van Heesch, © 1997-2000