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