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