/* * (c) Thomas Pornin 1999, 2000 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. The name of the authors may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include <stdio.h>#include <string.h>#include <setjmp.h>#include <limits.h>#include "ucppi.h"#include "tune.h"#include "mem.h" JMP_BUF eval_exception;long eval_line;static int emit_eval_warnings; /* * If you want to hardcode a conversion table, define a static array * of 256 int, and make transient_characters point to it. */int *transient_characters = 0; #define OCTAL(x) ((x) >= '0' && (x) <= '7')#define DECIM(x) ((x) >= '0' && (x) <= '9')#define HEXAD(x) (((x) >= '0' && (x) <= '9') \ || (x) == 'a' || (x) == 'b' || (x) == 'c' \ || (x) == 'd' || (x) == 'e' || (x) == 'f' \ || (x) == 'A' || (x) == 'B' || (x) == 'C' \ || (x) == 'D' || (x) == 'E' || (x) == 'F')#define OVAL(x) ((int)((x) - '0'))#define DVAL(x) ((int)((x) - '0'))#define HVAL(x) (DECIM(x) ? DVAL(x) \ : (x) == 'a' || (x) == 'A' ? 10 \ : (x) == 'b' || (x) == 'B' ? 11 \ : (x) == 'c' || (x) == 'C' ? 12 \ : (x) == 'd' || (x) == 'D' ? 13 \ : (x) == 'e' || (x) == 'E' ? 14 : 15) #if !defined(NATIVE_UINTMAX) && !defined(SIMUL_UINTMAX)# if __STDC__ && __STDC_VERSION__ >= 199901L# include <stdint.h># define NATIVE_UINTMAX uintmax_t# define NATIVE_INTMAX intmax_t# else# define NATIVE_UINTMAX unsigned long# define NATIVE_INTMAX long# endif#endif #ifdef NATIVE_UINTMAX typedef NATIVE_UINTMAX ucppulong;typedef NATIVE_INTMAX ucppslong; #define to_ulong(x) ((ucppulong)(x))#define to_slong(x) ((ucppslong)(x)) #define op_star_u(x, y) ((x) * (y)) static inline ucppulong op_slash_u(ucppulong x, ucppulong y){ if (y == 0) { error(eval_line, "division by 0"); throw(eval_exception); } return x / y;} static inline ucppulong op_pct_u(ucppulong x, ucppulong y){ if (y == 0) { error(eval_line, "division by 0"); throw(eval_exception); } return x % y;} #define op_plus_u(x, y) ((x) + (y))#define op_minus_u(x, y) ((x) - (y))#define op_neg_u(x) (-(x))#define op_lsh_u(x, y) ((x) << (y))#define op_rsh_u(x, y) ((x) >> (y))#define op_lt_u(x, y) ((x) < (y))#define op_leq_u(x, y) ((x) <= (y))#define op_gt_u(x, y) ((x) > (y))#define op_geq_u(x, y) ((x) >= (y))#define op_same_u(x, y) ((x) == (y))#define op_neq_u(x, y) ((x) != (y))#define op_and_u(x, y) ((x) & (y))#define op_circ_u(x, y) ((x) ^ (y))#define op_or_u(x, y) ((x) | (y))#define op_lval_u(x) ((x) != 0)#define op_lnot_u(x) (!(x))#define op_not_u(x) (~(x))#define op_uplus_u(x) (x)#define op_uminus_u(x) op_neg_u(x) #define op_star_s(x, y) ((x) * (y)) static inline ucppslong op_slash_s(ucppslong x, ucppslong y){ if (y == 0) { error(eval_line, "division by 0"); throw(eval_exception); } return x / y;} static inline ucppslong op_pct_s(ucppslong x, ucppslong y){ if (y == 0) { error(eval_line, "division by 0"); throw(eval_exception); } return x % y;} #define op_plus_s(x, y) ((x) + (y))#define op_minus_s(x, y) ((x) - (y))#define op_neg_s(x) (-(x))#define op_lsh_s(x, y) ((x) << (y))#define op_rsh_s(x, y) ((x) >> (y))#define op_lt_s(x, y) ((x) < (y))#define op_leq_s(x, y) ((x) <= (y))#define op_gt_s(x, y) ((x) > (y))#define op_geq_s(x, y) ((x) >= (y))#define op_same_s(x, y) ((x) == (y))#define op_neq_s(x, y) ((x) != (y))#define op_and_s(x, y) ((x) & (y))#define op_circ_s(x, y) ((x) ^ (y))#define op_or_s(x, y) ((x) | (y))#define op_lval_s(x) ((x) != 0)#define op_lnot_s(x) (!(x))#define op_not_s(x) (~(x))#define op_uplus_s(x) (x)#define op_uminus_s(x) op_neg_s(x) #define op_promo(x) ((ucppulong)x)#define back_ulong(x) ((unsigned long)x) #else /* * We suppose that the unsigned long is not padded in its memory * representation, and that it has an even binary length. * * We could explore the size of ULONG_MAX with some dichotomic * trick using a recursive #include, but this would be really ugly. */#define LONGSIZE (CHAR_BIT * sizeof(unsigned long))#define HALFLONGSIZE (LONGSIZE / 2)#define HUL_MASK ((1UL << HALFLONGSIZE) - 1)#define UL_MS(x) (((x) >> HALFLONGSIZE) & HUL_MASK)#define UL_LS(x) ((x) & HUL_MASK)#define SIGNBIT(x) ((x) & (1UL << (LONGSIZE - 1))) typedef struct { unsigned long msw, lsw;} ucppulong; #define ucppslong ucppulong static ucppulong to_ulong(unsigned long x){ ucppulong y; y.msw = 0; y.lsw = x; return y;} static ucppslong to_slong(long x){ ucppslong y; y.lsw = x; y.msw = x >= 0 ? 0 : (unsigned long)(-1); return y;} static ucppulong op_plus_u(ucppulong x, ucppulong y){ ucppulong z; z.lsw = x.lsw + y.lsw; z.msw = x.msw + y.msw; if (z.lsw < x.lsw) z.msw ++; return z;} static ucppulong op_neg_u(ucppulong x){ ucppulong z; z.lsw = ~x.lsw; z.msw = ~x.msw; if (!(++ z.lsw)) z.msw ++; return z;} #define op_minus_u(x, y) op_plus_u(x, op_neg_u(y)) static ucppulong op_lsh_u(ucppulong x, int s){ ucppulong z; s %= (2 * LONGSIZE); if (s == 0) return x; if (s >= LONGSIZE) { z.lsw = 0; z.msw = x.lsw; return op_lsh_u(z, s - LONGSIZE); } z.lsw = (x.lsw << s); z.msw = (x.msw << s) | (x.lsw >> (LONGSIZE - s)); return z;} static ucppulong op_rsh_u(ucppulong x, int s){ ucppulong z; s %= (2 * LONGSIZE); if (s == 0) return x; if (s >= LONGSIZE) { z.msw = 0; z.lsw = x.msw; return op_rsh_u(z, s - LONGSIZE); } z.lsw = (x.lsw >> s) | (x.msw << (LONGSIZE - s)); z.msw = (x.msw >> s); return z;} static int op_lt_u(ucppulong x, ucppulong y){ if (x.msw < y.msw) return 1; if (x.msw > y.msw) return 0; if (x.lsw < y.lsw) return 1; return 0;} static int op_leq_u(ucppulong x, ucppulong y){ if (x.msw < y.msw) return 1; if (x.msw > y.msw) return 0; if (x.lsw <= y.lsw) return 1; return 0;} #define op_gt_u(x, y) op_lt_u(y, x)#define op_geq_u(x, y) op_leq_u(y, x) static int op_same_u(ucppulong x, ucppulong y){ return x.msw == y.msw && x.lsw == y.lsw;} #define op_neq_u(x, y) (!op_same_u(x, y)) static ucppulong op_and_u(ucppulong x, ucppulong y){ ucppulong z; z.lsw = x.lsw & y.lsw; z.msw = x.msw & y.msw; return z;} static ucppulong op_circ_u(ucppulong x, ucppulong y){ ucppulong z; z.lsw = x.lsw ^ y.lsw; z.msw = x.msw ^ y.msw; return z;} static ucppulong op_or_u(ucppulong x, ucppulong y){ ucppulong z; z.lsw = x.lsw | y.lsw; z.msw = x.msw | y.msw; return z;} #define op_lval_u(x) op_neq_u(x, to_ulong(0))#define op_lnot_u(x) (!op_lval_u(x)) static ucppulong op_not_u(ucppulong x){ ucppulong z; z.lsw = ~x.lsw; z.msw = ~x.msw; return z;} #define op_uplus_u(x) (x)#define op_uminus_u(x) op_neg_u(x) static ucppulong umul(unsigned long x, unsigned long y){ ucppulong z; unsigned long t00, t01, t10, t11, c = 0, t; t00 = UL_LS(x) * UL_LS(y); t01 = UL_LS(x) * UL_MS(y); t10 = UL_MS(x) * UL_LS(y); t11 = UL_MS(x) * UL_MS(y); t = z.lsw = t00; if (t > (z.lsw += (UL_LS(t01) << HALFLONGSIZE))) c ++; t = z.lsw; if (t > (z.lsw += (UL_LS(t10) << HALFLONGSIZE))) c ++; z.msw = t11 + UL_MS(t10) + UL_MS(t01) + c; return z;} static ucppulong op_star_u(ucppulong x, ucppulong y){ ucppulong z1, z2; z1.lsw = z2.lsw = 0; z1.msw = x.lsw * y.msw; z2.msw = x.msw * y.lsw; return op_plus_u(umul(x.lsw, y.lsw), op_plus_u(z1, z2));} static void udiv(ucppulong x, ucppulong y, ucppulong *q, ucppulong *r){ int i, j; *q = to_ulong(0); for (i = 2 * LONGSIZE - 1; i >= 0; i --) { if (i >= LONGSIZE && (y.msw & (1UL << (i - LONGSIZE)))) break; if (i < LONGSIZE && (y.lsw & (1UL << i))) break; } if (i < 0) { error(eval_line, "division by 0"); throw(eval_exception); } for (j = 2 * LONGSIZE - 1 - i; j >= 0; j --) { ucppulong a = op_lsh_u(y, j); if (op_leq_u(a, x)) { x = op_minus_u(x, a); if (j >= LONGSIZE) q->msw |= (1UL << (j - LONGSIZE)); else q->lsw |= (1UL << j); } } *r = x;} static ucppulong op_slash_u(ucppulong x, ucppulong y){ ucppulong q, r; udiv(x, y, &q, &r); return q;} static ucppulong op_pct_u(ucppulong x, ucppulong y){ ucppulong q, r; udiv(x, y, &q, &r); return r;} static ucppslong op_star_s(ucppslong x, ucppslong y){ ucppulong a = x, b = y, c; int xn = 0, yn = 0; if (SIGNBIT(x.msw)) { a = op_neg_u(x); xn = 1; } if (SIGNBIT(y.msw)) { b = op_neg_u(y); yn = 1; } c = op_star_u(a, b); /* Turbo C seems to miscompile the ?: operators when operands are ulong/slong structures */ if (xn ^ yn) return op_neg_u(c); return c;} static void sdiv(ucppslong x, ucppslong y, ucppslong *q, ucppslong *r){ ucppulong a = x, b = y, c, d; int xn = 0, yn = 0; if (SIGNBIT(x.msw)) { a = op_neg_u(x); xn = 1; } if (SIGNBIT(y.msw)) { b = op_neg_u(y); yn = 1; } udiv(a, b, &c, &d); if (xn ^ yn) *q = op_neg_u(c); else *q = c; if (xn ^ yn) *r = op_neg_u(d); else *r = d;} static ucppslong op_slash_s(ucppslong x, ucppslong y){ ucppslong q, r; sdiv(x, y, &q, &r); return q;} static ucppslong op_pct_s(ucppslong x, ucppslong y){ ucppslong q, r; sdiv(x, y, &q, &r); return r;} #define op_plus_s(x, y) op_plus_u(x, y)#define op_minus_s(x, y) op_minus_u(x, y)#define op_neg_s(x) op_neg_u(x)#define op_lsh_s(x, y) op_lsh_u(x, y) /* * What happens if x represents a negative value, is implementation * specified. We emit a warning, and extend the sign (which is what * most implementations do). */static ucppslong op_rsh_s(ucppslong x, int y){ int xn = (SIGNBIT(x.msw) != 0); ucppulong q = op_rsh_u(x, y); if (xn && y > 0) { if (emit_eval_warnings) warning(eval_line, "right shift of a signed negative " "value in #if"); q = op_or_u(q, op_lsh_u(op_not_u(to_ulong(0)), 2 * LONGSIZE - y)); } return q;} static int op_lt_s(ucppslong x, ucppslong y){ int xn = (SIGNBIT(x.msw) != 0); int yn = (SIGNBIT(y.msw) != 0); if (xn && !yn) return 1; if (!xn && yn) return 0; if (xn) return op_lt_u(op_neg_u(y), op_neg_u(x)); return op_lt_u(x, y);} static int op_leq_s(ucppslong x, ucppslong y){ int xn = (SIGNBIT(x.msw) != 0); int yn = (SIGNBIT(y.msw) != 0); if (xn && !yn) return 1; if (!xn && yn) return 0; if (xn) return op_leq_u(op_neg_u(y), op_neg_u(x)); return op_leq_u(x, y);} #define op_gt_s(x, y) op_lt_s(y, x)#define op_geq_s(x, y) op_leq_s(y, x)#define op_same_s(x, y) op_same_u(x, y)#define op_neq_s(x, y) (!op_same_s(x, y)) #define op_and_s(x, y) op_and_u(x, y)#define op_circ_s(x, y) op_circ_u(x, y)#define op_or_s(x, y) op_or_u(x, y) #define op_lval_s(x) op_neq_s(x, to_slong(0))#define op_lnot_s(x) (!op_lval_s(x))#define op_not_s(x) op_not_u(x)#define op_uplus_s(x) (x)Lines 1–500 of 1087. Load more
/* * (c) Thomas Pornin 1999, 2000 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. The name of the authors may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include <stdio.h> #include <string.h> #include <setjmp.h> #include <limits.h> #include "ucppi.h" #include "tune.h" #include "mem.h" JMP_BUF eval_exception; long eval_line; static int emit_eval_warnings; /* * If you want to hardcode a conversion table, define a static array * of 256 int, and make transient_characters point to it. */ int *transient_characters = 0; #define OCTAL(x) ((x) >= '0' && (x) <= '7') #define DECIM(x) ((x) >= '0' && (x) <= '9') #define HEXAD(x) (((x) >= '0' && (x) <= '9') \ || (x) == 'a' || (x) == 'b' || (x) == 'c' \ || (x) == 'd' || (x) == 'e' || (x) == 'f' \ || (x) == 'A' || (x) == 'B' || (x) == 'C' \ || (x) == 'D' || (x) == 'E' || (x) == 'F') #define OVAL(x) ((int)((x) - '0')) #define DVAL(x) ((int)((x) - '0')) #define HVAL(x) (DECIM(x) ? DVAL(x) \ : (x) == 'a' || (x) == 'A' ? 10 \ : (x) == 'b' || (x) == 'B' ? 11 \ : (x) == 'c' || (x) == 'C' ? 12 \ : (x) == 'd' || (x) == 'D' ? 13 \ : (x) == 'e' || (x) == 'E' ? 14 : 15) #if !defined(NATIVE_UINTMAX) && !defined(SIMUL_UINTMAX) # if __STDC__ && __STDC_VERSION__ >= 199901L # include <stdint.h> # define NATIVE_UINTMAX uintmax_t # define NATIVE_INTMAX intmax_t # else # define NATIVE_UINTMAX unsigned long # define NATIVE_INTMAX long # endif #endif #ifdef NATIVE_UINTMAX typedef NATIVE_UINTMAX ucppulong; typedef NATIVE_INTMAX ucppslong; #define to_ulong(x) ((ucppulong)(x)) #define to_slong(x) ((ucppslong)(x)) #define op_star_u(x, y) ((x) * (y)) static inline ucppulong op_slash_u(ucppulong x, ucppulong y) { if (y == 0) { error(eval_line, "division by 0"); throw(eval_exception); } return x / y; } static inline ucppulong op_pct_u(ucppulong x, ucppulong y) { if (y == 0) { error(eval_line, "division by 0"); throw(eval_exception); } return x % y; } #define op_plus_u(x, y) ((x) + (y)) #define op_minus_u(x, y) ((x) - (y)) #define op_neg_u(x) (-(x)) #define op_lsh_u(x, y) ((x) << (y)) #define op_rsh_u(x, y) ((x) >> (y)) #define op_lt_u(x, y) ((x) < (y)) #define op_leq_u(x, y) ((x) <= (y)) #define op_gt_u(x, y) ((x) > (y)) #define op_geq_u(x, y) ((x) >= (y)) #define op_same_u(x, y) ((x) == (y)) #define op_neq_u(x, y) ((x) != (y)) #define op_and_u(x, y) ((x) & (y)) #define op_circ_u(x, y) ((x) ^ (y)) #define op_or_u(x, y) ((x) | (y)) #define op_lval_u(x) ((x) != 0) #define op_lnot_u(x) (!(x)) #define op_not_u(x) (~(x)) #define op_uplus_u(x) (x) #define op_uminus_u(x) op_neg_u(x) #define op_star_s(x, y) ((x) * (y)) static inline ucppslong op_slash_s(ucppslong x, ucppslong y) { if (y == 0) { error(eval_line, "division by 0"); throw(eval_exception); } return x / y; } static inline ucppslong op_pct_s(ucppslong x, ucppslong y) { if (y == 0) { error(eval_line, "division by 0"); throw(eval_exception); } return x % y; } #define op_plus_s(x, y) ((x) + (y)) #define op_minus_s(x, y) ((x) - (y)) #define op_neg_s(x) (-(x)) #define op_lsh_s(x, y) ((x) << (y)) #define op_rsh_s(x, y) ((x) >> (y)) #define op_lt_s(x, y) ((x) < (y)) #define op_leq_s(x, y) ((x) <= (y)) #define op_gt_s(x, y) ((x) > (y)) #define op_geq_s(x, y) ((x) >= (y)) #define op_same_s(x, y) ((x) == (y)) #define op_neq_s(x, y) ((x) != (y)) #define op_and_s(x, y) ((x) & (y)) #define op_circ_s(x, y) ((x) ^ (y)) #define op_or_s(x, y) ((x) | (y)) #define op_lval_s(x) ((x) != 0) #define op_lnot_s(x) (!(x)) #define op_not_s(x) (~(x)) #define op_uplus_s(x) (x) #define op_uminus_s(x) op_neg_s(x) #define op_promo(x) ((ucppulong)x) #define back_ulong(x) ((unsigned long)x) #else /* * We suppose that the unsigned long is not padded in its memory * representation, and that it has an even binary length. * * We could explore the size of ULONG_MAX with some dichotomic * trick using a recursive #include, but this would be really ugly. */ #define LONGSIZE (CHAR_BIT * sizeof(unsigned long)) #define HALFLONGSIZE (LONGSIZE / 2) #define HUL_MASK ((1UL << HALFLONGSIZE) - 1) #define UL_MS(x) (((x) >> HALFLONGSIZE) & HUL_MASK) #define UL_LS(x) ((x) & HUL_MASK) #define SIGNBIT(x) ((x) & (1UL << (LONGSIZE - 1))) typedef struct { unsigned long msw, lsw; } ucppulong; #define ucppslong ucppulong static ucppulong to_ulong(unsigned long x) { ucppulong y; y.msw = 0; y.lsw = x; return y; } static ucppslong to_slong(long x) { ucppslong y; y.lsw = x; y.msw = x >= 0 ? 0 : (unsigned long)(-1); return y; } static ucppulong op_plus_u(ucppulong x, ucppulong y) { ucppulong z; z.lsw = x.lsw + y.lsw; z.msw = x.msw + y.msw; if (z.lsw < x.lsw) z.msw ++; return z; } static ucppulong op_neg_u(ucppulong x) { ucppulong z; z.lsw = ~x.lsw; z.msw = ~x.msw; if (!(++ z.lsw)) z.msw ++; return z; } #define op_minus_u(x, y) op_plus_u(x, op_neg_u(y)) static ucppulong op_lsh_u(ucppulong x, int s) { ucppulong z; s %= (2 * LONGSIZE); if (s == 0) return x; if (s >= LONGSIZE) { z.lsw = 0; z.msw = x.lsw; return op_lsh_u(z, s - LONGSIZE); } z.lsw = (x.lsw << s); z.msw = (x.msw << s) | (x.lsw >> (LONGSIZE - s)); return z; } static ucppulong op_rsh_u(ucppulong x, int s) { ucppulong z; s %= (2 * LONGSIZE); if (s == 0) return x; if (s >= LONGSIZE) { z.msw = 0; z.lsw = x.msw; return op_rsh_u(z, s - LONGSIZE); } z.lsw = (x.lsw >> s) | (x.msw << (LONGSIZE - s)); z.msw = (x.msw >> s); return z; } static int op_lt_u(ucppulong x, ucppulong y) { if (x.msw < y.msw) return 1; if (x.msw > y.msw) return 0; if (x.lsw < y.lsw) return 1; return 0; } static int op_leq_u(ucppulong x, ucppulong y) { if (x.msw < y.msw) return 1; if (x.msw > y.msw) return 0; if (x.lsw <= y.lsw) return 1; return 0; } #define op_gt_u(x, y) op_lt_u(y, x) #define op_geq_u(x, y) op_leq_u(y, x) static int op_same_u(ucppulong x, ucppulong y) { return x.msw == y.msw && x.lsw == y.lsw; } #define op_neq_u(x, y) (!op_same_u(x, y)) static ucppulong op_and_u(ucppulong x, ucppulong y) { ucppulong z; z.lsw = x.lsw & y.lsw; z.msw = x.msw & y.msw; return z; } static ucppulong op_circ_u(ucppulong x, ucppulong y) { ucppulong z; z.lsw = x.lsw ^ y.lsw; z.msw = x.msw ^ y.msw; return z; } static ucppulong op_or_u(ucppulong x, ucppulong y) { ucppulong z; z.lsw = x.lsw | y.lsw; z.msw = x.msw | y.msw; return z; } #define op_lval_u(x) op_neq_u(x, to_ulong(0)) #define op_lnot_u(x) (!op_lval_u(x)) static ucppulong op_not_u(ucppulong x) { ucppulong z; z.lsw = ~x.lsw; z.msw = ~x.msw; return z; } #define op_uplus_u(x) (x) #define op_uminus_u(x) op_neg_u(x) static ucppulong umul(unsigned long x, unsigned long y) { ucppulong z; unsigned long t00, t01, t10, t11, c = 0, t; t00 = UL_LS(x) * UL_LS(y); t01 = UL_LS(x) * UL_MS(y); t10 = UL_MS(x) * UL_LS(y); t11 = UL_MS(x) * UL_MS(y); t = z.lsw = t00; if (t > (z.lsw += (UL_LS(t01) << HALFLONGSIZE))) c ++; t = z.lsw; if (t > (z.lsw += (UL_LS(t10) << HALFLONGSIZE))) c ++; z.msw = t11 + UL_MS(t10) + UL_MS(t01) + c; return z; } static ucppulong op_star_u(ucppulong x, ucppulong y) { ucppulong z1, z2; z1.lsw = z2.lsw = 0; z1.msw = x.lsw * y.msw; z2.msw = x.msw * y.lsw; return op_plus_u(umul(x.lsw, y.lsw), op_plus_u(z1, z2)); } static void udiv(ucppulong x, ucppulong y, ucppulong *q, ucppulong *r) { int i, j; *q = to_ulong(0); for (i = 2 * LONGSIZE - 1; i >= 0; i --) { if (i >= LONGSIZE && (y.msw & (1UL << (i - LONGSIZE)))) break; if (i < LONGSIZE && (y.lsw & (1UL << i))) break; } if (i < 0) { error(eval_line, "division by 0"); throw(eval_exception); } for (j = 2 * LONGSIZE - 1 - i; j >= 0; j --) { ucppulong a = op_lsh_u(y, j); if (op_leq_u(a, x)) { x = op_minus_u(x, a); if (j >= LONGSIZE) q->msw |= (1UL << (j - LONGSIZE)); else q->lsw |= (1UL << j); } } *r = x; } static ucppulong op_slash_u(ucppulong x, ucppulong y) { ucppulong q, r; udiv(x, y, &q, &r); return q; } static ucppulong op_pct_u(ucppulong x, ucppulong y) { ucppulong q, r; udiv(x, y, &q, &r); return r; } static ucppslong op_star_s(ucppslong x, ucppslong y) { ucppulong a = x, b = y, c; int xn = 0, yn = 0; if (SIGNBIT(x.msw)) { a = op_neg_u(x); xn = 1; } if (SIGNBIT(y.msw)) { b = op_neg_u(y); yn = 1; } c = op_star_u(a, b); /* Turbo C seems to miscompile the ?: operators when operands are ulong/slong structures */ if (xn ^ yn) return op_neg_u(c); return c; } static void sdiv(ucppslong x, ucppslong y, ucppslong *q, ucppslong *r) { ucppulong a = x, b = y, c, d; int xn = 0, yn = 0; if (SIGNBIT(x.msw)) { a = op_neg_u(x); xn = 1; } if (SIGNBIT(y.msw)) { b = op_neg_u(y); yn = 1; } udiv(a, b, &c, &d); if (xn ^ yn) *q = op_neg_u(c); else *q = c; if (xn ^ yn) *r = op_neg_u(d); else *r = d; } static ucppslong op_slash_s(ucppslong x, ucppslong y) { ucppslong q, r; sdiv(x, y, &q, &r); return q; } static ucppslong op_pct_s(ucppslong x, ucppslong y) { ucppslong q, r; sdiv(x, y, &q, &r); return r; } #define op_plus_s(x, y) op_plus_u(x, y) #define op_minus_s(x, y) op_minus_u(x, y) #define op_neg_s(x) op_neg_u(x) #define op_lsh_s(x, y) op_lsh_u(x, y) /* * What happens if x represents a negative value, is implementation * specified. We emit a warning, and extend the sign (which is what * most implementations do). */ static ucppslong op_rsh_s(ucppslong x, int y) { int xn = (SIGNBIT(x.msw) != 0); ucppulong q = op_rsh_u(x, y); if (xn && y > 0) { if (emit_eval_warnings) warning(eval_line, "right shift of a signed negative " "value in #if"); q = op_or_u(q, op_lsh_u(op_not_u(to_ulong(0)), 2 * LONGSIZE - y)); } return q; } static int op_lt_s(ucppslong x, ucppslong y) { int xn = (SIGNBIT(x.msw) != 0); int yn = (SIGNBIT(y.msw) != 0); if (xn && !yn) return 1; if (!xn && yn) return 0; if (xn) return op_lt_u(op_neg_u(y), op_neg_u(x)); return op_lt_u(x, y); } static int op_leq_s(ucppslong x, ucppslong y) { int xn = (SIGNBIT(x.msw) != 0); int yn = (SIGNBIT(y.msw) != 0); if (xn && !yn) return 1; if (!xn && yn) return 0; if (xn) return op_leq_u(op_neg_u(y), op_neg_u(x)); return op_leq_u(x, y); } #define op_gt_s(x, y) op_lt_s(y, x) #define op_geq_s(x, y) op_leq_s(y, x) #define op_same_s(x, y) op_same_u(x, y) #define op_neq_s(x, y) (!op_same_s(x, y)) #define op_and_s(x, y) op_and_u(x, y) #define op_circ_s(x, y) op_circ_u(x, y) #define op_or_s(x, y) op_or_u(x, y) #define op_lval_s(x) op_neq_s(x, to_slong(0)) #define op_lnot_s(x) (!op_lval_s(x)) #define op_not_s(x) op_not_u(x) #define op_uplus_s(x) (x)