File indexing completed on 2024-12-22 04:17:54
0001 /*************************************************************************** 0002 enodes.cpp 0003 ---------- 0004 begin : Feb 12 2004 0005 copyright : (C) 2004 The University of Toronto 0006 email : netterfield@astro.utoronto.ca 0007 ***************************************************************************/ 0008 0009 /*************************************************************************** 0010 * * 0011 * This program is free software; you can redistribute it and/or modify * 0012 * it under the terms of the GNU General Public License as published by * 0013 * the Free Software Foundation; either version 2 of the License, or * 0014 * (at your option) any later version. * 0015 * * 0016 ***************************************************************************/ 0017 0018 #include "enodes.h" 0019 0020 #include <assert.h> 0021 #include <math.h> 0022 #include <stdlib.h> 0023 #include <string.h> 0024 #include <qnamespace.h> 0025 #ifndef Q_OS_WIN32 0026 #include <unistd.h> 0027 #else 0028 #define strcasecmp _stricmp 0029 #endif 0030 0031 0032 0033 #include <QMutex> 0034 #include <QRegExp> 0035 0036 #include "datacollection.h" 0037 #include "debug.h" 0038 #include "math_kst.h" 0039 #include "objectstore.h" 0040 #include "doublecompare.h" 0041 0042 KSTMATH_EXPORT int yyparse(Kst::ObjectStore *store); 0043 KSTMATH_EXPORT extern void *ParsedEquation; 0044 KSTMATH_EXPORT/*"C"*/ struct yy_buffer_state *yy_scan_string(const char*); 0045 KSTMATH_EXPORT struct yy_buffer_state *yy_scan_bytes(const char*, int); 0046 typedef struct yy_buffer_state *YY_BUFFER_STATE; 0047 KSTMATH_EXPORT void yy_delete_buffer(YY_BUFFER_STATE); 0048 0049 using namespace Equations; 0050 using namespace Kst; 0051 0052 static QMutex _mutex; 0053 0054 QMutex& Equations::mutex() { 0055 return _mutex; 0056 } 0057 0058 0059 double Equations::interpret(ObjectStore *store, const char *txt, bool *ok, int len) { 0060 if (!txt || !*txt) { 0061 if (ok) { 0062 *ok = false; 0063 } 0064 return 0.0; 0065 } 0066 0067 mutex().lock(); 0068 YY_BUFFER_STATE b; 0069 if (len > 0) { 0070 b = yy_scan_bytes(txt, len); 0071 } else { 0072 b = yy_scan_string(txt); 0073 } 0074 int rc = yyparse(store); 0075 yy_delete_buffer(b); 0076 if (rc == 0) { 0077 Equations::Node *eq = static_cast<Equations::Node*>(ParsedEquation); 0078 ParsedEquation = 0L; 0079 mutex().unlock(); 0080 Equations::Context ctx; 0081 ctx.sampleCount = 2; 0082 ctx.noPoint = Kst::NOPOINT; 0083 ctx.x = 0.0; 0084 ctx.xVector = 0L; 0085 Equations::FoldVisitor vis(&ctx, &eq); 0086 double v = eq->value(&ctx); 0087 delete eq; 0088 if (ok) { 0089 *ok = true; 0090 } 0091 return v; 0092 } else { 0093 ParsedEquation = 0L; 0094 mutex().unlock(); 0095 if (ok) { 0096 *ok = false; 0097 } 0098 return 0.0; 0099 } 0100 } 0101 0102 0103 Node::Node() { 0104 _parentheses = false; 0105 } 0106 0107 0108 Node::~Node() { 0109 } 0110 0111 0112 bool Node::collectObjects(Kst::VectorMap&, Kst::ScalarMap&, Kst::StringMap&) { 0113 return true; 0114 } 0115 0116 0117 bool Node::takeVectors(const Kst::VectorMap&) { 0118 return true; 0119 } 0120 0121 0122 void Node::visit(NodeVisitor* v) { 0123 v->visitNode(this); 0124 } 0125 0126 0127 Kst::Object::UpdateType Node::update(Context *ctx) { 0128 Q_UNUSED(ctx) 0129 return Kst::Object::NoChange; 0130 } 0131 0132 0133 ///////////////////////////////////////////////////////////////// 0134 BinaryNode::BinaryNode(Node *left, Node *right) 0135 : Node(), _left(left), _right(right) { 0136 } 0137 0138 0139 BinaryNode::~BinaryNode() { 0140 delete _left; 0141 _left = 0L; 0142 delete _right; 0143 _right = 0L; 0144 } 0145 0146 0147 bool BinaryNode::collectObjects(Kst::VectorMap& v, Kst::ScalarMap& s, Kst::StringMap& t) { 0148 bool ok = true; 0149 ok = _left->collectObjects(v, s, t) ? ok : false; 0150 ok = _right->collectObjects(v, s, t) ? ok : false; 0151 return ok; 0152 } 0153 0154 0155 bool BinaryNode::takeVectors(const Kst::VectorMap& c) { 0156 bool rc = _left->takeVectors(c); 0157 rc = _right->takeVectors(c) && rc; 0158 return rc; 0159 } 0160 0161 0162 void BinaryNode::visit(NodeVisitor* v) { 0163 v->visitBinaryNode(this); 0164 } 0165 0166 0167 Node *& BinaryNode::left() { 0168 return _left; 0169 } 0170 0171 0172 Node *& BinaryNode::right() { 0173 return _right; 0174 } 0175 0176 0177 Kst::Object::UpdateType BinaryNode::update(Context *ctx) { 0178 Kst::Object::UpdateType l = _left->update(ctx); 0179 Kst::Object::UpdateType r = _right->update(ctx); 0180 0181 return (l == Kst::Object::Updated || r == Kst::Object::Updated) ? Kst::Object::Updated : Kst::Object::NoChange; 0182 } 0183 0184 0185 ///////////////////////////////////////////////////////////////// 0186 Addition::Addition(Node *left, Node *right) 0187 : BinaryNode(left, right) { 0188 //printf("%p: New Addition: %p + %p\n", (void*)this, (void*)left, (void*)right); 0189 } 0190 0191 0192 Addition::~Addition() { 0193 } 0194 0195 0196 double Addition::value(Context *ctx) { 0197 return _left->value(ctx) + _right->value(ctx); 0198 } 0199 0200 0201 bool Addition::isConst() { 0202 return _left->isConst() && _right->isConst(); 0203 } 0204 0205 0206 QString Addition::text() const { 0207 if (_parentheses) { 0208 return QString('(') + _left->text() + '+' + _right->text() + ')'; 0209 } else { 0210 return _left->text() + '+' + _right->text(); 0211 } 0212 } 0213 0214 0215 ///////////////////////////////////////////////////////////////// 0216 Subtraction::Subtraction(Node *left, Node *right) 0217 : BinaryNode(left, right) { 0218 //printf("%p: New Subtraction: %p - %p\n", (void*)this, (void*)left, (void*)right); 0219 } 0220 0221 0222 Subtraction::~Subtraction() { 0223 } 0224 0225 0226 double Subtraction::value(Context *ctx) { 0227 return _left->value(ctx) - _right->value(ctx); 0228 } 0229 0230 0231 bool Subtraction::isConst() { 0232 return _left->isConst() && _right->isConst(); 0233 } 0234 0235 0236 QString Subtraction::text() const { 0237 if (_parentheses) { 0238 return QString('(') + _left->text() + '-' + _right->text() + ')'; 0239 } else { 0240 return _left->text() + '-' + _right->text(); 0241 } 0242 } 0243 0244 0245 ///////////////////////////////////////////////////////////////// 0246 Multiplication::Multiplication(Node *left, Node *right) 0247 : BinaryNode(left, right) { 0248 //printf("%p: New Multiplication: %p - %p\n", (void*)this, (void*)left, (void*)right); 0249 } 0250 0251 0252 Multiplication::~Multiplication() { 0253 } 0254 0255 0256 double Multiplication::value(Context *ctx) { 0257 return _left->value(ctx) * _right->value(ctx); 0258 } 0259 0260 0261 bool Multiplication::isConst() { 0262 return _left->isConst() && _right->isConst(); 0263 } 0264 0265 0266 QString Multiplication::text() const { 0267 if (_parentheses) { 0268 return QString('(') + _left->text() + '*' + _right->text() + ')'; 0269 } else { 0270 return _left->text() + '*' + _right->text(); 0271 } 0272 } 0273 0274 0275 ///////////////////////////////////////////////////////////////// 0276 Division::Division(Node *left, Node *right) 0277 : BinaryNode(left, right) { 0278 //printf("%p: New Division: %p - %p\n", (void*)this, (void*)left, (void*)right); 0279 } 0280 0281 0282 Division::~Division() { 0283 } 0284 0285 0286 double Division::value(Context *ctx) { 0287 return _left->value(ctx) / _right->value(ctx); 0288 } 0289 0290 0291 bool Division::isConst() { 0292 return _left->isConst() && _right->isConst(); 0293 } 0294 0295 0296 QString Division::text() const { 0297 if (_parentheses) { 0298 return QString('(') + _left->text() + '/' + _right->text() + ')'; 0299 } else { 0300 return _left->text() + '/' + _right->text(); 0301 } 0302 } 0303 0304 0305 ///////////////////////////////////////////////////////////////// 0306 Modulo::Modulo(Node *left, Node *right) 0307 : BinaryNode(left, right) { 0308 //printf("%p: New Modulo: %p - %p\n", (void*)this, (void*)left, (void*)right); 0309 } 0310 0311 0312 Modulo::~Modulo() { 0313 } 0314 0315 0316 double Modulo::value(Context *ctx) { 0317 return fmod(_left->value(ctx), _right->value(ctx)); 0318 } 0319 0320 0321 bool Modulo::isConst() { 0322 return _left->isConst() && _right->isConst(); 0323 } 0324 0325 0326 QString Modulo::text() const { 0327 if (_parentheses) { 0328 return QString('(') + _left->text() + '%' + _right->text() + ')'; 0329 } else { 0330 return _left->text() + '%' + _right->text(); 0331 } 0332 } 0333 0334 0335 ///////////////////////////////////////////////////////////////// 0336 Power::Power(Node *left, Node *right) 0337 : BinaryNode(left, right) { 0338 //printf("%p: New Power: %p - %p\n", (void*)this, (void*)left, (void*)right); 0339 } 0340 0341 0342 Power::~Power() { 0343 } 0344 0345 0346 double Power::value(Context *ctx) { 0347 return pow(_left->value(ctx), _right->value(ctx)); 0348 } 0349 0350 0351 bool Power::isConst() { 0352 return _left->isConst() && _right->isConst(); 0353 } 0354 0355 0356 QString Power::text() const { 0357 if (_parentheses) { 0358 return QString('(') + _left->text() + '^' + _right->text() + ')'; 0359 } else { 0360 return _left->text() + '^' + _right->text(); 0361 } 0362 } 0363 0364 0365 ///////////////////////////////////////////////////////////////// 0366 0367 static double cot(double x) { 0368 return 1.0/tan(x); 0369 } 0370 0371 0372 static double csc(double x) { 0373 return 1.0/sin(x); 0374 } 0375 0376 0377 static double sec(double x) { 0378 return 1.0/cos(x); 0379 } 0380 0381 static double acosd(double x) { 0382 return 180.0/M_PI*acos(x); 0383 } 0384 0385 static double asind(double x) { 0386 return 180.0/M_PI*asin(x); 0387 } 0388 0389 static double atand(double x) { 0390 return 180.0/M_PI*atan(x); 0391 } 0392 0393 static double cosd(double x) { 0394 return cos(fmod(x, 360.0)*M_PI/180.0); 0395 } 0396 0397 static double cotd(double x) { 0398 return cot(fmod(x, 360.0)*M_PI/180.0); 0399 } 0400 0401 static double cscd(double x) { 0402 return csc(fmod(x, 360.0)*M_PI/180.0); 0403 } 0404 0405 static double secd(double x) { 0406 return sec(fmod(x, 360.0)*M_PI/180.0); 0407 } 0408 0409 static double sind(double x) { 0410 return sin(fmod(x, 360.0)*M_PI/180.0); 0411 } 0412 0413 static double tand(double x) { 0414 return tan(fmod(x, 360.0)*M_PI/180.0); 0415 } 0416 0417 static double atanx(double *x) { 0418 return atan2(x[0],x[1]); 0419 } 0420 0421 static double step(double x) { 0422 if (x>0.0) { 0423 return 1.0; 0424 } else { 0425 return 0.0; 0426 } 0427 } 0428 0429 0430 static struct { 0431 const char *name; 0432 double (*func)(double); 0433 } FTable[] = { 0434 {"abs", &fabs}, 0435 {"acos", &acos}, 0436 {"acosd", &acosd}, 0437 {"asin", &asin}, 0438 {"asind", &asind}, 0439 {"atan", &atan}, 0440 {"atand", &atand}, 0441 #ifndef Q_OS_WIN32 0442 {"cbrt", &cbrt}, 0443 #endif 0444 {"cos", &cos}, 0445 {"cosd", &cosd}, 0446 {"cosh", &cosh}, 0447 {"cot", &cot}, 0448 {"cotd", &cotd}, 0449 {"csc", &csc}, 0450 {"cscd", &cscd}, 0451 {"exp", &exp}, 0452 {"log", &log10}, 0453 {"ln", &log}, 0454 {"sec", &sec}, 0455 {"secd", &secd}, 0456 {"sin", &sin}, 0457 {"sind", &sind}, 0458 {"sinh", &sinh}, 0459 {"sqrt", &sqrt}, 0460 {"step", &step}, 0461 {"tan", &tan}, 0462 {"tand", &tand}, 0463 {"tanh", &tanh}, 0464 {0, 0} 0465 }; 0466 0467 static struct { 0468 const char *name; 0469 double (*func)(double*); 0470 } F2Table[] = { 0471 0472 {"atanx", &atanx}, 0473 //{"atan2d", &atand2d}, 0474 {0, 0} 0475 }; 0476 0477 Function::Function(char *name, ArgumentList *args) 0478 : Node(), _name(name), _args(args), _f(0L) { 0479 _argCount = 1; // Presently no functions take != 1 argument 0480 _inPid = 0L; 0481 _inScalars = 0L; 0482 _inVectors = 0L; 0483 _outScalars = 0L; 0484 _outVectors = 0L; 0485 _inArrayLens = 0L; 0486 _outArrayLens = 0L; 0487 _outputIndex = -424242; 0488 _localData = 0L; 0489 _outputVectorCnt = 0; 0490 _inputVectorCnt = 0; 0491 //printf("%p: New Function: %s - %p\n", (void*)this, name, (void*)args); 0492 for (int i = 0; FTable[i].name; ++i) { 0493 if (strcasecmp(FTable[i].name, name) == 0) { 0494 _f = (void*)FTable[i].func; 0495 break; 0496 } 0497 } 0498 if (!_f) { 0499 for (int i = 0; F2Table[i].name; ++i) { 0500 if (strcasecmp(F2Table[i].name, name) == 0) { 0501 _f = (void*)F2Table[i].func; 0502 _argCount = 2; 0503 break; 0504 } 0505 } 0506 } 0507 } 0508 0509 0510 Function::~Function() { 0511 free(_name); 0512 _name = 0L; 0513 delete _args; 0514 _args = 0L; 0515 _f = 0L; 0516 delete[] _inScalars; 0517 delete[] _inVectors; 0518 delete[] _outScalars; 0519 for (int i = 0; i < _outputVectorCnt; ++i) { 0520 free(_outVectors[i]); 0521 } 0522 delete[] _outVectors; 0523 delete[] _inArrayLens; 0524 delete[] _outArrayLens; 0525 } 0526 0527 0528 Kst::Object::UpdateType Function::update(Context *ctx) { 0529 _args->update(ctx); 0530 return Kst::Object::NoChange; 0531 } 0532 0533 0534 double Function::value(Context *ctx) { 0535 if (!_f) { 0536 return ctx->noPoint; 0537 } 0538 0539 if (_argCount == 1) { 0540 double x = _args->at(0, ctx); 0541 return ((double (*)(double))_f)(x); 0542 } else if (_argCount > 1) { 0543 double *x = new double[_argCount]; 0544 for (int i = 0; i < _argCount; ++i) { 0545 x[i] = _args->at(i, ctx); 0546 } 0547 double r = ((double (*)(double*))_f)(x); 0548 delete[] x; 0549 return r; 0550 } else { 0551 return ((double (*)())_f)(); 0552 } 0553 } 0554 0555 0556 bool Function::isConst() { 0557 return _args->isConst(); 0558 } 0559 0560 0561 bool Function::collectObjects(Kst::VectorMap& v, Kst::ScalarMap& s, Kst::StringMap& t) { 0562 return _args->collectObjects(v, s, t); 0563 } 0564 0565 0566 bool Function::takeVectors(const Kst::VectorMap& c) { 0567 return _args->takeVectors(c); 0568 } 0569 0570 0571 QString Function::text() const { 0572 return QString::fromLatin1(_name) + '(' + _args->text() + ')'; 0573 } 0574 0575 0576 ///////////////////////////////////////////////////////////////// 0577 ArgumentList::ArgumentList() 0578 : Node() { 0579 //printf("%p: New Argument List\n", (void*)this); 0580 } 0581 0582 0583 ArgumentList::~ArgumentList() { 0584 qDeleteAll(_args); 0585 } 0586 0587 0588 void ArgumentList::appendArgument(Node *arg) { 0589 _args.append(arg); 0590 } 0591 0592 0593 double ArgumentList::at(int arg, Context *ctx) { 0594 Node *n = _args.value(arg); // catches out-of-bounds 0595 if (n) { 0596 return n->value(ctx); 0597 } 0598 return ctx->noPoint; 0599 } 0600 0601 0602 bool ArgumentList::isConst() { 0603 foreach (Node *i, _args) { 0604 if (!i->isConst()) { 0605 return false; 0606 } 0607 } 0608 return true; 0609 } 0610 0611 0612 bool ArgumentList::collectObjects(Kst::VectorMap& v, Kst::ScalarMap& s, Kst::StringMap& t) { 0613 bool ok = true; 0614 foreach (Node *i, _args) { 0615 ok = i->collectObjects(v, s, t) ? ok : false; 0616 } 0617 return ok; 0618 } 0619 0620 0621 bool ArgumentList::takeVectors(const Kst::VectorMap& c) { 0622 bool rc = true; 0623 foreach (Node *i, _args) { 0624 rc = i->takeVectors(c) && rc; 0625 } 0626 return rc; 0627 } 0628 0629 0630 Node *ArgumentList::node(int idx) { 0631 return _args.at(idx); 0632 } 0633 0634 0635 Kst::Object::UpdateType ArgumentList::update(Context *ctx) { 0636 bool updated = false; 0637 foreach (Node *i, _args) { 0638 updated = updated || Kst::Object::Updated == i->update(ctx); 0639 } 0640 return updated ? Kst::Object::Updated : Kst::Object::NoChange; 0641 } 0642 0643 0644 QString ArgumentList::text() const { 0645 QString rc; 0646 bool first = true; 0647 QListIterator<Node*> it(_args); 0648 while (it.hasNext()) { 0649 if (!first) { 0650 rc += ", "; 0651 } else { 0652 first = false; 0653 } 0654 rc += it.next()->text(); 0655 } 0656 return rc; 0657 } 0658 0659 0660 ///////////////////////////////////////////////////////////////// 0661 static struct { 0662 const char *name; 0663 double value; 0664 } ITable[] = { 0665 {"e", 2.7128182846}, 0666 {"pi", 3.1415926536}, 0667 {0, 0.0} 0668 }; 0669 0670 Identifier::Identifier(char *name) 0671 : Node(), _name(name), _const(0L) { 0672 //printf("%p: New Identifier: %s\n", (void*)this, name); 0673 for (int i = 0; ITable[i].name; ++i) { 0674 if (strcasecmp(ITable[i].name, name) == 0) { 0675 _const = &ITable[i].value; 0676 break; 0677 } 0678 } 0679 } 0680 0681 0682 Identifier::~Identifier() { 0683 free(_name); 0684 _name = 0L; 0685 } 0686 0687 0688 const char *Identifier::name() const { 0689 return _name; 0690 } 0691 0692 0693 double Identifier::value(Context *ctx) { 0694 if (_const) { 0695 return *_const; 0696 } else if (_name[0] == 'x' && _name[1] == 0) { 0697 return ctx->x; 0698 } else { 0699 return ctx->noPoint; 0700 } 0701 } 0702 0703 0704 bool Identifier::isConst() { 0705 return _const != 0L || !(_name[0] == 'x' && _name[1] == 0); 0706 } 0707 0708 0709 QString Identifier::text() const { 0710 return _name; 0711 } 0712 0713 0714 ///////////////////////////////////////////////////////////////// 0715 DataNode::DataNode(ObjectStore *store, char *name) 0716 : Node(), _store(store), _isEquation(false), _equation(0L) { 0717 //printf("%p: New Data Object: [%s]\n", (void*)this, name); 0718 // ObjectStore *store = 0L; // FIXME: initialize this 0719 Q_ASSERT(store); 0720 if (name[0] == '=') { 0721 _tagName = QString(&name[1]).trimmed(); 0722 _isEquation = true; 0723 } else if (strchr(name, '[')) { 0724 _tagName = QString(name).trimmed(); 0725 QRegExp re("(.*)\\[(.*)\\]"); 0726 int hit = re.indexIn(_tagName); 0727 #ifdef QT5 0728 if (hit > -1 && re.captureCount() == 2) { 0729 #else 0730 if (hit > -1 && re.numCaptures() == 2) { 0731 #endif 0732 _vector = kst_cast<Vector>(store->retrieveObject(re.cap(1))); 0733 if (_vector) { 0734 _vectorIndex = re.cap(2); 0735 } 0736 } 0737 } else { 0738 _tagName = QString(name).trimmed(); 0739 ObjectPtr o = store->retrieveObject(_tagName); 0740 if (kst_cast<Vector>(o)) { 0741 _vector = kst_cast<Vector>(o); 0742 } else if (kst_cast<Scalar>(o)) { 0743 _scalar = kst_cast<Scalar>(o); 0744 } 0745 } 0746 free(name); 0747 name = 0L; 0748 } 0749 0750 0751 DataNode::~DataNode() { 0752 delete _equation; 0753 _equation = 0L; 0754 } 0755 0756 0757 double DataNode::value(Context *ctx) { 0758 if (_isEquation) { 0759 if (!_equation) { 0760 mutex().lock(); 0761 YY_BUFFER_STATE b = yy_scan_bytes(_tagName.toLatin1(), _tagName.length()); 0762 int rc = yyparse(_store); 0763 yy_delete_buffer(b); 0764 if (rc == 0 && ParsedEquation) { 0765 _equation = static_cast<Equations::Node*>(ParsedEquation); 0766 ParsedEquation = 0L; 0767 mutex().unlock(); 0768 Equations::Context ctx; 0769 ctx.sampleCount = 2; 0770 ctx.noPoint = Kst::NOPOINT; 0771 ctx.x = 0.0; 0772 ctx.xVector = 0L; 0773 Equations::FoldVisitor vis(&ctx, &_equation); 0774 } else { 0775 ParsedEquation = 0L; 0776 mutex().unlock(); 0777 _isEquation = false; 0778 return ctx->noPoint; 0779 } 0780 } 0781 return _equation->value(ctx); 0782 } else if (_vector) { 0783 if (!_equation && !_vectorIndex.isEmpty()) { 0784 mutex().lock(); 0785 YY_BUFFER_STATE b = yy_scan_bytes(_vectorIndex.toLatin1(), _vectorIndex.length()); 0786 int rc = yyparse(_store); 0787 yy_delete_buffer(b); 0788 if (rc == 0 && ParsedEquation) { 0789 _equation = static_cast<Equations::Node*>(ParsedEquation); 0790 ParsedEquation = 0L; 0791 mutex().unlock(); 0792 Equations::Context ctx; 0793 ctx.sampleCount = 2; 0794 ctx.noPoint = Kst::NOPOINT; 0795 ctx.x = 0.0; 0796 ctx.xVector = 0L; 0797 Equations::FoldVisitor vis(&ctx, &_equation); 0798 } else { 0799 ParsedEquation = 0L; 0800 mutex().unlock(); 0801 _vectorIndex.clear(); 0802 _vector = 0L; 0803 return ctx->noPoint; 0804 } 0805 } 0806 if (_equation) { 0807 // Note: should we use a fresh context here? 0808 return _vector->value(int(_equation->value(ctx))); 0809 } 0810 return _vector->interpolate(ctx->i, ctx->sampleCount); 0811 } else if (_scalar) { 0812 return _scalar->value(); 0813 } else { 0814 return ctx->noPoint; 0815 } 0816 } 0817 0818 0819 bool DataNode::isConst() { 0820 return (_isEquation && _equation) ? _equation->isConst() : false; 0821 } 0822 0823 0824 bool DataNode::collectObjects(Kst::VectorMap& v, Kst::ScalarMap& s, Kst::StringMap& t) { 0825 if (_isEquation) { 0826 if (_equation) { 0827 _equation->collectObjects(v, s, t); 0828 } 0829 } else if (_vector && !v.contains(_tagName)) { 0830 v.insert(_tagName, _vector); 0831 } else if (_scalar && !s.contains(_tagName)) { 0832 s.insert(_tagName, _scalar); 0833 } else if (!_scalar && !_vector) { 0834 Kst::Debug::self()->log(Kst::Debug::tr("Equation has unknown object [%1].").arg(_tagName), Kst::Debug::Error); 0835 return false; 0836 } 0837 return true; 0838 } 0839 0840 0841 bool DataNode::takeVectors(const Kst::VectorMap& c) { 0842 if (_isEquation) { 0843 if (_equation) { 0844 return _equation->takeVectors(c); 0845 } 0846 return false; 0847 } 0848 if (!_scalar) { 0849 if (c.contains(_tagName)) { 0850 _vector = c[_tagName]; 0851 } else { 0852 return false; 0853 } 0854 } 0855 return true; 0856 } 0857 0858 0859 Kst::Object::UpdateType DataNode::update(Context *ctx) { 0860 Q_UNUSED(ctx) 0861 if (_isEquation) { 0862 if (_equation) { 0863 //return _equation->update(ctx); 0864 } 0865 } else if (_vector) { 0866 KstWriteLocker l(_vector); 0867 //return _vector->update(); 0868 } else if (_scalar) { 0869 KstWriteLocker l(_scalar); 0870 //return _scalar->registerChange(); 0871 } 0872 //return Kst::Object::NoChange; 0873 return Kst::Object::Updated; 0874 } 0875 0876 0877 // Hack alert: [ and ] in names confuse the parser, so strip them out. 0878 QString DataNode::text() const { 0879 if (_isEquation) { 0880 return QString("[=") + _tagName + ']'; 0881 } else if (_vector) { 0882 QString Name = _vector->Name(); 0883 Name.remove("\\[").remove("\\]"); 0884 return QString('[') + Name.remove('[').remove(']') + QString(']'); 0885 } else if (_scalar) { 0886 QString Name = _scalar->Name(); 0887 Name.remove("\\[").remove("\\]"); 0888 return QString('[') + Name.remove('[').remove(']') + QString(']'); 0889 } else { 0890 return QString(); 0891 } 0892 } 0893 0894 ///////////////////////////////////////////////////////////////// 0895 Number::Number(double n) 0896 : Node(), _n(n) { 0897 } 0898 0899 0900 Number::~Number() { 0901 } 0902 0903 0904 double Number::value(Context*) { 0905 return _n; 0906 } 0907 0908 0909 bool Number::isConst() { 0910 return true; 0911 } 0912 0913 0914 QString Number::text() const { 0915 if (_parentheses) { 0916 return QString('(') + QString::number(_n, 'g', 15) + ')'; 0917 } else { 0918 return QString::number(_n, 'g', 15); 0919 } 0920 } 0921 0922 0923 ///////////////////////////////////////////////////////////////// 0924 Negation::Negation(Node *node) 0925 : Node(), _n(node) { 0926 //printf("%p: New Negation: %p\n", (void*)this, (void*)n); 0927 } 0928 0929 0930 Negation::~Negation() { 0931 delete _n; 0932 _n = 0L; 0933 } 0934 0935 0936 double Negation::value(Context *ctx) { 0937 double v = _n->value(ctx); 0938 return (v == v) ? -v : v; 0939 } 0940 0941 bool Negation::collectObjects(Kst::VectorMap& v, Kst::ScalarMap& s, Kst::StringMap& t) { 0942 bool ok = _n->collectObjects(v, s, t); 0943 return ok; 0944 } 0945 0946 0947 0948 bool Negation::isConst() { 0949 return _n->isConst(); 0950 } 0951 0952 0953 QString Negation::text() const { 0954 if (_parentheses) { 0955 return QString("(-") + _n->text() + ')'; 0956 } else { 0957 return QString('-') + _n->text(); 0958 } 0959 } 0960 0961 0962 ///////////////////////////////////////////////////////////////// 0963 LogicalNot::LogicalNot(Node *node) 0964 : Node(), _n(node) { 0965 //printf("%p: New LogicalNot: %p\n", (void*)this, (void*)n); 0966 } 0967 0968 0969 LogicalNot::~LogicalNot() { 0970 delete _n; 0971 _n = 0L; 0972 } 0973 0974 0975 double LogicalNot::value(Context *ctx) { 0976 double v = _n->value(ctx); 0977 return (v == v) ? (v == 0.0) : 1.0; 0978 } 0979 0980 0981 bool LogicalNot::isConst() { 0982 return _n->isConst(); 0983 } 0984 0985 0986 QString LogicalNot::text() const { 0987 if (_parentheses) { 0988 return QString("(!") + _n->text() + ')'; 0989 } else { 0990 return QString('!') + _n->text(); 0991 } 0992 } 0993 0994 0995 ///////////////////////////////////////////////////////////////// 0996 BitwiseAnd::BitwiseAnd(Node *left, Node *right) 0997 : BinaryNode(left, right) { 0998 //printf("%p: New And: %p & %p\n", (void*)this, (void*)left, (void*)right); 0999 } 1000 1001 1002 BitwiseAnd::~BitwiseAnd() { 1003 } 1004 1005 1006 double BitwiseAnd::value(Context *ctx) { 1007 return long(_left->value(ctx)) & long(_right->value(ctx)); 1008 } 1009 1010 1011 bool BitwiseAnd::isConst() { 1012 return _left->isConst() && _right->isConst(); 1013 } 1014 1015 1016 QString BitwiseAnd::text() const { 1017 if (_parentheses) { 1018 return QString('(') + _left->text() + QString('&') + _right->text() + ')'; 1019 } else { 1020 return _left->text() + QString('&') + _right->text(); 1021 } 1022 } 1023 1024 1025 ///////////////////////////////////////////////////////////////// 1026 BitwiseOr::BitwiseOr(Node *left, Node *right) 1027 : BinaryNode(left, right) { 1028 //printf("%p: New Or: %p | %p\n", (void*)this, (void*)left, (void*)right); 1029 } 1030 1031 1032 BitwiseOr::~BitwiseOr() { 1033 } 1034 1035 1036 double BitwiseOr::value(Context *ctx) { 1037 return long(_left->value(ctx)) | long(_right->value(ctx)); 1038 } 1039 1040 1041 bool BitwiseOr::isConst() { 1042 return _left->isConst() && _right->isConst(); 1043 } 1044 1045 1046 QString BitwiseOr::text() const { 1047 if (_parentheses) { 1048 return QString('(') + _left->text() + QString('|') + _right->text() + ')'; 1049 } else { 1050 return _left->text() + QString('|') + _right->text(); 1051 } 1052 } 1053 1054 1055 ///////////////////////////////////////////////////////////////// 1056 LogicalAnd::LogicalAnd(Node *left, Node *right) 1057 : BinaryNode(left, right) { 1058 //printf("%p: New And: %p && %p\n", (void*)this, (void*)left, (void*)right); 1059 } 1060 1061 1062 LogicalAnd::~LogicalAnd() { 1063 } 1064 1065 1066 double LogicalAnd::value(Context *ctx) { 1067 return (_left->value(ctx) && _right->value(ctx)) ? EQ_TRUE : EQ_FALSE; 1068 } 1069 1070 1071 bool LogicalAnd::isConst() { 1072 return _left->isConst() && _right->isConst(); 1073 } 1074 1075 1076 QString LogicalAnd::text() const { 1077 if (_parentheses) { 1078 return QString('(') + _left->text() + QString("&&") + _right->text() + ')'; 1079 } else { 1080 return _left->text() + QString("&&") + _right->text(); 1081 } 1082 } 1083 1084 1085 ///////////////////////////////////////////////////////////////// 1086 LogicalOr::LogicalOr(Node *left, Node *right) 1087 : BinaryNode(left, right) { 1088 //printf("%p: New Or: %p || %p\n", (void*)this, (void*)left, (void*)right); 1089 } 1090 1091 1092 LogicalOr::~LogicalOr() { 1093 } 1094 1095 1096 double LogicalOr::value(Context *ctx) { 1097 return (_left->value(ctx) || _right->value(ctx)) ? EQ_TRUE : EQ_FALSE; 1098 } 1099 1100 1101 bool LogicalOr::isConst() { 1102 return _left->isConst() && _right->isConst(); 1103 } 1104 1105 1106 QString LogicalOr::text() const { 1107 if (_parentheses) { 1108 return QString('(') + _left->text() + QString("||") + _right->text() + ')'; 1109 } else { 1110 return _left->text() + QString("||") + _right->text(); 1111 } 1112 } 1113 1114 1115 ///////////////////////////////////////////////////////////////// 1116 LessThan::LessThan(Node *left, Node *right) 1117 : BinaryNode(left, right) { 1118 //printf("%p: New LessThan: %p < %p\n", (void*)this, (void*)left, (void*)right); 1119 } 1120 1121 1122 LessThan::~LessThan() { 1123 } 1124 1125 1126 double LessThan::value(Context *ctx) { 1127 return doubleLessThan(_left->value(ctx), _right->value(ctx)) ? EQ_TRUE : EQ_FALSE; 1128 } 1129 1130 1131 bool LessThan::isConst() { 1132 return _left->isConst() && _right->isConst(); 1133 } 1134 1135 1136 QString LessThan::text() const { 1137 if (_parentheses) { 1138 return QString('(') + _left->text() + QString('<') + _right->text() + ')'; 1139 } else { 1140 return _left->text() + QString('<') + _right->text(); 1141 } 1142 } 1143 1144 1145 ///////////////////////////////////////////////////////////////// 1146 LessThanEqual::LessThanEqual(Node *left, Node *right) 1147 : BinaryNode(left, right) { 1148 //printf("%p: New LessThanEqual: %p <= %p\n", (void*)this, (void*)left, (void*)right); 1149 } 1150 1151 1152 LessThanEqual::~LessThanEqual() { 1153 } 1154 1155 1156 double LessThanEqual::value(Context *ctx) { 1157 return doubleLessThanEqual(_left->value(ctx), _right->value(ctx)) ? EQ_TRUE : EQ_FALSE; 1158 } 1159 1160 1161 bool LessThanEqual::isConst() { 1162 return _left->isConst() && _right->isConst(); 1163 } 1164 1165 1166 QString LessThanEqual::text() const { 1167 if (_parentheses) { 1168 return QString('(') + _left->text() + QString("<=") + _right->text() + ')'; 1169 } else { 1170 return _left->text() + QString("<=") + _right->text(); 1171 } 1172 } 1173 1174 1175 ///////////////////////////////////////////////////////////////// 1176 GreaterThan::GreaterThan(Node *left, Node *right) 1177 : BinaryNode(left, right) { 1178 //printf("%p: New GreaterThan: %p > %p\n", (void*)this, (void*)left, (void*)right); 1179 } 1180 1181 1182 GreaterThan::~GreaterThan() { 1183 } 1184 1185 1186 double GreaterThan::value(Context *ctx) { 1187 return doubleGreaterThan(_left->value(ctx), _right->value(ctx)) ? EQ_TRUE : EQ_FALSE; 1188 } 1189 1190 1191 bool GreaterThan::isConst() { 1192 return _left->isConst() && _right->isConst(); 1193 } 1194 1195 1196 QString GreaterThan::text() const { 1197 if (_parentheses) { 1198 return QString('(') + _left->text() + QString('>') + _right->text() + ')'; 1199 } else { 1200 return _left->text() + QString('>') + _right->text(); 1201 } 1202 } 1203 1204 1205 ///////////////////////////////////////////////////////////////// 1206 GreaterThanEqual::GreaterThanEqual(Node *left, Node *right) 1207 : BinaryNode(left, right) { 1208 //printf("%p: New GreaterThanEqual: %p >= %p\n", (void*)this, (void*)left, (void*)right); 1209 } 1210 1211 1212 GreaterThanEqual::~GreaterThanEqual() { 1213 } 1214 1215 1216 double GreaterThanEqual::value(Context *ctx) { 1217 return doubleGreaterThanEqual(_left->value(ctx), _right->value(ctx)) ? EQ_TRUE : EQ_FALSE; 1218 } 1219 1220 1221 bool GreaterThanEqual::isConst() { 1222 return _left->isConst() && _right->isConst(); 1223 } 1224 1225 1226 QString GreaterThanEqual::text() const { 1227 if (_parentheses) { 1228 return QString('(') + _left->text() + QString(">=") + _right->text() + ')'; 1229 } else { 1230 return _left->text() + QString(">=") + _right->text(); 1231 } 1232 } 1233 1234 1235 ///////////////////////////////////////////////////////////////// 1236 EqualTo::EqualTo(Node *left, Node *right) 1237 : BinaryNode(left, right) { 1238 //printf("%p: New EqualTo: %p == %p\n", (void*)this, (void*)left, (void*)right); 1239 } 1240 1241 1242 EqualTo::~EqualTo() { 1243 } 1244 1245 1246 double EqualTo::value(Context *ctx) { 1247 return doubleEqual(_left->value(ctx), _right->value(ctx)) ? EQ_TRUE : EQ_FALSE; 1248 } 1249 1250 1251 bool EqualTo::isConst() { 1252 return _left->isConst() && _right->isConst(); 1253 } 1254 1255 1256 QString EqualTo::text() const { 1257 if (_parentheses) { 1258 return QString('(') + _left->text() + QString("==") + _right->text() + ')'; 1259 } else { 1260 return _left->text() + QString("==") + _right->text(); 1261 } 1262 } 1263 1264 1265 ///////////////////////////////////////////////////////////////// 1266 NotEqualTo::NotEqualTo(Node *left, Node *right) 1267 : BinaryNode(left, right) { 1268 //printf("%p: New NotEqualTo: %p != %p\n", (void*)this, (void*)left, (void*)right); 1269 } 1270 1271 1272 NotEqualTo::~NotEqualTo() { 1273 } 1274 1275 1276 double NotEqualTo::value(Context *ctx) { 1277 return (!doubleEqual(_left->value(ctx), _right->value(ctx))) ? EQ_TRUE : EQ_FALSE; 1278 } 1279 1280 1281 bool NotEqualTo::isConst() { 1282 return _left->isConst() && _right->isConst(); 1283 } 1284 1285 1286 QString NotEqualTo::text() const { 1287 if (_parentheses) { 1288 return QString('(') + _left->text() + QString("!=") + _right->text() + ')'; 1289 } else { 1290 return _left->text() + QString("!=") + _right->text(); 1291 } 1292 } 1293 1294 1295 ///////////////////////////////////////////////////////////////// 1296 1297 NodeVisitor::NodeVisitor() { 1298 } 1299 1300 1301 NodeVisitor::~NodeVisitor() { 1302 } 1303 1304 1305 ///////////////////////////////////////////////////////////////// 1306 1307 FoldVisitor::FoldVisitor(Context* ctxIn, Node** rootNode) : NodeVisitor(), _ctx(ctxIn) { 1308 if ((*rootNode)->isConst() && dynamic_cast<Number*>(*rootNode) == 0L) { 1309 double v = (*rootNode)->value(ctxIn); 1310 delete *rootNode; 1311 *rootNode = new Number(v); 1312 } else { 1313 (*rootNode)->visit(this); 1314 } 1315 _ctx = 0L; // avoids context being marked as 'still reachable' 1316 } 1317 1318 1319 FoldVisitor::~FoldVisitor() { 1320 } 1321 1322 1323 void FoldVisitor::visitNode(Node*) { 1324 // useful? 1325 } 1326 1327 1328 void FoldVisitor::visitBinaryNode(BinaryNode *n) { 1329 if (n->left()->isConst() && dynamic_cast<Number*>(n->left()) == 0L) { 1330 double v = n->left()->value(_ctx); 1331 delete n->left(); 1332 n->left() = new Number(v); 1333 } else { 1334 n->left()->visit(this); 1335 } 1336 1337 if (n->right()->isConst() && dynamic_cast<Number*>(n->right()) == 0L) { 1338 double v = n->right()->value(_ctx); 1339 delete n->right(); 1340 n->right() = new Number(v); 1341 } else { 1342 n->right()->visit(this); 1343 } 1344 } 1345 1346 // vim: ts=2 sw=2 et