/* comdefs.cpp XIDEK: Extensible Script Language Development Kit Common code. Copyright (c) 1996-2002 Parsifal Software. All Rights Reserved. For further information about this program or the AnaGram parser generator, please contact: Parsifal Software http://www.parsifalsoft.com info@parsifalsoft.com +1-800-879-2577, Voice/Fax +1-508-358-2564 P.O. Box 219 Wayland, MA 01778 USA */ #include "comdefs.h" #include #include static const char *argRangeMsg = "Argument out of range"; static const char *hashUndefinedMsg = "Hash is not defined"; static const char *notIntegerMsg = "Operand is not an integer"; static const char *notLvalueMsg = "Not an lvalue"; static const char *notPointerMsg = "Operand is not a pointer"; static const char *notScalarMsg = "Operand is not scalar"; static const char *notStringMsg = "Operand is not a string"; static const char *notSupportedMsg = "Function not supported"; static const char *opUndefinedMsg = "Operation not defined"; static const char *uninitMsg = "Operand is not initialized"; static const char *uninitValueMsg = "Unitialized value"; static const char *wrongCountMsg = "Incorrect number of arguments"; static const char *zeroDivisorMsg = "Divide by zero"; ErrorMessage::ErrorMessage(const AgString &m) : msg(m) { // Nothing to do } const char *ErrorMessage::message() const { return (const char *) msg; } ErrorDiagnostic::ErrorDiagnostic(const AgString &m) : msg(m) { // Nothing to do } const char *ErrorDiagnostic::message() const { return (const char *) msg; } /*** Value class ************************************************************/ // Constructors Value::Value() : type(uninitType), value(0) {} Value::Value(int x) : type(integerType), value(x) {} Value::Value(long x) : type(integerType), value(x) {} Value::Value(double x, Type t) : type(t), value(x) { assertScalar(); } Value::Value(const AgString &s) : type(stringType), value(0) { new(&value) ValueWrapper(s); } Value::Value(Value *p) : type(pointerType), pointer(p) {} Value::Value(const Value &v) : type(v.type), value(0) { setValue(v); } Value &Value::setValue(const Value &v) { type = v.type; switch (type) { case integerType: case realType: value = v.value; break; case stringType: { new(&value) ValueWrapper(v.getString()); break; } case pointerType: pointer = v.pointer; break; } return *this; } // Value class destructor Value::~Value() { switch (type) { case stringType: { ValueWrapper *wrapper =(ValueWrapper *) &value; delete wrapper; break; } } } // Value class hash function // Only used for constant values int Value::hash(int hashcode) const { switch (type) { default: throw ErrorMessage(hashUndefinedMsg); case integerType: case realType: hashcode = agABTHash(value, hashcode); break; case stringType: hashcode = agABTHash((AgString &) *((ValueWrapper *) &value), hashcode); break; } return hashcode; } // Error checking void Value::assertInitialized() const { if (type != uninitType) return; throw ErrorMessage(uninitMsg); } void Value::assertScalar() const { if (type == integerType || type == realType) return; throw ErrorMessage(notScalarMsg); } void Value::assertString() const { if (type == stringType) return; throw ErrorMessage(notStringMsg); } void Value::assertPointer() const { if (type == pointerType) return; throw ErrorMessage(notPointerMsg); } void Value::assertInteger() const { if (type == integerType) return; throw ErrorMessage(notIntegerMsg); } Value &Value::deref() { switch (type) { default: throw ErrorMessage(notLvalueMsg); case pointerType: { setValue(*pointer); break; } } return *this; } int Value::isTrue() const { int returnValue; switch (type) { default: throw ErrorMessage(opUndefinedMsg); case stringType: returnValue = (getString().size() != 0); break; case integerType: case realType: returnValue = (value != 0); break; } return returnValue; } // Type conversions Value &Value::makeInteger() { assertScalar(); type = integerType; value = (long) value; return *this; } Value &Value::makeReal() { assertScalar(); type = realType; return *this; } AgString Value::asString() const { char buf[40]; switch (type) { case pointerType: return pointer->asString(); case integerType: sprintf(buf, "%ld", (long) value); break; case realType: sprintf(buf, "%G", value); break; case stringType: return getString(); default: return AgString(uninitValueMsg); } return AgString(buf); } AgString Value::asLiteral() const { if (type != stringType) return asString(); const char *s = getString(); AgString newString; newString.append('"'); while (*s) { unsigned char c = *s++; switch (c) { case '\'': newString.append("\\\'"); break; case '\"': newString.append("\\\""); break; case '\?': newString.append("\\?"); break; case '\\': newString.append("\\\\"); break; case '\a': newString.append("\\a"); break; case '\b': newString.append("\\b"); break; case '\f': newString.append("\\f"); break; case '\n': newString.append("\\n"); break; case '\r': newString.append("\\r"); break; case '\t': newString.append("\\t"); break; case '\v': newString.append("\\v"); break; default: newString.append(c); break; } } newString.append('"'); return newString; } Value Value::rdiv(const Value &divisor) { Value v(*this); if (v.type == integerType) v.type = realType; return v /= divisor; } Value Value::idiv(const Value &divisor) { assertInteger(); divisor.assertInteger(); Value v(*this); return v /= divisor; } // Operator overloads const Value &Value::operator = (const Value &v) { // check destination type switch (type) { case pointerType: return *pointer = v; case stringType: { ValueWrapper *wrapper =(ValueWrapper *) &value; delete wrapper; break; } } setValue(v); return *this; } const Value &Value::operator += (const Value &v) { switch (type) { default: throw ErrorMessage(opUndefinedMsg); case pointerType: return *pointer += v; case stringType: getString().append(v.asString()); break; case integerType: if (v.type == realType) type = realType; case realType: { value += v.value; break; } } return *this; } const Value &Value::operator -= (const Value &v) { switch (type) { default: throw ErrorMessage(notScalarMsg); case pointerType: return *pointer -= v; case integerType: if (v.type == realType) type = realType; case realType: value -= v.value; break; } return *this; } const Value &Value::operator *= (const Value &v) { switch (type) { default: throw ErrorMessage(notScalarMsg); case pointerType: return *pointer *= v; case integerType: if (v.type == realType) type = realType; case realType: value *= v.value; break; } return *this; } const Value &Value::operator /= (const Value &v) { switch (type) { case pointerType: return *pointer /= v; case integerType: if (v.type == integerType) { if (v.value == 0) throw ErrorMessage(zeroDivisorMsg); value = (long) value / (long) v.value; return *this; } } assertScalar(); v.assertScalar(); if (type < v.type) type = v.type; if (v.value == 0) throw ErrorMessage(zeroDivisorMsg); value /= v.value; return *this; } // Integer operations const Value &Value::operator %= (const Value &v) { switch (type) { default: throw ErrorMessage(notIntegerMsg); case pointerType: return *pointer %= v; case integerType: long k = v.getLong(); if (k == 0) throw ErrorMessage(zeroDivisorMsg); value = (long) value % k; break; } return *this; } const Value &Value::operator &= (const Value &v) { switch (type) { default: throw ErrorMessage(notIntegerMsg); case pointerType: return *pointer &= v; case integerType: value = (long) value & v.getLong(); break; } return *this; } const Value &Value::operator |= (const Value &v) { switch (type) { default: throw ErrorMessage(notIntegerMsg); case pointerType: return *pointer |= v; case integerType: value = (long) value | v.getLong(); break; } return *this; } const Value &Value::operator ^= (const Value &v) { switch (type) { default: throw ErrorMessage(notIntegerMsg); case pointerType: return *pointer ^= v; case integerType: value = (long) value ^ v.getLong(); break; } return *this; } const Value &Value::operator <<= (const Value &v) { switch (type) { default: throw ErrorMessage(notIntegerMsg); case pointerType: return *pointer <<= v; case integerType: value = (long) value << v.getLong(); break; } return *this; } const Value &Value::operator >>= (const Value &v) { switch (type) { default: throw ErrorMessage(notIntegerMsg); case pointerType: return *pointer >>= v; case integerType: value = (long) value >> v.getLong(); break; } return *this; } int Value::operator < (const Value &v) const { int returnValue; switch (type) { default: throw ErrorMessage(opUndefinedMsg); case integerType: case realType: { v.assertScalar(); returnValue = (value < v.value); break; } case stringType: { v.assertString(); returnValue = (getString() < v.getString()); break; } } return returnValue; } int Value::operator == (const Value &v) const { switch (type) { case integerType: case realType: { if (v.type == realType || v.type == integerType) return value == v.value; break; } case stringType: { if (v.type == stringType) return getString() == v.getString(); break; } } return 0; } Value Value::operator -() const { assertScalar(); return Value(-value, type); } // Postincrement operator Value Value::operator ++(int) { Value result; switch (type) { default: throw ErrorMessage(notIntegerMsg); case pointerType: return (*pointer)++; case integerType: { result = Value(value++); break; } } return result; } // Postdecrement operator Value Value::operator --(int) { Value result; switch (type) { default: throw ErrorMessage(notIntegerMsg); case pointerType: return (*pointer)--; case integerType: { result = Value(value--); break; } } return result; } // Preincreement operator Value Value::operator ++() { Value result; switch (type) { default: throw ErrorMessage(notIntegerMsg); case pointerType: return ++(*pointer); case integerType: { result = Value(++value); break; } } return result; } // Predecrement operator Value Value::operator --() { Value result; switch (type) { default: throw ErrorMessage(notIntegerMsg); case pointerType: return --(*pointer); case integerType: { result = Value(--value); break; } } return result; } /*** Dataset class **********************************************************/ // Construct a Dataset Dataset::Dataset(AgDictionary &d) : dictionary(d), data() { // Nothing to do } // Copy constructor for Dataset Dataset::Dataset(const Dataset &d) : dictionary(d.dictionary), data(d.data) {} // Access the value of a variable by index Value &Dataset::operator[] (int x) { while (data.size() < dictionary.size()) data.push(Value()); return data[x]; } // Access the value of a variable by name. Value &Dataset::value(const AgString &n) { return operator [] (dictionary.intern(n)); } /*** function objects and the function table ********************************/ void FunctionObject::notDefined() { throw ErrorMessage(wrongCountMsg); } // natural logarithm function static struct LogObject : public FunctionObject { Value oneArg(const Value &x) { double arg = x.getDouble(); if (arg <= 0) throw ErrorMessage(argRangeMsg); return Value(log(arg)); } } logObject; // exponential function static struct ExpObject : public FunctionObject { Value oneArg(const Value &x) { return Value(exp(x.getDouble())); } } expObject; // square root function static struct SqrtObject : public FunctionObject { Value oneArg(const Value &x) { return Value(sqrt(x.getDouble())); } } sqrtObject; // sine function static struct SinObject : public FunctionObject { Value oneArg(const Value &x) { return Value(sin(x.getDouble())); } } sinObject; // arc sin function static struct AsinObject : public FunctionObject { Value oneArg(const Value &x) { double arg = x.getDouble(); if (arg < -1 || arg > 1) throw ErrorMessage(argRangeMsg); return Value(asin(arg)); } } asinObject; // cosine function static struct CosObject : public FunctionObject { Value oneArg(const Value &x) { return Value(cos(x.getDouble())); } } cosObject; // arc cosine function static struct AcosObject : public FunctionObject { Value oneArg(const Value &x) { double arg = x.getDouble(); if (arg < -1 || arg > 1) throw ErrorMessage(argRangeMsg); return Value(acos(arg)); } } acosObject; // tangent function static struct TanObject : public FunctionObject { Value oneArg(const Value &x) { return Value(tan(x.getDouble())); } } tanObject; // arc tangent function, takes one or two arguments static struct AtanObject : public FunctionObject { Value oneArg(const Value &x) { return Value(atan(x.getDouble())); } Value twoArgs(const Value &x, const Value &y) { return Value(atan2(x.getDouble(), y.getDouble())); } } atanObject; // function table const FunctionDescriptor functionTable[] = { {"log", 1, &logObject}, {"exp", 1, &expObject}, {"sqrt", 1, &sqrtObject}, {"sin", 1, &sinObject}, {"asin", 1, &asinObject}, {"cos", 1, &cosObject}, {"acos", 1, &acosObject}, {"tan", 1, &tanObject}, {"atan", 1, &atanObject}, {"atan", 2, &atanObject}, {0,0,0} }; int idFunction(const AgString &name, int argCount) { int i; for (i = 0; functionTable[i].name; i++) { const FunctionDescriptor &f = functionTable[i]; if (name == f.name && argCount == f.argCount) break; } if (functionTable[i].name == NULL) throw ErrorMessage(notSupportedMsg); return i; } Value callFunction(const AgString &name, AgStack &args) { return callFunction(idFunction(name, args.size()), args); } Value callFunction(int i, AgStack &args) { const FunctionDescriptor &f = functionTable[i]; Value a0, a1; switch (f.argCount) { case 1: a0 = args.pop(); return f.function->oneArg(a0); case 2: a1 = args.pop(); a0 = args.pop(); return f.function->twoArgs(a0, a1); } return Value(); } /*** External Functions *****************************************************/ Value pow(const Value &base, const Value &exponent) { return Value(pow(base.getDouble(), exponent.getDouble())); } // What was thought to be an octal number turns out to be decimal. // Undo the octal representation and make it decimal. long makeDecimal(long octal) { int digits[20]; int k = 0; // Peel off octal digits do digits[k++] = octal/8; while ((octal /= 8) != 0); int decimal = 0; // Reconvert as decimal while (k--) decimal = 10*decimal + digits[k]; return decimal; }