1087 lines · 24.9 KB · C
RawDownload
/* * (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.