LCOV - code coverage report
Current view: top level - rsc/source/rscpp - cpp5.c (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 116 315 36.8 %
Date: 2014-11-03 Functions: 5 8 62.5 %
Legend: Lines: hit not hit

          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 <stdio.h>
      21             : #include <ctype.h>
      22             : #include "cppdef.h"
      23             : #include "cpp.h"
      24             : 
      25             : /*
      26             :  * Evaluate an #if expression.
      27             :  */
      28             : 
      29             : static char* opname[] = {       /* For debug and error messages */
      30             : "end of expression", "val", "id",
      31             :   "+",   "-",  "*",  "/",  "%",
      32             :   "<<", ">>",  "&",  "|",  "^",
      33             :   "==", "!=",  "<", "<=", ">=",  ">",
      34             :   "&&", "||",  "?",  ":",  ",",
      35             :   "unary +", "unary -", "~", "!",  "(",  ")", "(none)",
      36             : };
      37             : 
      38             : /*
      39             :  * opdope[] has the operator precedence:
      40             :  *     Bits
      41             :  *    7 Unused (so the value is always positive)
      42             :  *  6-2 Precedence (000x .. 017x)
      43             :  *  1-0 Binary op. flags:
      44             :  *      01  The binop flag should be set/cleared when this op is seen.
      45             :  *      10  The new value of the binop flag.
      46             :  * Note:  Expected, New binop
      47             :  * constant 0   1   Binop, end, or ) should follow constants
      48             :  * End of line  1   0   End may not be preceded by an operator
      49             :  * binary   1   0   Binary op follows a value, value follows.
      50             :  * unary    0   0   Unary op doesn't follow a value, value follows
      51             :  *   (      0   0   Doesn't follow value, value or unop follows
      52             :  *   )      1   1   Follows value.  Op follows.
      53             :  */
      54             : 
      55             : static char opdope[OP_MAX] = {
      56             :   0001,                 /* End of expression        */
      57             :   0002,                 /* Digit            */
      58             :   0000,                 /* Letter (identifier)      */
      59             :   0141, 0141, 0151, 0151, 0151,     /* ADD, SUB, MUL, DIV, MOD  */
      60             :   0131, 0131, 0101, 0071, 0071,     /* ASL, ASR, AND,  OR, XOR  */
      61             :   0111, 0111, 0121, 0121, 0121, 0121,   /*  EQ,  NE,  LT,  LE,  GE,  GT */
      62             :   0061, 0051, 0041, 0041, 0031,     /* ANA, ORO, QUE, COL, CMA  */
      63             : /*
      64             :  * Unary op's follow
      65             :  */
      66             :   0160, 0160, 0160, 0160,       /* NEG, PLU, COM, NOT       */
      67             :   0170, 0013, 0023,         /* LPA, RPA, END        */
      68             : };
      69             : /*
      70             :  * OP_QUE and OP_RPA have alternate precedences:
      71             :  */
      72             : #define OP_RPA_PREC 0013
      73             : #define OP_QUE_PREC 0034
      74             : 
      75             : /*
      76             :  * S_ANDOR and S_QUEST signal "short-circuit" boolean evaluation, so that
      77             :  *  #if FOO != 0 && 10 / FOO ...
      78             :  * doesn't generate an error message.  They are stored in optab.skip.
      79             :  */
      80             : #define S_ANDOR     2
      81             : #define S_QUEST     1
      82             : 
      83             : typedef struct optab
      84             : {
      85             :     char    op;         /* Operator         */
      86             :     char    prec;           /* Its precedence       */
      87             :     char    skip;           /* Short-circuit: TRUE to skip  */
      88             : } OPTAB;
      89             : static int  evalue;         /* Current value from evallex() */
      90             : 
      91             : #define isbinary(op)    (op >= FIRST_BINOP && op <= LAST_BINOP)
      92             : 
      93             : /*
      94             :  * The following definitions are used to specify basic variable sizes.
      95             :  */
      96             : 
      97             : #ifndef S_CHAR
      98             : #define S_CHAR      (sizeof (char))
      99             : #endif
     100             : #ifndef S_SINT
     101             : #define S_SINT      (sizeof (short int))
     102             : #endif
     103             : #ifndef S_INT
     104             : #define S_INT       (sizeof (int))
     105             : #endif
     106             : #ifndef S_LINT
     107             : #define S_LINT      (sizeof (long int))
     108             : #endif
     109             : #ifndef S_FLOAT
     110             : #define S_FLOAT     (sizeof (float))
     111             : #endif
     112             : #ifndef S_DOUBLE
     113             : #define S_DOUBLE    (sizeof (double))
     114             : #endif
     115             : #ifndef S_PCHAR
     116             : #define S_PCHAR     (sizeof (char *))
     117             : #endif
     118             : #ifndef S_PSINT
     119             : #define S_PSINT     (sizeof (short int *))
     120             : #endif
     121             : #ifndef S_PINT
     122             : #define S_PINT      (sizeof (int *))
     123             : #endif
     124             : #ifndef S_PLINT
     125             : #define S_PLINT     (sizeof (long int *))
     126             : #endif
     127             : #ifndef S_PFLOAT
     128             : #define S_PFLOAT    (sizeof (float *))
     129             : #endif
     130             : #ifndef S_PDOUBLE
     131             : #define S_PDOUBLE   (sizeof (double *))
     132             : #endif
     133             : #ifndef S_PFPTR
     134             : #define S_PFPTR     (sizeof (int (*)(void)))
     135             : #endif
     136             : 
     137             : typedef struct types
     138             : {
     139             :     short   type;           /* This is the bit if       */
     140             :     char    *name;          /* this is the token word   */
     141             : } TYPES;
     142             : 
     143             : static TYPES basic_types[] = {
     144             :     { T_CHAR,   "char",     },
     145             :     { T_INT,    "int",      },
     146             :     { T_FLOAT,  "float",    },
     147             :     { T_DOUBLE, "double",   },
     148             :     { T_SHORT,  "short",    },
     149             :     { T_LONG,   "long",     },
     150             :     { T_SIGNED, "signed",   },
     151             :     { T_UNSIGNED,   "unsigned", },
     152             :     { 0,        NULL,       },  /* Signal end       */
     153             : };
     154             : 
     155             : /*
     156             :  * Test_table[] is used to test for illegal combinations.
     157             :  */
     158             : static short test_table[] = {
     159             :     T_FLOAT | T_DOUBLE | T_LONG | T_SHORT,
     160             :     T_FLOAT | T_DOUBLE | T_CHAR | T_INT,
     161             :     T_FLOAT | T_DOUBLE | T_SIGNED | T_UNSIGNED,
     162             :     T_LONG  | T_SHORT  | T_CHAR,
     163             :     0                       /* end marker   */
     164             : };
     165             : 
     166             : /*
     167             :  * The order of this table is important -- it is also referenced by
     168             :  * the command line processor to allow run-time overriding of the
     169             :  * built-in size values.  The order must not be changed:
     170             :  *  char, short, int, long, float, double (func pointer)
     171             :  */
     172             : SIZES size_table[] = {
     173             :     { T_CHAR,   S_CHAR,     S_PCHAR     },  /* char     */
     174             :     { T_SHORT,  S_SINT,     S_PSINT     },  /* short int    */
     175             :     { T_INT,    S_INT,      S_PINT      },  /* int      */
     176             :     { T_LONG,   S_LINT,     S_PLINT     },  /* long     */
     177             :     { T_FLOAT,  S_FLOAT,    S_PFLOAT    },  /* float    */
     178             :     { T_DOUBLE, S_DOUBLE,   S_PDOUBLE   },  /* double   */
     179             :     { T_FPTR,   0,      S_PFPTR     },  /* int (*())    */
     180             :     { 0,    0,      0       },  /* End of table */
     181             : };
     182             : 
     183         363 : void InitCpp5()
     184             : {
     185             : 
     186         363 : }
     187             : 
     188             : 
     189             : /*
     190             :  * Evaluate an expression.  Straight-forward operator precedence.
     191             :  * This is called from control() on encountering an #if statement.
     192             :  * It calls the following routines:
     193             :  * evallex  Lexical analyser -- returns the type and value of
     194             :  *      the next input token.
     195             :  * evaleval Evaluate the current operator, given the values on
     196             :  *      the value stack.  Returns a pointer to the (new)
     197             :  *      value stack.
     198             :  * For compatibility with older cpp's, this return returns 1 (TRUE)
     199             :  * if a syntax error is detected.
     200             :  */
     201         469 : int eval()
     202             : {
     203             :     int op;         /* Current operator     */
     204             :     int* valp;      /* -> value vector      */
     205             :     OPTAB* opp;     /* Operator stack       */
     206             :     int prec;       /* Op precedence        */
     207             :     int binop;      /* Set if binary op. needed */
     208             :     int op1;        /* Operand from stack       */
     209             :     int skip;       /* For short-circuit testing    */
     210             :     int value[NEXP]; /* Value stack          */
     211             :     OPTAB opstack[NEXP]; /* Operand stack        */
     212             : 
     213         469 :     valp = value;
     214         469 :     opp = opstack;
     215         469 :     opp->op = OP_END;       /* Mark bottom of stack     */
     216         469 :     opp->prec = opdope[OP_END]; /* And its precedence       */
     217         469 :     opp->skip = 0;          /* Not skipping now     */
     218         469 :     binop = 0;
     219             : 
     220             : again:
     221             : #ifdef  DEBUG_EVAL
     222             :     fprintf( pCppOut, "In #if at again: skip = %d, binop = %d, line is: %s",
     223             :         opp->skip, binop, infile->bptr);
     224             : #endif
     225        9576 :     if ((op = evallex(opp->skip)) == OP_SUB && binop == 0)
     226           0 :         op = OP_NEG;            /* Unary minus      */
     227        9576 :     else if (op == OP_ADD && binop == 0)
     228           0 :         op = OP_PLU;            /* Unary plus       */
     229        9576 :     else if (op == OP_FAIL)
     230           0 :         return (1);             /* Error in evallex */
     231             : #ifdef  DEBUG_EVAL
     232             :     fprintf( pCppOut, "op = %s, opdope = %03o, binop = %d, skip = %d\n",
     233             :         opname[op], opdope[op], binop, opp->skip);
     234             : #endif
     235        9576 :     if (op == DIG)              /* Value?       */
     236             :     {
     237        3085 :         if (binop != 0)
     238             :         {
     239           0 :             cerror("misplaced constant in #if", NULLST);
     240           0 :             return (1);
     241             :         }
     242        3085 :         else if (valp >= &value[NEXP-1])
     243             :         {
     244           0 :             cerror("#if value stack overflow", NULLST);
     245           0 :             return (1);
     246             :         }
     247             :         else
     248             :         {
     249             : #ifdef  DEBUG_EVAL
     250             :             fprintf( pCppOut, "pushing %d onto value stack[%d]\n",
     251             :                      evalue, valp - value);
     252             : #endif
     253        3085 :             *valp++ = evalue;
     254        3085 :             binop = 1;
     255             :         }
     256        3085 :         goto again;
     257             :     }
     258        6491 :     else if (op > OP_END)
     259             :     {
     260           0 :         cerror("Illegal #if line", NULLST);
     261           0 :         return (1);
     262             :     }
     263        6491 :     prec = opdope[op];
     264        6491 :     if (binop != (prec & 1))
     265             :     {
     266           0 :         cerror("Operator %s in incorrect context", opname[op]);
     267           0 :         return (1);
     268             :     }
     269        6491 :     binop = (prec & 2) >> 1;
     270             :     for (;;)
     271             :     {
     272             : #ifdef  DEBUG_EVAL
     273             :         fprintf( pCppOut, "op %s, prec %d., stacked op %s, prec %d, skip %d\n",
     274             :         opname[op], prec, opname[opp->op], opp->prec, opp->skip);
     275             : #endif
     276        9107 :         if (prec > opp->prec)
     277             :         {
     278        4319 :             if (op == OP_LPA)
     279        1703 :                 prec = OP_RPA_PREC;
     280        2616 :             else if (op == OP_QUE)
     281           0 :                 prec = OP_QUE_PREC;
     282        4319 :             op1 = opp->skip;        /* Save skip for test   */
     283             :             /*
     284             :              * Push operator onto op. stack.
     285             :              */
     286        4319 :             opp++;
     287        4319 :             if (opp >= &opstack[NEXP])
     288             :             {
     289           0 :                 cerror("expression stack overflow at op \"%s\"",
     290             :                        opname[op]);
     291           0 :                 return (1);
     292             :             }
     293        4319 :             opp->op = (char)op;
     294        4319 :             opp->prec = (char)prec;
     295             :             /*
     296             :              * Do the short-circuit stuff here.  Short-circuiting
     297             :              * stops automagically when operators are evaluated.
     298             :              */
     299        4319 :             if ((op == OP_ANA && valp[-1] == 0) ||
     300           0 :                 (op == OP_ORO && valp[-1] != 0))
     301             :             {
     302           0 :                 opp->skip = S_ANDOR;    /* And/or skip starts   */
     303             :             }
     304        4319 :             else if (op == OP_QUE)      /* Start of ?: operator */
     305           0 :                 opp->skip = (char)((op1 & S_ANDOR) | ((valp[-1] == 0) ? S_QUEST : 0));
     306        4319 :             else if (op == OP_COL)      /* : inverts S_QUEST    */
     307             :             {
     308           0 :                 opp->skip = (char)((op1 & S_ANDOR)
     309           0 :                                    | (((op1 & S_QUEST) != 0) ? 0 : S_QUEST));
     310             :             }
     311             :             else                 /* Other ops leave  */
     312             :             {
     313        4319 :                 opp->skip = (char)op1;      /*  skipping unchanged. */
     314             :             }
     315             : #ifdef  DEBUG_EVAL
     316             :             fprintf( pCppOut, "stacking %s, valp[-1] == %d at %s",
     317             :                      opname[op], valp[-1], infile->bptr);
     318             :             dumpstack(opstack, opp, value, valp);
     319             : #endif
     320        4319 :             goto again;
     321             :         }
     322             :         /*
     323             :          * Pop operator from op. stack and evaluate it.
     324             :          * End of stack and '(' are specials.
     325             :          */
     326        4788 :         skip = opp->skip;           /* Remember skip value  */
     327        4788 :         switch ((op1 = opp->op))    /* Look at stacked op   */
     328             :         {
     329             :         case OP_END:                /* Stack end marker */
     330         469 :             if (op == OP_EOE)
     331         469 :                 return (valp[-1]);  /* Finished ok.     */
     332           0 :             goto again;             /* Read another op. */
     333             : 
     334             :         case OP_LPA:                /* ( on stack       */
     335        1703 :             if (op != OP_RPA)       /* Matches ) on input   */
     336             :             {
     337           0 :                 cerror("unbalanced paren's, op is \"%s\"", opname[op]);
     338           0 :                 return (1);
     339             :             }
     340        1703 :             opp--;                  /* Unstack it       */
     341             :             /* goto again;          -- Fall through     */
     342             : 
     343             :         case OP_QUE:
     344        1703 :             goto again;             /* Evaluate true expr.  */
     345             : 
     346             :         case OP_COL:                /* : on stack.      */
     347           0 :             opp--;                  /* Unstack :        */
     348           0 :             if (opp->op != OP_QUE)  /* Matches ? on stack?  */
     349             :             {
     350           0 :                 cerror("Misplaced '?' or ':', previous operator is %s",
     351           0 :                        opname[(int)opp->op]);
     352           0 :                 return (1);
     353             :             }
     354             :         /*
     355             :          * Evaluate op1.
     356             :          */
     357             :         default:                /* Others:      */
     358        2616 :             opp--;              /* Unstack the operator */
     359             : #ifdef  DEBUG_EVAL
     360             :             fprintf( pCppOut, "Stack before evaluation of %s\n", opname[op1]);
     361             :             dumpstack(opstack, opp, value, valp);
     362             : #endif
     363        2616 :             valp = evaleval(valp, op1, skip);
     364             : #ifdef  DEBUG_EVAL
     365             :             fprintf( pCppOut, "Stack after evaluation\n");
     366             :             dumpstack(opstack, opp, value, valp);
     367             : #endif
     368             :         }                   /* op1 switch end   */
     369        2616 :     }                   /* Stack unwind loop    */
     370             : }
     371             : 
     372             : /*
     373             :  * Return next eval operator or value.  Called from eval().  It
     374             :  * calls a special-purpose routines for 'char' strings and
     375             :  * numeric values:
     376             :  * evalchar called to evaluate 'x'
     377             :  * evalnum  called to evaluate numbers.
     378             :  */
     379        9576 : FILE_LOCAL int evallex(int skip)
     380             : {
     381             :     int c;
     382             :     int c1;
     383             :     int t;
     384             : 
     385             : again:
     386             :     do                              /* Collect the token    */
     387             :     {
     388        9576 :         c = skipws();
     389        9576 :         if ((c = macroid(c)) == EOF_CHAR || c == '\n')
     390             :         {
     391         469 :             unget();
     392         469 :             return (OP_EOE);        /* End of expression    */
     393             :         }
     394             :     }
     395        9107 :     while ((t = type[c]) == LET && catenate());
     396        9107 :     if (t == INV)                   /* Total nonsense   */
     397             :     {
     398           0 :         if (!skip)
     399             :         {
     400           0 :             if (isascii(c) && isprint(c))
     401           0 :                 cierror("illegal character '%c' in #if", c);
     402             :             else
     403           0 :                 cierror("illegal character (%d decimal) in #if", c);
     404             :         }
     405           0 :         return (OP_FAIL);
     406             :     }
     407        9107 :     else if (t == QUO)              /* ' or "       */
     408             :     {
     409           0 :         if (c == '\'')              /* Character constant   */
     410             :         {
     411           0 :             evalue = evalchar(skip);    /* Somewhat messy   */
     412             : #ifdef  DEBUG_EVAL
     413             :             fprintf( pCppOut, "evalchar returns %d.\n", evalue);
     414             : #endif
     415           0 :             return (DIG);           /* Return a value   */
     416             :         }
     417           0 :         cerror("Can't use a string in an #if", NULLST);
     418           0 :         return (OP_FAIL);
     419             :     }
     420        9107 :     else if (t == LET)              /* ID must be a macro   */
     421             :     {
     422           2 :         if (streq(token, "defined"))  /* Or defined name  */
     423             :         {
     424           1 :             c1 = c = skipws();
     425           1 :             if (c == '(')           /* Allow defined(name)  */
     426           1 :                 c = skipws();
     427           1 :             if (type[c] == LET)
     428             :             {
     429           1 :                 evalue = (lookid(c) != NULL);
     430           2 :                 if (c1 != '(' ||      /* Need to balance  */
     431           1 :                     skipws() == ')')    /* Did we balance?  */
     432             :                 {
     433           1 :                     return (DIG);       /* Parsed ok        */
     434             :                 }
     435             :             }
     436           0 :             cerror("Bad #if ... defined() syntax", NULLST);
     437           0 :             return (OP_FAIL);
     438             :         }
     439           1 :         else if (streq(token, "sizeof"))    /* New sizeof hackery   */
     440           0 :             return (dosizeof());        /* Gets own routine */
     441             :         /*
     442             :          * The Draft ANSI C Standard says that an undefined symbol
     443             :          * in an #if has the value zero.  We are a bit pickier,
     444             :          * warning except where the programmer was careful to write
     445             :          *      #if defined(foo) ? foo : 0
     446             :          */
     447             : #ifdef STRICT_UNDEF
     448             :         if (!skip)
     449             :             cwarn("undefined symbol \"%s\" in #if, 0 used", token);
     450             : #endif
     451           1 :         evalue = 0;
     452           1 :         return (DIG);
     453             :     }
     454        9105 :     else if (t == DIG)              /* Numbers are harder   */
     455             :     {
     456        3083 :         evalue = evalnum(c);
     457             : #ifdef  DEBUG_EVAL
     458             :         fprintf( pCppOut, "evalnum returns %d.\n", evalue);
     459             : #endif
     460             :     }
     461        6022 :     else if (strchr("!=<>&|\\", c) != NULL)
     462             :     {
     463             :         /*
     464             :          * Process a possible multi-byte lexeme.
     465             :          */
     466         468 :         c1 = cget();                /* Peek at next char    */
     467         468 :         switch (c)
     468             :         {
     469             :         case '!':
     470           0 :             if (c1 == '=')
     471           0 :                 return (OP_NE);
     472           0 :             break;
     473             : 
     474             :         case '=':
     475          96 :             if (c1 != '=')          /* Can't say a=b in #if */
     476             :             {
     477           0 :                 unget();
     478           0 :                 cerror("= not allowed in #if", NULLST);
     479           0 :                 return (OP_FAIL);
     480             :             }
     481          96 :             return (OP_EQ);
     482             : 
     483             :         case '>':
     484             :         case '<':
     485         372 :             if (c1 == c)
     486           0 :                 return ((c == '<') ? OP_ASL : OP_ASR);
     487         372 :             else if (c1 == '=')
     488           2 :                 return ((c == '<') ? OP_LE  : OP_GE);
     489         370 :             break;
     490             : 
     491             :         case '|':
     492             :         case '&':
     493           0 :             if (c1 == c)
     494           0 :                 return ((c == '|') ? OP_ORO : OP_ANA);
     495           0 :             break;
     496             : 
     497             :         case '\\':
     498           0 :             if (c1 == '\n')         /* Multi-line if    */
     499           0 :                 goto again;
     500           0 :             cerror("Unexpected \\ in #if", NULLST);
     501           0 :             return (OP_FAIL);
     502             :         }
     503         370 :         unget();
     504             :     }
     505        9007 :     return (t);
     506             : }
     507             : 
     508             : /*
     509             :  * Process the sizeof (basic type) operation in an #if string.
     510             :  * Sets evalue to the size and returns
     511             :  *  DIG     success
     512             :  *  OP_FAIL     bad parse or something.
     513             :  */
     514           0 : FILE_LOCAL int dosizeof()
     515             : {
     516             :     int c;
     517             :     TYPES* tp;
     518             :     SIZES* sizp;
     519             :     short* testp;
     520             :     short typecode;
     521             : 
     522           0 :     if ((c = skipws()) != '(')
     523           0 :         goto nogood;
     524             :     /*
     525             :      * Scan off the tokens.
     526             :      */
     527           0 :     typecode = 0;
     528           0 :     while (0 != (c = skipws()))
     529             :     {
     530           0 :         if ((c = macroid(c)) == EOF_CHAR || c == '\n')
     531             :             goto nogood;            /* End of line is a bug */
     532           0 :         else if (c == '(')          /* thing (*)() func ptr */
     533             :         {
     534           0 :             if (skipws() == '*' && skipws() == ')')
     535             :             {                       /* We found (*)     */
     536           0 :                 if (skipws() != '(')    /* Let () be optional   */
     537           0 :                     unget();
     538           0 :                 else if (skipws() != ')')
     539           0 :                     goto nogood;
     540           0 :                 typecode |= T_FPTR; /* Function pointer */
     541             :             }
     542             :             else                    /* Junk is a bug    */
     543             :                 goto nogood;
     544             :         }
     545           0 :         else if (type[c] != LET)    /* Exit if not a type   */
     546           0 :             break;
     547           0 :         else if (!catenate())       /* Maybe combine tokens */
     548             :         {
     549             :             /*
     550             :              * Look for this unexpandable token in basic_types.
     551             :              * The code accepts "int long" as well as "long int"
     552             :              * which is a minor bug as bugs go (and one shared with
     553             :              * a lot of C compilers).
     554             :              */
     555           0 :             for (tp = basic_types; tp->name != NULLST; tp++)
     556             :             {
     557           0 :                 if (streq(token, tp->name))
     558           0 :                     break;
     559             :             }
     560           0 :             if (tp->name == NULLST)
     561             :             {
     562           0 :                 cerror("#if sizeof, unknown type \"%s\"", token);
     563           0 :                 return (OP_FAIL);
     564             :             }
     565           0 :             typecode |= tp->type;   /* Or in the type bit   */
     566             :         }
     567             :     }
     568             :     /*
     569             :      * We are at the end of the type scan.  Chew off '*' if necessary.
     570             :      */
     571           0 :     if (c == '*')
     572             :     {
     573           0 :         typecode |= T_PTR;
     574           0 :         c = skipws();
     575             :     }
     576           0 :     if (c == ')')                   /* Last syntax check    */
     577             :     {
     578           0 :         for (testp = test_table; *testp != 0; testp++)
     579             :         {
     580           0 :             if (!bittest(typecode & *testp))
     581             :             {
     582           0 :                 cerror("#if ... sizeof: illegal type combination", NULLST);
     583           0 :                 return (OP_FAIL);
     584             :             }
     585             :         }
     586             :         /*
     587             :          * We assume that all function pointers are the same size:
     588             :          *      sizeof (int (*)()) == sizeof (float (*)())
     589             :          * We assume that signed and unsigned don't change the size:
     590             :          *      sizeof (signed int) == (sizeof unsigned int)
     591             :          */
     592           0 :         if ((typecode & T_FPTR) != 0) /* Function pointer */
     593           0 :             typecode = T_FPTR | T_PTR;
     594             :         else                        /* Var or var * datum   */
     595             :         {
     596           0 :             typecode &= ~(T_SIGNED | T_UNSIGNED);
     597           0 :             if ((typecode & (T_SHORT | T_LONG)) != 0)
     598           0 :                 typecode &= ~T_INT;
     599             :         }
     600           0 :         if ((typecode & ~T_PTR) == 0)
     601             :         {
     602           0 :             cerror("#if sizeof() error, no type specified", NULLST);
     603           0 :             return (OP_FAIL);
     604             :         }
     605             :         /*
     606             :          * Exactly one bit (and possibly T_PTR) may be set.
     607             :          */
     608           0 :         for (sizp = size_table; sizp->bits != 0; sizp++)
     609             :         {
     610           0 :             if ((typecode & ~T_PTR) == sizp->bits)
     611             :             {
     612           0 :                 evalue = ((typecode & T_PTR) != 0)
     613           0 :                     ? sizp->psize : sizp->size;
     614           0 :                 return (DIG);
     615             :             }
     616             :         }                   /* We shouldn't fail    */
     617           0 :         cierror("#if ... sizeof: bug, unknown type code 0x%x", typecode);
     618           0 :         return (OP_FAIL);
     619             :     }
     620             : 
     621             :   nogood:
     622           0 :     unget();
     623           0 :     cerror("#if ... sizeof() syntax error", NULLST);
     624           0 :     return (OP_FAIL);
     625             : }
     626             : 
     627             : /*
     628             :  * TRUE if value is zero or exactly one bit is set in value.
     629             :  */
     630           0 : FILE_LOCAL int bittest(int value)
     631             : {
     632             : /* whoaa!! really worried about non 2's complement machines...
     633             :  * but not at all about cross-compiling ?
     634             :  */
     635             : #if (4096 & ~(-4096)) == 0
     636           0 :     return ((value & ~(-value)) == 0);
     637             : #else
     638             :     /*
     639             :      * Do it the hard way (for non 2's complement machines)
     640             :      */
     641             :     return (value == 0 || value ^ (value - 1) == (value * 2 - 1));
     642             : #endif
     643             : }
     644             : 
     645             : /*
     646             :  * Expand number for #if lexical analysis.  Note: evalnum recognizes
     647             :  * the unsigned suffix, but only returns a signed int value.
     648             :  */
     649        3083 : FILE_LOCAL int evalnum(int c)
     650             : {
     651             :     int value;
     652             :     int base;
     653             :     int c1;
     654             : 
     655        3083 :     if (c != '0')
     656        3078 :         base = 10;
     657           5 :     else if ((c = cget()) == 'x' || c == 'X')
     658             :     {
     659           0 :         base = 16;
     660           0 :         c = cget();
     661             :     }
     662           5 :     else base = 8;
     663        3083 :     value = 0;
     664             :     for (;;)
     665             :     {
     666       13287 :         c1 = c;
     667       13287 :         if (isascii(c) && isupper(c1))
     668           0 :             c1 = tolower(c1);
     669       13287 :         if (c1 >= 'a')
     670           0 :             c1 -= ('a' - 10);
     671             :         else
     672       13287 :             c1 -= '0';
     673       13287 :         if (c1 < 0 || c1 >= base)
     674             :             break;
     675       10204 :         value *= base;
     676       10204 :         value += c1;
     677       10204 :         c = cget();
     678       10204 :     }
     679        3083 :     if (c == 'u' || c == 'U')   /* Unsigned nonsense        */
     680           0 :         cget();
     681        3083 :     unget();
     682        3083 :     return (value);
     683             : }
     684             : 
     685             : /*
     686             :  * Get a character constant
     687             :  */
     688           0 : FILE_LOCAL int evalchar(int skip)
     689             : {
     690             :     int c;
     691             :     int value;
     692             :     int count;
     693             : 
     694           0 :     instring = TRUE;
     695           0 :     if ((c = cget()) == '\\')
     696             :     {
     697           0 :         switch ((c = cget()))
     698             :         {
     699             :         case 'a':               /* New in Standard  */
     700             : #if ('a' == '\a' || '\a' == ALERT)
     701           0 :             value = ALERT;          /* Use predefined value */
     702             : #else
     703             :             value = '\a';           /* Use compiler's value */
     704             : #endif
     705           0 :             break;
     706             : 
     707             :         case 'b':
     708           0 :             value = '\b';
     709           0 :             break;
     710             : 
     711             :         case 'f':
     712           0 :             value = '\f';
     713           0 :             break;
     714             : 
     715             :         case 'n':
     716           0 :             value = '\n';
     717           0 :             break;
     718             : 
     719             :         case 'r':
     720           0 :             value = '\r';
     721           0 :             break;
     722             : 
     723             :         case 't':
     724           0 :             value = '\t';
     725           0 :             break;
     726             : 
     727             :         case 'v':               /* New in Standard  */
     728             : #if ('v' == '\v' || '\v' == VT)
     729           0 :             value = VT;         /* Use predefined value */
     730             : #else
     731             :             value = '\v';           /* Use compiler's value */
     732             : #endif
     733           0 :             break;
     734             : 
     735             :         case 'x':               /* '\xFF'       */
     736           0 :             count = 3;
     737           0 :             value = 0;
     738           0 :             while ((((c = get()) >= '0' && c <= '9') ||
     739           0 :                     (c >= 'a' && c <= 'f') ||
     740           0 :                     (c >= 'A' && c <= 'F')) &&
     741             :                    (--count >= 0))
     742             :             {
     743           0 :                 value *= 16;
     744           0 :                 value += (c >= '0') ? (c - '0') : ((c & 0xF) + 9);
     745             :             }
     746           0 :             unget();
     747           0 :             break;
     748             : 
     749             :         default:
     750           0 :             if (c >= '0' && c <= '7')
     751             :             {
     752           0 :                 count = 3;
     753           0 :                 value = 0;
     754           0 :                 while (c >= '0' && c <= '7' && --count >= 0)
     755             :                 {
     756           0 :                     value *= 8;
     757           0 :                     value += (c - '0');
     758           0 :                     c = get();
     759             :                 }
     760           0 :                 unget();
     761             :             }
     762           0 :             else value = c;
     763           0 :             break;
     764             :         }
     765             :     }
     766           0 :     else if (c == '\'')
     767           0 :         value = 0;
     768             :     else
     769           0 :         value = c;
     770             :     /*
     771             :      * We warn on multi-byte constants and try to hack
     772             :      * (big|little)endian machines.
     773             :      */
     774           0 :     while ((c = get()) != '\'' && c != EOF_CHAR && c != '\n')
     775             :     {
     776           0 :         if (!skip)
     777           0 :             ciwarn("multi-byte constant '%c' isn't portable", c);
     778           0 :         value <<= BITS_CHAR;
     779           0 :         value += c;
     780             :     }
     781           0 :     instring = FALSE;
     782           0 :     return (value);
     783             : }
     784             : 
     785             : /*
     786             :  * Apply the argument operator to the data on the value stack.
     787             :  * One or two values are popped from the value stack and the result
     788             :  * is pushed onto the value stack.
     789             :  *
     790             :  * OP_COL is a special case.
     791             :  *
     792             :  * evaleval() returns the new pointer to the top of the value stack.
     793             :  */
     794        2616 : FILE_LOCAL int * evaleval(int* valp, int op, int skip)
     795             : {
     796             :     int v1;
     797        2616 :     int v2 = 0;
     798             : 
     799        2616 :     if (isbinary(op))
     800        2616 :         v2 = *--valp;
     801        2616 :     v1 = *--valp;
     802             : #ifdef  DEBUG_EVAL
     803             :     fprintf( pCppOut, "%s op %s", (isbinary(op)) ? "binary" : "unary",
     804             :              opname[op]);
     805             :     if (isbinary(op))
     806             :         fprintf( pCppOut, ", v2 = %d.", v2);
     807             :     fprintf( pCppOut, ", v1 = %d.\n", v1);
     808             : #endif
     809        2616 :     switch (op)
     810             :     {
     811             :     case OP_EOE:
     812           0 :         break;
     813             : 
     814             :     case OP_ADD:
     815        2030 :         v1 += v2;
     816        2030 :         break;
     817             : 
     818             :     case OP_SUB:
     819         118 :         v1 -= v2;
     820         118 :         break;
     821             : 
     822             :     case OP_MUL:
     823           0 :         v1 *= v2;
     824           0 :         break;
     825             : 
     826             :     case OP_DIV:
     827             :     case OP_MOD:
     828           0 :         if (v2 == 0)
     829             :         {
     830           0 :             if (!skip)
     831             :             {
     832           0 :                 cwarn("%s by zero in #if, zero result assumed",
     833             :                       (op == OP_DIV) ? "divide" : "mod");
     834             :             }
     835           0 :             v1 = 0;
     836             :         }
     837           0 :         else if (op == OP_DIV)
     838           0 :             v1 /= v2;
     839             :         else
     840           0 :             v1 %= v2;
     841           0 :         break;
     842             : 
     843             :     case OP_ASL:
     844           0 :         v1 <<= v2;
     845           0 :         break;
     846             : 
     847             :     case OP_ASR:
     848           0 :         v1 >>= v2;
     849           0 :         break;
     850             : 
     851             :     case OP_AND:
     852           0 :         v1 &= v2;
     853           0 :         break;
     854             : 
     855             :     case OP_OR:
     856           0 :         v1 |= v2;
     857           0 :         break;
     858             : 
     859             :     case OP_XOR:
     860           0 :         v1 ^= v2;
     861           0 :         break;
     862             : 
     863             :     case OP_EQ:
     864          96 :         v1 = (v1 == v2);
     865          96 :         break;
     866             : 
     867             :     case OP_NE:
     868           0 :         v1 = (v1 != v2);
     869           0 :         break;
     870             : 
     871             :     case OP_LT:
     872           0 :         v1 = (v1 < v2);
     873           0 :         break;
     874             : 
     875             :     case OP_LE:
     876           0 :         v1 = (v1 <= v2);
     877           0 :         break;
     878             : 
     879             :     case OP_GE:
     880           2 :         v1 = (v1 >= v2);
     881           2 :         break;
     882             : 
     883             :     case OP_GT:
     884         370 :         v1 = (v1 > v2);
     885         370 :         break;
     886             : 
     887             :     case OP_ANA:
     888           0 :         v1 = (v1 && v2);
     889           0 :         break;
     890             : 
     891             :     case OP_ORO:
     892           0 :         v1 = (v1 || v2);
     893           0 :         break;
     894             : 
     895             :     case OP_COL:
     896             :         /*
     897             :          * v1 has the "true" value, v2 the "false" value.
     898             :          * The top of the value stack has the test.
     899             :          */
     900           0 :         v1 = (*--valp) ? v1 : v2;
     901           0 :         break;
     902             : 
     903             :     case OP_NEG:
     904           0 :         v1 = (-v1);
     905           0 :         break;
     906             : 
     907             :     case OP_PLU:
     908           0 :         break;
     909             : 
     910             :     case OP_COM:
     911           0 :         v1 = ~v1;
     912           0 :         break;
     913             : 
     914             :     case OP_NOT:
     915           0 :         v1 = !v1;
     916           0 :         break;
     917             : 
     918             :     default:
     919           0 :         cierror("#if bug, operand = %d.", op);
     920           0 :         v1 = 0;
     921             :     }
     922        2616 :     *valp++ = v1;
     923        2616 :     return (valp);
     924             : }
     925             : 
     926             : #ifdef  DEBUG_EVAL
     927             : dumpstack(opstack, opp, value, valp)
     928             : OPTAB   opstack[NEXP];  /* Operand stack        */
     929             : OPTAB  *opp;            /* Operator stack       */
     930             : int     value[NEXP];    /* Value stack          */
     931             : int    *valp;           /* -> value vector      */
     932             : {
     933             :     fprintf( pCppOut, "index op prec skip name -- op stack at %s", infile->bptr);
     934             :     while (opp > opstack)
     935             :     {
     936             :         fprintf( pCppOut, " [%2d] %2d  %03o    %d %s\n", opp - opstack,
     937             :                  opp->op, opp->prec, opp->skip, opname[opp->op]);
     938             :         opp--;
     939             :     }
     940             :     while (--valp >= value)
     941             :     {
     942             :         fprintf( pCppOut, "value[%d] = %d\n", (valp - value), *valp);
     943             :     }
     944             : }
     945             : #endif
     946             : 
     947             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10