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