1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
26 * Evaluate an #if expression.
29 static char *opname
[] = { /* For debug and error messages */
30 "end of expression", "val", "id",
31 "+", "-", "*", "/", "%",
32 "<<", ">>", "&", "|", "^",
33 "==", "!=", "<", "<=", ">=", ">",
34 "&&", "||", "?", ":", ",",
35 "unary +", "unary -", "~", "!", "(", ")", "(none)",
39 * opdope[] has the operator precedence:
41 * 7 Unused (so the value is always positive)
42 * 6-2 Precedence (000x .. 017x)
43 * 1-0 Binary op. flags:
44 * 01 The binop flag should be set/cleared when this op is seen.
45 * 10 The new value of the binop flag.
46 * Note: Expected, New binop
47 * constant 0 1 Binop, end, or ) should follow constants
48 * End of line 1 0 End may not be preceeded by an operator
49 * binary 1 0 Binary op follows a value, value follows.
50 * unary 0 0 Unary op doesn't follow a value, value follows
51 * ( 0 0 Doesn't follow value, value or unop follows
52 * ) 1 1 Follows value. Op follows.
55 static char opdope
[OP_MAX
] = {
56 0001, /* End of expression */
58 0000, /* Letter (identifier) */
59 0141, 0141, 0151, 0151, 0151, /* ADD, SUB, MUL, DIV, MOD */
60 0131, 0131, 0101, 0071, 0071, /* ASL, ASR, AND, OR, XOR */
61 0111, 0111, 0121, 0121, 0121, 0121, /* EQ, NE, LT, LE, GE, GT */
62 0061, 0051, 0041, 0041, 0031, /* ANA, ORO, QUE, COL, CMA */
66 0160, 0160, 0160, 0160, /* NEG, PLU, COM, NOT */
67 0170, 0013, 0023, /* LPA, RPA, END */
70 * OP_QUE and OP_RPA have alternate precedences:
72 #define OP_RPA_PREC 0013
73 #define OP_QUE_PREC 0034
76 * S_ANDOR and S_QUEST signal "short-circuit" boolean evaluation, so that
77 * #if FOO != 0 && 10 / FOO ...
78 * doesn't generate an error message. They are stored in optab.skip.
83 typedef struct optab
{
84 char op
; /* Operator */
85 char prec
; /* Its precedence */
86 char skip
; /* Short-circuit: TRUE to skip */
88 static int evalue
; /* Current value from evallex() */
95 return (op
>= FIRST_BINOP
&& op
<= LAST_BINOP
);
98 #define isbinary(op) (op >= FIRST_BINOP && op <= LAST_BINOP)
102 * The following definitions are used to specify basic variable sizes.
106 #define S_CHAR (sizeof (char))
109 #define S_SINT (sizeof (short int))
112 #define S_INT (sizeof (int))
115 #define S_LINT (sizeof (long int))
118 #define S_FLOAT (sizeof (float))
121 #define S_DOUBLE (sizeof (double))
124 #define S_PCHAR (sizeof (char *))
127 #define S_PSINT (sizeof (short int *))
130 #define S_PINT (sizeof (int *))
133 #define S_PLINT (sizeof (long int *))
136 #define S_PFLOAT (sizeof (float *))
139 #define S_PDOUBLE (sizeof (double *))
142 #define S_PFPTR (sizeof (int (*)()))
145 typedef struct types
{
146 short type
; /* This is the bit if */
147 char *name
; /* this is the token word */
150 static TYPES basic_types
[] = {
153 { T_FLOAT
, "float", },
154 { T_DOUBLE
, "double", },
155 { T_SHORT
, "short", },
157 { T_SIGNED
, "signed", },
158 { T_UNSIGNED
, "unsigned", },
159 { 0, NULL
, }, /* Signal end */
163 * Test_table[] is used to test for illegal combinations.
165 static short test_table
[] = {
166 T_FLOAT
| T_DOUBLE
| T_LONG
| T_SHORT
,
167 T_FLOAT
| T_DOUBLE
| T_CHAR
| T_INT
,
168 T_FLOAT
| T_DOUBLE
| T_SIGNED
| T_UNSIGNED
,
169 T_LONG
| T_SHORT
| T_CHAR
,
174 * The order of this table is important -- it is also referenced by
175 * the command line processor to allow run-time overriding of the
176 * built-in size values. The order must not be changed:
177 * char, short, int, long, float, double (func pointer)
179 SIZES size_table
[] = {
180 { T_CHAR
, S_CHAR
, S_PCHAR
}, /* char */
181 { T_SHORT
, S_SINT
, S_PSINT
}, /* short int */
182 { T_INT
, S_INT
, S_PINT
}, /* int */
183 { T_LONG
, S_LINT
, S_PLINT
}, /* long */
184 { T_FLOAT
, S_FLOAT
, S_PFLOAT
}, /* float */
185 { T_DOUBLE
, S_DOUBLE
, S_PDOUBLE
}, /* double */
186 { T_FPTR
, 0, S_PFPTR
}, /* int (*()) */
187 { 0, 0, 0 }, /* End of table */
200 * Evaluate an expression. Straight-forward operator precedence.
201 * This is called from control() on encountering an #if statement.
202 * It calls the following routines:
203 * evallex Lexical analyser -- returns the type and value of
204 * the next input token.
205 * evaleval Evaluate the current operator, given the values on
206 * the value stack. Returns a pointer to the (new)
208 * For compatiblity with older cpp's, this return returns 1 (TRUE)
209 * if a syntax error is detected.
212 register int op
; /* Current operator */
213 register int *valp
; /* -> value vector */
214 register OPTAB
*opp
; /* Operator stack */
215 int prec
; /* Op precedence */
216 int binop
; /* Set if binary op. needed */
217 int op1
; /* Operand from stack */
218 int skip
; /* For short-circuit testing */
219 int value
[NEXP
]; /* Value stack */
220 OPTAB opstack
[NEXP
]; /* Operand stack */
221 extern int *evaleval(); /* Does actual evaluation */
224 opp
->op
= OP_END
; /* Mark bottom of stack */
225 opp
->prec
= opdope
[OP_END
]; /* And its precedence */
226 opp
->skip
= 0; /* Not skipping now */
230 fprintf( pCppOut
, "In #if at again: skip = %d, binop = %d, line is: %s",
231 opp
->skip
, binop
, infile
->bptr
);
233 if ((op
= evallex(opp
->skip
)) == OP_SUB
&& binop
== 0)
234 op
= OP_NEG
; /* Unary minus */
235 else if (op
== OP_ADD
&& binop
== 0)
236 op
= OP_PLU
; /* Unary plus */
237 else if (op
== OP_FAIL
)
238 return (1); /* Error in evallex */
240 fprintf( pCppOut
, "op = %s, opdope = %03o, binop = %d, skip = %d\n",
241 opname
[op
], opdope
[op
], binop
, opp
->skip
);
243 if (op
== DIG
) { /* Value? */
245 cerror("misplaced constant in #if", NULLST
);
248 else if (valp
>= &value
[NEXP
-1]) {
249 cerror("#if value stack overflow", NULLST
);
254 fprintf( pCppOut
, "pushing %d onto value stack[%d]\n",
255 evalue
, valp
- value
);
262 else if (op
> OP_END
) {
263 cerror("Illegal #if line", NULLST
);
267 if (binop
!= (prec
& 1)) {
268 cerror("Operator %s in incorrect context", opname
[op
]);
271 binop
= (prec
& 2) >> 1;
274 fprintf( pCppOut
, "op %s, prec %d., stacked op %s, prec %d, skip %d\n",
275 opname
[op
], prec
, opname
[opp
->op
], opp
->prec
, opp
->skip
);
277 if (prec
> opp
->prec
) {
280 else if (op
== OP_QUE
)
282 op1
= opp
->skip
; /* Save skip for test */
284 * Push operator onto op. stack.
287 if (opp
>= &opstack
[NEXP
]) {
288 cerror("expression stack overflow at op \"%s\"",
293 opp
->prec
= (char)prec
;
294 skip
= (valp
[-1] != 0); /* Short-circuit tester */
296 * Do the short-circuit stuff here. Short-circuiting
297 * stops automagically when operators are evaluated.
299 if ((op
== OP_ANA
&& !skip
)
300 || (op
== OP_ORO
&& skip
))
301 opp
->skip
= S_ANDOR
; /* And/or skip starts */
302 else if (op
== OP_QUE
) /* Start of ?: operator */
303 opp
->skip
= (char)((op1
& S_ANDOR
) | ((!skip
) ? S_QUEST
: 0));
304 else if (op
== OP_COL
) { /* : inverts S_QUEST */
305 opp
->skip
= (char)((op1
& S_ANDOR
)
306 | (((op1
& S_QUEST
) != 0) ? 0 : S_QUEST
));
308 else { /* Other ops leave */
309 opp
->skip
= (char)op1
; /* skipping unchanged. */
312 fprintf( pCppOut
, "stacking %s, valp[-1] == %d at %s",
313 opname
[op
], valp
[-1], infile
->bptr
);
314 dumpstack(opstack
, opp
, value
, valp
);
319 * Pop operator from op. stack and evaluate it.
320 * End of stack and '(' are specials.
322 skip
= opp
->skip
; /* Remember skip value */
323 switch ((op1
= opp
->op
)) { /* Look at stacked op */
324 case OP_END
: /* Stack end marker */
326 return (valp
[-1]); /* Finished ok. */
327 goto again
; /* Read another op. */
329 case OP_LPA
: /* ( on stack */
330 if (op
!= OP_RPA
) { /* Matches ) on input */
331 cerror("unbalanced paren's, op is \"%s\"", opname
[op
]);
334 opp
--; /* Unstack it */
335 /* goto again; -- Fall through */
338 goto again
; /* Evaluate true expr. */
340 case OP_COL
: /* : on stack. */
341 opp
--; /* Unstack : */
342 if (opp
->op
!= OP_QUE
) { /* Matches ? on stack? */
343 cerror("Misplaced '?' or ':', previous operator is %s",
344 opname
[(int)opp
->op
]);
350 default: /* Others: */
351 opp
--; /* Unstack the operator */
353 fprintf( pCppOut
, "Stack before evaluation of %s\n", opname
[op1
]);
354 dumpstack(opstack
, opp
, value
, valp
);
356 valp
= evaleval(valp
, op1
, skip
);
358 fprintf( pCppOut
, "Stack after evaluation\n");
359 dumpstack(opstack
, opp
, value
, valp
);
361 } /* op1 switch end */
362 } /* Stack unwind loop */
368 * Return next eval operator or value. Called from eval(). It
369 * calls a special-purpose routines for 'char' strings and
371 * evalchar called to evaluate 'x'
372 * evalnum called to evaluate numbers.
375 register int c
, c1
, t
;
377 again
: do { /* Collect the token */
379 if ((c
= macroid(c
)) == EOF_CHAR
|| c
== '\n') {
381 return (OP_EOE
); /* End of expression */
383 } while ((t
= type
[c
]) == LET
&& catenate());
384 if (t
== INV
) { /* Total nonsense */
386 if (isascii(c
) && isprint(c
))
387 cierror("illegal character '%c' in #if", c
);
389 cierror("illegal character (%d decimal) in #if", c
);
393 else if (t
== QUO
) { /* ' or " */
394 if (c
== '\'') { /* Character constant */
395 evalue
= evalchar(skip
); /* Somewhat messy */
397 fprintf( pCppOut
, "evalchar returns %d.\n", evalue
);
399 return (DIG
); /* Return a value */
401 cerror("Can't use a string in an #if", NULLST
);
404 else if (t
== LET
) { /* ID must be a macro */
405 if (streq(token
, "defined")) { /* Or defined name */
407 if (c
== '(') /* Allow defined(name) */
409 if (type
[c
] == LET
) {
410 evalue
= (lookid(c
) != NULL
);
411 if (c1
!= '(' /* Need to balance */
412 || skipws() == ')') /* Did we balance? */
413 return (DIG
); /* Parsed ok */
415 cerror("Bad #if ... defined() syntax", NULLST
);
418 else if (streq(token
, "sizeof")) /* New sizeof hackery */
419 return (dosizeof()); /* Gets own routine */
421 * The Draft ANSI C Standard says that an undefined symbol
422 * in an #if has the value zero. We are a bit pickier,
423 * warning except where the programmer was careful to write
424 * #if defined(foo) ? foo : 0
428 cwarn("undefined symbol \"%s\" in #if, 0 used", token
);
433 else if (t
== DIG
) { /* Numbers are harder */
436 fprintf( pCppOut
, "evalnum returns %d.\n", evalue
);
439 else if (strchr("!=<>&|\\", c
) != NULL
) {
441 * Process a possible multi-byte lexeme.
443 c1
= cget(); /* Peek at next char */
451 if (c1
!= '=') { /* Can't say a=b in #if */
453 cerror("= not allowed in #if", NULLST
);
461 return ((c
== '<') ? OP_ASL
: OP_ASR
);
463 return ((c
== '<') ? OP_LE
: OP_GE
);
469 return ((c
== '|') ? OP_ORO
: OP_ANA
);
473 if (c1
== '\n') /* Multi-line if */
475 cerror("Unexpected \\ in #if", NULLST
);
486 * Process the sizeof (basic type) operation in an #if string.
487 * Sets evalue to the size and returns
489 * OP_FAIL bad parse or something.
494 register SIZES
*sizp
;
495 register short *testp
;
498 if ((c
= skipws()) != '(')
501 * Scan off the tokens.
504 while (0 != (c
= skipws())) {
505 if ((c
= macroid(c
)) == EOF_CHAR
|| c
== '\n')
506 goto nogood
; /* End of line is a bug */
507 else if (c
== '(') { /* thing (*)() func ptr */
509 && skipws() == ')') { /* We found (*) */
510 if (skipws() != '(') /* Let () be optional */
512 else if (skipws() != ')')
514 typecode
|= T_FPTR
; /* Function pointer */
516 else { /* Junk is a bug */
520 else if (type
[c
] != LET
) /* Exit if not a type */
522 else if (!catenate()) { /* Maybe combine tokens */
524 * Look for this unexpandable token in basic_types.
525 * The code accepts "int long" as well as "long int"
526 * which is a minor bug as bugs go (and one shared with
527 * a lot of C compilers).
529 for (tp
= basic_types
; tp
->name
!= NULLST
; tp
++) {
530 if (streq(token
, tp
->name
))
533 if (tp
->name
== NULLST
) {
534 cerror("#if sizeof, unknown type \"%s\"", token
);
537 typecode
|= tp
->type
; /* Or in the type bit */
541 * We are at the end of the type scan. Chew off '*' if necessary.
547 if (c
== ')') { /* Last syntax check */
548 for (testp
= test_table
; *testp
!= 0; testp
++) {
549 if (!bittest(typecode
& *testp
)) {
550 cerror("#if ... sizeof: illegal type combination", NULLST
);
555 * We assume that all function pointers are the same size:
556 * sizeof (int (*)()) == sizeof (float (*)())
557 * We assume that signed and unsigned don't change the size:
558 * sizeof (signed int) == (sizeof unsigned int)
560 if ((typecode
& T_FPTR
) != 0) /* Function pointer */
561 typecode
= T_FPTR
| T_PTR
;
562 else { /* Var or var * datum */
563 typecode
&= ~(T_SIGNED
| T_UNSIGNED
);
564 if ((typecode
& (T_SHORT
| T_LONG
)) != 0)
567 if ((typecode
& ~T_PTR
) == 0) {
568 cerror("#if sizeof() error, no type specified", NULLST
);
572 * Exactly one bit (and possibly T_PTR) may be set.
574 for (sizp
= size_table
; sizp
->bits
!= 0; sizp
++) {
575 if ((typecode
& ~T_PTR
) == sizp
->bits
) {
576 evalue
= ((typecode
& T_PTR
) != 0)
577 ? sizp
->psize
: sizp
->size
;
580 } /* We shouldn't fail */
581 cierror("#if ... sizeof: bug, unknown type code 0x%x", typecode
);
586 cerror("#if ... sizeof() syntax error", NULLST
);
593 * TRUE if value is zero or exactly one bit is set in value.
596 #if (4096 & ~(-4096)) == 0
597 return ((value
& ~(-value
)) == 0);
600 * Do it the hard way (for non 2's complement machines)
602 return (value
== 0 || value
^ (value
- 1) == (value
* 2 - 1));
609 * Expand number for #if lexical analysis. Note: evalnum recognizes
610 * the unsigned suffix, but only returns a signed int value.
619 else if ((c
= cget()) == 'x' || c
== 'X') {
627 if (isascii(c
) && isupper(c1
))
636 if (c1
< 0 || c1
>= base
)
642 if (c
== 'u' || c
== 'U') /* Unsigned nonsense */
651 * Get a character constant
659 if ((c
= cget()) == '\\') {
660 switch ((c
= cget())) {
661 case 'a': /* New in Standard */
662 #if ('a' == '\a' || '\a' == ALERT)
663 value
= ALERT
; /* Use predefined value */
665 value
= '\a'; /* Use compiler's value */
689 case 'v': /* New in Standard */
690 #if ('v' == '\v' || '\v' == VT)
691 value
= VT
; /* Use predefined value */
693 value
= '\v'; /* Use compiler's value */
697 case 'x': /* '\xFF' */
700 while ((((c
= get()) >= '0' && c
<= '9')
701 || (c
>= 'a' && c
<= 'f')
702 || (c
>= 'A' && c
<= 'F'))
706 value
+= (c
<= '9') ? (c
- '0') : ((c
& 0xF) + 9);
708 value
+= (c
>= '0') ? (c
- '0') : ((c
& 0xF) + 9);
715 if (c
>= '0' && c
<= '7') {
718 while (c
>= '0' && c
<= '7' && --count
>= 0) {
733 * We warn on multi-byte constants and try to hack
734 * (big|little)endian machines.
736 while ((c
= get()) != '\'' && c
!= EOF_CHAR
&& c
!= '\n') {
738 ciwarn("multi-byte constant '%c' isn't portable", c
);
747 evaleval(int* valp
, int op
, int skip
)
749 * Apply the argument operator to the data on the value stack.
750 * One or two values are popped from the value stack and the result
751 * is pushed onto the value stack.
753 * OP_COL is a special case.
755 * evaleval() returns the new pointer to the top of the value stack.
758 register int v1
, v2
= 0;
764 fprintf( pCppOut
, "%s op %s", (isbinary(op
)) ? "binary" : "unary",
767 fprintf( pCppOut
, ", v2 = %d.", v2
);
768 fprintf( pCppOut
, ", v1 = %d.\n", v1
);
790 cwarn("%s by zero in #if, zero result assumed",
791 (op
== OP_DIV
) ? "divide" : "mod");
795 else if (op
== OP_DIV
)
855 * v1 has the "true" value, v2 the "false" value.
856 * The top of the value stack has the test.
858 v1
= (*--valp
) ? v1
: v2
;
877 cierror("#if bug, operand = %d.", op
);
885 dumpstack(opstack
, opp
, value
, valp
)
886 OPTAB opstack
[NEXP
]; /* Operand stack */
887 register OPTAB
*opp
; /* Operator stack */
888 int value
[NEXP
]; /* Value stack */
889 register int *valp
; /* -> value vector */
891 fprintf( pCppOut
, "index op prec skip name -- op stack at %s", infile
->bptr
);
892 while (opp
> opstack
) {
893 fprintf( pCppOut
, " [%2d] %2d %03o %d %s\n", opp
- opstack
,
894 opp
->op
, opp
->prec
, opp
->skip
, opname
[opp
->op
]);
897 while (--valp
>= value
) {
898 fprintf( pCppOut
, "value[%d] = %d\n", (valp
- value
), *valp
);
903 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */