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