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