#include #include #include #include #include #include "value.h" #include "nt.h" #include "lextypes.h" // Globals Value value_none; // Special empty value static int64_t fast_power(int64_t b, int64_t e); void Value::convertToInt(Value& v) const { v.value_type = VALUE_TYPE_INT; if (value_type == VALUE_TYPE_INT) { v.int_value = int_value; } else if (value_type == VALUE_TYPE_DOUBLE) { v.int_value = (int) double_value; } else if (value_type == VALUE_TYPE_STRING) { v.int_value = atoi(string_value.c_str()); } else { throw InterpretatorException("Cannot convert value to int"); } } void Value::convertToDouble(Value& v) const { v.value_type = VALUE_TYPE_DOUBLE; if (value_type == VALUE_TYPE_INT) { v.double_value = int_value; } else if (value_type == VALUE_TYPE_DOUBLE) { v.double_value = double_value; } else if (value_type == VALUE_TYPE_STRING) { v.double_value = atof(string_value.c_str()); } else { throw InterpretatorException("Cannot convert value to double"); } } void Value::convertToString(Value& v) const { char line[64]; v.value_type = VALUE_TYPE_STRING; if (value_type == VALUE_TYPE_INT) { sprintf(line, "%lld", (long long) int_value); v.string_value = line; } else if (value_type == VALUE_TYPE_DOUBLE) { sprintf(line, "%g", double_value); v.string_value = line; } else if (value_type == VALUE_TYPE_STRING) { v.string_value = string_value; } else if (value_type == VALUE_TYPE_ARRAY) { v.string_value = "["; for (size_t i = 0; i < array_value.size(); ++i) { Value w; array_value[i].convertToString(w); if (i > 0) v.string_value += ", "; v.string_value += w.string_value; } v.string_value += "]"; } else if (value_type == VALUE_TYPE_FUNCTION) { v.string_value = "function " + string_value; } else if (value_type == VALUE_TYPE_STANDARD_FUNCTION) { v.string_value = "standard function " + string_value; } else { //.. throw InterpretatorException("Cannot convert value to string"); v.string_value = "none"; } } void Value::add( const Value& v0, const Value& v1, Value& res ) { assert(!v0.isLValue() && !v1.isLValue()); if ( v0.isFunction() || v1.isFunction() || v0.isStandardFunction() || v1.isStandardFunction() ) throw InterpretatorException("Cannot add functions"); //... if (!(v0.isNumber() && v1.isNumber())) //... throw InterpretatorException("Illegal operands of sum"); if (v0.isInt() && v1.isInt()) { res.value_type = VALUE_TYPE_INT; res.int_value = v0.int_value + v1.int_value; } else if (v0.isNumber() && v1.isNumber()) { double x; if (v0.isInt()) x = (double) v0.int_value; else x = v0.double_value; double y; if (v1.isInt()) y = (double) v1.int_value; else y = v1.double_value; res.value_type = VALUE_TYPE_DOUBLE; res.double_value = x + y; } else if (!v0.isArray() && !v1.isArray()) { res.value_type = VALUE_TYPE_STRING; res.string_value = ""; if (v0.isString()) { res.string_value += v0.string_value; } else { Value tmp; v0.convertToString(tmp); res.string_value += tmp.string_value; } if (v1.isString()) { res.string_value += v1.string_value; } else { Value tmp; v1.convertToString(tmp); res.string_value += tmp.string_value; } } else if (v0.isArray() && v1.isArray()) { res.value_type = VALUE_TYPE_ARRAY; res.array_value = v0.array_value; for (size_t i = 0; i < v1.array_value.size(); ++i) { res.array_value.push_back(v1.array_value[i]); } } else { throw InterpretatorException("Cannot add values"); } } void Value::sub( const Value& v0, const Value& v1, Value& res ) { assert(!v0.isLValue() && !v1.isLValue()); if (!(v0.isNumber() && v1.isNumber())) throw InterpretatorException("Illegal operands of subtraction"); if (v0.value_type == VALUE_TYPE_INT) { if (v1.value_type == VALUE_TYPE_INT) { res.value_type = VALUE_TYPE_INT; res.int_value = v0.int_value - v1.int_value; } else { assert(v1.value_type == VALUE_TYPE_DOUBLE); res.value_type = VALUE_TYPE_DOUBLE; res.double_value = (double) v0.int_value - v1.double_value; } } else { assert(v0.value_type == VALUE_TYPE_DOUBLE); res.value_type = VALUE_TYPE_DOUBLE; if (v1.value_type == VALUE_TYPE_INT) { res.double_value = v0.double_value - (double) v1.int_value; } else { assert(v1.value_type == VALUE_TYPE_DOUBLE); res.double_value = v0.double_value - v1.double_value; } } } void Value::mul( const Value& v0, const Value& v1, Value& res ) { assert(!v0.isLValue() && !v1.isLValue()); if (!(v0.isNumber() && v1.isNumber())) throw InterpretatorException("Illegal operands of product"); if (v0.value_type == VALUE_TYPE_INT) { if (v1.value_type == VALUE_TYPE_INT) { res.value_type = VALUE_TYPE_INT; res.int_value = v0.int_value * v1.int_value; } else { assert(v1.value_type == VALUE_TYPE_DOUBLE); res.value_type = VALUE_TYPE_DOUBLE; res.double_value = (double) v0.int_value * v1.double_value; } } else { assert(v0.value_type == VALUE_TYPE_DOUBLE); res.value_type = VALUE_TYPE_DOUBLE; if (v1.value_type == VALUE_TYPE_INT) { res.double_value = v0.double_value * (double) v1.int_value; } else { assert(v1.value_type == VALUE_TYPE_DOUBLE); res.double_value = v0.double_value * v1.double_value; } } } void Value::div( const Value& v0, const Value& v1, Value& res ) { assert(!v0.isLValue() && !v1.isLValue()); if (!(v0.isNumber() && v1.isNumber())) throw InterpretatorException("Illegal operands of division"); if (v0.value_type == VALUE_TYPE_INT) { if (v1.value_type == VALUE_TYPE_INT) { res.value_type = VALUE_TYPE_INT; if (v1.int_value == 0) throw InterpretatorException("Integer zero division"); res.int_value = v0.int_value / v1.int_value; } else { assert(v1.value_type == VALUE_TYPE_DOUBLE); res.value_type = VALUE_TYPE_DOUBLE; if (v1.double_value == 0) throw InterpretatorException("Float zero division"); res.double_value = (double) v0.int_value / v1.double_value; } } else { assert(v0.value_type == VALUE_TYPE_DOUBLE); res.value_type = VALUE_TYPE_DOUBLE; if (v1.value_type == VALUE_TYPE_INT) { if (v1.int_value == 0) throw InterpretatorException("Float zero division"); res.double_value = v0.double_value / (double) v1.int_value; } else { assert(v1.value_type == VALUE_TYPE_DOUBLE); res.double_value = v0.double_value / v1.double_value; } } } void Value::mod( const Value& v0, const Value& v1, Value& res ) { assert(!v0.isLValue() && !v1.isLValue()); if (!(v0.isNumber() && v1.isNumber())) throw InterpretatorException("Illegal operands of mod"); if (v0.value_type == VALUE_TYPE_INT) { if (v1.value_type == VALUE_TYPE_INT) { res.value_type = VALUE_TYPE_INT; if (v1.int_value == 0) throw InterpretatorException("Integer zero division"); res.int_value = v0.int_value % v1.int_value; } else { assert(v1.value_type == VALUE_TYPE_DOUBLE); res.value_type = VALUE_TYPE_DOUBLE; if (v1.double_value == 0) throw InterpretatorException("Float zero division"); res.double_value = fmod( (double) v0.int_value, v1.double_value ); } } else { assert(v0.value_type == VALUE_TYPE_DOUBLE); res.value_type = VALUE_TYPE_DOUBLE; if (v1.value_type == VALUE_TYPE_INT) { if (v1.int_value == 0) throw InterpretatorException("Float zero division"); res.double_value = fmod( (double) v0.double_value, (double) v1.int_value ); } else { assert(v1.value_type == VALUE_TYPE_DOUBLE); res.double_value = fmod(v0.double_value, v1.double_value); } } } void Value::power( const Value& v0, const Value& v1, Value& res ) { assert(!v0.isLValue() && !v1.isLValue()); if (!(v0.isNumber() && v1.isNumber())) throw InterpretatorException("Illegal operands of power"); if ( v0.value_type == VALUE_TYPE_INT && v1.value_type == VALUE_TYPE_INT && v1.int_value >= 0 ) { res.value_type = VALUE_TYPE_INT; res.int_value = fast_power(v0.int_value, v1.int_value); } else { res.value_type = VALUE_TYPE_DOUBLE; double b = 0.; if (v0.value_type == VALUE_TYPE_DOUBLE) { b = v0.double_value; } else { assert(v0.value_type == VALUE_TYPE_INT); b = double(v0.int_value); } double e = 0.; if (v1.value_type == VALUE_TYPE_DOUBLE) { e = v1.double_value; } else { assert(v1.value_type == VALUE_TYPE_INT); e = double(v1.int_value); } res.double_value = pow(b, e); } } void Value::negate( const Value& v0, Value& res ) { assert(!v0.isLValue()); if (!v0.isNumber()) throw InterpretatorException("Illegal operands of unary minus"); if (v0.value_type == VALUE_TYPE_INT) { res.value_type = VALUE_TYPE_INT; res.int_value = (-v0.int_value); } else { assert(v0.value_type == VALUE_TYPE_DOUBLE); res.value_type = VALUE_TYPE_DOUBLE; res.double_value = (-v0.double_value); } } void Value::compare( // static methos const Value& v0, const Value& v1, Value& res ) { if (!( (v0.isNumber() && v1.isNumber()) || (v0.isString() && v1.isString()) || (v0.isArray() && v1.isArray()) || v0.isFunction() || v1.isFunction() || v0.isStandardFunction() || v1.isStandardFunction() )) throw InterpretatorException("Illegal operands of comparing"); if (v0.isNumber() && v1.isNumber()) { Value s; sub(v0, v1, s); if (s.value_type != VALUE_TYPE_INT) { assert(s.value_type == VALUE_TYPE_DOUBLE); if (s.double_value < 0.) s.int_value = (-1); else if (s.double_value > 0.) s.int_value = 1; else s.int_value = 0; s.value_type = VALUE_TYPE_INT; } res = s; } else if (v0.isString() && v1.isString()) { int s = v0.string_value.compare(v1.string_value); res.value_type = VALUE_TYPE_INT; res.int_value = s; } else { assert(v0.isArray() && v1.isArray()); res.value_type = VALUE_TYPE_INT; res.int_value = 0; for (size_t i = 0; i < v0.array_value.size(); ++i) { if (i >= v1.array_value.size()) { res.int_value = 1; return; } Value v; Value::compare( v0.array_value[i], v1.array_value[i], v ); if (v.int_value != 0) { res.int_value = v.int_value; return; } } if (v0.array_value.size() < v1.array_value.size()) res.int_value = (-1); assert( v0.array_value.size() == v1.array_value.size() && res.int_value == 0 ); } } void Value::print() const { if (isInt()) { printf("%lld", (long long) int_value); } else if (isDouble()) { printf("%g", double_value); } else if (isString()) { printf("%s", string_value.c_str()); } else if (isArray()) { Value v; convertToString(v); printf("%s", v.string_value.c_str()); } else if (isArrayElement()) { printf( "array element %s[%lld]", string_value.c_str(), (long long) int_value ); } else if (isVariable()) { printf("variable %s", string_value.c_str()); } else if (isFunction()) { printf("function %s", string_value.c_str()); } else if (isStandardFunction()) { printf("standard function %s", string_value.c_str()); } else { printf( "value type=%d int=%lld double=%g str=\"%s\"", value_type, (long long) int_value, double_value, string_value.c_str() ); } } void Value::scan() { //... This is done now in interpreter //... if (!isLValue()) //... throw InterpretatorException("Incorrect input: no l-value"); // We always input a string char line[1024]; fgets(line, 1022, stdin); line[1022] = 0; int len = strlen(line); if (len > 0 && line[len-1] == '\n') { line[len-1] = 0; --len; } if (len > 0 && line[len-1] == '\r') { line[len-1] = 0; --len; } value_type = VALUE_TYPE_STRING; string_value = line; int_value = 0; double_value = 0.; array_value.clear(); } void Value::array_append( Value& v0, const Value& v1 ) { if (!(v0.isArray())) throw InterpretatorException("Cannot append to object"); v0.array_value.push_back(v1); } void Value::clear() { //... value_type = 0; int_value = 0; double_value = 0.; string_value.clear(); array_value.clear(); } static int64_t fast_power(int64_t b, int64_t e) { int64_t p = 1; while (e > 0) { if (e%2 == 0) { e /= 2; b *= b; } else { --e; p *= b; } } return p; }