xref: /aoo42x/main/rsc/source/rscpp/cpp5.c (revision 26d9e9dd)
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 preceded 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 compatibility 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 again:
244 #ifdef	DEBUG_EVAL
245     fprintf( pCppOut, "In #if at again: skip = %d, binop = %d, line is: %s",
246 	    opp->skip, binop, infile->bptr);
247 #endif
248 	if ((op = evallex(opp->skip)) == OP_SUB && binop == 0)
249 	    op = OP_NEG;			/* Unary minus		*/
250 	else if (op == OP_ADD && binop == 0)
251 	    op = OP_PLU;			/* Unary plus		*/
252 	else if (op == OP_FAIL)
253 	    return (1);				/* Error in evallex	*/
254 #ifdef	DEBUG_EVAL
255     fprintf( pCppOut, "op = %s, opdope = %03o, binop = %d, skip = %d\n",
256 	    opname[op], opdope[op], binop, opp->skip);
257 #endif
258 	if (op == DIG) {			/* Value?		*/
259 	    if (binop != 0) {
260 		cerror("misplaced constant in #if", NULLST);
261 		return (1);
262 	    }
263 	    else if (valp >= &value[NEXP-1]) {
264 		cerror("#if value stack overflow", NULLST);
265 		return (1);
266 	    }
267 	    else {
268 #ifdef	DEBUG_EVAL
269         fprintf( pCppOut, "pushing %d onto value stack[%d]\n",
270 		    evalue, valp - value);
271 #endif
272 		*valp++ = evalue;
273 		binop = 1;
274 	    }
275 	    goto again;
276 	}
277 	else if (op > OP_END) {
278 	    cerror("Illegal #if line", NULLST);
279 	    return (1);
280 	}
281 	prec = opdope[op];
282 	if (binop != (prec & 1)) {
283 	    cerror("Operator %s in incorrect context", opname[op]);
284 	    return (1);
285 	}
286 	binop = (prec & 2) >> 1;
287 	for (;;) {
288 #ifdef	DEBUG_EVAL
289         fprintf( pCppOut, "op %s, prec %d., stacked op %s, prec %d, skip %d\n",
290 		opname[op], prec, opname[opp->op], opp->prec, opp->skip);
291 #endif
292 	    if (prec > opp->prec) {
293 		if (op == OP_LPA)
294 		    prec = OP_RPA_PREC;
295 		else if (op == OP_QUE)
296 		    prec = OP_QUE_PREC;
297 		op1 = opp->skip;		/* Save skip for test	*/
298 		/*
299 		 * Push operator onto op. stack.
300 		 */
301 		opp++;
302 		if (opp >= &opstack[NEXP]) {
303 		    cerror("expression stack overflow at op \"%s\"",
304 			opname[op]);
305 		    return (1);
306 		}
307 		opp->op = (char)op;
308 		opp->prec = (char)prec;
309 		skip = (valp[-1] != 0);		/* Short-circuit tester	*/
310 		/*
311 		 * Do the short-circuit stuff here.  Short-circuiting
312 		 * stops automagically when operators are evaluated.
313 		 */
314 		if ((op == OP_ANA && !skip)
315 		 || (op == OP_ORO && skip))
316 		    opp->skip = S_ANDOR;	/* And/or skip starts	*/
317 		else if (op == OP_QUE)		/* Start of ?: operator	*/
318 		    opp->skip = (char)((op1 & S_ANDOR) | ((!skip) ? S_QUEST : 0));
319 		else if (op == OP_COL) {	/* : inverts S_QUEST	*/
320 		    opp->skip = (char)((op1 & S_ANDOR)
321 			      | (((op1 & S_QUEST) != 0) ? 0 : S_QUEST));
322 		}
323 		else {				/* Other ops leave	*/
324 		    opp->skip = (char)op1;		/*  skipping unchanged.	*/
325 		}
326 #ifdef	DEBUG_EVAL
327         fprintf( pCppOut, "stacking %s, valp[-1] == %d at %s",
328 		    opname[op], valp[-1], infile->bptr);
329 		dumpstack(opstack, opp, value, valp);
330 #endif
331 		goto again;
332 	    }
333 	    /*
334 	     * Pop operator from op. stack and evaluate it.
335 	     * End of stack and '(' are specials.
336 	     */
337 	    skip = opp->skip;			/* Remember skip value	*/
338 	    switch ((op1 = opp->op)) {		/* Look at stacked op	*/
339 	    case OP_END:			/* Stack end marker	*/
340 		if (op == OP_EOE)
341 		    return (valp[-1]);		/* Finished ok.		*/
342 		goto again;			/* Read another op.	*/
343 
344 	    case OP_LPA:			/* ( on stack		*/
345 		if (op != OP_RPA) {		/* Matches ) on input	*/
346 		    cerror("unbalanced paren's, op is \"%s\"", opname[op]);
347 		    return (1);
348 		}
349 		opp--;				/* Unstack it		*/
350 		/* goto again;			-- Fall through		*/
351 
352 	    case OP_QUE:
353 		goto again;			/* Evaluate true expr.	*/
354 
355 	    case OP_COL:			/* : on stack.		*/
356 		opp--;				/* Unstack :		*/
357 		if (opp->op != OP_QUE) {	/* Matches ? on stack?	*/
358 		    cerror("Misplaced '?' or ':', previous operator is %s",
359                    opname[(int)opp->op]);
360 		    return (1);
361 		}
362 		/*
363 		 * Evaluate op1.
364 		 */
365 	    default:				/* Others:		*/
366 		opp--;				/* Unstack the operator	*/
367 #ifdef	DEBUG_EVAL
368         fprintf( pCppOut, "Stack before evaluation of %s\n", opname[op1]);
369 		dumpstack(opstack, opp, value, valp);
370 #endif
371 		valp = evaleval(valp, op1, skip);
372 #ifdef	DEBUG_EVAL
373         fprintf( pCppOut, "Stack after evaluation\n");
374 		dumpstack(opstack, opp, value, valp);
375 #endif
376 	    }					/* op1 switch end	*/
377 	}					/* Stack unwind loop	*/
378 }
379 
380 FILE_LOCAL int
evallex(int skip)381 evallex(int skip)
382 /*
383  * Return next eval operator or value.  Called from eval().  It
384  * calls a special-purpose routines for 'char' strings and
385  * numeric values:
386  * evalchar	called to evaluate 'x'
387  * evalnum	called to evaluate numbers.
388  */
389 {
390 	register int	c, c1, t;
391 
392 again:  do {					/* Collect the token	*/
393 	    c = skipws();
394 	    if ((c = macroid(c)) == EOF_CHAR || c == '\n') {
395 		unget();
396 		return (OP_EOE);		/* End of expression	*/
397 	    }
398 	} while ((t = type[c]) == LET && catenate());
399 	if (t == INV) {				/* Total nonsense	*/
400 	    if (!skip) {
401 		if (isascii(c) && isprint(c))
402 		    cierror("illegal character '%c' in #if", c);
403 		else
404 		    cierror("illegal character (%d decimal) in #if", c);
405 	    }
406 	    return (OP_FAIL);
407 	}
408 	else if (t == QUO) {			/* ' or "		*/
409 	    if (c == '\'') {			/* Character constant	*/
410 		evalue = evalchar(skip);	/* Somewhat messy	*/
411 #ifdef	DEBUG_EVAL
412         fprintf( pCppOut, "evalchar returns %d.\n", evalue);
413 #endif
414 		return (DIG);			/* Return a value	*/
415 	    }
416 	    cerror("Can't use a string in an #if", NULLST);
417 	    return (OP_FAIL);
418 	}
419 	else if (t == LET) {			/* ID must be a macro	*/
420 	    if (streq(token, "defined")) {	/* Or defined name	*/
421 		c1 = c = skipws();
422 		if (c == '(')			/* Allow defined(name)	*/
423 		    c = skipws();
424 		if (type[c] == LET) {
425 		    evalue = (lookid(c) != NULL);
426 		    if (c1 != '('		/* Need to balance	*/
427 		     || skipws() == ')')	/* Did we balance?	*/
428 			return (DIG);		/* Parsed ok		*/
429 		}
430 		cerror("Bad #if ... defined() syntax", NULLST);
431 		return (OP_FAIL);
432 	    }
433 	    else if (streq(token, "sizeof"))	/* New sizeof hackery	*/
434 		return (dosizeof());		/* Gets own routine	*/
435 	    /*
436 	     * The Draft ANSI C Standard says that an undefined symbol
437 	     * in an #if has the value zero.  We are a bit pickier,
438 	     * warning except where the programmer was careful to write
439 	     * 		#if defined(foo) ? foo : 0
440 	     */
441 #ifdef STRICT_UNDEF
442 	    if (!skip)
443 		cwarn("undefined symbol \"%s\" in #if, 0 used", token);
444 #endif
445 	    evalue = 0;
446 	    return (DIG);
447 	}
448 	else if (t == DIG) {			/* Numbers are harder	*/
449 	    evalue = evalnum(c);
450 #ifdef	DEBUG_EVAL
451         fprintf( pCppOut, "evalnum returns %d.\n", evalue);
452 #endif
453 	}
454 	else if (strchr("!=<>&|\\", c) != NULL) {
455 	    /*
456 	     * Process a possible multi-byte lexeme.
457 	     */
458 	    c1 = cget();			/* Peek at next char	*/
459 	    switch (c) {
460 	    case '!':
461 		if (c1 == '=')
462 		    return (OP_NE);
463 		break;
464 
465 	    case '=':
466 		if (c1 != '=') {		/* Can't say a=b in #if	*/
467 		    unget();
468 		    cerror("= not allowed in #if", NULLST);
469 		    return (OP_FAIL);
470 		}
471 		return (OP_EQ);
472 
473 	    case '>':
474 	    case '<':
475 		if (c1 == c)
476 		    return ((c == '<') ? OP_ASL : OP_ASR);
477 		else if (c1 == '=')
478 		    return ((c == '<') ? OP_LE  : OP_GE);
479 		break;
480 
481 	    case '|':
482 	    case '&':
483 		if (c1 == c)
484 		    return ((c == '|') ? OP_ORO : OP_ANA);
485 		break;
486 
487 	    case '\\':
488 		if (c1 == '\n')			/* Multi-line if	*/
489 		    goto again;
490 		cerror("Unexpected \\ in #if", NULLST);
491 		return (OP_FAIL);
492 	    }
493 	    unget();
494 	}
495 	return (t);
496 }
497 
498 FILE_LOCAL int
dosizeof()499 dosizeof()
500 /*
501  * Process the sizeof (basic type) operation in an #if string.
502  * Sets evalue to the size and returns
503  *	DIG		success
504  *	OP_FAIL		bad parse or something.
505  */
506 {
507 	register int	c;
508 	register TYPES	*tp;
509 	register SIZES	*sizp;
510 	register short	*testp;
511 	short		typecode;
512 
513 	if ((c = skipws()) != '(')
514 	    goto nogood;
515 	/*
516 	 * Scan off the tokens.
517 	 */
518 	typecode = 0;
519 	while (0 != (c = skipws())) {
520 	    if ((c = macroid(c)) == EOF_CHAR || c == '\n')
521 		goto nogood;			/* End of line is a bug	*/
522 	    else if (c == '(') {		/* thing (*)() func ptr	*/
523 		if (skipws() == '*'
524 		 && skipws() == ')') {		/* We found (*)		*/
525 		    if (skipws() != '(')	/* Let () be optional	*/
526 			unget();
527 		    else if (skipws() != ')')
528 			goto nogood;
529 		    typecode |= T_FPTR;		/* Function pointer	*/
530 		}
531 		else {				/* Junk is a bug	*/
532 		    goto nogood;
533 		}
534 	    }
535 	    else if (type[c] != LET)		/* Exit if not a type	*/
536 		break;
537 	    else if (!catenate()) {		/* Maybe combine tokens	*/
538 		/*
539 		 * Look for this unexpandable token in basic_types.
540 		 * The code accepts "int long" as well as "long int"
541 		 * which is a minor bug as bugs go (and one shared with
542 		 * a lot of C compilers).
543 		 */
544 		for (tp = basic_types; tp->name != NULLST; tp++) {
545 		    if (streq(token, tp->name))
546 			break;
547 		}
548 		if (tp->name == NULLST) {
549 		    cerror("#if sizeof, unknown type \"%s\"", token);
550 		    return (OP_FAIL);
551 		}
552 		typecode |= tp->type;		/* Or in the type bit	*/
553 	    }
554 	}
555 	/*
556 	 * We are at the end of the type scan.  Chew off '*' if necessary.
557 	 */
558 	if (c == '*') {
559 	    typecode |= T_PTR;
560 	    c = skipws();
561 	}
562 	if (c == ')') {				/* Last syntax check	*/
563 	    for (testp = test_table; *testp != 0; testp++) {
564 		if (!bittest(typecode & *testp)) {
565 		    cerror("#if ... sizeof: illegal type combination", NULLST);
566 		    return (OP_FAIL);
567 		}
568 	    }
569 	    /*
570 	     * We assume that all function pointers are the same size:
571 	     *		sizeof (int (*)()) == sizeof (float (*)())
572 	     * We assume that signed and unsigned don't change the size:
573 	     *		sizeof (signed int) == (sizeof unsigned int)
574 	     */
575 	    if ((typecode & T_FPTR) != 0)	/* Function pointer	*/
576 		typecode = T_FPTR | T_PTR;
577 	    else {				/* Var or var * datum	*/
578 		typecode &= ~(T_SIGNED | T_UNSIGNED);
579 		if ((typecode & (T_SHORT | T_LONG)) != 0)
580 		    typecode &= ~T_INT;
581 	    }
582 	    if ((typecode & ~T_PTR) == 0) {
583 		cerror("#if sizeof() error, no type specified", NULLST);
584 		return (OP_FAIL);
585 	    }
586 	    /*
587 	     * Exactly one bit (and possibly T_PTR) may be set.
588 	     */
589 	    for (sizp = size_table; sizp->bits != 0; sizp++) {
590 		if ((typecode & ~T_PTR) == sizp->bits) {
591 		    evalue = ((typecode & T_PTR) != 0)
592 			? sizp->psize : sizp->size;
593 		    return (DIG);
594 		}
595 	    }					/* We shouldn't fail	*/
596 	    cierror("#if ... sizeof: bug, unknown type code 0x%x", typecode);
597 	    return (OP_FAIL);
598 	}
599 
600 nogood:	unget();
601 	cerror("#if ... sizeof() syntax error", NULLST);
602 	return (OP_FAIL);
603 }
604 
605 FILE_LOCAL int
bittest(int value)606 bittest(int value)
607 /*
608  * TRUE if value is zero or exactly one bit is set in value.
609  */
610 {
611 #if (4096 & ~(-4096)) == 0
612 	return ((value & ~(-value)) == 0);
613 #else
614 	/*
615 	 * Do it the hard way (for non 2's complement machines)
616 	 */
617 	return (value == 0 || value ^ (value - 1) == (value * 2 - 1));
618 #endif
619 }
620 
621 FILE_LOCAL int
evalnum(int c)622 evalnum(int c)
623 /*
624  * Expand number for #if lexical analysis.  Note: evalnum recognizes
625  * the unsigned suffix, but only returns a signed int value.
626  */
627 {
628 	register int	value;
629 	register int	base;
630 	register int	c1;
631 
632 	if (c != '0')
633 	    base = 10;
634 	else if ((c = cget()) == 'x' || c == 'X') {
635 		base = 16;
636 		c = cget();
637 	}
638 	else base = 8;
639 	value = 0;
640 	for (;;) {
641 	    c1 = c;
642 	    if (isascii(c) && isupper(c1))
643 		c1 = tolower(c1);
644 #ifdef EBCDIC
645 	    if (c1 <= 'f')
646 #else
647 	    if (c1 >= 'a')
648 #endif
649 		c1 -= ('a' - 10);
650 	    else c1 -= '0';
651 	    if (c1 < 0 || c1 >= base)
652 		break;
653 	    value *= base;
654 	    value += c1;
655 	    c = cget();
656 	}
657 	if (c == 'u' || c == 'U')	/* Unsigned nonsense		*/
658 	    c = cget();
659 	unget();
660 	return (value);
661 }
662 
663 FILE_LOCAL int
evalchar(int skip)664 evalchar(int skip)
665 /*
666  * Get a character constant
667  */
668 {
669 	register int	c;
670 	register int	value;
671 	register int	count;
672 
673 	instring = TRUE;
674 	if ((c = cget()) == '\\') {
675 	    switch ((c = cget())) {
676 	    case 'a':				/* New in Standard	*/
677 #if ('a' == '\a' || '\a' == ALERT)
678 		value = ALERT;			/* Use predefined value	*/
679 #else
680 		value = '\a';			/* Use compiler's value	*/
681 #endif
682 		break;
683 
684 	    case 'b':
685 		value = '\b';
686 		break;
687 
688 	    case 'f':
689 		value = '\f';
690 		break;
691 
692 	    case 'n':
693 		value = '\n';
694 		break;
695 
696 	    case 'r':
697 		value = '\r';
698 		break;
699 
700 	    case 't':
701 		value = '\t';
702 		break;
703 
704 	    case 'v':				/* New in Standard	*/
705 #if ('v' == '\v' || '\v' == VT)
706 		value = VT;			/* Use predefined value	*/
707 #else
708 		value = '\v';			/* Use compiler's value	*/
709 #endif
710 		break;
711 
712 	    case 'x':				/* '\xFF'		*/
713 		count = 3;
714 		value = 0;
715 		while ((((c = get()) >= '0' && c <= '9')
716 		     || (c >= 'a' && c <= 'f')
717 		     || (c >= 'A' && c <= 'F'))
718 		    && (--count >= 0)) {
719 			value *= 16;
720 #ifdef EBCDIC
721 			value += (c <= '9') ? (c - '0') : ((c & 0xF) + 9);
722 #else
723 			value += (c >= '0') ? (c - '0') : ((c & 0xF) + 9);
724 #endif
725 		}
726 		unget();
727 		break;
728 
729 	    default:
730 		if (c >= '0' && c <= '7') {
731 		    count = 3;
732 		    value = 0;
733 		    while (c >= '0' && c <= '7' && --count >= 0) {
734 			value *= 8;
735 			value += (c - '0');
736 			c = get();
737 		    }
738 		    unget();
739 		}
740 		else value = c;
741 		break;
742 	    }
743 	}
744 	else if (c == '\'')
745 	    value = 0;
746 	else value = c;
747 	/*
748 	 * We warn on multi-byte constants and try to hack
749 	 * (big|little)endian machines.
750 	 */
751 #if BIG_ENDIAN
752 	count = 0;
753 #endif
754 	while ((c = get()) != '\'' && c != EOF_CHAR && c != '\n') {
755 	    if (!skip)
756 		ciwarn("multi-byte constant '%c' isn't portable", c);
757 #if BIG_ENDIAN
758 	    count += BITS_CHAR;
759 	    value += (c << count);
760 #else
761 	    value <<= BITS_CHAR;
762 	    value += c;
763 #endif
764 	}
765 	instring = FALSE;
766 	return (value);
767 }
768 
769 FILE_LOCAL int *
evaleval(int * valp,int op,int skip)770 evaleval(int* valp, int op, int skip)
771 /*
772  * Apply the argument operator to the data on the value stack.
773  * One or two values are popped from the value stack and the result
774  * is pushed onto the value stack.
775  *
776  * OP_COL is a special case.
777  *
778  * evaleval() returns the new pointer to the top of the value stack.
779  */
780 {
781 	register int	v1, v2 = 0;
782 
783 	if (isbinary(op))
784 	    v2 = *--valp;
785 	v1 = *--valp;
786 #ifdef	DEBUG_EVAL
787     fprintf( pCppOut, "%s op %s", (isbinary(op)) ? "binary" : "unary",
788 	    opname[op]);
789 	if (isbinary(op))
790         fprintf( pCppOut, ", v2 = %d.", v2);
791     fprintf( pCppOut, ", v1 = %d.\n", v1);
792 #endif
793 	switch (op) {
794 	case OP_EOE:
795 	     break;
796 
797 	case OP_ADD:
798 	    v1 += v2;
799 	    break;
800 
801 	case OP_SUB:
802 	    v1 -= v2;
803 	    break;
804 
805 	case OP_MUL:
806 	    v1 *= v2;
807 	    break;
808 
809 	case OP_DIV:
810 	case OP_MOD:
811 	    if (v2 == 0) {
812 		if (!skip) {
813 		    cwarn("%s by zero in #if, zero result assumed",
814 			(op == OP_DIV) ? "divide" : "mod");
815 		}
816 		v1 = 0;
817 	    }
818 	    else if (op == OP_DIV)
819 		v1 /= v2;
820 	    else
821 		v1 %= v2;
822 	    break;
823 
824 	case OP_ASL:
825 	    v1 <<= v2;
826 	    break;
827 
828 	case OP_ASR:
829 	    v1 >>= v2;
830 	    break;
831 
832 	case OP_AND:
833 	    v1 &= v2;
834 	    break;
835 
836 	case OP_OR:
837 	    v1 |= v2;
838 	    break;
839 
840 	case OP_XOR:
841 	    v1 ^= v2;
842 	    break;
843 
844 	case OP_EQ:
845 	    v1 = (v1 == v2);
846 	    break;
847 
848 	case OP_NE:
849 	    v1 = (v1 != v2);
850 	    break;
851 
852 	case OP_LT:
853 	    v1 = (v1 < v2);
854 	    break;
855 
856 	case OP_LE:
857 	    v1 = (v1 <= v2);
858 	    break;
859 
860 	case OP_GE:
861 	    v1 = (v1 >= v2);
862 	    break;
863 
864 	case OP_GT:
865 	    v1 = (v1 > v2);
866 	    break;
867 
868 	case OP_ANA:
869 	    v1 = (v1 && v2);
870 	    break;
871 
872 	case OP_ORO:
873 	    v1 = (v1 || v2);
874 	    break;
875 
876 	case OP_COL:
877 	    /*
878 	     * v1 has the "true" value, v2 the "false" value.
879 	     * The top of the value stack has the test.
880 	     */
881 	    v1 = (*--valp) ? v1 : v2;
882 	    break;
883 
884 	case OP_NEG:
885 	    v1 = (-v1);
886 	    break;
887 
888 	case OP_PLU:
889 	    break;
890 
891 	case OP_COM:
892 	    v1 = ~v1;
893 	    break;
894 
895 	case OP_NOT:
896 	    v1 = !v1;
897 	    break;
898 
899 	default:
900 	    cierror("#if bug, operand = %d.", op);
901 	    v1 = 0;
902 	}
903 	*valp++ = v1;
904 	return (valp);
905 }
906 
907 #ifdef	DEBUG_EVAL
dumpstack(opstack,opp,value,valp)908 dumpstack(opstack, opp, value, valp)
909 OPTAB		opstack[NEXP];	/* Operand stack		*/
910 register OPTAB	*opp;		/* Operator stack		*/
911 int		value[NEXP];	/* Value stack			*/
912 register int	*valp;		/* -> value vector		*/
913 {
914     fprintf( pCppOut, "index op prec skip name -- op stack at %s", infile->bptr);
915 	while (opp > opstack) {
916         fprintf( pCppOut, " [%2d] %2d  %03o    %d %s\n", opp - opstack,
917 		opp->op, opp->prec, opp->skip, opname[opp->op]);
918 	    opp--;
919 	}
920 	while (--valp >= value) {
921         fprintf( pCppOut, "value[%d] = %d\n", (valp - value), *valp);
922 	}
923 }
924 #endif
925 
926