/*************************************************************************** gbx_subr_math.c (c) 2000-2009 BenoƮt Minisini This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ***************************************************************************/ #define __GBX_SUBR_MATH_C #ifdef OS_SOLARIS /* Make math.h define M_PI and a few other things */ #define __EXTENSIONS__ /* Get definition for finite() */ #include #endif #include "gb_common.h" #include "gbx_value.h" #include "gbx_subr.h" #include "gbx_math.h" #define ABS(x) ((x) < 0 ? (-x) : (x)) #define SMT_NAME SUBR_quo #define SMT_TYPE 3 #define SMT_OP / #include "gbx_subr_math_temp.h" #define SMT_NAME SUBR_rem #define SMT_TYPE 3 #define SMT_OP % #include "gbx_subr_math_temp.h" void SUBR_pi(ushort code) { SUBR_ENTER(); if (NPARAM == 0) { SP->type = T_FLOAT; SP->_float.value = M_PI; SP++; } else { VALUE_conv_float(PARAM); PARAM->_float.value = M_PI * PARAM->_float.value; } } void SUBR_randomize(ushort code) { SUBR_ENTER(); if (NPARAM == 0) randomize(FALSE, 0); else randomize(TRUE, (uint)SUBR_get_integer(PARAM)); RETURN->type = T_VOID; SUBR_LEAVE(); } void SUBR_rnd(ushort code) { double min = 0.0, max = 1.0; SUBR_ENTER(); if (NPARAM >= 1) { VALUE_conv_float(&PARAM[0]); max = PARAM->_float.value; } if (NPARAM == 2) { min = max; VALUE_conv_float(&PARAM[1]); max = PARAM[1]._float.value; } RETURN->type = T_FLOAT; RETURN->_float.value = (rnd() * (max - min)) + min; SUBR_LEAVE(); } void SUBR_round(ushort code) { int val = 0; double power; SUBR_ENTER(); if (NPARAM == 2) val = SUBR_get_integer(&PARAM[1]); power = pow(10, val); VALUE_conv_float(&PARAM[0]); RETURN->type = T_FLOAT; /*RETURN->_float.value = rint(PARAM->_float.value / power) * power;*/ RETURN->_float.value = floor(PARAM->_float.value / power + 0.5) * power; SUBR_LEAVE(); } void SUBR_math(ushort code) { static void *jump[] = { NULL, &&__FRAC, &&__LOG, &&__EXP, &&__SQRT, &&__SIN, &&__COS, &&__TAN, &&__ATAN, &&__ASIN, &&__ACOS, &&__DEG, &&__RAD, &&__LOG10, &&__SINH, &&__COSH, &&__TANH, &&__ASINH, &&__ACOSH, &&__ATANH, &&__EXP2, &&__EXP10, &&__LOG2, &&__CBRT, &&__EXPM1, &&__LOG1P }; SUBR_ENTER_PARAM(1); VALUE_conv_float(PARAM); goto *jump[code & 0x1F]; __FRAC: PARAM->_float.value = frac(PARAM->_float.value); goto __END; __LOG: PARAM->_float.value = __builtin_log(PARAM->_float.value); goto __END; __EXP: PARAM->_float.value = __builtin_exp(PARAM->_float.value); goto __END; __SQRT: PARAM->_float.value = __builtin_sqrt(PARAM->_float.value); goto __END; __SIN: PARAM->_float.value = __builtin_sin(PARAM->_float.value); goto __END; __COS: PARAM->_float.value = __builtin_cos(PARAM->_float.value); goto __END; __TAN: PARAM->_float.value = __builtin_tan(PARAM->_float.value); goto __END; __ATAN: PARAM->_float.value = __builtin_atan(PARAM->_float.value); goto __END; __ASIN: PARAM->_float.value = __builtin_asin(PARAM->_float.value); goto __END; __ACOS: PARAM->_float.value = __builtin_acos(PARAM->_float.value); goto __END; __DEG: PARAM->_float.value = deg(PARAM->_float.value); goto __END; __RAD: PARAM->_float.value = rad(PARAM->_float.value); goto __END; __LOG10: PARAM->_float.value = log10(PARAM->_float.value); goto __END; __SINH: PARAM->_float.value = __builtin_sinh(PARAM->_float.value); goto __END; __COSH: PARAM->_float.value = __builtin_cosh(PARAM->_float.value); goto __END; __TANH: PARAM->_float.value = __builtin_tanh(PARAM->_float.value); goto __END; __ASINH: PARAM->_float.value = __builtin_asinh(PARAM->_float.value); goto __END; __ACOSH: PARAM->_float.value = __builtin_acosh(PARAM->_float.value); goto __END; __ATANH: PARAM->_float.value = __builtin_atanh(PARAM->_float.value); goto __END; __EXP2: PARAM->_float.value = __builtin_exp2(PARAM->_float.value); goto __END; __EXP10: PARAM->_float.value = __builtin_exp10(PARAM->_float.value); goto __END; __LOG2: PARAM->_float.value = __builtin_log2(PARAM->_float.value); goto __END; __CBRT: PARAM->_float.value = __builtin_cbrt(PARAM->_float.value); goto __END; __EXPM1: PARAM->_float.value = __builtin_expm1(PARAM->_float.value); goto __END; __LOG1P: PARAM->_float.value = __builtin_log1p(PARAM->_float.value); goto __END; __END: if (!finite(PARAM->_float.value)) THROW(E_MATH); } void SUBR_math2(ushort code) { static void *jump[] = { NULL, &&__ATAN2, &&__ANG, &&__HYPOT }; SUBR_ENTER_PARAM(2); VALUE_conv_float(&PARAM[0]); VALUE_conv_float(&PARAM[1]); goto *jump[code & 0x1F]; __ATAN2: PARAM->_float.value = __builtin_atan2(PARAM[0]._float.value, PARAM[1]._float.value); goto __END; __ANG: PARAM->_float.value = __builtin_atan2(PARAM[1]._float.value, PARAM[0]._float.value); goto __END; __HYPOT: PARAM->_float.value = sqrt(PARAM[0]._float.value * PARAM[0]._float.value + PARAM[1]._float.value * PARAM[1]._float.value); goto __END; __END: if (!finite(PARAM->_float.value)) THROW(E_MATH); SP--; } void SUBR_pow(void) { SUBR_ENTER_PARAM(2); VALUE_conv_float(&PARAM[0]); if (TYPE_is_integer(PARAM[1].type)) { static void *jump[] = { &&__M4, &&__M3, &&__M2, &&__M1, &&__P0, &&__END, &&__P2, &&__P3, &&__P4 }; int val = PARAM[1]._integer.value; if (val >= -4 && val <= 4) goto *jump[val + 4]; else goto __FLOAT; __P0: PARAM->_float.value = 1.0; goto __END; __P2: PARAM->_float.value *= PARAM->_float.value; goto __END; __P3: PARAM->_float.value *= PARAM->_float.value * PARAM->_float.value; goto __END; __P4: PARAM->_float.value *= PARAM->_float.value;PARAM->_float.value *= PARAM->_float.value; goto __END; __M1: PARAM->_float.value = 1.0 / PARAM->_float.value; goto __END; __M2: PARAM->_float.value = 1.0 / PARAM->_float.value / PARAM->_float.value; goto __END; __M3: PARAM->_float.value = 1.0 / PARAM->_float.value / PARAM->_float.value / PARAM->_float.value; goto __END; __M4: PARAM->_float.value = 1.0 / PARAM->_float.value / PARAM->_float.value / PARAM->_float.value / PARAM->_float.value; goto __END; } __FLOAT: VALUE_conv_float(&PARAM[1]); PARAM->_float.value = pow(PARAM[0]._float.value, PARAM[1]._float.value); __END: if (!finite(PARAM->_float.value)) THROW(E_MATH); SP--; } void SUBR_not(ushort code) { static void *jump[17] = { &&__VARIANT, &&__BOOLEAN, &&__BYTE, &&__SHORT, &&__INTEGER, &&__LONG, &&__SINGLE, &&__FLOAT, &&__DATE, &&__STRING, &&__STRING, &&__ERROR, &&__ERROR, &&__ERROR, &&__ERROR, &&__NULL, &&__OBJECT }; VALUE *P1; void *jump_end; TYPE type = code & 0x1F; bool test; P1 = SP - 1; jump_end = &&__END; goto *jump[type]; __BOOLEAN: P1->_integer.value = P1->_integer.value ? 0 : (-1); goto *jump_end; __BYTE: P1->_integer.value = (unsigned char)~P1->_integer.value; goto *jump_end; __SHORT: P1->_integer.value = (short)~P1->_integer.value; goto *jump_end; __INTEGER: P1->_integer.value = ~P1->_integer.value; goto *jump_end; __LONG: P1->_long.value = ~P1->_long.value; goto *jump_end; __SINGLE: __FLOAT: __DATE: goto __ERROR; __STRING: __OBJECT: __NULL: test = VALUE_is_null(P1); RELEASE(P1); P1->_integer.value = test ? (-1) : 0; P1->type = T_BOOLEAN; goto *jump_end; __VARIANT: type = P1->type; if (TYPE_is_variant(type)) { type = P1->_variant.vtype; jump_end = &&__VARIANT_END; VARIANT_undo(P1); } else if (TYPE_is_object(type)) *PC |= T_OBJECT; else if (type) *PC |= type; else goto __ERROR; if (TYPE_is_object(type)) goto __OBJECT; else goto *jump[type]; __ERROR: THROW(E_TYPE, "Number, String or Object", TYPE_get_name(type)); __VARIANT_END: VALUE_conv_variant(P1); __END: return; } void SUBR_and_(ushort code) { static void *jump[] = { &&__VARIANT, &&__BOOLEAN, &&__BYTE, &&__SHORT, &&__INTEGER, &&__LONG, &&__ERROR, &&__ERROR, &&__ERROR }; TYPE type; VALUE *P1, *P2; void *jump_end; short op; P1 = SP - 2; P2 = P1 + 1; jump_end = &&__END; type = code & 0x0F; op = (code >> 8) - (C_AND >> 8); goto *jump[type]; __BYTE: P1->type = type; { static void *exec[] = { &&__AND_C, && __OR_C, &&__XOR_C }; goto *exec[op]; __AND_C: P1->_integer.value = (unsigned char)(P1->_integer.value & P2->_integer.value); goto *jump_end; __OR_C: P1->_integer.value = (unsigned char)(P1->_integer.value | P2->_integer.value); goto *jump_end; __XOR_C: P1->_integer.value = (unsigned char)(P1->_integer.value ^ P2->_integer.value); goto *jump_end; } goto *jump_end; __SHORT: P1->type = type; { static void *exec[] = { &&__AND_H, && __OR_H, &&__XOR_H }; goto *exec[op]; __AND_H: P1->_integer.value = (short)(P1->_integer.value & P2->_integer.value); goto *jump_end; __OR_H: P1->_integer.value = (short)(P1->_integer.value | P2->_integer.value); goto *jump_end; __XOR_H: P1->_integer.value = (short)(P1->_integer.value ^ P2->_integer.value); goto *jump_end; } goto *jump_end; __BOOLEAN: __INTEGER: P1->type = type; { static void *exec[] = { &&__AND_I, && __OR_I, &&__XOR_I }; goto *exec[op]; __AND_I: P1->_integer.value &= P2->_integer.value; goto *jump_end; __OR_I: P1->_integer.value |= P2->_integer.value; goto *jump_end; __XOR_I: P1->_integer.value ^= P2->_integer.value; goto *jump_end; } goto *jump_end; __LONG: VALUE_conv(P1, T_LONG); VALUE_conv(P2, T_LONG); P1->type = type; { static void *exec[] = { &&__AND_L, && __OR_L, &&__XOR_L }; goto *exec[op]; __AND_L: P1->_long.value &= P2->_long.value; goto *jump_end; __OR_L: P1->_long.value |= P2->_long.value; goto *jump_end; __XOR_L: P1->_long.value ^= P2->_long.value; goto *jump_end; } __VARIANT: type = Max(P1->type, P2->type); if (TYPE_is_number_date(type)) { *PC |= type; goto *jump[type]; } if (TYPE_is_variant(P1->type)) VARIANT_undo(P1); if (TYPE_is_variant(P2->type)) VARIANT_undo(P2); if (TYPE_is_string(P1->type)) VALUE_convert_boolean(P1); if (TYPE_is_string(P2->type)) VALUE_convert_boolean(P2); if (TYPE_is_null(P1->type) || TYPE_is_null(P2->type)) type = T_NULL; else type = Max(P1->type, P2->type); if (TYPE_is_number_date(type)) { jump_end = &&__VARIANT_END; goto *jump[type]; } __ERROR: THROW(E_TYPE, "Number", TYPE_get_name(type)); __VARIANT_END: VALUE_conv_variant(P1); __END: SP--; } #define MANAGE_VARIANT(_func) \ ({ \ type = P1->type; \ \ if (TYPE_is_number_date(type)) \ { \ *PC |= type; \ goto *jump[type]; \ } \ \ if (TYPE_is_variant(type)) \ { \ type = P1->_variant.vtype; \ if (TYPE_is_number_date(type)) \ { \ VARIANT_undo(P1); \ (_func)(code | type); \ VALUE_conv_variant(P1); \ return; \ } \ } \ }) void SUBR_sgn(ushort code) { static void *jump[] = { &&__VARIANT, &&__INTEGER, &&__INTEGER, &&__INTEGER, &&__INTEGER, &&__LONG, &&__FLOAT, &&__FLOAT, &&__ERROR }; VALUE *P1; TYPE type; P1 = SP - 1; type = code & 0x0F; goto *jump[type]; __INTEGER: P1->_integer.value = lsgn(P1->_integer.value); goto __END; __LONG: P1->_integer.value = llsgn(P1->_long.value); goto __END; __FLOAT: P1->_integer.value = fsgn(P1->_float.value); goto __END; __VARIANT: type = P1->type; if (TYPE_is_number(type)) { *PC |= type; goto *jump[type]; } if (TYPE_is_variant(type)) { type = P1->_variant.vtype; if (TYPE_is_number(type)) { VARIANT_undo(P1); goto *jump[type]; } } goto __ERROR; __ERROR: THROW(E_TYPE, "Number", TYPE_get_name(type)); __END: P1->type = T_INTEGER; } void SUBR_neg(ushort code) { static void *jump[] = { &&__VARIANT, &&__BOOLEAN, &&__BYTE, &&__SHORT, &&__INTEGER, &&__LONG, &&__SINGLE, &&__FLOAT, &&__ERROR }; VALUE *P1; TYPE type; P1 = SP - 1; type = code & 0x0F; goto *jump[type]; __BOOLEAN: return; __BYTE: P1->_integer.value = (unsigned char)(-P1->_integer.value); return; __SHORT: P1->_integer.value = (short)(-P1->_integer.value); return; __INTEGER: P1->_integer.value = (-P1->_integer.value); return; __LONG: P1->_long.value = (-P1->_long.value); return; __SINGLE: VALUE_conv_float(P1); __FLOAT: P1->_float.value = (-P1->_float.value); return; __VARIANT: MANAGE_VARIANT(SUBR_neg); __ERROR: THROW(E_TYPE, "Number", TYPE_get_name(type)); } void SUBR_abs(ushort code) { static void *jump[] = { &&__VARIANT, &&__BOOLEAN, &&__BYTE, &&__SHORT, &&__INTEGER, &&__LONG, &&__SINGLE, &&__FLOAT, &&__ERROR }; VALUE *P1; TYPE type; P1 = SP - 1; type = code & 0x0F; goto *jump[type]; __BOOLEAN: return; __BYTE: P1->_integer.value = (unsigned char)ABS(-P1->_integer.value); return; __SHORT: P1->_integer.value = (short)ABS(P1->_integer.value); return; __INTEGER: P1->_integer.value = ABS(P1->_integer.value); return; __LONG: P1->_long.value = ABS(P1->_long.value); return; __SINGLE: VALUE_conv_float(P1); __FLOAT: P1->_float.value = fabs(P1->_float.value); return; __VARIANT: MANAGE_VARIANT(SUBR_abs); __ERROR: THROW(E_TYPE, "Number", TYPE_get_name(type)); } void SUBR_int(ushort code) { static void *jump[] = { &&__VARIANT, &&__BOOLEAN, &&__BYTE, &&__SHORT, &&__INTEGER, &&__LONG, &&__SINGLE, &&__FLOAT, &&__ERROR }; VALUE *P1; TYPE type; P1 = SP - 1; type = code & 0x0F; goto *jump[type]; __BOOLEAN: __BYTE: __SHORT: __INTEGER: __LONG: return; __SINGLE: VALUE_conv_float(P1); __FLOAT: P1->_float.value = floor(P1->_float.value); return; __VARIANT: MANAGE_VARIANT(SUBR_int); __ERROR: THROW(E_TYPE, "Number", TYPE_get_name(type)); } void SUBR_fix(ushort code) { static void *jump[] = { &&__VARIANT, &&__BOOLEAN, &&__BYTE, &&__SHORT, &&__INTEGER, &&__LONG, &&__SINGLE, &&__FLOAT, &&__ERROR }; VALUE *P1; TYPE type; P1 = SP - 1; type = code & 0x0F; goto *jump[type]; __BOOLEAN: __BYTE: __SHORT: __INTEGER: __LONG: return; __SINGLE: VALUE_conv_float(P1); __FLOAT: P1->_float.value = fix(P1->_float.value); return; __VARIANT: MANAGE_VARIANT(SUBR_fix); __ERROR: THROW(E_TYPE, "Number", TYPE_get_name(type)); } #if 0 void SUBR_neg_(ushort code) { static void *jump[] = { &&__VARIANT, &&__BOOLEAN, &&__BYTE, &&__SHORT, &&__INTEGER, &&__LONG, &&__FLOAT, &&__FLOAT, &&__ERROR }; VALUE *P1; void *jump_end; TYPE type; short op; P1 = SP - 1; jump_end = &&__END; type = code & 0x0F; op = code >> 8; op = (op == (C_NEG >> 8)) ? 0 : op - CODE_ABS + 1; goto *jump[type]; __BYTE: { static void *exec[] = { &&__NEG_C, &&__ABS_C, &&__INT_C, &&__FIX_C }; //, &&__SGN_I }; goto *exec[op]; __NEG_C: P1->_integer.value = (unsigned char)(-P1->_integer.value); goto *jump_end; __ABS_C: P1->_integer.value = (unsigned char)ABS(P1->_integer.value); goto *jump_end; __INT_C: goto *jump_end; __FIX_C: goto *jump_end; } __SHORT: { static void *exec[] = { &&__NEG_H, &&__ABS_H, &&__INT_H, &&__FIX_H }; //, &&__SGN_I }; goto *exec[op]; __NEG_H: P1->_integer.value = (short)(-P1->_integer.value); goto *jump_end; __ABS_H: P1->_integer.value = (short)ABS(P1->_integer.value); goto *jump_end; __INT_H: goto *jump_end; __FIX_H: goto *jump_end; } __BOOLEAN: __INTEGER: { static void *exec[] = { &&__NEG_I, &&__ABS_I, &&__INT_I, &&__FIX_I }; //, &&__SGN_I }; goto *exec[op]; __NEG_I: P1->_integer.value = (-P1->_integer.value); goto *jump_end; __ABS_I: P1->_integer.value = ABS(P1->_integer.value); goto *jump_end; __INT_I: goto *jump_end; __FIX_I: goto *jump_end; //__SGN_I: P1->_integer.value = lsgn(P1->_integer.value); goto __END_SGN; } __LONG: //VALUE_conv(P1, T_LONG); { static void *exec[] = { &&__NEG_L, &&__ABS_L, &&__INT_L, &&__FIX_L }; //, &&__SGN_L }; goto *exec[op]; __NEG_L: P1->_long.value = (-P1->_long.value); goto *jump_end; __ABS_L: P1->_long.value = ABS(P1->_long.value); goto *jump_end; __INT_L: goto *jump_end; __FIX_L: goto *jump_end; //__SGN_L: P1->_integer.value = llsgn(P1->_integer.value); P1->type = T_INTEGER; goto __END_SGN; } __FLOAT: VALUE_conv_float(P1); { static void *exec[] = { &&__NEG_F, &&__ABS_F, &&__INT_F, &&__FIX_F }; //, &&__SGN_F }; goto *exec[op]; __NEG_F: P1->_float.value = (-P1->_float.value); goto *jump_end; __ABS_F: P1->_float.value = fabs(P1->_float.value); goto *jump_end; __INT_F: P1->_float.value = floor(P1->_float.value); goto *jump_end; __FIX_F: P1->_float.value = fix(P1->_float.value); goto *jump_end; //__SGN_F: P1->_integer.value = fsgn(P1->_integer.value); P1->type = T_INTEGER; goto __END_SGN; } __VARIANT: type = P1->type; if (TYPE_is_number_date(type)) { *PC |= type; goto *jump[type]; } if (TYPE_is_variant(type)) { type = P1->_variant.vtype; if (TYPE_is_number_date(type)) { VARIANT_undo(P1); jump_end = &&__VARIANT_END; goto *jump[type]; } } __ERROR: THROW(E_TYPE, "Number", TYPE_get_name(type)); __VARIANT_END: VALUE_conv_variant(P1); //__END_SGN: // P1->type = T_INTEGER; __END: return; } void SUBR_add_(ushort code) { static void *jump[] = { &&__VARIANT, &&__BOOLEAN, &&__BYTE, &&__SHORT, &&__INTEGER, &&__LONG, &&__FLOAT, &&__FLOAT, &&__DATE }; TYPE type; VALUE *P1, *P2; int op; P1 = SP - 2; P2 = P1 + 1; type = code & 0x0F; op = (code >> 8) - (C_ADD >> 8); goto *jump[type]; __BOOLEAN: P1->type = type; { static void *exec[] = { &&__ADD_B, && __SUB_B, &&__MUL_B, &&__FLOAT }; goto *exec[op]; __ADD_B: P1->_integer.value = P1->_integer.value | P2->_integer.value; goto __END; __SUB_B: P1->_integer.value = P1->_integer.value ^ P2->_integer.value; goto __END; __MUL_B: P1->_integer.value = P1->_integer.value & P2->_integer.value; goto __END; } __BYTE: P1->type = type; { static void *exec[] = { &&__ADD_C, && __SUB_C, &&__MUL_C, &&__FLOAT }; goto *exec[op]; __ADD_C: P1->_integer.value = (unsigned char)(P1->_integer.value + P2->_integer.value); goto __END; __SUB_C: P1->_integer.value = (unsigned char)(P1->_integer.value - P2->_integer.value); goto __END; __MUL_C: P1->_integer.value = (unsigned char)(P1->_integer.value * P2->_integer.value); goto __END; } __SHORT: P1->type = type; { static void *exec[] = { &&__ADD_H, && __SUB_H, &&__MUL_H, &&__FLOAT }; goto *exec[op]; __ADD_H: P1->_integer.value = (short)(P1->_integer.value + P2->_integer.value); goto __END; __SUB_H: P1->_integer.value = (short)(P1->_integer.value - P2->_integer.value); goto __END; __MUL_H: P1->_integer.value = (short)(P1->_integer.value * P2->_integer.value); goto __END; } __INTEGER: P1->type = type; { static void *exec[] = { &&__ADD_I, && __SUB_I, &&__MUL_I, &&__FLOAT }; goto *exec[op]; __ADD_I: P1->_integer.value += P2->_integer.value; goto __END; __SUB_I: P1->_integer.value -= P2->_integer.value; goto __END; __MUL_I: P1->_integer.value *= P2->_integer.value; goto __END; } __LONG: VALUE_conv(P1, T_LONG); VALUE_conv(P2, T_LONG); P1->type = type; { static void *exec[] = { &&__ADD_L, && __SUB_L, &&__MUL_L, &&__FLOAT }; goto *exec[op]; __ADD_L: P1->_long.value += P2->_long.value; goto __END; __SUB_L: P1->_long.value -= P2->_long.value; goto __END; __MUL_L: P1->_long.value *= P2->_long.value; goto __END; } __DATE: VALUE_conv_float(P1); VALUE_conv_float(P2); { static void *exec[] = { &&__ADD_F, && __SUB_F, &&__ERROR, &&__ERROR }; goto *exec[op]; } __FLOAT: VALUE_conv_float(P1); VALUE_conv_float(P2); { static void *exec[] = { &&__ADD_F, && __SUB_F, &&__MUL_F, &&__DIV_F }; goto *exec[op]; __ADD_F: P1->_float.value += P2->_float.value; goto __END; __SUB_F: P1->_float.value -= P2->_float.value; goto __END; __MUL_F: P1->_float.value *= P2->_float.value; goto __END; __DIV_F: P1->_float.value /= P2->_float.value; if (!finite(P1->_float.value)) { if (P2->_float.value == 0.0) THROW(E_ZERO); else THROW(E_MATH); } goto __END; } __VARIANT: type = Max(P1->type, P2->type); if (TYPE_is_number_date(type)) { *PC |= type; goto *jump[type]; } if (TYPE_is_variant(P1->type)) VARIANT_undo(P1); if (TYPE_is_variant(P2->type)) VARIANT_undo(P2); if (TYPE_is_string(P1->type)) VALUE_conv_float(P1); if (TYPE_is_string(P2->type)) VALUE_conv_float(P2); if (TYPE_is_null(P1->type) || TYPE_is_null(P2->type)) type = T_NULL; else type = Max(P1->type, P2->type); if (TYPE_is_number_date(type)) { SUBR_add_(code | type); VALUE_conv_variant(P1); return; } goto __ERROR; __ERROR: THROW(E_TYPE, "Number", TYPE_get_name(type)); __END: SP--; } #define MANAGE_VARIANT(_func) \ ({ \ type = Max(P1->type, P2->type); \ \ if (TYPE_is_number_date(type)) \ { \ *PC |= type; \ goto *jump[type]; \ } \ \ VARIANT_undo(P1); \ VARIANT_undo(P2); \ \ if (TYPE_is_string(P1->type)) \ VALUE_conv_float(P1); \ \ if (TYPE_is_string(P2->type)) \ VALUE_conv_float(P2); \ \ if (TYPE_is_null(P1->type) || TYPE_is_null(P2->type)) \ type = T_NULL; \ else \ type = Max(P1->type, P2->type); \ \ if (TYPE_is_number_date(type)) \ { \ (_func)(code | type); \ VALUE_conv_variant(P1); \ return; \ } \ }) void SUBR_add(ushort code) { static void *jump[] = { &&__VARIANT, &&__BOOLEAN, &&__BYTE, &&__SHORT, &&__INTEGER, &&__LONG, &&__FLOAT, &&__FLOAT, &&__DATE }; TYPE type; VALUE *P1, *P2; P1 = SP - 2; P2 = P1 + 1; type = code & 0x0F; goto *jump[type]; __BOOLEAN: P1->type = T_BOOLEAN; P1->_integer.value = P1->_integer.value | P2->_integer.value; goto __END; __BYTE: P1->type = T_BYTE; P1->_integer.value = (unsigned char)(P1->_integer.value + P2->_integer.value); goto __END; __SHORT: P1->type = T_SHORT; P1->_integer.value = (short)(P1->_integer.value + P2->_integer.value); goto __END; __INTEGER: P1->type = T_INTEGER; P1->_integer.value += P2->_integer.value; goto __END; __LONG: VALUE_conv(P1, T_LONG); VALUE_conv(P2, T_LONG); P1->_long.value += P2->_long.value; goto __END; __DATE: __FLOAT: VALUE_conv_float(P1); VALUE_conv_float(P2); P1->_float.value += P2->_float.value; goto __END; __VARIANT: MANAGE_VARIANT(SUBR_add); goto __ERROR; __ERROR: THROW(E_TYPE, "Number", TYPE_get_name(type)); __END: SP--; } void SUBR_sub(ushort code) { static void *jump[] = { &&__VARIANT, &&__BOOLEAN, &&__BYTE, &&__SHORT, &&__INTEGER, &&__LONG, &&__FLOAT, &&__FLOAT, &&__DATE }; TYPE type; VALUE *P1, *P2; P1 = SP - 2; P2 = P1 + 1; type = code & 0x0F; goto *jump[type]; __BOOLEAN: P1->type = T_BOOLEAN; P1->_integer.value = P1->_integer.value ^ P2->_integer.value; goto __END; __BYTE: P1->type = T_BYTE; P1->_integer.value = (unsigned char)(P1->_integer.value - P2->_integer.value); goto __END; __SHORT: P1->type = T_SHORT; P1->_integer.value = (short)(P1->_integer.value - P2->_integer.value); goto __END; __INTEGER: P1->type = T_INTEGER; P1->_integer.value -= P2->_integer.value; goto __END; __LONG: VALUE_conv(P1, T_LONG); VALUE_conv(P2, T_LONG); P1->_long.value -= P2->_long.value; goto __END; __DATE: __FLOAT: VALUE_conv_float(P1); VALUE_conv_float(P2); P1->_float.value -= P2->_float.value; goto __END; __VARIANT: MANAGE_VARIANT(SUBR_sub); goto __ERROR; __ERROR: THROW(E_TYPE, "Number", TYPE_get_name(type)); __END: SP--; } void SUBR_mul(ushort code) { static void *jump[] = { &&__VARIANT, &&__BOOLEAN, &&__BYTE, &&__SHORT, &&__INTEGER, &&__LONG, &&__FLOAT, &&__FLOAT, &&__ERROR }; TYPE type; VALUE *P1, *P2; P1 = SP - 2; P2 = P1 + 1; type = code & 0x0F; goto *jump[type]; __BOOLEAN: P1->type = T_BOOLEAN; P1->_integer.value = P1->_integer.value & P2->_integer.value; goto __END; __BYTE: P1->type = T_BYTE; P1->_integer.value = (unsigned char)(P1->_integer.value * P2->_integer.value); goto __END; __SHORT: P1->type = T_SHORT; P1->_integer.value = (short)(P1->_integer.value * P2->_integer.value); goto __END; __INTEGER: P1->type = T_INTEGER; P1->_integer.value *= P2->_integer.value; goto __END; __LONG: VALUE_conv(P1, T_LONG); VALUE_conv(P2, T_LONG); P1->_long.value *= P2->_long.value; goto __END; __FLOAT: VALUE_conv_float(P1); VALUE_conv_float(P2); P1->_float.value *= P2->_float.value; goto __END; __VARIANT: MANAGE_VARIANT(SUBR_mul); goto __ERROR; __ERROR: THROW(E_TYPE, "Number", TYPE_get_name(type)); __END: SP--; } void SUBR_div(ushort code) { static void *jump[] = { &&__VARIANT, &&__BOOLEAN, &&__BYTE, &&__SHORT, &&__INTEGER, &&__LONG, &&__FLOAT, &&__FLOAT, &&__ERROR }; TYPE type; VALUE *P1, *P2; P1 = SP - 2; P2 = P1 + 1; type = code & 0x0F; goto *jump[type]; __BOOLEAN: __BYTE: __SHORT: __INTEGER: __LONG: __FLOAT: VALUE_conv_float(P1); VALUE_conv_float(P2); P1->_float.value /= P2->_float.value; if (!finite(P1->_float.value)) { if (P2->_float.value == 0.0) THROW(E_ZERO); else THROW(E_MATH); } goto __END; __VARIANT: MANAGE_VARIANT(SUBR_div); goto __ERROR; __ERROR: THROW(E_TYPE, "Number", TYPE_get_name(type)); __END: SP--; } #endif