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