From 362638066a7d17e6eb40fb3f4ae1516ae475cff5 Mon Sep 17 00:00:00 2001 From: dismine Date: Thu, 1 May 2014 14:33:40 +0300 Subject: [PATCH] Vera++. --HG-- branch : feature --- src/app/container/vmeasurement.cpp | 4 - src/app/container/vmeasurement.h | 34 +- src/app/dialogs/app/dialogincrements.cpp | 10 +- .../app/dialogindividualmeasurements.cpp | 6 +- .../app/dialogstandardmeasurements.cpp | 4 +- src/app/dialogs/tools/dialogdetail.cpp | 4 +- src/app/dialogs/tools/dialoguniondetails.h | 3 +- src/app/main.cpp | 3 +- src/app/mainwindow.cpp | 32 +- src/app/options.h | 2 +- src/app/tablewindow.cpp | 40 +- src/app/tools/drawTools/vtoolpoint.cpp | 2 +- src/app/tools/drawTools/vtooltriangle.cpp | 6 +- src/app/tools/nodeDetails/vnodearc.h | 5 +- src/app/tools/nodeDetails/vnodepoint.h | 28 +- src/app/tools/nodeDetails/vnodespline.h | 23 +- src/app/tools/nodeDetails/vnodesplinepath.cpp | 4 +- src/app/tools/nodeDetails/vnodesplinepath.h | 5 +- src/app/tools/vtooluniondetails.cpp | 2 +- src/app/widgets/vapplication.cpp | 2 +- src/app/xml/vdomdocument.cpp | 5 +- src/app/xml/vdomdocument.h | 10 +- src/app/xml/vpattern.cpp | 7 +- src/app/xml/vstandardmeasurements.cpp | 2 +- src/libs/qmuparser/qmuparser.cpp | 342 +- src/libs/qmuparser/qmuparser.h | 2 +- src/libs/qmuparser/qmuparserbase.cpp | 4988 ++++++++--------- src/libs/qmuparser/qmuparserbase.h | 523 +- src/libs/qmuparser/qmuparserbytecode.cpp | 1906 +++---- src/libs/qmuparser/qmuparserbytecode.h | 250 +- src/libs/qmuparser/qmuparsercallback.cpp | 222 +- src/libs/qmuparser/qmuparsercallback.h | 229 +- src/libs/qmuparser/qmuparserdef.h | 9 +- src/libs/qmuparser/qmuparsererror.cpp | 256 +- src/libs/qmuparser/qmuparsererror.h | 69 +- src/libs/qmuparser/qmuparserfixes.h | 116 +- src/libs/qmuparser/qmuparsertest.cpp | 2264 ++++---- src/libs/qmuparser/qmuparsertest.h | 396 +- src/libs/qmuparser/qmuparsertoken.h | 846 +-- src/libs/qmuparser/qmuparsertokenreader.cpp | 1223 ++-- src/libs/qmuparser/qmuparsertokenreader.h | 310 +- 41 files changed, 7158 insertions(+), 7036 deletions(-) diff --git a/src/app/container/vmeasurement.cpp b/src/app/container/vmeasurement.cpp index 248181a7f..2200c5cad 100644 --- a/src/app/container/vmeasurement.cpp +++ b/src/app/container/vmeasurement.cpp @@ -61,7 +61,3 @@ qreal VMeasurement::GetValue(const qreal &size, const qreal &height) const const qreal k_height = ( height - 176.0 ) / 6.0; return base + k_size * ksize + k_height * kheight; } - - - - diff --git a/src/app/container/vmeasurement.h b/src/app/container/vmeasurement.h index 8e2138f05..c4071a086 100644 --- a/src/app/container/vmeasurement.h +++ b/src/app/container/vmeasurement.h @@ -37,23 +37,23 @@ class VMeasurement { public: - /** - * @brief VStandardTableRow create empty row - */ - VMeasurement(); - /** - * @brief VStandardTableRow create row - * @param base value in base size and growth - * @param ksize increment in sizes - * @param kgrowth increment in growths - * @param description description of increment - */ - VMeasurement(const qreal &base, const qreal &ksize, const qreal &kheight, - const QString &gui_text = QString(), const QString &number = QString(), - const QString &TagName = QString()); - VMeasurement(const qreal &base, const QString &gui_text = QString(), - const QString &number = QString(), const QString &TagName = QString()); - ~VMeasurement(){} + /** + * @brief VStandardTableRow create empty row + */ + VMeasurement(); + /** + * @brief VStandardTableRow create row + * @param base value in base size and growth + * @param ksize increment in sizes + * @param kgrowth increment in growths + * @param description description of increment + */ + VMeasurement(const qreal &base, const qreal &ksize, const qreal &kheight, + const QString &gui_text = QString(), const QString &number = QString(), + const QString &TagName = QString()); + VMeasurement(const qreal &base, const QString &gui_text = QString(), + const QString &number = QString(), const QString &TagName = QString()); + ~VMeasurement(){} /** * @brief GetBase return value in base size and growth * @return value diff --git a/src/app/dialogs/app/dialogincrements.cpp b/src/app/dialogs/app/dialogincrements.cpp index 560a21f1a..4b0552647 100644 --- a/src/app/dialogs/app/dialogincrements.cpp +++ b/src/app/dialogs/app/dialogincrements.cpp @@ -54,7 +54,7 @@ DialogIncrements::DialogIncrements(VContainer *data, VPattern *doc, QWidget *par m = new VIndividualMeasurements(data); m->setContent(filePath); } - catch(VException &e) + catch (VException &e) { e.CriticalMessageBox(tr("File error."), this); emit DialogClosed(QDialog::Rejected); @@ -101,8 +101,8 @@ DialogIncrements::DialogIncrements(VContainer *data, VPattern *doc, QWidget *par ui->lineEditGivenName->setText(m->GivenName()); ui->lineEditFamilyName->setText(m->FamilyName()); - ui->comboBoxSex->addItem(tr("male"),QVariant(m->GenderToStr(VIndividualMeasurements::Male))); - ui->comboBoxSex->addItem(tr("female"),QVariant(m->GenderToStr(VIndividualMeasurements::Female))); + ui->comboBoxSex->addItem(tr("male"), QVariant(m->GenderToStr(VIndividualMeasurements::Male))); + ui->comboBoxSex->addItem(tr("female"), QVariant(m->GenderToStr(VIndividualMeasurements::Female))); qint32 index = ui->comboBoxSex->findData(m->GenderToStr(m->Sex())); if (index != -1) { @@ -473,7 +473,7 @@ void DialogIncrements::OpenTable() m1 = new VIndividualMeasurements(data); m1->setContent(filePath); } - catch(VException &e) + catch (VException &e) { e.CriticalMessageBox(tr("File error."), this); delete m1; @@ -529,7 +529,7 @@ void DialogIncrements::OpenTable() doc->SetPath(filePath); emit haveLiteChange(); } - catch(VException &e) + catch (VException &e) { e.CriticalMessageBox(tr("File error."), this); delete m1; diff --git a/src/app/dialogs/app/dialogindividualmeasurements.cpp b/src/app/dialogs/app/dialogindividualmeasurements.cpp index 9b8337cf4..e112a3012 100644 --- a/src/app/dialogs/app/dialogindividualmeasurements.cpp +++ b/src/app/dialogs/app/dialogindividualmeasurements.cpp @@ -116,7 +116,7 @@ void DialogIndividualMeasurements::DialogAccepted() iMeasur.close(); } } - catch(VException &e) + catch (VException &e) { e.CriticalMessageBox(tr("File error."), this); qDebug()<<"File error."<comboBoxLang->addItem(lang, QVariant(fi.absoluteFilePath())); } - catch(VException &e) + catch (VException &e) { qDebug()<<"File error."<setPatternUnit(m.Unit()); } - catch(VException &e) + catch (VException &e) { e.CriticalMessageBox(tr("File error."), this); qDebug()<<"File error."<comboBoxTables->addItem(m.Description(), QVariant(fi.absoluteFilePath())); } - catch(VException &e) + catch (VException &e) { qDebug()<<"File error."<ClearGObjects(); //Create single point - const quint32 id = pattern->AddGObject(new VPointF(qApp->toPixel((10+comboBoxDraws->count()*5)), qApp->toPixel(10), "А", 5, - 10)); + const quint32 id = pattern->AddGObject(new VPointF(qApp->toPixel((10+comboBoxDraws->count()*5)), qApp->toPixel(10), + "А", 5, 10)); VToolSinglePoint *spoint = new VToolSinglePoint(doc, pattern, id, Valentina::FromGui); sceneDraw->addItem(spoint); connect(spoint, &VToolPoint::ChoosedTool, sceneDraw, &VMainGraphicsScene::ChoosedItem); @@ -261,8 +261,8 @@ void MainWindow::ClosedDialogLine(int result) void MainWindow::ToolAlongLine(bool checked) { - SetToolButton(checked, Valentina::AlongLineTool, ":/cursor/alongline_cursor.png", tr("Select point"), - &MainWindow::ClosedDialogAlongLine); + SetToolButton(checked, Valentina::AlongLineTool, ":/cursor/alongline_cursor.png", + tr("Select point"), &MainWindow::ClosedDialogAlongLine); } void MainWindow::ClosedDialogAlongLine(int result) @@ -360,8 +360,9 @@ void MainWindow::ClosedDialogSplinePath(int result) void MainWindow::ToolCutSplinePath(bool checked) { - SetToolButton(checked, Valentina::CutSplinePathTool, ":/cursor/splinepath_cut_point_cursor.png", - tr("Select curve path"), &MainWindow::ClosedDialogCutSplinePath); + SetToolButton(checked, Valentina::CutSplinePathTool, + ":/cursor/splinepath_cut_point_cursor.png", tr("Select curve path"), + &MainWindow::ClosedDialogCutSplinePath); } void MainWindow::ClosedDialogCutSplinePath(int result) @@ -420,8 +421,9 @@ void MainWindow::ClosedDialogTriangle(int result) void MainWindow::ToolPointOfIntersection(bool checked) { - SetToolButton(checked, Valentina::PointOfIntersection, ":/cursor/pointofintersect_cursor.png", - tr("Select point vertically"), &MainWindow::ClosedDialogPointOfIntersection); + SetToolButton(checked, Valentina::PointOfIntersection, + ":/cursor/pointofintersect_cursor.png", tr("Select point vertically"), + &MainWindow::ClosedDialogPointOfIntersection); } void MainWindow::ClosedDialogPointOfIntersection(int result) @@ -431,8 +433,8 @@ void MainWindow::ClosedDialogPointOfIntersection(int result) void MainWindow::ToolUnionDetails(bool checked) { - SetToolButton(checked, Valentina::UnionDetails, ":/cursor/union_cursor.png", tr("Select detail"), - &MainWindow::ClosedDialogUnionDetails); + SetToolButton(checked, Valentina::UnionDetails, ":/cursor/union_cursor.png", + tr("Select detail"), &MainWindow::ClosedDialogUnionDetails); //Must disconnect this signal here. disconnect(doc, &VPattern::FullUpdateFromFile, dialogTool, &DialogTool::UpdateList); } @@ -1358,7 +1360,7 @@ void MainWindow::LoadPattern(const QString &fileName) QString path = doc->MPath(); path = CheckPathToMeasurements(path, qApp->patternType()); - if(path.isEmpty()) + if (path.isEmpty()) { Clear(); return; @@ -1394,7 +1396,7 @@ void MainWindow::LoadPattern(const QString &fileName) } } } - catch(VException &e) + catch (VException &e) { e.CriticalMessageBox(tr("File error."), this); Clear(); @@ -1440,7 +1442,7 @@ void MainWindow::LoadPattern(const QString &fileName) Clear(); return; } - catch(VException &e) + catch (VException &e) { e.CriticalMessageBox(tr("Error parsing file."), this); Clear(); @@ -1478,7 +1480,7 @@ QString MainWindow::CheckPathToMeasurements(const QString &path, const Pattern:: QMessageBox::StandardButton res = QMessageBox::question(this, "Loading measurements file", text, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); - if(res == QMessageBox::No) + if (res == QMessageBox::No) { return QString(); } @@ -1495,7 +1497,7 @@ QString MainWindow::CheckPathToMeasurements(const QString &path, const Pattern:: } QString mPath = QFileDialog::getOpenFileName(this, tr("Open file"), QDir::homePath(), filter); - if(mPath.isEmpty()) + if (mPath.isEmpty()) { return mPath; } diff --git a/src/app/options.h b/src/app/options.h index cff42b632..90caecb8a 100644 --- a/src/app/options.h +++ b/src/app/options.h @@ -111,6 +111,6 @@ namespace Pattern enum Measurement { Standard, Individual }; Q_DECLARE_FLAGS(Measurements, Measurement) } -Q_DECLARE_OPERATORS_FOR_FLAGS( Pattern::Measurements ) +Q_DECLARE_OPERATORS_FOR_FLAGS( Pattern::Measurements ) #endif // OPTIONS_H diff --git a/src/app/tablewindow.cpp b/src/app/tablewindow.cpp index 23ff21da2..1c88edb4f 100644 --- a/src/app/tablewindow.cpp +++ b/src/app/tablewindow.cpp @@ -222,26 +222,26 @@ void TableWindow::saveScene() suffix << "svg" << "png" << "pdf" << "eps" << "ps"; switch (suffix.indexOf(fi.suffix())) { - case 0: //svg - paper->setVisible(false); - SvgFile(name); - paper->setVisible(true); - break; - case 1: //png - PngFile(name); - break; - case 2: //pdf - PdfFile(name); - break; - case 3: //eps - EpsFile(name); - break; - case 4: //ps - PsFile(name); - break; - default: - qDebug() << "Bad file suffix"<setVisible(false); + SvgFile(name); + paper->setVisible(true); + break; + case 1: //png + PngFile(name); + break; + case 2: //pdf + PdfFile(name); + break; + case 3: //eps + EpsFile(name); + break; + case 4: //ps + PsFile(name); + break; + default: + qDebug() << "Bad file suffix"<setPen(QPen(Qt::black, qApp->toPixel(qApp->widthMainLine()))); brush->setColor( QColor( Qt::gray ) ); diff --git a/src/app/tools/drawTools/vtoolpoint.cpp b/src/app/tools/drawTools/vtoolpoint.cpp index 0c03e937c..a6ab0578b 100644 --- a/src/app/tools/drawTools/vtoolpoint.cpp +++ b/src/app/tools/drawTools/vtoolpoint.cpp @@ -36,7 +36,7 @@ const QString VToolPoint::TagName = QStringLiteral("point"); VToolPoint::VToolPoint(VPattern *doc, VContainer *data, quint32 id, QGraphicsItem *parent):VDrawTool(doc, data, id), QGraphicsEllipseItem(parent), radius(DefRadius), namePoint(0), lineName(0) { - switch(qApp->patternUnit()) + switch (qApp->patternUnit()) { case Valentina::Mm: radius = qApp->toPixel(DefRadius); diff --git a/src/app/tools/drawTools/vtooltriangle.cpp b/src/app/tools/drawTools/vtooltriangle.cpp index c88450982..542092d75 100644 --- a/src/app/tools/drawTools/vtooltriangle.cpp +++ b/src/app/tools/drawTools/vtooltriangle.cpp @@ -31,9 +31,9 @@ const QString VToolTriangle::ToolType = QStringLiteral("triangle"); -VToolTriangle::VToolTriangle(VPattern *doc, VContainer *data, const quint32 &id, - const quint32 &axisP1Id, const quint32 &axisP2Id, const quint32 &firstPointId, - const quint32 &secondPointId, const Valentina::Sources &typeCreation, QGraphicsItem *parent) +VToolTriangle::VToolTriangle(VPattern *doc, VContainer *data, const quint32 &id, const quint32 &axisP1Id, + const quint32 &axisP2Id, const quint32 &firstPointId, const quint32 &secondPointId, + const Valentina::Sources &typeCreation, QGraphicsItem *parent) :VToolPoint(doc, data, id, parent), axisP1Id(axisP1Id), axisP2Id(axisP2Id), firstPointId(firstPointId), secondPointId(secondPointId) { diff --git a/src/app/tools/nodeDetails/vnodearc.h b/src/app/tools/nodeDetails/vnodearc.h index a73e6c517..48e2d5a96 100644 --- a/src/app/tools/nodeDetails/vnodearc.h +++ b/src/app/tools/nodeDetails/vnodearc.h @@ -48,8 +48,9 @@ public: * @param typeCreation way we create this tool. * @param parent parent object. */ - VNodeArc(VPattern *doc, VContainer *data, quint32 id, quint32 idArc, const Valentina::Sources &typeCreation, - const quint32 &idTool = 0, QObject *qoParent = nullptr, QGraphicsItem * parent = nullptr); + VNodeArc(VPattern *doc, VContainer *data, quint32 id, quint32 idArc, + const Valentina::Sources &typeCreation, const quint32 &idTool = 0, + QObject *qoParent = nullptr, QGraphicsItem * parent = nullptr); /** * @brief Create help create tool. * @param doc dom document container. diff --git a/src/app/tools/nodeDetails/vnodepoint.h b/src/app/tools/nodeDetails/vnodepoint.h index 46c643771..762d0cf3e 100644 --- a/src/app/tools/nodeDetails/vnodepoint.h +++ b/src/app/tools/nodeDetails/vnodepoint.h @@ -39,18 +39,17 @@ class VNodePoint: public VAbstractNode, public QGraphicsEllipseItem { Q_OBJECT public: - /** - * @brief VNodePoint constructor. - * @param doc dom document container. - * @param data container with variables. - * @param id object id in container. - * @param id object id in containerPoint. - * @param typeCreation way we create this tool. - * @param parent parent object. - */ - VNodePoint(VPattern *doc, VContainer *data, quint32 id, quint32 idPoint, - const Valentina::Sources &typeCreation, const quint32 &idTool = 0, QObject *qoParent = nullptr, - QGraphicsItem * parent = nullptr ); + /** + * @brief VNodePoint constructor. + * @param doc dom document container. + * @param data container with variables. + * @param id object id in container. + * @param id object id in containerPoint. + * @param typeCreation way we create this tool. + * @param parent parent object. + */ + VNodePoint(VPattern *doc, VContainer *data, quint32 id, quint32 idPoint, const Valentina::Sources &typeCreation, + const quint32 &idTool = 0, QObject *qoParent = nullptr, QGraphicsItem * parent = nullptr ); /** * @brief Create help create tool. * @param doc dom document container. @@ -60,9 +59,8 @@ public: * @param parse parser file mode. * @param typeCreation way we create this tool. */ - static void Create(VPattern *doc, VContainer *data, quint32 id, quint32 idPoint, - const Document::Documents &parse, const Valentina::Sources &typeCreation, const quint32 &idTool = 0, - QObject *parent = nullptr); + static void Create(VPattern *doc, VContainer *data, quint32 id, quint32 idPoint, const Document::Documents &parse, + const Valentina::Sources &typeCreation, const quint32 &idTool = 0, QObject *parent = nullptr); static const QString TagName; static const QString ToolType; /** diff --git a/src/app/tools/nodeDetails/vnodespline.h b/src/app/tools/nodeDetails/vnodespline.h index a21b44842..b83a969a9 100644 --- a/src/app/tools/nodeDetails/vnodespline.h +++ b/src/app/tools/nodeDetails/vnodespline.h @@ -39,18 +39,17 @@ class VNodeSpline:public VAbstractNode, public QGraphicsPathItem { Q_OBJECT public: - /** - * @brief VNodeSpline constructor. - * @param doc dom document container. - * @param data container with variables. - * @param id object id in container. - * @param id object id in containerSpline. - * @param typeCreation way we create this tool. - * @param parent parent object. - */ - VNodeSpline(VPattern *doc, VContainer *data, quint32 id, quint32 idSpline, - const Valentina::Sources &typeCreation, const quint32 &idTool = 0, QObject *qoParent = nullptr, - QGraphicsItem * parent = nullptr); + /** + * @brief VNodeSpline constructor. + * @param doc dom document container. + * @param data container with variables. + * @param id object id in container. + * @param id object id in containerSpline. + * @param typeCreation way we create this tool. + * @param parent parent object. + */ + VNodeSpline(VPattern *doc, VContainer *data, quint32 id, quint32 idSpline, const Valentina::Sources &typeCreation, + const quint32 &idTool = 0, QObject *qoParent = nullptr, QGraphicsItem * parent = nullptr); /** * @brief Create help create tool. * @param doc dom document container. diff --git a/src/app/tools/nodeDetails/vnodesplinepath.cpp b/src/app/tools/nodeDetails/vnodesplinepath.cpp index 35a02aee4..49008ceee 100644 --- a/src/app/tools/nodeDetails/vnodesplinepath.cpp +++ b/src/app/tools/nodeDetails/vnodesplinepath.cpp @@ -53,8 +53,8 @@ VNodeSplinePath::VNodeSplinePath(VPattern *doc, VContainer *data, quint32 id, qu } void VNodeSplinePath::Create(VPattern *doc, VContainer *data, quint32 id, quint32 idSpline, - const Document::Documents &parse, const Valentina::Sources &typeCreation, const quint32 &idTool, - QObject *parent) + const Document::Documents &parse, const Valentina::Sources &typeCreation, + const quint32 &idTool, QObject *parent) { VAbstractTool::AddRecord(id, Valentina::NodeSplinePath, doc); if (parse == Document::FullParse) diff --git a/src/app/tools/nodeDetails/vnodesplinepath.h b/src/app/tools/nodeDetails/vnodesplinepath.h index 843c4038c..4e9facca4 100644 --- a/src/app/tools/nodeDetails/vnodesplinepath.h +++ b/src/app/tools/nodeDetails/vnodesplinepath.h @@ -60,9 +60,8 @@ public: * @param parse parser file mode. * @param typeCreation way we create this tool. */ - static void Create(VPattern *doc, VContainer *data, quint32 id, quint32 idSpline, - const Document::Documents &parse, const Valentina::Sources &typeCreation, const quint32 &idTool = 0, - QObject *parent = 0); + static void Create(VPattern *doc, VContainer *data, quint32 id, quint32 idSpline, const Document::Documents &parse, + const Valentina::Sources &typeCreation, const quint32 &idTool = 0, QObject *parent = 0); static const QString TagName; static const QString ToolType; /** diff --git a/src/app/tools/vtooluniondetails.cpp b/src/app/tools/vtooluniondetails.cpp index 006403c9e..7281ac086 100644 --- a/src/app/tools/vtooluniondetails.cpp +++ b/src/app/tools/vtooluniondetails.cpp @@ -481,7 +481,7 @@ void VToolUnionDetails::Create(const quint32 _id, const VDetail &d1, const VDeta ++j; } while (pointsD2 < d2.RemoveEdge(indexD2).CountNode()); } - } while(i < d1.RemoveEdge(indexD1).CountNode()); + } while (i < d1.RemoveEdge(indexD1).CountNode()); newDetail.setName("Detail"); VToolDetail::Create(0, newDetail, scene, doc, data, parse, Valentina::FromTool); diff --git a/src/app/widgets/vapplication.cpp b/src/app/widgets/vapplication.cpp index e754ffc63..061ca841c 100644 --- a/src/app/widgets/vapplication.cpp +++ b/src/app/widgets/vapplication.cpp @@ -174,7 +174,7 @@ QString VApplication::translationsPath() const void VApplication::InitLineWidth() { - switch(_patternUnit) + switch (_patternUnit) { case Valentina::Mm: _widthMainLine = DefWidth; diff --git a/src/app/xml/vdomdocument.cpp b/src/app/xml/vdomdocument.cpp index 0cb27e2eb..d0fd35ae9 100644 --- a/src/app/xml/vdomdocument.cpp +++ b/src/app/xml/vdomdocument.cpp @@ -293,7 +293,8 @@ void VDomDocument::ValidateXML(const QString &schema, const QString &fileName) pattern.close(); fileSchema.close(); VException e(messageHandler.statusMessage()); - e.AddMoreInformation(tr("Validation error in line %1 column %2").arg(messageHandler.line()).arg(messageHandler.column())); + e.AddMoreInformation(tr("Validation error in line %1 column %2").arg(messageHandler.line()) + .arg(messageHandler.column())); throw e; } pattern.close(); @@ -347,7 +348,7 @@ Valentina::Units VDomDocument::StrToUnits(const QString &unit) QString VDomDocument::UnitsToStr(const Valentina::Units &unit) { QString result; - switch(unit) + switch (unit) { case Valentina::Mm: result = "mm"; diff --git a/src/app/xml/vdomdocument.h b/src/app/xml/vdomdocument.h index c2765254d..a0369050e 100644 --- a/src/app/xml/vdomdocument.h +++ b/src/app/xml/vdomdocument.h @@ -42,21 +42,21 @@ /** * @brief The VDomDocument class represents a Valentina document (.val file). - * - * A Valentina document describes the construction of a sewing pattern. The + * + * A Valentina document describes the construction of a sewing pattern. The * information is stored in XML format. By parsing a VDomDocument, the contained * pattern is rendered to a Valentina graphics scene (VMainGraphicsScene). * - * A sewing pattern consists of zero or more increments and one + * A sewing pattern consists of zero or more increments and one * or more pattern pieces. * * An increment is an auxiliary variable that is calculated from regular measurement * variables (that belong to the standard measurements table). Increments are used to * create a graduation schema for the sewing pattern. * - * A pattern piece contains + * A pattern piece contains * 1) auxiliary pattern construction elements (calculation), - * 2) pattern construction elements (modeling), and + * 2) pattern construction elements (modeling), and * 3) special markers, e.g. seam allowances (details). * Of these, 2) and 3) are visible in the final pattern (draw mode 'Modeling'), * 1) is only displayed when editing (draw mode 'Calculation') the pattern. diff --git a/src/app/xml/vpattern.cpp b/src/app/xml/vpattern.cpp index ec8f0db9e..56ca2737b 100644 --- a/src/app/xml/vpattern.cpp +++ b/src/app/xml/vpattern.cpp @@ -460,7 +460,7 @@ Valentina::Units VPattern::MUnit() const QStringList units; units << "mm" << "cm" << "inch"; QString unit = GetParametrString(element, AttrUnit); - switch(units.indexOf(unit)) + switch (units.indexOf(unit)) { case 0:// mm return Valentina::Mm; @@ -491,7 +491,7 @@ Pattern::Measurements VPattern::MType() const QString type = GetParametrString(element, AttrType); QStringList types; types << "standard" << "individual"; - switch(types.indexOf(type)) + switch (types.indexOf(type)) { case 0:// standard return Pattern::Standard; @@ -1049,7 +1049,8 @@ void VPattern::ParsePointElement(VMainGraphicsScene *scene, const QDomElement &d const QString formula = GetParametrString(domElement, VAbstractTool::AttrLength, "0"); const quint32 splineId = GetParametrUInt(domElement, VToolCutSpline::AttrSpline, "0"); - VToolCutSpline::Create(id, name, formula, splineId, mx, my, scene, this, data, parse, Valentina::FromFile); + VToolCutSpline::Create(id, name, formula, splineId, mx, my, scene, this, data, parse, + Valentina::FromFile); } catch (const VExceptionBadId &e) { diff --git a/src/app/xml/vstandardmeasurements.cpp b/src/app/xml/vstandardmeasurements.cpp index cb96b7908..354b6c1a6 100644 --- a/src/app/xml/vstandardmeasurements.cpp +++ b/src/app/xml/vstandardmeasurements.cpp @@ -70,7 +70,7 @@ void VStandardMeasurements::Measurements() } else { - for(qint32 i = 0; i < nodeList.size(); ++i) + for (qint32 i = 0; i < nodeList.size(); ++i) { const QDomNode domNode = nodeList.at(i); if (domNode.isNull() == false && domNode.isElement()) diff --git a/src/libs/qmuparser/qmuparser.cpp b/src/libs/qmuparser/qmuparser.cpp index 0c7d38ea0..09919f9c4 100644 --- a/src/libs/qmuparser/qmuparser.cpp +++ b/src/libs/qmuparser/qmuparser.cpp @@ -39,78 +39,78 @@ namespace qmu // Trigonometric function qreal QmuParser::Sinh(qreal v) { - return sinh(v); + return sinh(v); } qreal QmuParser::Cosh(qreal v) { - return cosh(v); + return cosh(v); } qreal QmuParser::Tanh(qreal v) { - return tanh(v); + return tanh(v); } qreal QmuParser::ASinh(qreal v) { - return log(v + qSqrt(v * v + 1)); + return log(v + qSqrt(v * v + 1)); } qreal QmuParser::ACosh(qreal v) { - return log(v + qSqrt(v * v - 1)); + return log(v + qSqrt(v * v - 1)); } qreal QmuParser::ATanh(qreal v) { - return (0.5 * log((1 + v) / (1 - v))); + return (0.5 * log((1 + v) / (1 - v))); } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- // Logarithm functions // Logarithm base 2 qreal QmuParser::Log2(qreal v) { #ifdef MUP_MATH_EXCEPTIONS - if (v<=0) - { - throw QmuParserError(ecDOMAIN_ERROR, "Log2"); - } + if (v<=0) + { + throw QmuParserError(ecDOMAIN_ERROR, "Log2"); + } #endif - return log(v)/log(2.0); + return log(v)/log(2.0); } // Logarithm base 10 qreal QmuParser::Log10(qreal v) { #ifdef MUP_MATH_EXCEPTIONS - if (v<=0) - { - throw QmuParserError(ecDOMAIN_ERROR, "Log10"); - } + if (v<=0) + { + throw QmuParserError(ecDOMAIN_ERROR, "Log10"); + } #endif - return log10(v); + return log10(v); } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- // misc qreal QmuParser::Abs(qreal v) { - return qAbs(v); + return qAbs(v); } qreal QmuParser::Rint(qreal v) { - return qFloor(v + 0.5); + return qFloor(v + 0.5); } qreal QmuParser::Sign(qreal v) { - return ((v<0) ? -1 : (v>0) ? 1 : 0); + return ((v<0) ? -1 : (v>0) ? 1 : 0); } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Callback for the unary minus operator. * @param v The value to negate @@ -118,10 +118,10 @@ qreal QmuParser::Sign(qreal v) */ qreal QmuParser::UnaryMinus(qreal v) { - return -v; + return -v; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Callback for adding multiple values. * @param [in] a_afArg Vector with the function arguments @@ -129,16 +129,19 @@ qreal QmuParser::UnaryMinus(qreal v) */ qreal QmuParser::Sum(const qreal *a_afArg, int a_iArgc) { - if (!a_iArgc) - { - throw exception_type("too few arguments for function sum."); - } - qreal fRes=0; - for (int i=0; i(a_iArgc); + if (a_iArgc == false) + { + throw exception_type("too few arguments for function sum."); + } + qreal fRes=0; + for (int i=0; i(a_iArgc); } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Callback for determining the minimum value out of a vector. * @param [in] a_afArg Vector with the function arguments @@ -163,19 +169,19 @@ qreal QmuParser::Avg(const qreal *a_afArg, int a_iArgc) */ qreal QmuParser::Min(const qreal *a_afArg, int a_iArgc) { - if (!a_iArgc) - { - throw exception_type("too few arguments for function min."); - } - qreal fRes=a_afArg[0]; - for (int i=0; i> fVal; - stringstream_type::pos_type iEnd = stream.tellg(); // Position after reading + #if defined(_UNICODE) + std::wstring a_szExprStd = a_szExpr.toStdWString(); + #else + std::string a_szExprStd = a_szExpr.toStdString(); + #endif + stringstream_type stream(a_szExprStd); + stream.seekg(0); // todo: check if this really is necessary + stream.imbue(QmuParser::s_locale); + stream >> fVal; + stringstream_type::pos_type iEnd = stream.tellg(); // Position after reading - if (iEnd==static_cast(-1)) - { - return 0; - } + if (iEnd==static_cast(-1)) + { + return 0; + } - *a_iPos += static_cast(iEnd); - *a_fVal = fVal; - return 1; + *a_iPos += static_cast(iEnd); + *a_fVal = fVal; + return 1; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Constructor. * @@ -236,15 +242,15 @@ int QmuParser::IsVal(const QString &a_szExpr, int *a_iPos, qreal *a_fVal) */ QmuParser::QmuParser():QmuParserBase() { - AddValIdent(IsVal); + AddValIdent(IsVal); - InitCharSets(); - InitFun(); - InitConst(); - InitOprt(); + InitCharSets(); + InitFun(); + InitConst(); + InitOprt(); } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Define the character sets. * @sa DefineNameChars, DefineOprtChars, DefineInfixOprtChars @@ -254,53 +260,53 @@ QmuParser::QmuParser():QmuParserBase() */ void QmuParser::InitCharSets() { - DefineNameChars( "0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" ); - DefineOprtChars( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+-*^/?<>=#!$%&|~'_{}" ); - DefineInfixOprtChars( "/+-*^?<>=#!$%&|~'_" ); + DefineNameChars( "0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" ); + DefineOprtChars( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+-*^/?<>=#!$%&|~'_{}" ); + DefineInfixOprtChars( "/+-*^?<>=#!$%&|~'_" ); } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Initialize the default functions. */ void QmuParser::InitFun() { - // trigonometric functions - DefineFun("sin", qSin); - DefineFun("cos", qCos); - DefineFun("tan", qTan); - // arcus functions - DefineFun("asin", qAsin); - DefineFun("acos", qAcos); - DefineFun("atan", qAtan); - DefineFun("atan2", qAtan2); - // hyperbolic functions - DefineFun("sinh", Sinh); - DefineFun("cosh", Cosh); - DefineFun("tanh", Tanh); - // arcus hyperbolic functions - DefineFun("asinh", ASinh); - DefineFun("acosh", ACosh); - DefineFun("atanh", ATanh); - // Logarithm functions - DefineFun("log2", Log2); - DefineFun("log10", Log10); - DefineFun("log", Log10); - DefineFun("ln", qLn); - // misc - DefineFun("exp", qExp); - DefineFun("sqrt", qSqrt); - DefineFun("sign", Sign); - DefineFun("rint", Rint); - DefineFun("abs", Abs); - // Functions with variable number of arguments - DefineFun("sum", Sum); - DefineFun("avg", Avg); - DefineFun("min", Min); - DefineFun("max", Max); + // trigonometric functions + DefineFun("sin", qSin); + DefineFun("cos", qCos); + DefineFun("tan", qTan); + // arcus functions + DefineFun("asin", qAsin); + DefineFun("acos", qAcos); + DefineFun("atan", qAtan); + DefineFun("atan2", qAtan2); + // hyperbolic functions + DefineFun("sinh", Sinh); + DefineFun("cosh", Cosh); + DefineFun("tanh", Tanh); + // arcus hyperbolic functions + DefineFun("asinh", ASinh); + DefineFun("acosh", ACosh); + DefineFun("atanh", ATanh); + // Logarithm functions + DefineFun("log2", Log2); + DefineFun("log10", Log10); + DefineFun("log", Log10); + DefineFun("ln", qLn); + // misc + DefineFun("exp", qExp); + DefineFun("sqrt", qSqrt); + DefineFun("sign", Sign); + DefineFun("rint", Rint); + DefineFun("abs", Abs); + // Functions with variable number of arguments + DefineFun("sum", Sum); + DefineFun("avg", Avg); + DefineFun("min", Min); + DefineFun("max", Max); } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Initialize constants. * @@ -309,11 +315,11 @@ void QmuParser::InitFun() */ void QmuParser::InitConst() { - DefineConst("_pi", (qreal)M_PI); - DefineConst("_e", (qreal)M_E); + DefineConst("_pi", (qreal)M_PI); + DefineConst("_e", (qreal)M_E); } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Initialize operators. * @@ -321,38 +327,38 @@ void QmuParser::InitConst() */ void QmuParser::InitOprt() { - DefineInfixOprt("-", UnaryMinus); + DefineInfixOprt("-", UnaryMinus); } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- void QmuParser::OnDetectVar(const QString &pExpr, int &nStart, int &nEnd) { - Q_UNUSED(pExpr); - Q_UNUSED(nStart); - Q_UNUSED(nEnd); - // this is just sample code to illustrate modifying variable names on the fly. - // I'm not sure anyone really needs such a feature... - /* + Q_UNUSED(pExpr); + Q_UNUSED(nStart); + Q_UNUSED(nEnd); + // this is just sample code to illustrate modifying variable names on the fly. + // I'm not sure anyone really needs such a feature... + /* - string sVar(pExpr->begin()+nStart, pExpr->begin()+nEnd); - string sRepl = std::string("_") + sVar + "_"; + string sVar(pExpr->begin()+nStart, pExpr->begin()+nEnd); + string sRepl = std::string("_") + sVar + "_"; - int nOrigVarEnd = nEnd; - cout << "variable detected!\n"; - cout << " Expr: " << *pExpr << "\n"; - cout << " Start: " << nStart << "\n"; - cout << " End: " << nEnd << "\n"; - cout << " Var: \"" << sVar << "\"\n"; - cout << " Repl: \"" << sRepl << "\"\n"; - nEnd = nStart + sRepl.length(); - cout << " End: " << nEnd << "\n"; - pExpr->replace(pExpr->begin()+nStart, pExpr->begin()+nOrigVarEnd, sRepl); - cout << " New expr: " << *pExpr << "\n"; - */ + int nOrigVarEnd = nEnd; + cout << "variable detected!\n"; + cout << " Expr: " << *pExpr << "\n"; + cout << " Start: " << nStart << "\n"; + cout << " End: " << nEnd << "\n"; + cout << " Var: \"" << sVar << "\"\n"; + cout << " Repl: \"" << sRepl << "\"\n"; + nEnd = nStart + sRepl.length(); + cout << " End: " << nEnd << "\n"; + pExpr->replace(pExpr->begin()+nStart, pExpr->begin()+nOrigVarEnd, sRepl); + cout << " New expr: " << *pExpr << "\n"; + */ } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Numerically differentiate with regard to a variable. * @param [in] a_Var Pointer to the differentiation variable. @@ -368,25 +374,25 @@ void QmuParser::OnDetectVar(const QString &pExpr, int &nStart, int &nEnd) */ qreal QmuParser::Diff(qreal *a_Var, qreal a_fPos, qreal a_fEpsilon) const { - qreal fRes(0), - fBuf(*a_Var), - f[4] = {0,0,0,0}, - fEpsilon(a_fEpsilon); + qreal fRes(0), + fBuf(*a_Var), + f[4] = {0, 0, 0, 0}, + fEpsilon(a_fEpsilon); - // Backwards compatible calculation of epsilon inc case the user doesnt provide - // his own epsilon - if (qFuzzyCompare(fEpsilon + 1, 1 + 0)) - { - fEpsilon = (qFuzzyCompare(a_fPos + 1, 1 + 0)) ? static_cast(1e-10) : static_cast(1e-7) * a_fPos; - } + // Backwards compatible calculation of epsilon inc case the user doesnt provide + // his own epsilon + if (qFuzzyCompare(fEpsilon + 1, 1 + 0)) + { + fEpsilon = (qFuzzyCompare(a_fPos + 1, 1 + 0)) ? static_cast(1e-10) : static_cast(1e-7) * a_fPos; + } - *a_Var = a_fPos+2 * fEpsilon; f[0] = Eval(); - *a_Var = a_fPos+1 * fEpsilon; f[1] = Eval(); - *a_Var = a_fPos-1 * fEpsilon; f[2] = Eval(); - *a_Var = a_fPos-2 * fEpsilon; f[3] = Eval(); - *a_Var = fBuf; // restore variable + *a_Var = a_fPos+2 * fEpsilon; f[0] = Eval(); + *a_Var = a_fPos+1 * fEpsilon; f[1] = Eval(); + *a_Var = a_fPos-1 * fEpsilon; f[2] = Eval(); + *a_Var = a_fPos-2 * fEpsilon; f[3] = Eval(); + *a_Var = fBuf; // restore variable - fRes = (-f[0] + 8*f[1] - 8*f[2] + f[3]) / (12*fEpsilon); - return fRes; + fRes = (-f[0] + 8*f[1] - 8*f[2] + f[3]) / (12*fEpsilon); + return fRes; } } // namespace qmu diff --git a/src/libs/qmuparser/qmuparser.h b/src/libs/qmuparser/qmuparser.h index bb713ed76..e64178122 100644 --- a/src/libs/qmuparser/qmuparser.h +++ b/src/libs/qmuparser/qmuparser.h @@ -51,7 +51,7 @@ namespace qmu virtual void InitFun(); virtual void InitConst(); virtual void InitOprt(); - virtual void OnDetectVar(const QString &pExpr, int &nStart, int &nEnd); + virtual void OnDetectVar(const QString &pExpr, int &nStart, int &nEnd); qreal Diff(qreal *a_Var, qreal a_fPos, qreal a_fEpsilon = 0) const; protected: static int IsVal(const QString &a_szExpr, int *a_iPos, qreal *a_fVal); diff --git a/src/libs/qmuparser/qmuparserbase.cpp b/src/libs/qmuparser/qmuparserbase.cpp index 07ecfea7a..3b29c6396 100644 --- a/src/libs/qmuparser/qmuparserbase.cpp +++ b/src/libs/qmuparser/qmuparserbase.cpp @@ -1,2494 +1,2494 @@ -/*************************************************************************************************** - ** - ** Original work Copyright (C) 2013 Ingo Berg - ** Modified work Copyright 2014 Roman Telezhynskyi - ** - ** Permission is hereby granted, free of charge, to any person obtaining a copy of this - ** software and associated documentation files (the "Software"), to deal in the Software - ** without restriction, including without limitation the rights to use, copy, modify, - ** merge, publish, distribute, sublicense, and/or sell copies of the Software, and to - ** permit persons to whom the Software is furnished to do so, subject to the following conditions: - ** - ** The above copyright notice and this permission notice shall be included in all copies or - ** substantial portions of the Software. - ** - ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT - ** NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - ** DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ** - ******************************************************************************************************/ - -#include "qmuparserbase.h" -#include -#include -#ifdef QMUP_USE_OPENMP - #include -#endif - -using namespace std; - -/** - * @file - * @brief This file contains the basic implementation of the muparser engine. - */ - -namespace qmu -{ -std::locale QmuParserBase::s_locale = std::locale(std::locale::classic(), new change_dec_sep('.')); - -bool QmuParserBase::g_DbgDumpCmdCode = false; -bool QmuParserBase::g_DbgDumpStack = false; - -/** - * @brief Identifiers for built in binary operators. - * - * When defining custom binary operators with #AddOprt(...) make sure not to choose - * names conflicting with these definitions. - */ -const QStringList QmuParserBase::c_DefaultOprt = QStringList() << "<=" << ">=" << "!=" << "==" << "<" << ">" - << "+" << "-" << "*" << "/" << "^" << "&&" - << "||" << "=" << "(" << ")" << "?" << ":"; - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Constructor. - * @param a_szFormula the formula to interpret. - * @throw ParserException if a_szFormula is null. - */ -QmuParserBase::QmuParserBase() - :m_pParseFormula(&QmuParserBase::ParseString), m_vRPN(), m_vStringBuf(), m_vStringVarBuf(), m_pTokenReader(), - m_FunDef(), m_PostOprtDef(), m_InfixOprtDef(), m_OprtDef(), m_ConstDef(), m_StrVarDef(), m_VarDef(), - m_bBuiltInOp(true), m_sNameChars(), m_sOprtChars(), m_sInfixOprtChars(), m_nIfElseCounter(0), m_vStackBuffer(), - m_nFinalResultIdx(0) -{ - InitTokenReader(); -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Copy constructor. - * - * Tha parser can be safely copy constructed but the bytecode is reset during copy construction. - */ -QmuParserBase::QmuParserBase(const QmuParserBase &a_Parser) - :m_pParseFormula(&QmuParserBase::ParseString), m_vRPN(), m_vStringBuf(), m_vStringVarBuf(), m_pTokenReader(), - m_FunDef(), m_PostOprtDef(), m_InfixOprtDef(), m_OprtDef(), m_ConstDef(), m_StrVarDef(), m_VarDef(), - m_bBuiltInOp(true), m_sNameChars(), m_sOprtChars(), m_sInfixOprtChars(), m_nIfElseCounter(0), m_vStackBuffer(), - m_nFinalResultIdx(0) -{ - m_pTokenReader.reset(new token_reader_type(this)); - Assign(a_Parser); -} - -//---------------------------------------------------------------------------------------------------------------------- -QmuParserBase::~QmuParserBase() -{} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Assignement operator. - * - * Implemented by calling Assign(a_Parser). Self assignement is suppressed. - * @param a_Parser Object to copy to this. - * @return *this - * @throw nothrow - */ -QmuParserBase& QmuParserBase::operator=(const QmuParserBase &a_Parser) -{ - Assign(a_Parser); - return *this; -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Copy state of a parser object to this. - * - * Clears Variables and Functions of this parser. - * Copies the states of all internal variables. - * Resets parse function to string parse mode. - * - * @param a_Parser the source object. - */ -void QmuParserBase::Assign(const QmuParserBase &a_Parser) -{ - if (&a_Parser==this) - { - return; - } - - // Don't copy bytecode instead cause the parser to create new bytecode - // by resetting the parse function. - ReInit(); - - m_ConstDef = a_Parser.m_ConstDef; // Copy user define constants - m_VarDef = a_Parser.m_VarDef; // Copy user defined variables - m_bBuiltInOp = a_Parser.m_bBuiltInOp; - m_vStringBuf = a_Parser.m_vStringBuf; - m_vStackBuffer = a_Parser.m_vStackBuffer; - m_nFinalResultIdx = a_Parser.m_nFinalResultIdx; - m_StrVarDef = a_Parser.m_StrVarDef; - m_vStringVarBuf = a_Parser.m_vStringVarBuf; - m_nIfElseCounter = a_Parser.m_nIfElseCounter; - m_pTokenReader.reset(a_Parser.m_pTokenReader->Clone(this)); - - // Copy function and operator callbacks - m_FunDef = a_Parser.m_FunDef; // Copy function definitions - m_PostOprtDef = a_Parser.m_PostOprtDef; // post value unary operators - m_InfixOprtDef = a_Parser.m_InfixOprtDef; // unary operators for infix notation - m_OprtDef = a_Parser.m_OprtDef; // binary operators - - m_sNameChars = a_Parser.m_sNameChars; - m_sOprtChars = a_Parser.m_sOprtChars; - m_sInfixOprtChars = a_Parser.m_sInfixOprtChars; -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Set the decimal separator. - * @param cDecSep Decimal separator as a character value. - * @sa SetThousandsSep - * - * By default muparser uses the "C" locale. The decimal separator of this - * locale is overwritten by the one provided here. - */ -void QmuParserBase::SetDecSep(char_type cDecSep) -{ - char_type cThousandsSep = std::use_facet< change_dec_sep >(s_locale).thousands_sep(); - s_locale = std::locale(std::locale("C"), new change_dec_sep(cDecSep, cThousandsSep)); -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Sets the thousands operator. - * @param cThousandsSep The thousands separator as a character - * @sa SetDecSep - * - * By default muparser uses the "C" locale. The thousands separator of this - * locale is overwritten by the one provided here. - */ -void QmuParserBase::SetThousandsSep(char_type cThousandsSep) -{ - char_type cDecSep = std::use_facet< change_dec_sep >(s_locale).decimal_point(); - s_locale = std::locale(std::locale("C"), new change_dec_sep(cDecSep, cThousandsSep)); -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Resets the locale. - * - * The default locale used "." as decimal separator, no thousands separator and "," as function argument separator. - */ -void QmuParserBase::ResetLocale() -{ - s_locale = std::locale(std::locale("C"), new change_dec_sep('.')); - SetArgSep(','); -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Initialize the token reader. - * - * Create new token reader object and submit pointers to function, operator, constant and variable definitions. - * - * @post m_pTokenReader.get()!=0 - * @throw nothrow - */ -void QmuParserBase::InitTokenReader() -{ - m_pTokenReader.reset(new token_reader_type(this)); -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Reset parser to string parsing mode and clear internal buffers. - * - * Clear bytecode, reset the token reader. - * @throw nothrow - */ -void QmuParserBase::ReInit() const -{ - m_pParseFormula = &QmuParserBase::ParseString; - m_vStringBuf.clear(); - m_vRPN.clear(); - m_pTokenReader->ReInit(); - m_nIfElseCounter = 0; -} - -//---------------------------------------------------------------------------------------------------------------------- -void QmuParserBase::OnDetectVar(const QString &pExpr, int &nStart, int &nEnd) -{ - Q_UNUSED(pExpr); - Q_UNUSED(nStart); - Q_UNUSED(nEnd); -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Returns the version of muparser. - * @param eInfo A flag indicating whether the full version info should be returned or not. - * - * Format is as follows: "MAJOR.MINOR (COMPILER_FLAGS)" The COMPILER_FLAGS are returned only if eInfo==pviFULL. - */ -QString QmuParserBase::GetVersion(EParserVersionInfo eInfo) const -{ - QString versionInfo; - QTextStream ss(&versionInfo); - - ss << QMUP_VERSION; - - if (eInfo==pviFULL) - { - ss << " (" << QMUP_VERSION_DATE; - ss << "; " << sizeof(void*)*8 << "BIT"; - - #ifdef _DEBUG - ss << "; DEBUG"; - #else - ss << "; RELEASE"; - #endif - - #ifdef _UNICODE - ss << "; UNICODE"; - #else - #ifdef _MBCS - ss << "; MBCS"; - #else - ss << "; ASCII"; - #endif - #endif - - #ifdef QMUP_USE_OPENMP - ss << "; OPENMP"; - //#else - // ss << "; NO_OPENMP"; - #endif - - #if defined(MUP_MATH_EXCEPTIONS) - ss << "; MATHEXC"; - //#else - // ss << "; NO_MATHEXC"; - #endif - - ss << ")"; - } - return versionInfo; -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Add a value parsing function. - * - * When parsing an expression muParser tries to detect values in the expression string using different valident - * callbacks. Thuis it's possible to parse for hex values, binary values and floating point values. - */ -void QmuParserBase::AddValIdent(identfun_type a_pCallback) -{ - m_pTokenReader->AddValIdent(a_pCallback); -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Set a function that can create variable pointer for unknown expression variables. - * @param a_pFactory A pointer to the variable factory. - * @param pUserData A user defined context pointer. - */ -void QmuParserBase::SetVarFactory(facfun_type a_pFactory, void *pUserData) -{ - m_pTokenReader->SetVarCreator(a_pFactory, pUserData); -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Add a function or operator callback to the parser. - */ -void QmuParserBase::AddCallback(const QString &a_strName, const QmuParserCallback &a_Callback, - funmap_type &a_Storage, const QString &a_szCharSet ) -{ - if (a_Callback.GetAddr()==0) - { - Error(ecINVALID_FUN_PTR); - } - - const funmap_type *pFunMap = &a_Storage; - - // Check for conflicting operator or function names - if ( pFunMap!=&m_FunDef && m_FunDef.find(a_strName)!=m_FunDef.end() ) - { - Error(ecNAME_CONFLICT, -1, a_strName); - } - - if ( pFunMap!=&m_PostOprtDef && m_PostOprtDef.find(a_strName)!=m_PostOprtDef.end() ) - { - Error(ecNAME_CONFLICT, -1, a_strName); - } - - if ( pFunMap!=&m_InfixOprtDef && pFunMap!=&m_OprtDef && m_InfixOprtDef.find(a_strName)!=m_InfixOprtDef.end() ) - { - Error(ecNAME_CONFLICT, -1, a_strName); - } - - if ( pFunMap!=&m_InfixOprtDef && pFunMap!=&m_OprtDef && m_OprtDef.find(a_strName)!=m_OprtDef.end() ) - { - Error(ecNAME_CONFLICT, -1, a_strName); - } - - CheckOprt(a_strName, a_Callback, a_szCharSet); - a_Storage[a_strName] = a_Callback; - ReInit(); -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Check if a name contains invalid characters. - * - * @throw ParserException if the name contains invalid charakters. - */ -void QmuParserBase::CheckOprt(const QString &a_sName, const QmuParserCallback &a_Callback, - const QString &a_szCharSet) const -{ -#if defined(_UNICODE) - const std::wstring a_sNameStd = a_sName.toStdWString(); - const std::wstring a_szCharSetStd = a_szCharSet.toStdWString(); -#else - const std::string a_sNameStd = a_sName.toStdString(); - const std::string a_szCharSetStd = a_szCharSet.toStdString(); -#endif - if ( !a_sNameStd.length() || (a_sNameStd.find_first_not_of(a_szCharSetStd)!=string_type::npos) || - (a_sNameStd.at(0)>='0' && a_sNameStd.at(0)<='9')) - { - switch(a_Callback.GetCode()) - { - case cmOPRT_POSTFIX: - Error(ecINVALID_POSTFIX_IDENT, -1, a_sName); - break; - case cmOPRT_INFIX: - Error(ecINVALID_INFIX_IDENT, -1, a_sName); - break; - case cmLE: - Q_UNREACHABLE(); - break; - case cmGE: - Q_UNREACHABLE(); - break; - case cmNEQ: - Q_UNREACHABLE(); - break; - case cmEQ: - Q_UNREACHABLE(); - break; - case cmLT: - Q_UNREACHABLE(); - break; - case cmGT: - Q_UNREACHABLE(); - break; - case cmADD: - Q_UNREACHABLE(); - break; - case cmSUB: - Q_UNREACHABLE(); - break; - case cmMUL: - Q_UNREACHABLE(); - break; - case cmDIV: - Q_UNREACHABLE(); - break; - case cmPOW: - Q_UNREACHABLE(); - break; - case cmLAND: - Q_UNREACHABLE(); - break; - case cmLOR: - Q_UNREACHABLE(); - break; - case cmASSIGN: - Q_UNREACHABLE(); - break; - case cmBO: - Q_UNREACHABLE(); - break; - case cmBC: - Q_UNREACHABLE(); - break; - case cmIF: - Q_UNREACHABLE(); - break; - case cmELSE: - Q_UNREACHABLE(); - break; - case cmENDIF: - Q_UNREACHABLE(); - break; - case cmARG_SEP: - Q_UNREACHABLE(); - break; - case cmVAR: - Q_UNREACHABLE(); - break; - case cmVAL: - Q_UNREACHABLE(); - break; - case cmVARPOW2: - Q_UNREACHABLE(); - break; - case cmVARPOW3: - Q_UNREACHABLE(); - break; - case cmVARPOW4: - Q_UNREACHABLE(); - break; - case cmVARMUL: - Q_UNREACHABLE(); - break; - case cmPOW2: - Q_UNREACHABLE(); - break; - case cmFUNC: - Q_UNREACHABLE(); - break; - case cmFUNC_STR: - Q_UNREACHABLE(); - break; - case cmFUNC_BULK: - Q_UNREACHABLE(); - break; - case cmSTRING: - Q_UNREACHABLE(); - break; - case cmOPRT_BIN: - Q_UNREACHABLE(); - break; - case cmEND: - Q_UNREACHABLE(); - break; - case cmUNKNOWN: - Q_UNREACHABLE(); - break; - default: - Error(ecINVALID_NAME, -1, a_sName); - break; - } - } -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Check if a name contains invalid characters. - * - * @throw ParserException if the name contains invalid charakters. - */ -void QmuParserBase::CheckName(const QString &a_sName, const QString &a_szCharSet) const -{ -#if defined(_UNICODE) - std::wstring a_sNameStd = a_sName.toStdWString(); - std::wstring a_szCharSetStd = a_szCharSet.toStdWString(); -#else - std::string a_sNameStd = a_sName.toStdString(); - std::string a_szCharSetStd = a_szCharSet.toStdString(); -#endif - if ( !a_sNameStd.length() || (a_sNameStd.find_first_not_of(a_szCharSetStd)!=string_type::npos) || - (a_sNameStd[0]>='0' && a_sNameStd[0]<='9')) - { - Error(ecINVALID_NAME); - } -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Set the formula. - * @param a_strFormula Formula as string_type - * @throw ParserException in case of syntax errors. - * - * Triggers first time calculation thus the creation of the bytecode and scanning of used variables. - */ -void QmuParserBase::SetExpr(const QString &a_sExpr) -{ - // Check locale compatibility - std::locale loc; - if (m_pTokenReader->GetArgSep()==std::use_facet >(loc).decimal_point()) - { - Error(ecLOCALE); - } - - // 20060222: Bugfix for Borland-Kylix: - // adding a space to the expression will keep Borlands KYLIX from going wild - // when calling tellg on a stringstream created from the expression after - // reading a value at the end of an expression. (qmu::QmuParser::IsVal function) - // (tellg returns -1 otherwise causing the parser to ignore the value) - QString sBuf(a_sExpr + " " ); - m_pTokenReader->SetFormula(sBuf); - ReInit(); -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Get the default symbols used for the built in operators. - * @sa c_DefaultOprt - */ -const QStringList &QmuParserBase::GetOprtDef() const -{ - return c_DefaultOprt; -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Define the set of valid characters to be used in names of functions, variables, constants. - */ -void QmuParserBase::DefineNameChars(const QString &a_szCharset) -{ - m_sNameChars = a_szCharset; -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Define the set of valid characters to be used in names of binary operators and postfix operators. - */ -void QmuParserBase::DefineOprtChars(const QString &a_szCharset) -{ - m_sOprtChars = a_szCharset; -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Define the set of valid characters to be used in names of infix operators. - */ -void QmuParserBase::DefineInfixOprtChars(const QString &a_szCharset) -{ - m_sInfixOprtChars = a_szCharset; -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Virtual function that defines the characters allowed in name identifiers. - * @sa #ValidOprtChars, #ValidPrefixOprtChars - */ -const QString& QmuParserBase::ValidNameChars() const -{ - assert(m_sNameChars.size()); - return m_sNameChars; -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Virtual function that defines the characters allowed in operator definitions. - * @sa #ValidNameChars, #ValidPrefixOprtChars - */ -const QString &QmuParserBase::ValidOprtChars() const -{ - assert(m_sOprtChars.size()); - return m_sOprtChars; -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Virtual function that defines the characters allowed in infix operator definitions. - * @sa #ValidNameChars, #ValidOprtChars - */ -const QString &QmuParserBase::ValidInfixOprtChars() const -{ - assert(m_sInfixOprtChars.size()); - return m_sInfixOprtChars; -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Add a user defined operator. - * @post Will reset the Parser to string parsing mode. - */ -void QmuParserBase::DefinePostfixOprt(const QString &a_sName, fun_type1 a_pFun, bool a_bAllowOpt) -{ - AddCallback(a_sName, QmuParserCallback(a_pFun, a_bAllowOpt, prPOSTFIX, cmOPRT_POSTFIX), m_PostOprtDef, - ValidOprtChars() ); -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Initialize user defined functions. - * - * Calls the virtual functions InitFun(), InitConst() and InitOprt(). - */ -void QmuParserBase::Init() -{ - InitCharSets(); - InitFun(); - InitConst(); - InitOprt(); -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Add a user defined operator. - * @post Will reset the Parser to string parsing mode. - * @param [in] a_sName operator Identifier - * @param [in] a_pFun Operator callback function - * @param [in] a_iPrec Operator Precedence (default=prSIGN) - * @param [in] a_bAllowOpt True if operator is volatile (default=false) - * @sa EPrec - */ -void QmuParserBase::DefineInfixOprt(const QString &a_sName, fun_type1 a_pFun, int a_iPrec, bool a_bAllowOpt) -{ - AddCallback(a_sName, QmuParserCallback(a_pFun, a_bAllowOpt, a_iPrec, cmOPRT_INFIX), m_InfixOprtDef, - ValidInfixOprtChars() ); -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Define a binary operator. - * @param [in] a_sName The identifier of the operator. - * @param [in] a_pFun Pointer to the callback function. - * @param [in] a_iPrec Precedence of the operator. - * @param [in] a_eAssociativity The associativity of the operator. - * @param [in] a_bAllowOpt If this is true the operator may be optimized away. - * - * Adds a new Binary operator the the parser instance. - */ -void QmuParserBase::DefineOprt( const QString &a_sName, fun_type2 a_pFun, unsigned a_iPrec, - EOprtAssociativity a_eAssociativity, bool a_bAllowOpt ) -{ - // Check for conflicts with built in operator names - for (int i=0; m_bBuiltInOp && iIgnoreUndefVar(true); - CreateRPN(); // try to create bytecode, but don't use it for any further calculations since it - // may contain references to nonexisting variables. - m_pParseFormula = &QmuParserBase::ParseString; - m_pTokenReader->IgnoreUndefVar(false); - } - catch(exception_type &e) - { - // Make sure to stay in string parse mode, dont call ReInit() - // because it deletes the array with the used variables - m_pParseFormula = &QmuParserBase::ParseString; - m_pTokenReader->IgnoreUndefVar(false); - throw e; - } - return m_pTokenReader->GetUsedVar(); -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Return a map containing the used variables only. - */ -const varmap_type& QmuParserBase::GetVar() const -{ - return m_VarDef; -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Return a map containing all parser constants. - */ -const valmap_type& QmuParserBase::GetConst() const -{ - return m_ConstDef; -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Return prototypes of all parser functions. - * @return #m_FunDef - * @sa FunProt - * @throw nothrow - * - * The return type is a map of the public type #funmap_type containing the prototype definitions for all numerical - * parser functions. String functions are not part of this map. The Prototype definition is encapsulated in objects - * of the class FunProt one per parser function each associated with function names via a map construct. - */ -const funmap_type& QmuParserBase::GetFunDef() const -{ - return m_FunDef; -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Retrieve the formula. - */ -const QString& QmuParserBase::GetExpr() const -{ - return m_pTokenReader->GetExpr(); -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Execute a function that takes a single string argument. - * @param a_FunTok Function token. - * @throw exception_type If the function token is not a string function - */ -QmuParserBase::token_type QmuParserBase::ApplyStrFunc(const token_type &a_FunTok, - const QVector &a_vArg) const -{ - if (a_vArg.back().GetCode()!=cmSTRING) - { - Error(ecSTRING_EXPECTED, m_pTokenReader->GetPos(), a_FunTok.GetAsString()); - } - - token_type valTok; - generic_fun_type pFunc = a_FunTok.GetFuncAddr(); - assert(pFunc); - - try - { - // Check function arguments; write dummy value into valtok to represent the result - switch(a_FunTok.GetArgCount()) - { - case 0: - valTok.SetVal(1); - a_vArg[0].GetAsString(); - break; - case 1: - valTok.SetVal(1); - a_vArg[1].GetAsString(); - a_vArg[0].GetVal(); - break; - case 2: - valTok.SetVal(1); - a_vArg[2].GetAsString(); - a_vArg[1].GetVal(); - a_vArg[0].GetVal(); - break; - default: - Error(ecINTERNAL_ERROR); - break; - } - } - catch(QmuParserError& ) - { - Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), a_FunTok.GetAsString()); - } - - // string functions won't be optimized - m_vRPN.AddStrFun(pFunc, a_FunTok.GetArgCount(), a_vArg.back().GetIdx()); - - // Push dummy value representing the function result to the stack - return valTok; -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Apply a function token. - * @param iArgCount Number of Arguments actually gathered used only for multiarg functions. - * @post The result is pushed to the value stack - * @post The function token is removed from the stack - * @throw exception_type if Argument count does not mach function requirements. - */ -void QmuParserBase::ApplyFunc( QStack &a_stOpt, QStack &a_stVal, int a_iArgCount) const -{ - assert(m_pTokenReader.get()); - - // Operator stack empty or does not contain tokens with callback functions - if (a_stOpt.empty() || a_stOpt.top().GetFuncAddr()==0 ) - { - return; - } - - token_type funTok = a_stOpt.pop(); - assert(funTok.GetFuncAddr()); - - // Binary operators must rely on their internal operator number - // since counting of operators relies on commas for function arguments - // binary operators do not have commas in their expression - int iArgCount = (funTok.GetCode()==cmOPRT_BIN) ? funTok.GetArgCount() : a_iArgCount; - - // determine how many parameters the function needs. To remember iArgCount includes the - // string parameter whilst GetArgCount() counts only numeric parameters. - int iArgRequired = funTok.GetArgCount() + ((funTok.GetType()==tpSTR) ? 1 : 0); - - // Thats the number of numerical parameters - int iArgNumerical = iArgCount - ((funTok.GetType()==tpSTR) ? 1 : 0); - - if (funTok.GetCode()==cmFUNC_STR && iArgCount-iArgNumerical>1) - { - Error(ecINTERNAL_ERROR); - } - - if (funTok.GetArgCount()>=0 && iArgCount>iArgRequired) - { - Error(ecTOO_MANY_PARAMS, m_pTokenReader->GetPos()-1, funTok.GetAsString()); - } - - if (funTok.GetCode()!=cmOPRT_BIN && iArgCountGetPos()-1, funTok.GetAsString()); - } - - if (funTok.GetCode()==cmFUNC_STR && iArgCount>iArgRequired ) - { - Error(ecTOO_MANY_PARAMS, m_pTokenReader->GetPos()-1, funTok.GetAsString()); - } - - // Collect the numeric function arguments from the value stack and store them - // in a vector - QVector stArg; - for (int i=0; iGetPos(), funTok.GetAsString()); - } - } - - switch(funTok.GetCode()) - { - case cmFUNC_STR: - stArg.push_back(a_stVal.pop()); - - if ( stArg.back().GetType()==tpSTR && funTok.GetType()!=tpSTR ) - { - Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), funTok.GetAsString()); - } - - ApplyStrFunc(funTok, stArg); - break; - case cmFUNC_BULK: - m_vRPN.AddBulkFun(funTok.GetFuncAddr(), stArg.size()); - break; - case cmOPRT_BIN: - case cmOPRT_POSTFIX: - case cmOPRT_INFIX: - case cmFUNC: - if (funTok.GetArgCount()==-1 && iArgCount==0) - { - Error(ecTOO_FEW_PARAMS, m_pTokenReader->GetPos(), funTok.GetAsString()); - } - - m_vRPN.AddFun(funTok.GetFuncAddr(), (funTok.GetArgCount()==-1) ? -iArgNumerical : iArgNumerical); - break; - case cmLE: - Q_UNREACHABLE(); - break; - case cmGE: - Q_UNREACHABLE(); - break; - case cmNEQ: - Q_UNREACHABLE(); - break; - case cmEQ: - Q_UNREACHABLE(); - break; - case cmLT: - Q_UNREACHABLE(); - break; - case cmGT: - Q_UNREACHABLE(); - break; - case cmADD: - Q_UNREACHABLE(); - break; - case cmSUB: - Q_UNREACHABLE(); - break; - case cmMUL: - Q_UNREACHABLE(); - break; - case cmDIV: - Q_UNREACHABLE(); - break; - case cmPOW: - Q_UNREACHABLE(); - break; - case cmLAND: - Q_UNREACHABLE(); - break; - case cmLOR: - Q_UNREACHABLE(); - break; - case cmASSIGN: - Q_UNREACHABLE(); - break; - case cmBO: - Q_UNREACHABLE(); - break; - case cmBC: - Q_UNREACHABLE(); - break; - case cmIF: - Q_UNREACHABLE(); - break; - case cmELSE: - Q_UNREACHABLE(); - break; - case cmENDIF: - Q_UNREACHABLE(); - break; - case cmARG_SEP: - Q_UNREACHABLE(); - break; - case cmVAR: - Q_UNREACHABLE(); - break; - case cmVAL: - Q_UNREACHABLE(); - break; - case cmVARPOW2: - Q_UNREACHABLE(); - break; - case cmVARPOW3: - Q_UNREACHABLE(); - break; - case cmVARPOW4: - Q_UNREACHABLE(); - break; - case cmVARMUL: - Q_UNREACHABLE(); - break; - case cmPOW2: - Q_UNREACHABLE(); - break; - case cmSTRING: - Q_UNREACHABLE(); - break; - case cmEND: - Q_UNREACHABLE(); - break; - case cmUNKNOWN: - Q_UNREACHABLE(); - break; - default: - break; - } - // Push dummy value representing the function result to the stack - token_type token; - token.SetVal(1); - a_stVal.push(token); -} - -//---------------------------------------------------------------------------------------------------------------------- -void QmuParserBase::ApplyIfElse(QStack &a_stOpt, QStack &a_stVal) const -{ - // Check if there is an if Else clause to be calculated - while (a_stOpt.size() && a_stOpt.top().GetCode()==cmELSE) - { - token_type opElse = a_stOpt.pop(); - Q_ASSERT(a_stOpt.size()>0); - - // Take the value associated with the else branch from the value stack - token_type vVal2 = a_stVal.pop(); - - Q_ASSERT(a_stOpt.size()>0); - Q_ASSERT(a_stVal.size()>=2); - - // it then else is a ternary operator Pop all three values from the value s - // tack and just return the right value - token_type vVal1 = a_stVal.pop(); - token_type vExpr = a_stVal.pop(); - - a_stVal.push( (qFuzzyCompare(vExpr.GetVal()+1, 1+0)==false) ? vVal1 : vVal2); - - token_type opIf = a_stOpt.pop(); - Q_ASSERT(opElse.GetCode()==cmELSE); - Q_ASSERT(opIf.GetCode()==cmIF); - - m_vRPN.AddIfElse(cmENDIF); - } // while pending if-else-clause found -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Performs the necessary steps to write code for the execution of binary operators into the bytecode. - */ -void QmuParserBase::ApplyBinOprt(QStack &a_stOpt, QStack &a_stVal) const -{ - // is it a user defined binary operator? - if (a_stOpt.top().GetCode()==cmOPRT_BIN) - { - ApplyFunc(a_stOpt, a_stVal, 2); - } - else - { - Q_ASSERT(a_stVal.size()>=2); - token_type valTok1 = a_stVal.pop(), - valTok2 = a_stVal.pop(), - optTok = a_stOpt.pop(), - resTok; - - if ( valTok1.GetType()!=valTok2.GetType() || (valTok1.GetType()==tpSTR && valTok2.GetType()==tpSTR) ) - { - Error(ecOPRT_TYPE_CONFLICT, m_pTokenReader->GetPos(), optTok.GetAsString()); - } - - if (optTok.GetCode()==cmASSIGN) - { - if (valTok2.GetCode()!=cmVAR) - { - Error(ecUNEXPECTED_OPERATOR, -1, "="); - } - m_vRPN.AddAssignOp(valTok2.GetVar()); - } - else - { - m_vRPN.AddOp(optTok.GetCode()); - } - resTok.SetVal(1); - a_stVal.push(resTok); - } -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Apply a binary operator. - * @param a_stOpt The operator stack - * @param a_stVal The value stack - */ -void QmuParserBase::ApplyRemainingOprt(QStack &stOpt, QStack &stVal) const -{ - while (stOpt.size() && stOpt.top().GetCode() != cmBO && stOpt.top().GetCode() != cmIF) - { - token_type tok = stOpt.top(); - switch (tok.GetCode()) - { - case cmOPRT_INFIX: - case cmOPRT_BIN: - case cmLE: - case cmGE: - case cmNEQ: - case cmEQ: - case cmLT: - case cmGT: - case cmADD: - case cmSUB: - case cmMUL: - case cmDIV: - case cmPOW: - case cmLAND: - case cmLOR: - case cmASSIGN: - if (stOpt.top().GetCode()==cmOPRT_INFIX) - { - ApplyFunc(stOpt, stVal, 1); - } - else - { - ApplyBinOprt(stOpt, stVal); - } - break; - case cmELSE: - ApplyIfElse(stOpt, stVal); - break; - case cmBO: - Q_UNREACHABLE(); - break; - case cmBC: - Q_UNREACHABLE(); - break; - case cmIF: - Q_UNREACHABLE(); - break; - case cmENDIF: - Q_UNREACHABLE(); - break; - case cmARG_SEP: - Q_UNREACHABLE(); - break; - case cmVAR: - Q_UNREACHABLE(); - break; - case cmVAL: - Q_UNREACHABLE(); - break; - case cmVARPOW2: - Q_UNREACHABLE(); - break; - case cmVARPOW3: - Q_UNREACHABLE(); - break; - case cmVARPOW4: - Q_UNREACHABLE(); - break; - case cmVARMUL: - Q_UNREACHABLE(); - break; - case cmPOW2: - Q_UNREACHABLE(); - break; - case cmFUNC: - Q_UNREACHABLE(); - break; - case cmFUNC_STR: - Q_UNREACHABLE(); - break; - case cmFUNC_BULK: - Q_UNREACHABLE(); - break; - case cmSTRING: - Q_UNREACHABLE(); - break; - case cmOPRT_POSTFIX: - Q_UNREACHABLE(); - break; - case cmEND: - Q_UNREACHABLE(); - break; - case cmUNKNOWN: - Q_UNREACHABLE(); - break; - default: - Error(ecINTERNAL_ERROR); - break; - } - } -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Parse the command code. - * @sa ParseString(...) - * - * Command code contains precalculated stack positions of the values and the associated operators. The Stack is - * filled beginning from index one the value at index zero is not used at all. - */ -qreal QmuParserBase::ParseCmdCode() const -{ - return ParseCmdCodeBulk(0, 0); -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Evaluate the RPN. - * @param nOffset The offset added to variable addresses (for bulk mode) - * @param nThreadID OpenMP Thread id of the calling thread - */ -qreal QmuParserBase::ParseCmdCodeBulk(int nOffset, int nThreadID) const -{ - assert(nThreadID<=s_MaxNumOpenMPThreads); - - // Note: The check for nOffset==0 and nThreadID here is not necessary but - // brings a minor performance gain when not in bulk mode. - qreal *Stack = ((nOffset==0) && (nThreadID==0)) ? &m_vStackBuffer[0] : &m_vStackBuffer[nThreadID * - (m_vStackBuffer.size() / s_MaxNumOpenMPThreads)]; - qreal buf; - int sidx(0); - for (const SToken *pTok = m_vRPN.GetBase(); pTok->Cmd!=cmEND ; ++pTok) - { - switch (pTok->Cmd) - { - // built in binary operators - case cmLE: - --sidx; - Stack[sidx] = Stack[sidx] <= Stack[sidx+1]; - continue; - case cmGE: - --sidx; - Stack[sidx] = Stack[sidx] >= Stack[sidx+1]; - continue; - case cmNEQ: - --sidx; - Stack[sidx] = (qFuzzyCompare(Stack[sidx], Stack[sidx+1])==false); - continue; - case cmEQ: - --sidx; - Stack[sidx] = qFuzzyCompare(Stack[sidx], Stack[sidx+1]); - continue; - case cmLT: - --sidx; - Stack[sidx] = Stack[sidx] < Stack[sidx+1]; - continue; - case cmGT: - --sidx; - Stack[sidx] = Stack[sidx] > Stack[sidx+1]; - continue; - case cmADD: - --sidx; - Stack[sidx] += Stack[1+sidx]; - continue; - case cmSUB: - --sidx; - Stack[sidx] -= Stack[1+sidx]; - continue; - case cmMUL: - --sidx; - Stack[sidx] *= Stack[1+sidx]; - continue; - case cmDIV: - --sidx; - #if defined(MUP_MATH_EXCEPTIONS) - if (Stack[1+sidx]==0) - { - Error(ecDIV_BY_ZERO); - } - #endif - Stack[sidx] /= Stack[1+sidx]; - continue; - case cmPOW: - --sidx; - Stack[sidx] = qPow(Stack[sidx], Stack[1+sidx]); - continue; - case cmLAND: - --sidx; -#ifdef Q_CC_GNU - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wfloat-equal" -#endif - Stack[sidx] = Stack[sidx] && Stack[sidx+1]; -#ifdef Q_CC_GNU - #pragma GCC diagnostic pop -#endif - continue; - case cmLOR: - --sidx; -#ifdef Q_CC_GNU - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wfloat-equal" -#endif - Stack[sidx] = Stack[sidx] || Stack[sidx+1]; -#ifdef Q_CC_GNU - #pragma GCC diagnostic pop -#endif - continue; - case cmASSIGN: - --sidx; - Stack[sidx] = *pTok->Oprt.ptr = Stack[sidx+1]; - continue; - case cmBO: // unused, listed for compiler optimization purposes - Q_UNREACHABLE(); - break; - case cmBC: - Q_UNREACHABLE(); - break; - // Q_ASSERT(INVALID_CODE_IN_BYTECODE); - // continue; - case cmIF: - if (qFuzzyCompare(Stack[sidx--]+1, 1+0)) - { - pTok += pTok->Oprt.offset; - } - continue; - case cmELSE: - pTok += pTok->Oprt.offset; - continue; - case cmENDIF: - continue; - case cmARG_SEP: - Q_UNREACHABLE(); - break; - // Q_ASSERT(INVALID_CODE_IN_BYTECODE); - // continue; - - // value and variable tokens - case cmVAR: - Stack[++sidx] = *(pTok->Val.ptr + nOffset); - continue; - case cmVAL: - Stack[++sidx] = pTok->Val.data2; - continue; - case cmVARPOW2: - buf = *(pTok->Val.ptr + nOffset); - Stack[++sidx] = buf*buf; - continue; - case cmVARPOW3: - buf = *(pTok->Val.ptr + nOffset); - Stack[++sidx] = buf*buf*buf; - continue; - case cmVARPOW4: - buf = *(pTok->Val.ptr + nOffset); - Stack[++sidx] = buf*buf*buf*buf; - continue; - case cmVARMUL: - Stack[++sidx] = *(pTok->Val.ptr + nOffset) * pTok->Val.data + pTok->Val.data2; - continue; - // Next is treatment of numeric functions - case cmFUNC: - { - int iArgCount = pTok->Fun.argc; - - // switch according to argument count - switch(iArgCount) - { - case 0: - sidx += 1; - Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(); - continue; - case 1: - Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(Stack[sidx]); - continue; - case 2: - sidx -= 1; - Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(Stack[sidx], Stack[sidx+1]); - continue; - case 3: - sidx -= 2; - Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(Stack[sidx], Stack[sidx+1], - Stack[sidx+2]); - continue; - case 4: - sidx -= 3; - Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(Stack[sidx], Stack[sidx+1], - Stack[sidx+2], Stack[sidx+3]); - continue; - case 5: - sidx -= 4; - Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(Stack[sidx], Stack[sidx+1], - Stack[sidx+2], Stack[sidx+3], Stack[sidx+4]); - continue; - case 6: - sidx -= 5; - Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(Stack[sidx], Stack[sidx+1], - Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5]); - continue; - case 7: - sidx -= 6; - Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(Stack[sidx], Stack[sidx+1], - Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6]); - continue; - case 8: - sidx -= 7; - Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(Stack[sidx], Stack[sidx+1], - Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], - Stack[sidx+7]); - continue; - case 9: - sidx -= 8; - Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(Stack[sidx], Stack[sidx+1], - Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], - Stack[sidx+7], Stack[sidx+8]); - continue; - case 10: - sidx -= 9; - Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(Stack[sidx], Stack[sidx+1], - Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], - Stack[sidx+7], Stack[sidx+8], Stack[sidx+9]); - continue; - default: - if (iArgCount>0) // function with variable arguments store the number as a negative value - { - Error(ecINTERNAL_ERROR, 1); - } - - sidx -= -iArgCount - 1; - Stack[sidx] =(*reinterpret_cast(pTok->Fun.ptr))(&Stack[sidx], -iArgCount); - continue; - } - } - // Next is treatment of string functions - case cmFUNC_STR: - { - sidx -= pTok->Fun.argc -1; - - // The index of the string argument in the string table - int iIdxStack = pTok->Fun.idx; - Q_ASSERT( iIdxStack>=0 && iIdxStackFun.argc) // switch according to argument count - { - case 0: - Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(m_vStringBuf.at(iIdxStack)); - continue; - case 1: - Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(m_vStringBuf.at(iIdxStack), - Stack[sidx]); - continue; - case 2: - Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(m_vStringBuf.at(iIdxStack), - Stack[sidx], Stack[sidx+1]); - continue; - default: - break; - } - - continue; - } - case cmFUNC_BULK: - { - int iArgCount = pTok->Fun.argc; - - // switch according to argument count - switch(iArgCount) - { - case 0: - sidx += 1; - Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(nOffset, nThreadID); - continue; - case 1: - Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(nOffset, nThreadID, - Stack[sidx]); - continue; - case 2: - sidx -= 1; - Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(nOffset, nThreadID, Stack[sidx], - Stack[sidx+1]); - continue; - case 3: - sidx -= 2; - Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(nOffset, nThreadID, Stack[sidx], - Stack[sidx+1], Stack[sidx+2]); - continue; - case 4: - sidx -= 3; - Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(nOffset, nThreadID, Stack[sidx], - Stack[sidx+1], Stack[sidx+2], Stack[sidx+3]); - continue; - case 5: - sidx -= 4; - Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(nOffset, nThreadID, Stack[sidx], - Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], - Stack[sidx+4]); - continue; - case 6: - sidx -= 5; - Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(nOffset, nThreadID, Stack[sidx], - Stack[sidx+1], Stack[sidx+2], - Stack[sidx+3], Stack[sidx+4], Stack[sidx+5]); - continue; - case 7: - sidx -= 6; - Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(nOffset, nThreadID, Stack[sidx], - Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], - Stack[sidx+4], Stack[sidx+5], Stack[sidx+6]); - continue; - case 8: - sidx -= 7; - Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(nOffset, nThreadID, Stack[sidx], - Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], - Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7]); - continue; - case 9: - sidx -= 8; - Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(nOffset, nThreadID, Stack[sidx], - Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], - Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7], Stack[sidx+8]); - continue; - case 10: - sidx -= 9; - Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(nOffset, nThreadID, - Stack[sidx], - Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], - Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7], Stack[sidx+8], - Stack[sidx+9]); - continue; - default: - Error(ecINTERNAL_ERROR, 2); - continue; - } - } - case cmSTRING: - Q_UNREACHABLE(); - break; - case cmOPRT_BIN: - Q_UNREACHABLE(); - break; - case cmOPRT_POSTFIX: - Q_UNREACHABLE(); - break; - case cmOPRT_INFIX: - Q_UNREACHABLE(); - break; - // Q_ASSERT(INVALID_CODE_IN_BYTECODE); - // continue; - case cmEND: - Q_UNREACHABLE(); - break; - // return Stack[m_nFinalResultIdx]; - case cmPOW2: - Q_UNREACHABLE(); - break; - case cmUNKNOWN: - Q_UNREACHABLE(); - break; - default: - Error(ecINTERNAL_ERROR, 3); - return 0; - } // switch CmdCode - } // for all bytecode tokens - - return Stack[m_nFinalResultIdx]; -} - -//---------------------------------------------------------------------------------------------------------------------- -void QmuParserBase::CreateRPN() const -{ - if (!m_pTokenReader->GetExpr().length()) - { - Error(ecUNEXPECTED_EOF, 0); - } - - QStack stOpt, stVal; - QStack stArgCount; - token_type opta, opt; // for storing operators - token_type val, tval; // for storing value - string_type strBuf; // buffer for string function arguments - - ReInit(); - - // The outermost counter counts the number of seperated items - // such as in "a=10,b=20,c=c+a" - stArgCount.push(1); - - for(;;) - { - opt = m_pTokenReader->ReadNextToken(); - - switch (opt.GetCode()) - { - // - // Next three are different kind of value entries - // - case cmSTRING: - opt.SetIdx(m_vStringBuf.size()); // Assign buffer index to token - stVal.push(opt); - m_vStringBuf.push_back(opt.GetAsString()); // Store string in internal buffer - break; - case cmVAR: - stVal.push(opt); - m_vRPN.AddVar( static_cast(opt.GetVar()) ); - break; - case cmVAL: - stVal.push(opt); - m_vRPN.AddVal( opt.GetVal() ); - break; - case cmELSE: - m_nIfElseCounter--; - if (m_nIfElseCounter<0) - { - Error(ecMISPLACED_COLON, m_pTokenReader->GetPos()); - } - ApplyRemainingOprt(stOpt, stVal); - m_vRPN.AddIfElse(cmELSE); - stOpt.push(opt); - break; - case cmARG_SEP: - if (stArgCount.empty()) - { - Error(ecUNEXPECTED_ARG_SEP, m_pTokenReader->GetPos()); - } - ++stArgCount.top(); - // fallthrough intentional (no break!) - case cmEND: - ApplyRemainingOprt(stOpt, stVal); - break; - case cmBC: - { - // The argument count for parameterless functions is zero - // by default an opening bracket sets parameter count to 1 - // in preparation of arguments to come. If the last token - // was an opening bracket we know better... - if (opta.GetCode()==cmBO) - { - --stArgCount.top(); - } - - ApplyRemainingOprt(stOpt, stVal); - - // Check if the bracket content has been evaluated completely - if (stOpt.size() && stOpt.top().GetCode()==cmBO) - { - // if opt is ")" and opta is "(" the bracket has been evaluated, now its time to check - // if there is either a function or a sign pending - // neither the opening nor the closing bracket will be pushed back to - // the operator stack - // Check if a function is standing in front of the opening bracket, - // if yes evaluate it afterwards check for infix operators - assert(stArgCount.size()); - int iArgCount = stArgCount.pop(); - - stOpt.pop(); // Take opening bracket from stack - - if (iArgCount>1 && ( stOpt.size()==0 || (stOpt.top().GetCode()!=cmFUNC && - stOpt.top().GetCode()!=cmFUNC_BULK && - stOpt.top().GetCode()!=cmFUNC_STR) ) ) - { - Error(ecUNEXPECTED_ARG, m_pTokenReader->GetPos()); - } - - // The opening bracket was popped from the stack now check if there - // was a function before this bracket - if (stOpt.size() && stOpt.top().GetCode()!=cmOPRT_INFIX && stOpt.top().GetCode()!=cmOPRT_BIN && - stOpt.top().GetFuncAddr()!=0) - { - ApplyFunc(stOpt, stVal, iArgCount); - } - } - } // if bracket content is evaluated - break; - // - // Next are the binary operator entries - // - //case cmAND: // built in binary operators - //case cmOR: - //case cmXOR: - case cmIF: - m_nIfElseCounter++; - // fallthrough intentional (no break!) - case cmLAND: - case cmLOR: - case cmLT: - case cmGT: - case cmLE: - case cmGE: - case cmNEQ: - case cmEQ: - case cmADD: - case cmSUB: - case cmMUL: - case cmDIV: - case cmPOW: - case cmASSIGN: - case cmOPRT_BIN: - // A binary operator (user defined or built in) has been found. - while ( stOpt.size() && stOpt.top().GetCode() != cmBO && stOpt.top().GetCode() != cmELSE && - stOpt.top().GetCode() != cmIF) - { - int nPrec1 = GetOprtPrecedence(stOpt.top()), - nPrec2 = GetOprtPrecedence(opt); - - if (stOpt.top().GetCode()==opt.GetCode()) - { - // Deal with operator associativity - EOprtAssociativity eOprtAsct = GetOprtAssociativity(opt); - if ( (eOprtAsct==oaRIGHT && (nPrec1 <= nPrec2)) || - (eOprtAsct==oaLEFT && (nPrec1 < nPrec2)) ) - { - break; - } - } - else if (nPrec1 < nPrec2) - { - // In case the operators are not equal the precedence decides alone... - break; - } - if (stOpt.top().GetCode()==cmOPRT_INFIX) - { - ApplyFunc(stOpt, stVal, 1); - } - else - { - ApplyBinOprt(stOpt, stVal); - } - } // while ( ... ) - - if (opt.GetCode()==cmIF) - { - m_vRPN.AddIfElse(opt.GetCode()); - } - - // The operator can't be evaluated right now, push back to the operator stack - stOpt.push(opt); - break; - // - // Last section contains functions and operators implicitely mapped to functions - // - case cmBO: - stArgCount.push(1); - stOpt.push(opt); - break; - case cmOPRT_INFIX: - case cmFUNC: - case cmFUNC_BULK: - case cmFUNC_STR: - stOpt.push(opt); - break; - case cmOPRT_POSTFIX: - stOpt.push(opt); - ApplyFunc(stOpt, stVal, 1); // this is the postfix operator - break; - case cmENDIF: - Q_UNREACHABLE(); - break; - case cmVARPOW2: - Q_UNREACHABLE(); - break; - case cmVARPOW3: - Q_UNREACHABLE(); - break; - case cmVARPOW4: - Q_UNREACHABLE(); - break; - case cmVARMUL: - Q_UNREACHABLE(); - break; - case cmPOW2: - Q_UNREACHABLE(); - break; - case cmUNKNOWN: - Q_UNREACHABLE(); - break; - default: - Error(ecINTERNAL_ERROR, 3); - } // end of switch operator-token - - opta = opt; - - if ( opt.GetCode() == cmEND ) - { - m_vRPN.Finalize(); - break; - } - - if (QmuParserBase::g_DbgDumpStack) - { - StackDump(stVal, stOpt); - m_vRPN.AsciiDump(); - } - } // while (true) - - if (QmuParserBase::g_DbgDumpCmdCode) - { - m_vRPN.AsciiDump(); - } - - if (m_nIfElseCounter>0) - { - Error(ecMISSING_ELSE_CLAUSE); - } - - // get the last value (= final result) from the stack - Q_ASSERT(stArgCount.size()==1); - m_nFinalResultIdx = stArgCount.top(); - if (m_nFinalResultIdx==0) - { - Error(ecINTERNAL_ERROR, 9); - } - - if (stVal.size()==0) - { - Error(ecEMPTY_EXPRESSION); - } - - if (stVal.top().GetType()!=tpDBL) - { - Error(ecSTR_RESULT); - } - - m_vStackBuffer.resize(m_vRPN.GetMaxStackSize() * s_MaxNumOpenMPThreads); -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief One of the two main parse functions. - * @sa ParseCmdCode(...) - * - * Parse expression from input string. Perform syntax checking and create bytecode. After parsing the string and - * creating the bytecode the function pointer #m_pParseFormula will be changed to the second parse routine the - * uses bytecode instead of string parsing. - */ -qreal QmuParserBase::ParseString() const -{ - try - { - CreateRPN(); - m_pParseFormula = &QmuParserBase::ParseCmdCode; - return (this->*m_pParseFormula)(); - } - catch(QmuParserError &exc) - { - exc.SetFormula(m_pTokenReader->GetExpr()); - throw; - } -} - -//---------------------------------------------------------------------------------------------------------------------- -/** -* @brief Create an error containing the parse error position. -* -* This function will create an Parser Exception object containing the error text and its position. -* -* @param a_iErrc [in] The error code of type #EErrorCodes. -* @param a_iPos [in] The position where the error was detected. -* @param a_strTok [in] The token string representation associated with the error. -* @throw ParserException always throws thats the only purpose of this function. -*/ -void Q_NORETURN QmuParserBase::Error(EErrorCodes a_iErrc, int a_iPos, const QString &a_sTok) const -{ - throw exception_type(a_iErrc, a_sTok, m_pTokenReader->GetExpr(), a_iPos); -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Clear all user defined variables. - * @throw nothrow - * - * Resets the parser to string parsing mode by calling #ReInit. - */ -void QmuParserBase::ClearVar() -{ - m_VarDef.clear(); - ReInit(); -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Remove a variable from internal storage. - * @throw nothrow - * - * Removes a variable if it exists. If the Variable does not exist nothing will be done. - */ -void QmuParserBase::RemoveVar(const QString &a_strVarName) -{ - varmap_type::iterator item = m_VarDef.find(a_strVarName); - if (item!=m_VarDef.end()) - { - m_VarDef.erase(item); - ReInit(); - } -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Clear all functions. - * @post Resets the parser to string parsing mode. - * @throw nothrow - */ -void QmuParserBase::ClearFun() -{ - m_FunDef.clear(); - ReInit(); -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Clear all user defined constants. - * - * Both numeric and string constants will be removed from the internal storage. - * @post Resets the parser to string parsing mode. - * @throw nothrow - */ -void QmuParserBase::ClearConst() -{ - m_ConstDef.clear(); - m_StrVarDef.clear(); - ReInit(); -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Clear all user defined postfix operators. - * @post Resets the parser to string parsing mode. - * @throw nothrow - */ -void QmuParserBase::ClearPostfixOprt() -{ - m_PostOprtDef.clear(); - ReInit(); -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Clear all user defined binary operators. - * @post Resets the parser to string parsing mode. - * @throw nothrow - */ -void QmuParserBase::ClearOprt() -{ - m_OprtDef.clear(); - ReInit(); -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Clear the user defined Prefix operators. - * @post Resets the parser to string parser mode. - * @throw nothrow - */ -void QmuParserBase::ClearInfixOprt() -{ - m_InfixOprtDef.clear(); - ReInit(); -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Enable or disable the formula optimization feature. - * @post Resets the parser to string parser mode. - * @throw nothrow - */ -void QmuParserBase::EnableOptimizer(bool a_bIsOn) -{ - m_vRPN.EnableOptimizer(a_bIsOn); - ReInit(); -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Enable the dumping of bytecode amd stack content on the console. - * @param bDumpCmd Flag to enable dumping of the current bytecode to the console. - * @param bDumpStack Flag to enable dumping of the stack content is written to the console. - * - * This function is for debug purposes only! - */ -void QmuParserBase::EnableDebugDump(bool bDumpCmd, bool bDumpStack) -{ - QmuParserBase::g_DbgDumpCmdCode = bDumpCmd; - QmuParserBase::g_DbgDumpStack = bDumpStack; -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Enable or disable the built in binary operators. - * @throw nothrow - * @sa m_bBuiltInOp, ReInit() - * - * If you disable the built in binary operators there will be no binary operators defined. Thus you must add them - * manually one by one. It is not possible to disable built in operators selectively. This function will Reinitialize - * the parser by calling ReInit(). - */ -void QmuParserBase::EnableBuiltInOprt(bool a_bIsOn) -{ - m_bBuiltInOp = a_bIsOn; - ReInit(); -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Query status of built in variables. - * @return #m_bBuiltInOp; true if built in operators are enabled. - * @throw nothrow - */ -bool QmuParserBase::HasBuiltInOprt() const -{ - return m_bBuiltInOp; -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Get the argument separator character. - */ -QChar QmuParserBase::GetArgSep() const -{ - return m_pTokenReader->GetArgSep(); -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Set argument separator. - * @param cArgSep the argument separator character. - */ -void QmuParserBase::SetArgSep(char_type cArgSep) -{ - m_pTokenReader->SetArgSep(cArgSep); -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Dump stack content. - * - * This function is used for debugging only. - */ -void QmuParserBase::StackDump(const QStack &a_stVal, const QStack &a_stOprt) const -{ - QStack stOprt(a_stOprt), - stVal(a_stVal); - - qDebug() << "\nValue stack:\n"; - while ( !stVal.empty() ) - { - token_type val = stVal.pop(); - if (val.GetType()==tpSTR) - { - qDebug() << " \"" << val.GetAsString() << "\" "; - } - else - { - qDebug() << " " << val.GetVal() << " "; - } - } - qDebug() << "\nOperator stack:\n"; - - while ( !stOprt.empty() ) - { - if (stOprt.top().GetCode()<=cmASSIGN) - { - qDebug() << "OPRT_INTRNL \"" << QmuParserBase::c_DefaultOprt[stOprt.top().GetCode()] << "\" \n"; - } - else - { - switch(stOprt.top().GetCode()) - { - case cmVAR: - qDebug() << "VAR\n"; - break; - case cmVAL: - qDebug() << "VAL\n"; - break; - case cmFUNC: - qDebug() << "FUNC \"" << stOprt.top().GetAsString() << "\"\n"; - break; - case cmFUNC_BULK: - qDebug() << "FUNC_BULK \"" << stOprt.top().GetAsString() << "\"\n"; - break; - case cmOPRT_INFIX: - qDebug() << "OPRT_INFIX \"" << stOprt.top().GetAsString() << "\"\n"; - break; - case cmOPRT_BIN: - qDebug() << "OPRT_BIN \"" << stOprt.top().GetAsString() << "\"\n"; - break; - case cmFUNC_STR: - qDebug() << "FUNC_STR\n"; - break; - case cmEND: - qDebug() << "END\n"; - break; - case cmUNKNOWN: - qDebug() << "UNKNOWN\n"; - break; - case cmBO: - qDebug() << "BRACKET \"(\"\n"; - break; - case cmBC: - qDebug() << "BRACKET \")\"\n"; - break; - case cmIF: - qDebug() << "IF\n"; - break; - case cmELSE: - qDebug() << "ELSE\n"; - break; - case cmENDIF: - qDebug() << "ENDIF\n"; - break; - case cmLE: - Q_UNREACHABLE(); - break; - case cmGE: - Q_UNREACHABLE(); - break; - case cmNEQ: - Q_UNREACHABLE(); - break; - case cmEQ: - Q_UNREACHABLE(); - break; - case cmLT: - Q_UNREACHABLE(); - break; - case cmGT: - Q_UNREACHABLE(); - break; - case cmADD: - Q_UNREACHABLE(); - break; - case cmSUB: - Q_UNREACHABLE(); - break; - case cmMUL: - Q_UNREACHABLE(); - break; - case cmDIV: - Q_UNREACHABLE(); - break; - case cmPOW: - Q_UNREACHABLE(); - break; - case cmLAND: - Q_UNREACHABLE(); - break; - case cmLOR: - Q_UNREACHABLE(); - break; - case cmASSIGN: - Q_UNREACHABLE(); - break; - case cmARG_SEP: - Q_UNREACHABLE(); - break; - case cmVARPOW2: - Q_UNREACHABLE(); - break; - case cmVARPOW3: - Q_UNREACHABLE(); - break; - case cmVARPOW4: - Q_UNREACHABLE(); - break; - case cmVARMUL: - Q_UNREACHABLE(); - break; - case cmPOW2: - Q_UNREACHABLE(); - break; - case cmSTRING: - Q_UNREACHABLE(); - break; - case cmOPRT_POSTFIX: - Q_UNREACHABLE(); - break; - default: - qDebug() << stOprt.top().GetCode() << " "; - break; - } - } - stOprt.pop(); - } - qDebug() << dec; -} - -//---------------------------------------------------------------------------------------------------------------------- -/** @brief Evaluate an expression containing comma seperated subexpressions - * @param [out] nStackSize The total number of results available - * @return Pointer to the array containing all expression results - * - * This member function can be used to retriev all results of an expression made up of multiple comma seperated - * subexpressions (i.e. "x+y,sin(x),cos(y)") - */ -qreal* QmuParserBase::Eval(int &nStackSize) const -{ - (this->*m_pParseFormula)(); - nStackSize = m_nFinalResultIdx; - - // (for historic reasons the stack starts at position 1) - return &m_vStackBuffer[1]; -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Return the number of results on the calculation stack. - * - * If the expression contains comma seperated subexpressions (i.e. "sin(y), x+y"). There mey be more than one return - * value. This function returns the number of available results. - */ -int QmuParserBase::GetNumResults() const -{ - return m_nFinalResultIdx; -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Calculate the result. - * - * A note on const correctness: - * I consider it important that Calc is a const function. - * Due to caching operations Calc changes only the state of internal variables with one exception - * m_UsedVar this is reset during string parsing and accessible from the outside. Instead of making - * Calc non const GetUsedVar is non const because it explicitely calls Eval() forcing this update. - * - * @pre A formula must be set. - * @pre Variables must have been set (if needed) - * - * @sa #m_pParseFormula - * @return The evaluation result - * @throw ParseException if no Formula is set or in case of any other error related to the formula. - */ -qreal QmuParserBase::Eval() const -{ - return (this->*m_pParseFormula)(); -} - -//---------------------------------------------------------------------------------------------------------------------- -void QmuParserBase::Eval(qreal *results, int nBulkSize) -{ - CreateRPN(); - - int i = 0; - - #ifdef QMUP_USE_OPENMP - //#define DEBUG_OMP_STUFF - #ifdef DEBUG_OMP_STUFF - int *pThread = new int[nBulkSize]; - int *pIdx = new int[nBulkSize]; - #endif - - int nMaxThreads = std::min(omp_get_max_threads(), s_MaxNumOpenMPThreads); - int nThreadID, ct=0; - omp_set_num_threads(nMaxThreads); - - #pragma omp parallel for schedule(static, nBulkSize/nMaxThreads) private(nThreadID) - for (i=0; i + ** + ** Permission is hereby granted, free of charge, to any person obtaining a copy of this + ** software and associated documentation files (the "Software"), to deal in the Software + ** without restriction, including without limitation the rights to use, copy, modify, + ** merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + ** permit persons to whom the Software is furnished to do so, subject to the following conditions: + ** + ** The above copyright notice and this permission notice shall be included in all copies or + ** substantial portions of the Software. + ** + ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + ** NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + ** DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ** + ******************************************************************************************************/ + +#include "qmuparserbase.h" +#include +#include +#ifdef QMUP_USE_OPENMP + #include +#endif + +using namespace std; + +/** + * @file + * @brief This file contains the basic implementation of the muparser engine. + */ + +namespace qmu +{ +std::locale QmuParserBase::s_locale = std::locale(std::locale::classic(), new change_dec_sep('.')); + +bool QmuParserBase::g_DbgDumpCmdCode = false; +bool QmuParserBase::g_DbgDumpStack = false; + +/** + * @brief Identifiers for built in binary operators. + * + * When defining custom binary operators with #AddOprt(...) make sure not to choose + * names conflicting with these definitions. + */ +const QStringList QmuParserBase::c_DefaultOprt = QStringList() << "<=" << ">=" << "!=" << "==" << "<" << ">" + << "+" << "-" << "*" << "/" << "^" << "&&" + << "||" << "=" << "(" << ")" << "?" << ":"; + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Constructor. + * @param a_szFormula the formula to interpret. + * @throw ParserException if a_szFormula is null. + */ +QmuParserBase::QmuParserBase() + :m_pParseFormula(&QmuParserBase::ParseString), m_vRPN(), m_vStringBuf(), m_vStringVarBuf(), m_pTokenReader(), + m_FunDef(), m_PostOprtDef(), m_InfixOprtDef(), m_OprtDef(), m_ConstDef(), m_StrVarDef(), m_VarDef(), + m_bBuiltInOp(true), m_sNameChars(), m_sOprtChars(), m_sInfixOprtChars(), m_nIfElseCounter(0), m_vStackBuffer(), + m_nFinalResultIdx(0) +{ + InitTokenReader(); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Copy constructor. + * + * Tha parser can be safely copy constructed but the bytecode is reset during copy construction. + */ +QmuParserBase::QmuParserBase(const QmuParserBase &a_Parser) + :m_pParseFormula(&QmuParserBase::ParseString), m_vRPN(), m_vStringBuf(), m_vStringVarBuf(), m_pTokenReader(), + m_FunDef(), m_PostOprtDef(), m_InfixOprtDef(), m_OprtDef(), m_ConstDef(), m_StrVarDef(), m_VarDef(), + m_bBuiltInOp(true), m_sNameChars(), m_sOprtChars(), m_sInfixOprtChars(), m_nIfElseCounter(0), m_vStackBuffer(), + m_nFinalResultIdx(0) +{ + m_pTokenReader.reset(new token_reader_type(this)); + Assign(a_Parser); +} + +//--------------------------------------------------------------------------------------------------------------------- +QmuParserBase::~QmuParserBase() +{} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Assignement operator. + * + * Implemented by calling Assign(a_Parser). Self assignement is suppressed. + * @param a_Parser Object to copy to this. + * @return *this + * @throw nothrow + */ +QmuParserBase& QmuParserBase::operator=(const QmuParserBase &a_Parser) +{ + Assign(a_Parser); + return *this; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Copy state of a parser object to this. + * + * Clears Variables and Functions of this parser. + * Copies the states of all internal variables. + * Resets parse function to string parse mode. + * + * @param a_Parser the source object. + */ +void QmuParserBase::Assign(const QmuParserBase &a_Parser) +{ + if (&a_Parser==this) + { + return; + } + + // Don't copy bytecode instead cause the parser to create new bytecode + // by resetting the parse function. + ReInit(); + + m_ConstDef = a_Parser.m_ConstDef; // Copy user define constants + m_VarDef = a_Parser.m_VarDef; // Copy user defined variables + m_bBuiltInOp = a_Parser.m_bBuiltInOp; + m_vStringBuf = a_Parser.m_vStringBuf; + m_vStackBuffer = a_Parser.m_vStackBuffer; + m_nFinalResultIdx = a_Parser.m_nFinalResultIdx; + m_StrVarDef = a_Parser.m_StrVarDef; + m_vStringVarBuf = a_Parser.m_vStringVarBuf; + m_nIfElseCounter = a_Parser.m_nIfElseCounter; + m_pTokenReader.reset(a_Parser.m_pTokenReader->Clone(this)); + + // Copy function and operator callbacks + m_FunDef = a_Parser.m_FunDef; // Copy function definitions + m_PostOprtDef = a_Parser.m_PostOprtDef; // post value unary operators + m_InfixOprtDef = a_Parser.m_InfixOprtDef; // unary operators for infix notation + m_OprtDef = a_Parser.m_OprtDef; // binary operators + + m_sNameChars = a_Parser.m_sNameChars; + m_sOprtChars = a_Parser.m_sOprtChars; + m_sInfixOprtChars = a_Parser.m_sInfixOprtChars; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Set the decimal separator. + * @param cDecSep Decimal separator as a character value. + * @sa SetThousandsSep + * + * By default muparser uses the "C" locale. The decimal separator of this + * locale is overwritten by the one provided here. + */ +void QmuParserBase::SetDecSep(char_type cDecSep) +{ + char_type cThousandsSep = std::use_facet< change_dec_sep >(s_locale).thousands_sep(); + s_locale = std::locale(std::locale("C"), new change_dec_sep(cDecSep, cThousandsSep)); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Sets the thousands operator. + * @param cThousandsSep The thousands separator as a character + * @sa SetDecSep + * + * By default muparser uses the "C" locale. The thousands separator of this + * locale is overwritten by the one provided here. + */ +void QmuParserBase::SetThousandsSep(char_type cThousandsSep) +{ + char_type cDecSep = std::use_facet< change_dec_sep >(s_locale).decimal_point(); + s_locale = std::locale(std::locale("C"), new change_dec_sep(cDecSep, cThousandsSep)); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Resets the locale. + * + * The default locale used "." as decimal separator, no thousands separator and "," as function argument separator. + */ +void QmuParserBase::ResetLocale() +{ + s_locale = std::locale(std::locale("C"), new change_dec_sep('.')); + SetArgSep(','); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Initialize the token reader. + * + * Create new token reader object and submit pointers to function, operator, constant and variable definitions. + * + * @post m_pTokenReader.get()!=0 + * @throw nothrow + */ +void QmuParserBase::InitTokenReader() +{ + m_pTokenReader.reset(new token_reader_type(this)); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Reset parser to string parsing mode and clear internal buffers. + * + * Clear bytecode, reset the token reader. + * @throw nothrow + */ +void QmuParserBase::ReInit() const +{ + m_pParseFormula = &QmuParserBase::ParseString; + m_vStringBuf.clear(); + m_vRPN.clear(); + m_pTokenReader->ReInit(); + m_nIfElseCounter = 0; +} + +//--------------------------------------------------------------------------------------------------------------------- +void QmuParserBase::OnDetectVar(const QString &pExpr, int &nStart, int &nEnd) +{ + Q_UNUSED(pExpr); + Q_UNUSED(nStart); + Q_UNUSED(nEnd); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Returns the version of muparser. + * @param eInfo A flag indicating whether the full version info should be returned or not. + * + * Format is as follows: "MAJOR.MINOR (COMPILER_FLAGS)" The COMPILER_FLAGS are returned only if eInfo==pviFULL. + */ +QString QmuParserBase::GetVersion(EParserVersionInfo eInfo) const +{ + QString versionInfo; + QTextStream ss(&versionInfo); + + ss << QMUP_VERSION; + + if (eInfo==pviFULL) + { + ss << " (" << QMUP_VERSION_DATE; + ss << "; " << sizeof(void*)*8 << "BIT"; + + #ifdef _DEBUG + ss << "; DEBUG"; + #else + ss << "; RELEASE"; + #endif + + #ifdef _UNICODE + ss << "; UNICODE"; + #else + #ifdef _MBCS + ss << "; MBCS"; + #else + ss << "; ASCII"; + #endif + #endif + + #ifdef QMUP_USE_OPENMP + ss << "; OPENMP"; + //#else + // ss << "; NO_OPENMP"; + #endif + + #if defined(MUP_MATH_EXCEPTIONS) + ss << "; MATHEXC"; + //#else + // ss << "; NO_MATHEXC"; + #endif + + ss << ")"; + } + return versionInfo; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Add a value parsing function. + * + * When parsing an expression muParser tries to detect values in the expression string using different valident + * callbacks. Thuis it's possible to parse for hex values, binary values and floating point values. + */ +void QmuParserBase::AddValIdent(identfun_type a_pCallback) +{ + m_pTokenReader->AddValIdent(a_pCallback); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Set a function that can create variable pointer for unknown expression variables. + * @param a_pFactory A pointer to the variable factory. + * @param pUserData A user defined context pointer. + */ +void QmuParserBase::SetVarFactory(facfun_type a_pFactory, void *pUserData) +{ + m_pTokenReader->SetVarCreator(a_pFactory, pUserData); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Add a function or operator callback to the parser. + */ +void QmuParserBase::AddCallback(const QString &a_strName, const QmuParserCallback &a_Callback, + funmap_type &a_Storage, const QString &a_szCharSet ) +{ + if (a_Callback.GetAddr()==0) + { + Error(ecINVALID_FUN_PTR); + } + + const funmap_type *pFunMap = &a_Storage; + + // Check for conflicting operator or function names + if ( pFunMap!=&m_FunDef && m_FunDef.find(a_strName)!=m_FunDef.end() ) + { + Error(ecNAME_CONFLICT, -1, a_strName); + } + + if ( pFunMap!=&m_PostOprtDef && m_PostOprtDef.find(a_strName)!=m_PostOprtDef.end() ) + { + Error(ecNAME_CONFLICT, -1, a_strName); + } + + if ( pFunMap!=&m_InfixOprtDef && pFunMap!=&m_OprtDef && m_InfixOprtDef.find(a_strName)!=m_InfixOprtDef.end() ) + { + Error(ecNAME_CONFLICT, -1, a_strName); + } + + if ( pFunMap!=&m_InfixOprtDef && pFunMap!=&m_OprtDef && m_OprtDef.find(a_strName)!=m_OprtDef.end() ) + { + Error(ecNAME_CONFLICT, -1, a_strName); + } + + CheckOprt(a_strName, a_Callback, a_szCharSet); + a_Storage[a_strName] = a_Callback; + ReInit(); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Check if a name contains invalid characters. + * + * @throw ParserException if the name contains invalid charakters. + */ +void QmuParserBase::CheckOprt(const QString &a_sName, const QmuParserCallback &a_Callback, + const QString &a_szCharSet) const +{ +#if defined(_UNICODE) + const std::wstring a_sNameStd = a_sName.toStdWString(); + const std::wstring a_szCharSetStd = a_szCharSet.toStdWString(); +#else + const std::string a_sNameStd = a_sName.toStdString(); + const std::string a_szCharSetStd = a_szCharSet.toStdString(); +#endif + if ( a_sNameStd.length() == false || (a_sNameStd.find_first_not_of(a_szCharSetStd)!=string_type::npos) || + (a_sNameStd.at(0)>='0' && a_sNameStd.at(0)<='9')) + { + switch (a_Callback.GetCode()) + { + case cmOPRT_POSTFIX: + Error(ecINVALID_POSTFIX_IDENT, -1, a_sName); + break; + case cmOPRT_INFIX: + Error(ecINVALID_INFIX_IDENT, -1, a_sName); + break; + case cmLE: + Q_UNREACHABLE(); + break; + case cmGE: + Q_UNREACHABLE(); + break; + case cmNEQ: + Q_UNREACHABLE(); + break; + case cmEQ: + Q_UNREACHABLE(); + break; + case cmLT: + Q_UNREACHABLE(); + break; + case cmGT: + Q_UNREACHABLE(); + break; + case cmADD: + Q_UNREACHABLE(); + break; + case cmSUB: + Q_UNREACHABLE(); + break; + case cmMUL: + Q_UNREACHABLE(); + break; + case cmDIV: + Q_UNREACHABLE(); + break; + case cmPOW: + Q_UNREACHABLE(); + break; + case cmLAND: + Q_UNREACHABLE(); + break; + case cmLOR: + Q_UNREACHABLE(); + break; + case cmASSIGN: + Q_UNREACHABLE(); + break; + case cmBO: + Q_UNREACHABLE(); + break; + case cmBC: + Q_UNREACHABLE(); + break; + case cmIF: + Q_UNREACHABLE(); + break; + case cmELSE: + Q_UNREACHABLE(); + break; + case cmENDIF: + Q_UNREACHABLE(); + break; + case cmARG_SEP: + Q_UNREACHABLE(); + break; + case cmVAR: + Q_UNREACHABLE(); + break; + case cmVAL: + Q_UNREACHABLE(); + break; + case cmVARPOW2: + Q_UNREACHABLE(); + break; + case cmVARPOW3: + Q_UNREACHABLE(); + break; + case cmVARPOW4: + Q_UNREACHABLE(); + break; + case cmVARMUL: + Q_UNREACHABLE(); + break; + case cmPOW2: + Q_UNREACHABLE(); + break; + case cmFUNC: + Q_UNREACHABLE(); + break; + case cmFUNC_STR: + Q_UNREACHABLE(); + break; + case cmFUNC_BULK: + Q_UNREACHABLE(); + break; + case cmSTRING: + Q_UNREACHABLE(); + break; + case cmOPRT_BIN: + Q_UNREACHABLE(); + break; + case cmEND: + Q_UNREACHABLE(); + break; + case cmUNKNOWN: + Q_UNREACHABLE(); + break; + default: + Error(ecINVALID_NAME, -1, a_sName); + break; + } + } +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Check if a name contains invalid characters. + * + * @throw ParserException if the name contains invalid charakters. + */ +void QmuParserBase::CheckName(const QString &a_sName, const QString &a_szCharSet) const +{ +#if defined(_UNICODE) + std::wstring a_sNameStd = a_sName.toStdWString(); + std::wstring a_szCharSetStd = a_szCharSet.toStdWString(); +#else + std::string a_sNameStd = a_sName.toStdString(); + std::string a_szCharSetStd = a_szCharSet.toStdString(); +#endif + if ( a_sNameStd.length() == false || (a_sNameStd.find_first_not_of(a_szCharSetStd)!=string_type::npos) || + (a_sNameStd[0]>='0' && a_sNameStd[0]<='9')) + { + Error(ecINVALID_NAME); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Set the formula. + * @param a_strFormula Formula as string_type + * @throw ParserException in case of syntax errors. + * + * Triggers first time calculation thus the creation of the bytecode and scanning of used variables. + */ +void QmuParserBase::SetExpr(const QString &a_sExpr) +{ + // Check locale compatibility + std::locale loc; + if (m_pTokenReader->GetArgSep()==std::use_facet >(loc).decimal_point()) + { + Error(ecLOCALE); + } + + // 20060222: Bugfix for Borland-Kylix: + // adding a space to the expression will keep Borlands KYLIX from going wild + // when calling tellg on a stringstream created from the expression after + // reading a value at the end of an expression. (qmu::QmuParser::IsVal function) + // (tellg returns -1 otherwise causing the parser to ignore the value) + QString sBuf(a_sExpr + " " ); + m_pTokenReader->SetFormula(sBuf); + ReInit(); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Get the default symbols used for the built in operators. + * @sa c_DefaultOprt + */ +const QStringList &QmuParserBase::GetOprtDef() const +{ + return c_DefaultOprt; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Define the set of valid characters to be used in names of functions, variables, constants. + */ +void QmuParserBase::DefineNameChars(const QString &a_szCharset) +{ + m_sNameChars = a_szCharset; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Define the set of valid characters to be used in names of binary operators and postfix operators. + */ +void QmuParserBase::DefineOprtChars(const QString &a_szCharset) +{ + m_sOprtChars = a_szCharset; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Define the set of valid characters to be used in names of infix operators. + */ +void QmuParserBase::DefineInfixOprtChars(const QString &a_szCharset) +{ + m_sInfixOprtChars = a_szCharset; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Virtual function that defines the characters allowed in name identifiers. + * @sa #ValidOprtChars, #ValidPrefixOprtChars + */ +const QString& QmuParserBase::ValidNameChars() const +{ + assert(m_sNameChars.size()); + return m_sNameChars; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Virtual function that defines the characters allowed in operator definitions. + * @sa #ValidNameChars, #ValidPrefixOprtChars + */ +const QString &QmuParserBase::ValidOprtChars() const +{ + assert(m_sOprtChars.size()); + return m_sOprtChars; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Virtual function that defines the characters allowed in infix operator definitions. + * @sa #ValidNameChars, #ValidOprtChars + */ +const QString &QmuParserBase::ValidInfixOprtChars() const +{ + assert(m_sInfixOprtChars.size()); + return m_sInfixOprtChars; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Add a user defined operator. + * @post Will reset the Parser to string parsing mode. + */ +void QmuParserBase::DefinePostfixOprt(const QString &a_sName, fun_type1 a_pFun, bool a_bAllowOpt) +{ + AddCallback(a_sName, QmuParserCallback(a_pFun, a_bAllowOpt, prPOSTFIX, cmOPRT_POSTFIX), m_PostOprtDef, + ValidOprtChars() ); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Initialize user defined functions. + * + * Calls the virtual functions InitFun(), InitConst() and InitOprt(). + */ +void QmuParserBase::Init() +{ + InitCharSets(); + InitFun(); + InitConst(); + InitOprt(); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Add a user defined operator. + * @post Will reset the Parser to string parsing mode. + * @param [in] a_sName operator Identifier + * @param [in] a_pFun Operator callback function + * @param [in] a_iPrec Operator Precedence (default=prSIGN) + * @param [in] a_bAllowOpt True if operator is volatile (default=false) + * @sa EPrec + */ +void QmuParserBase::DefineInfixOprt(const QString &a_sName, fun_type1 a_pFun, int a_iPrec, bool a_bAllowOpt) +{ + AddCallback(a_sName, QmuParserCallback(a_pFun, a_bAllowOpt, a_iPrec, cmOPRT_INFIX), m_InfixOprtDef, + ValidInfixOprtChars() ); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Define a binary operator. + * @param [in] a_sName The identifier of the operator. + * @param [in] a_pFun Pointer to the callback function. + * @param [in] a_iPrec Precedence of the operator. + * @param [in] a_eAssociativity The associativity of the operator. + * @param [in] a_bAllowOpt If this is true the operator may be optimized away. + * + * Adds a new Binary operator the the parser instance. + */ +void QmuParserBase::DefineOprt( const QString &a_sName, fun_type2 a_pFun, unsigned a_iPrec, + EOprtAssociativity a_eAssociativity, bool a_bAllowOpt ) +{ + // Check for conflicts with built in operator names + for (int i=0; m_bBuiltInOp && iIgnoreUndefVar(true); + CreateRPN(); // try to create bytecode, but don't use it for any further calculations since it + // may contain references to nonexisting variables. + m_pParseFormula = &QmuParserBase::ParseString; + m_pTokenReader->IgnoreUndefVar(false); + } + catch (exception_type &e) + { + // Make sure to stay in string parse mode, dont call ReInit() + // because it deletes the array with the used variables + m_pParseFormula = &QmuParserBase::ParseString; + m_pTokenReader->IgnoreUndefVar(false); + throw e; + } + return m_pTokenReader->GetUsedVar(); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Return a map containing the used variables only. + */ +const varmap_type& QmuParserBase::GetVar() const +{ + return m_VarDef; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Return a map containing all parser constants. + */ +const valmap_type& QmuParserBase::GetConst() const +{ + return m_ConstDef; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Return prototypes of all parser functions. + * @return #m_FunDef + * @sa FunProt + * @throw nothrow + * + * The return type is a map of the public type #funmap_type containing the prototype definitions for all numerical + * parser functions. String functions are not part of this map. The Prototype definition is encapsulated in objects + * of the class FunProt one per parser function each associated with function names via a map construct. + */ +const funmap_type& QmuParserBase::GetFunDef() const +{ + return m_FunDef; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Retrieve the formula. + */ +const QString& QmuParserBase::GetExpr() const +{ + return m_pTokenReader->GetExpr(); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Execute a function that takes a single string argument. + * @param a_FunTok Function token. + * @throw exception_type If the function token is not a string function + */ +QmuParserBase::token_type QmuParserBase::ApplyStrFunc(const token_type &a_FunTok, + const QVector &a_vArg) const +{ + if (a_vArg.back().GetCode()!=cmSTRING) + { + Error(ecSTRING_EXPECTED, m_pTokenReader->GetPos(), a_FunTok.GetAsString()); + } + + token_type valTok; + generic_fun_type pFunc = a_FunTok.GetFuncAddr(); + assert(pFunc); + + try + { + // Check function arguments; write dummy value into valtok to represent the result + switch (a_FunTok.GetArgCount()) + { + case 0: + valTok.SetVal(1); + a_vArg[0].GetAsString(); + break; + case 1: + valTok.SetVal(1); + a_vArg[1].GetAsString(); + a_vArg[0].GetVal(); + break; + case 2: + valTok.SetVal(1); + a_vArg[2].GetAsString(); + a_vArg[1].GetVal(); + a_vArg[0].GetVal(); + break; + default: + Error(ecINTERNAL_ERROR); + break; + } + } + catch (QmuParserError& ) + { + Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), a_FunTok.GetAsString()); + } + + // string functions won't be optimized + m_vRPN.AddStrFun(pFunc, a_FunTok.GetArgCount(), a_vArg.back().GetIdx()); + + // Push dummy value representing the function result to the stack + return valTok; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Apply a function token. + * @param iArgCount Number of Arguments actually gathered used only for multiarg functions. + * @post The result is pushed to the value stack + * @post The function token is removed from the stack + * @throw exception_type if Argument count does not mach function requirements. + */ +void QmuParserBase::ApplyFunc( QStack &a_stOpt, QStack &a_stVal, int a_iArgCount) const +{ + assert(m_pTokenReader.get()); + + // Operator stack empty or does not contain tokens with callback functions + if (a_stOpt.empty() || a_stOpt.top().GetFuncAddr()==0 ) + { + return; + } + + token_type funTok = a_stOpt.pop(); + assert(funTok.GetFuncAddr()); + + // Binary operators must rely on their internal operator number + // since counting of operators relies on commas for function arguments + // binary operators do not have commas in their expression + int iArgCount = (funTok.GetCode()==cmOPRT_BIN) ? funTok.GetArgCount() : a_iArgCount; + + // determine how many parameters the function needs. To remember iArgCount includes the + // string parameter whilst GetArgCount() counts only numeric parameters. + int iArgRequired = funTok.GetArgCount() + ((funTok.GetType()==tpSTR) ? 1 : 0); + + // Thats the number of numerical parameters + int iArgNumerical = iArgCount - ((funTok.GetType()==tpSTR) ? 1 : 0); + + if (funTok.GetCode()==cmFUNC_STR && iArgCount-iArgNumerical>1) + { + Error(ecINTERNAL_ERROR); + } + + if (funTok.GetArgCount()>=0 && iArgCount>iArgRequired) + { + Error(ecTOO_MANY_PARAMS, m_pTokenReader->GetPos()-1, funTok.GetAsString()); + } + + if (funTok.GetCode()!=cmOPRT_BIN && iArgCountGetPos()-1, funTok.GetAsString()); + } + + if (funTok.GetCode()==cmFUNC_STR && iArgCount>iArgRequired ) + { + Error(ecTOO_MANY_PARAMS, m_pTokenReader->GetPos()-1, funTok.GetAsString()); + } + + // Collect the numeric function arguments from the value stack and store them + // in a vector + QVector stArg; + for (int i=0; iGetPos(), funTok.GetAsString()); + } + } + + switch (funTok.GetCode()) + { + case cmFUNC_STR: + stArg.push_back(a_stVal.pop()); + + if ( stArg.back().GetType()==tpSTR && funTok.GetType()!=tpSTR ) + { + Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), funTok.GetAsString()); + } + + ApplyStrFunc(funTok, stArg); + break; + case cmFUNC_BULK: + m_vRPN.AddBulkFun(funTok.GetFuncAddr(), stArg.size()); + break; + case cmOPRT_BIN: + case cmOPRT_POSTFIX: + case cmOPRT_INFIX: + case cmFUNC: + if (funTok.GetArgCount()==-1 && iArgCount==0) + { + Error(ecTOO_FEW_PARAMS, m_pTokenReader->GetPos(), funTok.GetAsString()); + } + + m_vRPN.AddFun(funTok.GetFuncAddr(), (funTok.GetArgCount()==-1) ? -iArgNumerical : iArgNumerical); + break; + case cmLE: + Q_UNREACHABLE(); + break; + case cmGE: + Q_UNREACHABLE(); + break; + case cmNEQ: + Q_UNREACHABLE(); + break; + case cmEQ: + Q_UNREACHABLE(); + break; + case cmLT: + Q_UNREACHABLE(); + break; + case cmGT: + Q_UNREACHABLE(); + break; + case cmADD: + Q_UNREACHABLE(); + break; + case cmSUB: + Q_UNREACHABLE(); + break; + case cmMUL: + Q_UNREACHABLE(); + break; + case cmDIV: + Q_UNREACHABLE(); + break; + case cmPOW: + Q_UNREACHABLE(); + break; + case cmLAND: + Q_UNREACHABLE(); + break; + case cmLOR: + Q_UNREACHABLE(); + break; + case cmASSIGN: + Q_UNREACHABLE(); + break; + case cmBO: + Q_UNREACHABLE(); + break; + case cmBC: + Q_UNREACHABLE(); + break; + case cmIF: + Q_UNREACHABLE(); + break; + case cmELSE: + Q_UNREACHABLE(); + break; + case cmENDIF: + Q_UNREACHABLE(); + break; + case cmARG_SEP: + Q_UNREACHABLE(); + break; + case cmVAR: + Q_UNREACHABLE(); + break; + case cmVAL: + Q_UNREACHABLE(); + break; + case cmVARPOW2: + Q_UNREACHABLE(); + break; + case cmVARPOW3: + Q_UNREACHABLE(); + break; + case cmVARPOW4: + Q_UNREACHABLE(); + break; + case cmVARMUL: + Q_UNREACHABLE(); + break; + case cmPOW2: + Q_UNREACHABLE(); + break; + case cmSTRING: + Q_UNREACHABLE(); + break; + case cmEND: + Q_UNREACHABLE(); + break; + case cmUNKNOWN: + Q_UNREACHABLE(); + break; + default: + break; + } + // Push dummy value representing the function result to the stack + token_type token; + token.SetVal(1); + a_stVal.push(token); +} + +//--------------------------------------------------------------------------------------------------------------------- +void QmuParserBase::ApplyIfElse(QStack &a_stOpt, QStack &a_stVal) const +{ + // Check if there is an if Else clause to be calculated + while (a_stOpt.size() && a_stOpt.top().GetCode()==cmELSE) + { + token_type opElse = a_stOpt.pop(); + Q_ASSERT(a_stOpt.size()>0); + + // Take the value associated with the else branch from the value stack + token_type vVal2 = a_stVal.pop(); + + Q_ASSERT(a_stOpt.size()>0); + Q_ASSERT(a_stVal.size()>=2); + + // it then else is a ternary operator Pop all three values from the value s + // tack and just return the right value + token_type vVal1 = a_stVal.pop(); + token_type vExpr = a_stVal.pop(); + + a_stVal.push( (qFuzzyCompare(vExpr.GetVal()+1, 1+0)==false) ? vVal1 : vVal2); + + token_type opIf = a_stOpt.pop(); + Q_ASSERT(opElse.GetCode()==cmELSE); + Q_ASSERT(opIf.GetCode()==cmIF); + + m_vRPN.AddIfElse(cmENDIF); + } // while pending if-else-clause found +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Performs the necessary steps to write code for the execution of binary operators into the bytecode. + */ +void QmuParserBase::ApplyBinOprt(QStack &a_stOpt, QStack &a_stVal) const +{ + // is it a user defined binary operator? + if (a_stOpt.top().GetCode()==cmOPRT_BIN) + { + ApplyFunc(a_stOpt, a_stVal, 2); + } + else + { + Q_ASSERT(a_stVal.size()>=2); + token_type valTok1 = a_stVal.pop(), + valTok2 = a_stVal.pop(), + optTok = a_stOpt.pop(), + resTok; + + if ( valTok1.GetType()!=valTok2.GetType() || (valTok1.GetType()==tpSTR && valTok2.GetType()==tpSTR) ) + { + Error(ecOPRT_TYPE_CONFLICT, m_pTokenReader->GetPos(), optTok.GetAsString()); + } + + if (optTok.GetCode()==cmASSIGN) + { + if (valTok2.GetCode()!=cmVAR) + { + Error(ecUNEXPECTED_OPERATOR, -1, "="); + } + m_vRPN.AddAssignOp(valTok2.GetVar()); + } + else + { + m_vRPN.AddOp(optTok.GetCode()); + } + resTok.SetVal(1); + a_stVal.push(resTok); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Apply a binary operator. + * @param a_stOpt The operator stack + * @param a_stVal The value stack + */ +void QmuParserBase::ApplyRemainingOprt(QStack &stOpt, QStack &stVal) const +{ + while (stOpt.size() && stOpt.top().GetCode() != cmBO && stOpt.top().GetCode() != cmIF) + { + token_type tok = stOpt.top(); + switch (tok.GetCode()) + { + case cmOPRT_INFIX: + case cmOPRT_BIN: + case cmLE: + case cmGE: + case cmNEQ: + case cmEQ: + case cmLT: + case cmGT: + case cmADD: + case cmSUB: + case cmMUL: + case cmDIV: + case cmPOW: + case cmLAND: + case cmLOR: + case cmASSIGN: + if (stOpt.top().GetCode()==cmOPRT_INFIX) + { + ApplyFunc(stOpt, stVal, 1); + } + else + { + ApplyBinOprt(stOpt, stVal); + } + break; + case cmELSE: + ApplyIfElse(stOpt, stVal); + break; + case cmBO: + Q_UNREACHABLE(); + break; + case cmBC: + Q_UNREACHABLE(); + break; + case cmIF: + Q_UNREACHABLE(); + break; + case cmENDIF: + Q_UNREACHABLE(); + break; + case cmARG_SEP: + Q_UNREACHABLE(); + break; + case cmVAR: + Q_UNREACHABLE(); + break; + case cmVAL: + Q_UNREACHABLE(); + break; + case cmVARPOW2: + Q_UNREACHABLE(); + break; + case cmVARPOW3: + Q_UNREACHABLE(); + break; + case cmVARPOW4: + Q_UNREACHABLE(); + break; + case cmVARMUL: + Q_UNREACHABLE(); + break; + case cmPOW2: + Q_UNREACHABLE(); + break; + case cmFUNC: + Q_UNREACHABLE(); + break; + case cmFUNC_STR: + Q_UNREACHABLE(); + break; + case cmFUNC_BULK: + Q_UNREACHABLE(); + break; + case cmSTRING: + Q_UNREACHABLE(); + break; + case cmOPRT_POSTFIX: + Q_UNREACHABLE(); + break; + case cmEND: + Q_UNREACHABLE(); + break; + case cmUNKNOWN: + Q_UNREACHABLE(); + break; + default: + Error(ecINTERNAL_ERROR); + break; + } + } +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Parse the command code. + * @sa ParseString(...) + * + * Command code contains precalculated stack positions of the values and the associated operators. The Stack is + * filled beginning from index one the value at index zero is not used at all. + */ +qreal QmuParserBase::ParseCmdCode() const +{ + return ParseCmdCodeBulk(0, 0); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Evaluate the RPN. + * @param nOffset The offset added to variable addresses (for bulk mode) + * @param nThreadID OpenMP Thread id of the calling thread + */ +qreal QmuParserBase::ParseCmdCodeBulk(int nOffset, int nThreadID) const +{ + assert(nThreadID<=s_MaxNumOpenMPThreads); + + // Note: The check for nOffset==0 and nThreadID here is not necessary but + // brings a minor performance gain when not in bulk mode. + qreal *Stack = ((nOffset==0) && (nThreadID==0)) ? &m_vStackBuffer[0] : &m_vStackBuffer[nThreadID * + (m_vStackBuffer.size() / s_MaxNumOpenMPThreads)]; + qreal buf; + int sidx(0); + for (const SToken *pTok = m_vRPN.GetBase(); pTok->Cmd!=cmEND ; ++pTok) + { + switch (pTok->Cmd) + { + // built in binary operators + case cmLE: + --sidx; + Stack[sidx] = Stack[sidx] <= Stack[sidx+1]; + continue; + case cmGE: + --sidx; + Stack[sidx] = Stack[sidx] >= Stack[sidx+1]; + continue; + case cmNEQ: + --sidx; + Stack[sidx] = (qFuzzyCompare(Stack[sidx], Stack[sidx+1])==false); + continue; + case cmEQ: + --sidx; + Stack[sidx] = qFuzzyCompare(Stack[sidx], Stack[sidx+1]); + continue; + case cmLT: + --sidx; + Stack[sidx] = Stack[sidx] < Stack[sidx+1]; + continue; + case cmGT: + --sidx; + Stack[sidx] = Stack[sidx] > Stack[sidx+1]; + continue; + case cmADD: + --sidx; + Stack[sidx] += Stack[1+sidx]; + continue; + case cmSUB: + --sidx; + Stack[sidx] -= Stack[1+sidx]; + continue; + case cmMUL: + --sidx; + Stack[sidx] *= Stack[1+sidx]; + continue; + case cmDIV: + --sidx; + #if defined(MUP_MATH_EXCEPTIONS) + if (Stack[1+sidx]==0) + { + Error(ecDIV_BY_ZERO); + } + #endif + Stack[sidx] /= Stack[1+sidx]; + continue; + case cmPOW: + --sidx; + Stack[sidx] = qPow(Stack[sidx], Stack[1+sidx]); + continue; + case cmLAND: + --sidx; +#ifdef Q_CC_GNU + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + Stack[sidx] = Stack[sidx] && Stack[sidx+1]; +#ifdef Q_CC_GNU + #pragma GCC diagnostic pop +#endif + continue; + case cmLOR: + --sidx; +#ifdef Q_CC_GNU + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + Stack[sidx] = Stack[sidx] || Stack[sidx+1]; +#ifdef Q_CC_GNU + #pragma GCC diagnostic pop +#endif + continue; + case cmASSIGN: + --sidx; + Stack[sidx] = *pTok->Oprt.ptr = Stack[sidx+1]; + continue; + case cmBO: // unused, listed for compiler optimization purposes + Q_UNREACHABLE(); + break; + case cmBC: + Q_UNREACHABLE(); + break; + // Q_ASSERT(INVALID_CODE_IN_BYTECODE); + // continue; + case cmIF: + if (qFuzzyCompare(Stack[sidx--]+1, 1+0)) + { + pTok += pTok->Oprt.offset; + } + continue; + case cmELSE: + pTok += pTok->Oprt.offset; + continue; + case cmENDIF: + continue; + case cmARG_SEP: + Q_UNREACHABLE(); + break; + // Q_ASSERT(INVALID_CODE_IN_BYTECODE); + // continue; + + // value and variable tokens + case cmVAR: + Stack[++sidx] = *(pTok->Val.ptr + nOffset); + continue; + case cmVAL: + Stack[++sidx] = pTok->Val.data2; + continue; + case cmVARPOW2: + buf = *(pTok->Val.ptr + nOffset); + Stack[++sidx] = buf*buf; + continue; + case cmVARPOW3: + buf = *(pTok->Val.ptr + nOffset); + Stack[++sidx] = buf*buf*buf; + continue; + case cmVARPOW4: + buf = *(pTok->Val.ptr + nOffset); + Stack[++sidx] = buf*buf*buf*buf; + continue; + case cmVARMUL: + Stack[++sidx] = *(pTok->Val.ptr + nOffset) * pTok->Val.data + pTok->Val.data2; + continue; + // Next is treatment of numeric functions + case cmFUNC: + { + int iArgCount = pTok->Fun.argc; + + // switch according to argument count + switch (iArgCount) + { + case 0: + sidx += 1; + Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(); + continue; + case 1: + Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(Stack[sidx]); + continue; + case 2: + sidx -= 1; + Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(Stack[sidx], Stack[sidx+1]); + continue; + case 3: + sidx -= 2; + Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(Stack[sidx], Stack[sidx+1], + Stack[sidx+2]); + continue; + case 4: + sidx -= 3; + Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(Stack[sidx], Stack[sidx+1], + Stack[sidx+2], Stack[sidx+3]); + continue; + case 5: + sidx -= 4; + Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(Stack[sidx], Stack[sidx+1], + Stack[sidx+2], Stack[sidx+3], Stack[sidx+4]); + continue; + case 6: + sidx -= 5; + Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(Stack[sidx], Stack[sidx+1], + Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5]); + continue; + case 7: + sidx -= 6; + Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(Stack[sidx], Stack[sidx+1], + Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6]); + continue; + case 8: + sidx -= 7; + Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(Stack[sidx], Stack[sidx+1], + Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], + Stack[sidx+7]); + continue; + case 9: + sidx -= 8; + Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(Stack[sidx], Stack[sidx+1], + Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], + Stack[sidx+7], Stack[sidx+8]); + continue; + case 10: + sidx -= 9; + Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(Stack[sidx], Stack[sidx+1], + Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], + Stack[sidx+7], Stack[sidx+8], Stack[sidx+9]); + continue; + default: + if (iArgCount>0) // function with variable arguments store the number as a negative value + { + Error(ecINTERNAL_ERROR, 1); + } + + sidx -= -iArgCount - 1; + Stack[sidx] =(*reinterpret_cast(pTok->Fun.ptr))(&Stack[sidx], -iArgCount); + continue; + } + } + // Next is treatment of string functions + case cmFUNC_STR: + { + sidx -= pTok->Fun.argc -1; + + // The index of the string argument in the string table + int iIdxStack = pTok->Fun.idx; + Q_ASSERT( iIdxStack>=0 && iIdxStackFun.argc) // switch according to argument count + { + case 0: + Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(m_vStringBuf.at(iIdxStack)); + continue; + case 1: + Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(m_vStringBuf.at(iIdxStack), + Stack[sidx]); + continue; + case 2: + Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(m_vStringBuf.at(iIdxStack), + Stack[sidx], Stack[sidx+1]); + continue; + default: + break; + } + + continue; + } + case cmFUNC_BULK: + { + int iArgCount = pTok->Fun.argc; + + // switch according to argument count + switch (iArgCount) + { + case 0: + sidx += 1; + Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(nOffset, nThreadID); + continue; + case 1: + Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(nOffset, nThreadID, + Stack[sidx]); + continue; + case 2: + sidx -= 1; + Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(nOffset, nThreadID, Stack[sidx], + Stack[sidx+1]); + continue; + case 3: + sidx -= 2; + Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(nOffset, nThreadID, Stack[sidx], + Stack[sidx+1], Stack[sidx+2]); + continue; + case 4: + sidx -= 3; + Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(nOffset, nThreadID, Stack[sidx], + Stack[sidx+1], Stack[sidx+2], Stack[sidx+3]); + continue; + case 5: + sidx -= 4; + Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(nOffset, nThreadID, Stack[sidx], + Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], + Stack[sidx+4]); + continue; + case 6: + sidx -= 5; + Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(nOffset, nThreadID, Stack[sidx], + Stack[sidx+1], Stack[sidx+2], + Stack[sidx+3], Stack[sidx+4], Stack[sidx+5]); + continue; + case 7: + sidx -= 6; + Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(nOffset, nThreadID, Stack[sidx], + Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], + Stack[sidx+4], Stack[sidx+5], Stack[sidx+6]); + continue; + case 8: + sidx -= 7; + Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(nOffset, nThreadID, Stack[sidx], + Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], + Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7]); + continue; + case 9: + sidx -= 8; + Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(nOffset, nThreadID, Stack[sidx], + Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], + Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7], Stack[sidx+8]); + continue; + case 10: + sidx -= 9; + Stack[sidx] = (*reinterpret_cast(pTok->Fun.ptr))(nOffset, nThreadID, + Stack[sidx], + Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], + Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7], Stack[sidx+8], + Stack[sidx+9]); + continue; + default: + Error(ecINTERNAL_ERROR, 2); + continue; + } + } + case cmSTRING: + Q_UNREACHABLE(); + break; + case cmOPRT_BIN: + Q_UNREACHABLE(); + break; + case cmOPRT_POSTFIX: + Q_UNREACHABLE(); + break; + case cmOPRT_INFIX: + Q_UNREACHABLE(); + break; + // Q_ASSERT(INVALID_CODE_IN_BYTECODE); + // continue; + case cmEND: + Q_UNREACHABLE(); + break; + // return Stack[m_nFinalResultIdx]; + case cmPOW2: + Q_UNREACHABLE(); + break; + case cmUNKNOWN: + Q_UNREACHABLE(); + break; + default: + Error(ecINTERNAL_ERROR, 3); + return 0; + } // switch CmdCode + } // for all bytecode tokens + + return Stack[m_nFinalResultIdx]; +} + +//--------------------------------------------------------------------------------------------------------------------- +void QmuParserBase::CreateRPN() const +{ + if (m_pTokenReader->GetExpr().length() == false) + { + Error(ecUNEXPECTED_EOF, 0); + } + + QStack stOpt, stVal; + QStack stArgCount; + token_type opta, opt; // for storing operators + token_type val, tval; // for storing value + string_type strBuf; // buffer for string function arguments + + ReInit(); + + // The outermost counter counts the number of seperated items + // such as in "a=10,b=20,c=c+a" + stArgCount.push(1); + + for (;;) + { + opt = m_pTokenReader->ReadNextToken(); + + switch (opt.GetCode()) + { + // + // Next three are different kind of value entries + // + case cmSTRING: + opt.SetIdx(m_vStringBuf.size()); // Assign buffer index to token + stVal.push(opt); + m_vStringBuf.push_back(opt.GetAsString()); // Store string in internal buffer + break; + case cmVAR: + stVal.push(opt); + m_vRPN.AddVar( static_cast(opt.GetVar()) ); + break; + case cmVAL: + stVal.push(opt); + m_vRPN.AddVal( opt.GetVal() ); + break; + case cmELSE: + m_nIfElseCounter--; + if (m_nIfElseCounter<0) + { + Error(ecMISPLACED_COLON, m_pTokenReader->GetPos()); + } + ApplyRemainingOprt(stOpt, stVal); + m_vRPN.AddIfElse(cmELSE); + stOpt.push(opt); + break; + case cmARG_SEP: + if (stArgCount.empty()) + { + Error(ecUNEXPECTED_ARG_SEP, m_pTokenReader->GetPos()); + } + ++stArgCount.top(); + // fallthrough intentional (no break!) + case cmEND: + ApplyRemainingOprt(stOpt, stVal); + break; + case cmBC: + { + // The argument count for parameterless functions is zero + // by default an opening bracket sets parameter count to 1 + // in preparation of arguments to come. If the last token + // was an opening bracket we know better... + if (opta.GetCode()==cmBO) + { + --stArgCount.top(); + } + + ApplyRemainingOprt(stOpt, stVal); + + // Check if the bracket content has been evaluated completely + if (stOpt.size() && stOpt.top().GetCode()==cmBO) + { + // if opt is ")" and opta is "(" the bracket has been evaluated, now its time to check + // if there is either a function or a sign pending + // neither the opening nor the closing bracket will be pushed back to + // the operator stack + // Check if a function is standing in front of the opening bracket, + // if yes evaluate it afterwards check for infix operators + assert(stArgCount.size()); + int iArgCount = stArgCount.pop(); + + stOpt.pop(); // Take opening bracket from stack + + if (iArgCount>1 && ( stOpt.size()==0 || (stOpt.top().GetCode()!=cmFUNC && + stOpt.top().GetCode()!=cmFUNC_BULK && + stOpt.top().GetCode()!=cmFUNC_STR) ) ) + { + Error(ecUNEXPECTED_ARG, m_pTokenReader->GetPos()); + } + + // The opening bracket was popped from the stack now check if there + // was a function before this bracket + if (stOpt.size() && stOpt.top().GetCode()!=cmOPRT_INFIX && stOpt.top().GetCode()!=cmOPRT_BIN && + stOpt.top().GetFuncAddr()!=0) + { + ApplyFunc(stOpt, stVal, iArgCount); + } + } + } // if bracket content is evaluated + break; + // + // Next are the binary operator entries + // + //case cmAND: // built in binary operators + //case cmOR: + //case cmXOR: + case cmIF: + m_nIfElseCounter++; + // fallthrough intentional (no break!) + case cmLAND: + case cmLOR: + case cmLT: + case cmGT: + case cmLE: + case cmGE: + case cmNEQ: + case cmEQ: + case cmADD: + case cmSUB: + case cmMUL: + case cmDIV: + case cmPOW: + case cmASSIGN: + case cmOPRT_BIN: + // A binary operator (user defined or built in) has been found. + while ( stOpt.size() && stOpt.top().GetCode() != cmBO && stOpt.top().GetCode() != cmELSE && + stOpt.top().GetCode() != cmIF) + { + int nPrec1 = GetOprtPrecedence(stOpt.top()), + nPrec2 = GetOprtPrecedence(opt); + + if (stOpt.top().GetCode()==opt.GetCode()) + { + // Deal with operator associativity + EOprtAssociativity eOprtAsct = GetOprtAssociativity(opt); + if ( (eOprtAsct==oaRIGHT && (nPrec1 <= nPrec2)) || + (eOprtAsct==oaLEFT && (nPrec1 < nPrec2)) ) + { + break; + } + } + else if (nPrec1 < nPrec2) + { + // In case the operators are not equal the precedence decides alone... + break; + } + if (stOpt.top().GetCode()==cmOPRT_INFIX) + { + ApplyFunc(stOpt, stVal, 1); + } + else + { + ApplyBinOprt(stOpt, stVal); + } + } // while ( ... ) + + if (opt.GetCode()==cmIF) + { + m_vRPN.AddIfElse(opt.GetCode()); + } + + // The operator can't be evaluated right now, push back to the operator stack + stOpt.push(opt); + break; + // + // Last section contains functions and operators implicitely mapped to functions + // + case cmBO: + stArgCount.push(1); + stOpt.push(opt); + break; + case cmOPRT_INFIX: + case cmFUNC: + case cmFUNC_BULK: + case cmFUNC_STR: + stOpt.push(opt); + break; + case cmOPRT_POSTFIX: + stOpt.push(opt); + ApplyFunc(stOpt, stVal, 1); // this is the postfix operator + break; + case cmENDIF: + Q_UNREACHABLE(); + break; + case cmVARPOW2: + Q_UNREACHABLE(); + break; + case cmVARPOW3: + Q_UNREACHABLE(); + break; + case cmVARPOW4: + Q_UNREACHABLE(); + break; + case cmVARMUL: + Q_UNREACHABLE(); + break; + case cmPOW2: + Q_UNREACHABLE(); + break; + case cmUNKNOWN: + Q_UNREACHABLE(); + break; + default: + Error(ecINTERNAL_ERROR, 3); + } // end of switch operator-token + + opta = opt; + + if ( opt.GetCode() == cmEND ) + { + m_vRPN.Finalize(); + break; + } + + if (QmuParserBase::g_DbgDumpStack) + { + StackDump(stVal, stOpt); + m_vRPN.AsciiDump(); + } + } // while (true) + + if (QmuParserBase::g_DbgDumpCmdCode) + { + m_vRPN.AsciiDump(); + } + + if (m_nIfElseCounter>0) + { + Error(ecMISSING_ELSE_CLAUSE); + } + + // get the last value (= final result) from the stack + Q_ASSERT(stArgCount.size()==1); + m_nFinalResultIdx = stArgCount.top(); + if (m_nFinalResultIdx==0) + { + Error(ecINTERNAL_ERROR, 9); + } + + if (stVal.size()==0) + { + Error(ecEMPTY_EXPRESSION); + } + + if (stVal.top().GetType()!=tpDBL) + { + Error(ecSTR_RESULT); + } + + m_vStackBuffer.resize(m_vRPN.GetMaxStackSize() * s_MaxNumOpenMPThreads); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief One of the two main parse functions. + * @sa ParseCmdCode(...) + * + * Parse expression from input string. Perform syntax checking and create bytecode. After parsing the string and + * creating the bytecode the function pointer #m_pParseFormula will be changed to the second parse routine the + * uses bytecode instead of string parsing. + */ +qreal QmuParserBase::ParseString() const +{ + try + { + CreateRPN(); + m_pParseFormula = &QmuParserBase::ParseCmdCode; + return (this->*m_pParseFormula)(); + } + catch (QmuParserError &exc) + { + exc.SetFormula(m_pTokenReader->GetExpr()); + throw; + } +} + +//--------------------------------------------------------------------------------------------------------------------- +/** +* @brief Create an error containing the parse error position. +* +* This function will create an Parser Exception object containing the error text and its position. +* +* @param a_iErrc [in] The error code of type #EErrorCodes. +* @param a_iPos [in] The position where the error was detected. +* @param a_strTok [in] The token string representation associated with the error. +* @throw ParserException always throws thats the only purpose of this function. +*/ +void Q_NORETURN QmuParserBase::Error(EErrorCodes a_iErrc, int a_iPos, const QString &a_sTok) const +{ + throw exception_type(a_iErrc, a_sTok, m_pTokenReader->GetExpr(), a_iPos); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Clear all user defined variables. + * @throw nothrow + * + * Resets the parser to string parsing mode by calling #ReInit. + */ +void QmuParserBase::ClearVar() +{ + m_VarDef.clear(); + ReInit(); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Remove a variable from internal storage. + * @throw nothrow + * + * Removes a variable if it exists. If the Variable does not exist nothing will be done. + */ +void QmuParserBase::RemoveVar(const QString &a_strVarName) +{ + varmap_type::iterator item = m_VarDef.find(a_strVarName); + if (item!=m_VarDef.end()) + { + m_VarDef.erase(item); + ReInit(); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Clear all functions. + * @post Resets the parser to string parsing mode. + * @throw nothrow + */ +void QmuParserBase::ClearFun() +{ + m_FunDef.clear(); + ReInit(); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Clear all user defined constants. + * + * Both numeric and string constants will be removed from the internal storage. + * @post Resets the parser to string parsing mode. + * @throw nothrow + */ +void QmuParserBase::ClearConst() +{ + m_ConstDef.clear(); + m_StrVarDef.clear(); + ReInit(); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Clear all user defined postfix operators. + * @post Resets the parser to string parsing mode. + * @throw nothrow + */ +void QmuParserBase::ClearPostfixOprt() +{ + m_PostOprtDef.clear(); + ReInit(); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Clear all user defined binary operators. + * @post Resets the parser to string parsing mode. + * @throw nothrow + */ +void QmuParserBase::ClearOprt() +{ + m_OprtDef.clear(); + ReInit(); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Clear the user defined Prefix operators. + * @post Resets the parser to string parser mode. + * @throw nothrow + */ +void QmuParserBase::ClearInfixOprt() +{ + m_InfixOprtDef.clear(); + ReInit(); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Enable or disable the formula optimization feature. + * @post Resets the parser to string parser mode. + * @throw nothrow + */ +void QmuParserBase::EnableOptimizer(bool a_bIsOn) +{ + m_vRPN.EnableOptimizer(a_bIsOn); + ReInit(); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Enable the dumping of bytecode amd stack content on the console. + * @param bDumpCmd Flag to enable dumping of the current bytecode to the console. + * @param bDumpStack Flag to enable dumping of the stack content is written to the console. + * + * This function is for debug purposes only! + */ +void QmuParserBase::EnableDebugDump(bool bDumpCmd, bool bDumpStack) +{ + QmuParserBase::g_DbgDumpCmdCode = bDumpCmd; + QmuParserBase::g_DbgDumpStack = bDumpStack; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Enable or disable the built in binary operators. + * @throw nothrow + * @sa m_bBuiltInOp, ReInit() + * + * If you disable the built in binary operators there will be no binary operators defined. Thus you must add them + * manually one by one. It is not possible to disable built in operators selectively. This function will Reinitialize + * the parser by calling ReInit(). + */ +void QmuParserBase::EnableBuiltInOprt(bool a_bIsOn) +{ + m_bBuiltInOp = a_bIsOn; + ReInit(); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Query status of built in variables. + * @return #m_bBuiltInOp; true if built in operators are enabled. + * @throw nothrow + */ +bool QmuParserBase::HasBuiltInOprt() const +{ + return m_bBuiltInOp; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Get the argument separator character. + */ +QChar QmuParserBase::GetArgSep() const +{ + return m_pTokenReader->GetArgSep(); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Set argument separator. + * @param cArgSep the argument separator character. + */ +void QmuParserBase::SetArgSep(char_type cArgSep) +{ + m_pTokenReader->SetArgSep(cArgSep); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Dump stack content. + * + * This function is used for debugging only. + */ +void QmuParserBase::StackDump(const QStack &a_stVal, const QStack &a_stOprt) const +{ + QStack stOprt(a_stOprt), + stVal(a_stVal); + + qDebug() << "\nValue stack:\n"; + while ( stVal.empty() == false ) + { + token_type val = stVal.pop(); + if (val.GetType()==tpSTR) + { + qDebug() << " \"" << val.GetAsString() << "\" "; + } + else + { + qDebug() << " " << val.GetVal() << " "; + } + } + qDebug() << "\nOperator stack:\n"; + + while ( stOprt.empty() == false ) + { + if (stOprt.top().GetCode()<=cmASSIGN) + { + qDebug() << "OPRT_INTRNL \"" << QmuParserBase::c_DefaultOprt[stOprt.top().GetCode()] << "\" \n"; + } + else + { + switch ( stOprt.top().GetCode()) + { + case cmVAR: + qDebug() << "VAR\n"; + break; + case cmVAL: + qDebug() << "VAL\n"; + break; + case cmFUNC: + qDebug() << "FUNC \"" << stOprt.top().GetAsString() << "\"\n"; + break; + case cmFUNC_BULK: + qDebug() << "FUNC_BULK \"" << stOprt.top().GetAsString() << "\"\n"; + break; + case cmOPRT_INFIX: + qDebug() << "OPRT_INFIX \"" << stOprt.top().GetAsString() << "\"\n"; + break; + case cmOPRT_BIN: + qDebug() << "OPRT_BIN \"" << stOprt.top().GetAsString() << "\"\n"; + break; + case cmFUNC_STR: + qDebug() << "FUNC_STR\n"; + break; + case cmEND: + qDebug() << "END\n"; + break; + case cmUNKNOWN: + qDebug() << "UNKNOWN\n"; + break; + case cmBO: + qDebug() << "BRACKET \"(\"\n"; + break; + case cmBC: + qDebug() << "BRACKET \")\"\n"; + break; + case cmIF: + qDebug() << "IF\n"; + break; + case cmELSE: + qDebug() << "ELSE\n"; + break; + case cmENDIF: + qDebug() << "ENDIF\n"; + break; + case cmLE: + Q_UNREACHABLE(); + break; + case cmGE: + Q_UNREACHABLE(); + break; + case cmNEQ: + Q_UNREACHABLE(); + break; + case cmEQ: + Q_UNREACHABLE(); + break; + case cmLT: + Q_UNREACHABLE(); + break; + case cmGT: + Q_UNREACHABLE(); + break; + case cmADD: + Q_UNREACHABLE(); + break; + case cmSUB: + Q_UNREACHABLE(); + break; + case cmMUL: + Q_UNREACHABLE(); + break; + case cmDIV: + Q_UNREACHABLE(); + break; + case cmPOW: + Q_UNREACHABLE(); + break; + case cmLAND: + Q_UNREACHABLE(); + break; + case cmLOR: + Q_UNREACHABLE(); + break; + case cmASSIGN: + Q_UNREACHABLE(); + break; + case cmARG_SEP: + Q_UNREACHABLE(); + break; + case cmVARPOW2: + Q_UNREACHABLE(); + break; + case cmVARPOW3: + Q_UNREACHABLE(); + break; + case cmVARPOW4: + Q_UNREACHABLE(); + break; + case cmVARMUL: + Q_UNREACHABLE(); + break; + case cmPOW2: + Q_UNREACHABLE(); + break; + case cmSTRING: + Q_UNREACHABLE(); + break; + case cmOPRT_POSTFIX: + Q_UNREACHABLE(); + break; + default: + qDebug() << stOprt.top().GetCode() << " "; + break; + } + } + stOprt.pop(); + } + qDebug() << dec; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** @brief Evaluate an expression containing comma seperated subexpressions + * @param [out] nStackSize The total number of results available + * @return Pointer to the array containing all expression results + * + * This member function can be used to retriev all results of an expression made up of multiple comma seperated + * subexpressions (i.e. "x+y,sin(x),cos(y)") + */ +qreal* QmuParserBase::Eval(int &nStackSize) const +{ + (this->*m_pParseFormula)(); + nStackSize = m_nFinalResultIdx; + + // (for historic reasons the stack starts at position 1) + return &m_vStackBuffer[1]; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Return the number of results on the calculation stack. + * + * If the expression contains comma seperated subexpressions (i.e. "sin(y), x+y"). There mey be more than one return + * value. This function returns the number of available results. + */ +int QmuParserBase::GetNumResults() const +{ + return m_nFinalResultIdx; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Calculate the result. + * + * A note on const correctness: + * I consider it important that Calc is a const function. + * Due to caching operations Calc changes only the state of internal variables with one exception + * m_UsedVar this is reset during string parsing and accessible from the outside. Instead of making + * Calc non const GetUsedVar is non const because it explicitely calls Eval() forcing this update. + * + * @pre A formula must be set. + * @pre Variables must have been set (if needed) + * + * @sa #m_pParseFormula + * @return The evaluation result + * @throw ParseException if no Formula is set or in case of any other error related to the formula. + */ +qreal QmuParserBase::Eval() const +{ + return (this->*m_pParseFormula)(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void QmuParserBase::Eval(qreal *results, int nBulkSize) +{ + CreateRPN(); + + int i = 0; + + #ifdef QMUP_USE_OPENMP + //#define DEBUG_OMP_STUFF + #ifdef DEBUG_OMP_STUFF + int *pThread = new int[nBulkSize]; + int *pIdx = new int[nBulkSize]; + #endif + + int nMaxThreads = qMin(omp_get_max_threads(), s_MaxNumOpenMPThreads); + int nThreadID, ct=0; + omp_set_num_threads(nMaxThreads); + + #pragma omp parallel for schedule(static, nBulkSize/nMaxThreads) private(nThreadID) + for (i=0; i - ** - ** Permission is hereby granted, free of charge, to any person obtaining a copy of this - ** software and associated documentation files (the "Software"), to deal in the Software - ** without restriction, including without limitation the rights to use, copy, modify, - ** merge, publish, distribute, sublicense, and/or sell copies of the Software, and to - ** permit persons to whom the Software is furnished to do so, subject to the following conditions: - ** - ** The above copyright notice and this permission notice shall be included in all copies or - ** substantial portions of the Software. - ** - ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT - ** NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - ** DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ** - ******************************************************************************************************/ - -#ifndef QMUQPARSERBASE_H -#define QMUQPARSERBASE_H - -#include -#include -#include - -#include "qmuparserdef.h" -#include "qmuparsertokenreader.h" -#include "qmuparserbytecode.h" -#include "qmuparsererror.h" - - -namespace qmu -{ -/** - * @file - * @brief This file contains the class definition of the qmuparser engine. - */ - -/** - * @brief Mathematical expressions parser (base parser engine). - * @author (C) 2013 Ingo Berg - * - * This is the implementation of a bytecode based mathematical expressions parser. - * The formula will be parsed from string and converted into a bytecode. - * Future calculations will be done with the bytecode instead the formula string - * resulting in a significant performance increase. - * Complementary to a set of internally implemented functions the parser is able to handle - * user defined functions and variables. - */ -class QmuParserBase -{ - friend class QmuParserTokenReader; -public: - /** - * @brief Type of the error class. - * - * Included for backwards compatibility. - */ - typedef QmuParserError exception_type; - - QmuParserBase(); - QmuParserBase(const QmuParserBase &a_Parser); - QmuParserBase& operator=(const QmuParserBase &a_Parser); - virtual ~QmuParserBase(); - - static void EnableDebugDump(bool bDumpCmd, bool bDumpStack); - qreal Eval() const; - qreal* Eval(int &nStackSize) const; - void Eval(qreal *results, int nBulkSize); - int GetNumResults() const; - void SetExpr(const QString &a_sExpr); - void SetVarFactory(facfun_type a_pFactory, void *pUserData = NULL); - void SetDecSep(char_type cDecSep); - void SetThousandsSep(char_type cThousandsSep = 0); - void ResetLocale(); - void EnableOptimizer(bool a_bIsOn=true); - void EnableBuiltInOprt(bool a_bIsOn=true); - bool HasBuiltInOprt() const; - void AddValIdent(identfun_type a_pCallback); - void DefineOprt(const QString &a_strName, fun_type2 a_pFun, unsigned a_iPri=0, - EOprtAssociativity a_eAssociativity = oaLEFT, bool a_bAllowOpt = false); - void DefineConst(const QString &a_sName, qreal a_fVal); - void DefineStrConst(const QString &a_sName, const QString &a_strVal); - void DefineVar(const QString &a_sName, qreal *a_fVar); - void DefinePostfixOprt(const QString &a_strFun, fun_type1 a_pOprt, bool a_bAllowOpt=true); - void DefineInfixOprt(const QString &a_strName, fun_type1 a_pOprt, int a_iPrec=prINFIX, - bool a_bAllowOpt=true); - // Clear user defined variables, constants or functions - void ClearVar(); - void ClearFun(); - void ClearConst(); - void ClearInfixOprt(); - void ClearPostfixOprt(); - void ClearOprt(); - void RemoveVar(const QString &a_strVarName); - const varmap_type& GetUsedVar() const; - const varmap_type& GetVar() const; - const valmap_type& GetConst() const; - const QString& GetExpr() const; - const funmap_type& GetFunDef() const; - QString GetVersion(EParserVersionInfo eInfo = pviFULL) const; - const QStringList& GetOprtDef() const; - void DefineNameChars(const QString &a_szCharset); - void DefineOprtChars(const QString &a_szCharset); - void DefineInfixOprtChars(const QString &a_szCharset); - const QString& ValidNameChars() const; - const QString& ValidOprtChars() const; - const QString& ValidInfixOprtChars() const; - void SetArgSep(char_type cArgSep); - QChar GetArgSep() const; - void Error(EErrorCodes a_iErrc, int a_iPos = -1, const QString &a_strTok = QString() ) const; - /** - * @fn void qmu::QmuParserBase::DefineFun(const string_type &a_strName, fun_type0 a_pFun, - * bool a_bAllowOpt = true) - * @brief Define a parser function without arguments. - * @param a_strName Name of the function - * @param a_pFun Pointer to the callback function - * @param a_bAllowOpt A flag indicating this function may be optimized - */ - template - void DefineFun(const QString &a_strName, T a_pFun, bool a_bAllowOpt = true) - { - AddCallback( a_strName, QmuParserCallback(a_pFun, a_bAllowOpt), m_FunDef, ValidNameChars() ); - } -protected: - static const QStringList c_DefaultOprt; - static std::locale s_locale; ///< The locale used by the parser - static bool g_DbgDumpCmdCode; - static bool g_DbgDumpStack; - void Init(); - virtual void InitCharSets() = 0; - virtual void InitFun() = 0; - virtual void InitConst() = 0; - virtual void InitOprt() = 0; - virtual void OnDetectVar(const QString &pExpr, int &nStart, int &nEnd); - /** - * @brief A facet class used to change decimal and thousands separator. - */ - template - class change_dec_sep : public std::numpunct - { - public: - explicit change_dec_sep(char_type cDecSep, char_type cThousandsSep = 0, int nGroup = 3) - :std::numpunct(), m_nGroup(nGroup), m_cDecPoint(cDecSep), m_cThousandsSep(cThousandsSep) - {} - protected: - virtual char_type do_decimal_point() const - { - return m_cDecPoint; - } - - virtual char_type do_thousands_sep() const - { - return m_cThousandsSep; - } - - virtual std::string do_grouping() const - { - return std::string(1, m_nGroup); - } - private: - int m_nGroup; - char_type m_cDecPoint; - char_type m_cThousandsSep; - }; -private: - /** - * @brief Typedef for the parse functions. - * - * The parse function do the actual work. The parser exchanges - * the function pointer to the parser function depending on - * which state it is in. (i.e. bytecode parser vs. string parser) - */ - typedef qreal (QmuParserBase::*ParseFunction)() const; - - /** - * @brief Type used for storing an array of values. - */ - typedef QVector valbuf_type; - - /** - * @brief Type for a vector of strings. - */ - typedef QVector stringbuf_type; - - /** - * @brief Typedef for the token reader. - */ - typedef QmuParserTokenReader token_reader_type; - - /** - * @brief Type used for parser tokens. - */ - typedef QmuParserToken token_type; - - /** - * @brief Maximum number of threads spawned by OpenMP when using the bulk mode. - */ - static const int s_MaxNumOpenMPThreads = 4; - - /** - * @brief Pointer to the parser function. - * - * Eval() calls the function whose address is stored there. - */ - mutable ParseFunction m_pParseFormula; - mutable QmuParserByteCode m_vRPN; ///< The Bytecode class. - mutable stringbuf_type m_vStringBuf; ///< String buffer, used for storing string function arguments - stringbuf_type m_vStringVarBuf; - - std::unique_ptr m_pTokenReader; ///< Managed pointer to the token reader object. - - funmap_type m_FunDef; ///< Map of function names and pointers. - funmap_type m_PostOprtDef; ///< Postfix operator callbacks - funmap_type m_InfixOprtDef; ///< unary infix operator. - funmap_type m_OprtDef; ///< Binary operator callbacks - valmap_type m_ConstDef; ///< user constants. - strmap_type m_StrVarDef; ///< user defined string constants - varmap_type m_VarDef; ///< user defind variables. - - bool m_bBuiltInOp; ///< Flag that can be used for switching built in operators on and off - - QString m_sNameChars; ///< Charset for names - QString m_sOprtChars; ///< Charset for postfix/ binary operator tokens - QString m_sInfixOprtChars; ///< Charset for infix operator tokens - - mutable int m_nIfElseCounter; ///< Internal counter for keeping track of nested if-then-else clauses - - // items merely used for caching state information - mutable valbuf_type m_vStackBuffer; ///< This is merely a buffer used for the stack in the cmd parsing routine - mutable int m_nFinalResultIdx; - - void Assign(const QmuParserBase &a_Parser); - void InitTokenReader(); - void ReInit() const; - void AddCallback(const QString &a_strName, const QmuParserCallback &a_Callback, - funmap_type &a_Storage, const QString &a_szCharSet ); - void ApplyRemainingOprt(QStack &a_stOpt, QStack &a_stVal) const; - void ApplyBinOprt(QStack &a_stOpt, QStack &a_stVal) const; - void ApplyIfElse(QStack &a_stOpt, QStack &a_stVal) const; - void ApplyFunc(QStack &a_stOpt, QStack &a_stVal, int iArgCount) const; - token_type ApplyStrFunc(const token_type &a_FunTok, const QVector &a_vArg) const; - int GetOprtPrecedence(const token_type &a_Tok) const; - EOprtAssociativity GetOprtAssociativity(const token_type &a_Tok) const; - void CreateRPN() const; - qreal ParseString() const; - qreal ParseCmdCode() const; - qreal ParseCmdCodeBulk(int nOffset, int nThreadID) const; - void CheckName(const QString &a_strName, const QString &a_CharSet) const; - void CheckOprt(const QString &a_sName, const QmuParserCallback &a_Callback, - const QString &a_szCharSet) const; - void StackDump(const QStack &a_stVal, const QStack &a_stOprt) const; -}; - -} // namespace qmu - -#endif - +/*************************************************************************************************** + ** + ** Original work Copyright (C) 2013 Ingo Berg + ** Modified work Copyright 2014 Roman Telezhynskyi + ** + ** Permission is hereby granted, free of charge, to any person obtaining a copy of this + ** software and associated documentation files (the "Software"), to deal in the Software + ** without restriction, including without limitation the rights to use, copy, modify, + ** merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + ** permit persons to whom the Software is furnished to do so, subject to the following conditions: + ** + ** The above copyright notice and this permission notice shall be included in all copies or + ** substantial portions of the Software. + ** + ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + ** NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + ** DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ** + ******************************************************************************************************/ + +#ifndef QMUQPARSERBASE_H +#define QMUQPARSERBASE_H + +#include +#include +#include + +#include "qmuparserdef.h" +#include "qmuparsertokenreader.h" +#include "qmuparserbytecode.h" +#include "qmuparsererror.h" + + +namespace qmu +{ +/** + * @file + * @brief This file contains the class definition of the qmuparser engine. + */ + +/** + * @brief Mathematical expressions parser (base parser engine). + * @author (C) 2013 Ingo Berg + * + * This is the implementation of a bytecode based mathematical expressions parser. + * The formula will be parsed from string and converted into a bytecode. + * Future calculations will be done with the bytecode instead the formula string + * resulting in a significant performance increase. + * Complementary to a set of internally implemented functions the parser is able to handle + * user defined functions and variables. + */ +class QmuParserBase +{ + friend class QmuParserTokenReader; +public: + /** + * @brief Type of the error class. + * + * Included for backwards compatibility. + */ + typedef QmuParserError exception_type; + + QmuParserBase(); + QmuParserBase(const QmuParserBase &a_Parser); + QmuParserBase& operator=(const QmuParserBase &a_Parser); + virtual ~QmuParserBase(); + + static void EnableDebugDump(bool bDumpCmd, bool bDumpStack); + qreal Eval() const; + qreal* Eval(int &nStackSize) const; + void Eval(qreal *results, int nBulkSize); + int GetNumResults() const; + void SetExpr(const QString &a_sExpr); + void SetVarFactory(facfun_type a_pFactory, void *pUserData = NULL); + void SetDecSep(char_type cDecSep); + void SetThousandsSep(char_type cThousandsSep = 0); + void ResetLocale(); + void EnableOptimizer(bool a_bIsOn=true); + void EnableBuiltInOprt(bool a_bIsOn=true); + bool HasBuiltInOprt() const; + void AddValIdent(identfun_type a_pCallback); + void DefineOprt(const QString &a_strName, fun_type2 a_pFun, unsigned a_iPri=0, + EOprtAssociativity a_eAssociativity = oaLEFT, bool a_bAllowOpt = false); + void DefineConst(const QString &a_sName, qreal a_fVal); + void DefineStrConst(const QString &a_sName, const QString &a_strVal); + void DefineVar(const QString &a_sName, qreal *a_fVar); + void DefinePostfixOprt(const QString &a_strFun, fun_type1 a_pOprt, bool a_bAllowOpt=true); + void DefineInfixOprt(const QString &a_strName, fun_type1 a_pOprt, int a_iPrec=prINFIX, + bool a_bAllowOpt=true); + // Clear user defined variables, constants or functions + void ClearVar(); + void ClearFun(); + void ClearConst(); + void ClearInfixOprt(); + void ClearPostfixOprt(); + void ClearOprt(); + void RemoveVar(const QString &a_strVarName); + const varmap_type& GetUsedVar() const; + const varmap_type& GetVar() const; + const valmap_type& GetConst() const; + const QString& GetExpr() const; + const funmap_type& GetFunDef() const; + QString GetVersion(EParserVersionInfo eInfo = pviFULL) const; + const QStringList& GetOprtDef() const; + void DefineNameChars(const QString &a_szCharset); + void DefineOprtChars(const QString &a_szCharset); + void DefineInfixOprtChars(const QString &a_szCharset); + const QString& ValidNameChars() const; + const QString& ValidOprtChars() const; + const QString& ValidInfixOprtChars() const; + void SetArgSep(char_type cArgSep); + QChar GetArgSep() const; + void Error(EErrorCodes a_iErrc, int a_iPos = -1, const QString &a_strTok = QString() ) const; + /** + * @fn void qmu::QmuParserBase::DefineFun(const string_type &a_strName, fun_type0 a_pFun, + * bool a_bAllowOpt = true) + * @brief Define a parser function without arguments. + * @param a_strName Name of the function + * @param a_pFun Pointer to the callback function + * @param a_bAllowOpt A flag indicating this function may be optimized + */ + template + void DefineFun(const QString &a_strName, T a_pFun, bool a_bAllowOpt = true) + { + AddCallback( a_strName, QmuParserCallback(a_pFun, a_bAllowOpt), m_FunDef, ValidNameChars() ); + } +protected: + static const QStringList c_DefaultOprt; + static std::locale s_locale; ///< The locale used by the parser + static bool g_DbgDumpCmdCode; + static bool g_DbgDumpStack; + void Init(); + virtual void InitCharSets() = 0; + virtual void InitFun() = 0; + virtual void InitConst() = 0; + virtual void InitOprt() = 0; + virtual void OnDetectVar(const QString &pExpr, int &nStart, int &nEnd); + /** + * @brief A facet class used to change decimal and thousands separator. + */ + template + class change_dec_sep : public std::numpunct + { + public: + explicit change_dec_sep(char_type cDecSep, char_type cThousandsSep = 0, int nGroup = 3) + :std::numpunct(), m_nGroup(nGroup), m_cDecPoint(cDecSep), m_cThousandsSep(cThousandsSep) + {} + protected: + virtual char_type do_decimal_point() const + { + return m_cDecPoint; + } + + virtual char_type do_thousands_sep() const + { + return m_cThousandsSep; + } + + virtual std::string do_grouping() const + { + return std::string(1, m_nGroup); + } + private: + int m_nGroup; + char_type m_cDecPoint; + char_type m_cThousandsSep; + }; +private: + /** + * @brief Typedef for the parse functions. + * + * The parse function do the actual work. The parser exchanges + * the function pointer to the parser function depending on + * which state it is in. (i.e. bytecode parser vs. string parser) + */ + typedef qreal (QmuParserBase::*ParseFunction)() const; + + /** + * @brief Type used for storing an array of values. + */ + typedef QVector valbuf_type; + + /** + * @brief Type for a vector of strings. + */ + typedef QVector stringbuf_type; + + /** + * @brief Typedef for the token reader. + */ + typedef QmuParserTokenReader token_reader_type; + + /** + * @brief Type used for parser tokens. + */ + typedef QmuParserToken token_type; + + /** + * @brief Maximum number of threads spawned by OpenMP when using the bulk mode. + */ + static const int s_MaxNumOpenMPThreads = 4; + + /** + * @brief Pointer to the parser function. + * + * Eval() calls the function whose address is stored there. + */ + mutable ParseFunction m_pParseFormula; + mutable QmuParserByteCode m_vRPN; ///< The Bytecode class. + mutable stringbuf_type m_vStringBuf; ///< String buffer, used for storing string function arguments + stringbuf_type m_vStringVarBuf; + + std::unique_ptr m_pTokenReader; ///< Managed pointer to the token reader object. + + funmap_type m_FunDef; ///< Map of function names and pointers. + funmap_type m_PostOprtDef; ///< Postfix operator callbacks + funmap_type m_InfixOprtDef; ///< unary infix operator. + funmap_type m_OprtDef; ///< Binary operator callbacks + valmap_type m_ConstDef; ///< user constants. + strmap_type m_StrVarDef; ///< user defined string constants + varmap_type m_VarDef; ///< user defind variables. + + bool m_bBuiltInOp; ///< Flag that can be used for switching built in operators on and off + + QString m_sNameChars; ///< Charset for names + QString m_sOprtChars; ///< Charset for postfix/ binary operator tokens + QString m_sInfixOprtChars; ///< Charset for infix operator tokens + + mutable int m_nIfElseCounter; ///< Internal counter for keeping track of nested if-then-else clauses + + // items merely used for caching state information + mutable valbuf_type m_vStackBuffer; ///< This is merely a buffer used for the stack in the cmd parsing routine + mutable int m_nFinalResultIdx; + + void Assign(const QmuParserBase &a_Parser); + void InitTokenReader(); + void ReInit() const; + void AddCallback(const QString &a_strName, const QmuParserCallback &a_Callback, + funmap_type &a_Storage, const QString &a_szCharSet ); + void ApplyRemainingOprt(QStack &a_stOpt, QStack &a_stVal) const; + void ApplyBinOprt(QStack &a_stOpt, QStack &a_stVal) const; + void ApplyIfElse(QStack &a_stOpt, QStack &a_stVal) const; + void ApplyFunc(QStack &a_stOpt, QStack &a_stVal, int iArgCount) const; + token_type ApplyStrFunc(const token_type &a_FunTok, const QVector &a_vArg) const; + int GetOprtPrecedence(const token_type &a_Tok) const; + EOprtAssociativity GetOprtAssociativity(const token_type &a_Tok) const; + void CreateRPN() const; + qreal ParseString() const; + qreal ParseCmdCode() const; + qreal ParseCmdCodeBulk(int nOffset, int nThreadID) const; + void CheckName(const QString &a_strName, const QString &a_CharSet) const; + void CheckOprt(const QString &a_sName, const QmuParserCallback &a_Callback, + const QString &a_szCharSet) const; + void StackDump(const QStack &a_stVal, const QStack &a_stOprt) const; +}; + +} // namespace qmu + +#endif diff --git a/src/libs/qmuparser/qmuparserbytecode.cpp b/src/libs/qmuparser/qmuparserbytecode.cpp index 80e6822ea..296d89c53 100644 --- a/src/libs/qmuparser/qmuparserbytecode.cpp +++ b/src/libs/qmuparser/qmuparserbytecode.cpp @@ -1,953 +1,953 @@ -/*************************************************************************************************** - ** - ** Original work Copyright (C) 2013 Ingo Berg - ** Modified work Copyright 2014 Roman Telezhynskyi - ** - ** Permission is hereby granted, free of charge, to any person obtaining a copy of this - ** software and associated documentation files (the "Software"), to deal in the Software - ** without restriction, including without limitation the rights to use, copy, modify, - ** merge, publish, distribute, sublicense, and/or sell copies of the Software, and to - ** permit persons to whom the Software is furnished to do so, subject to the following conditions: - ** - ** The above copyright notice and this permission notice shall be included in all copies or - ** substantial portions of the Software. - ** - ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT - ** NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - ** DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ** - ******************************************************************************************************/ - -#include "qmuparserbytecode.h" - -#include -#include -#include -#include -#include - -#include "qmuparserdef.h" -#include "qmuparsererror.h" -#include "qmuparsertoken.h" - - -namespace qmu -{ -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Bytecode default constructor. - */ -QmuParserByteCode::QmuParserByteCode() - :m_iStackPos(0), m_iMaxStackSize(0), m_vRPN(), m_bEnableOptimizer(true) -{ - m_vRPN.reserve(50); -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Copy constructor. - * - * Implemented in Terms of Assign(const QParserByteCode &a_ByteCode) - */ -QmuParserByteCode::QmuParserByteCode(const QmuParserByteCode &a_ByteCode) - :m_iStackPos(a_ByteCode.m_iStackPos), m_iMaxStackSize(a_ByteCode.m_iMaxStackSize), m_vRPN(a_ByteCode.m_vRPN), - m_bEnableOptimizer(true) -{ - Assign(a_ByteCode); -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Assignment operator. - * - * Implemented in Terms of Assign(const QParserByteCode &a_ByteCode) - */ -QmuParserByteCode& QmuParserByteCode::operator=(const QmuParserByteCode &a_ByteCode) -{ - Assign(a_ByteCode); - return *this; -} - -//---------------------------------------------------------------------------------------------------------------------- -void QmuParserByteCode::EnableOptimizer(bool bStat) -{ - m_bEnableOptimizer = bStat; -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Copy state of another object to this. - * - * @throw nowthrow - */ -void QmuParserByteCode::Assign(const QmuParserByteCode &a_ByteCode) -{ - if (this==&a_ByteCode) - { - return; - } - - m_iStackPos = a_ByteCode.m_iStackPos; - m_vRPN = a_ByteCode.m_vRPN; - m_iMaxStackSize = a_ByteCode.m_iMaxStackSize; -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Add a Variable pointer to bytecode. - * @param a_pVar Pointer to be added. - * @throw nothrow - */ -void QmuParserByteCode::AddVar(qreal *a_pVar) -{ - ++m_iStackPos; - m_iMaxStackSize = qMax(m_iMaxStackSize, static_cast(m_iStackPos)); - - // optimization does not apply - SToken tok; - tok.Cmd = cmVAR; - tok.Val.ptr = a_pVar; - tok.Val.data = 1; - tok.Val.data2 = 0; - m_vRPN.push_back(tok); -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Add a Variable pointer to bytecode. - * - * Value entries in byte code consist of: - *
    - *
  • value array position of the value
  • - *
  • the operator code according to ParserToken::cmVAL
  • - *
  • the value stored in #mc_iSizeVal number of bytecode entries.
  • - *
- * - * @param a_pVal Value to be added. - * @throw nothrow - */ -void QmuParserByteCode::AddVal(qreal a_fVal) -{ - ++m_iStackPos; - m_iMaxStackSize = qMax(m_iMaxStackSize, static_cast(m_iStackPos)); - - // If optimization does not apply - SToken tok; - tok.Cmd = cmVAL; - tok.Val.ptr = NULL; - tok.Val.data = 0; - tok.Val.data2 = a_fVal; - m_vRPN.push_back(tok); -} - -//---------------------------------------------------------------------------------------------------------------------- -void QmuParserByteCode::ConstantFolding(ECmdCode a_Oprt) -{ - std::size_t sz = m_vRPN.size(); - qreal &x = m_vRPN[sz-2].Val.data2, - &y = m_vRPN[sz-1].Val.data2; - switch (a_Oprt) - { - case cmLAND: - x = static_cast(x) && static_cast(y); - m_vRPN.pop_back(); - break; - case cmLOR: - x = static_cast(x) || static_cast(y); - m_vRPN.pop_back(); - break; - case cmLT: - x = x < y; - m_vRPN.pop_back(); - break; - case cmGT: - x = x > y; - m_vRPN.pop_back(); - break; - case cmLE: - x = x <= y; - m_vRPN.pop_back(); - break; - case cmGE: - x = x >= y; - m_vRPN.pop_back(); - break; - case cmNEQ: - x = (qFuzzyCompare(x, y) == false); - m_vRPN.pop_back(); - break; - case cmEQ: - x = qFuzzyCompare(x, y); - m_vRPN.pop_back(); - break; - case cmADD: - x = x + y; - m_vRPN.pop_back(); - break; - case cmSUB: - x = x - y; - m_vRPN.pop_back(); - break; - case cmMUL: - x = x * y; - m_vRPN.pop_back(); - break; - case cmDIV: - #if defined(MUP_MATH_EXCEPTIONS) - if (y==0) - { - throw ParserError(ecDIV_BY_ZERO, "0"); - } - #endif - x = x / y; - m_vRPN.pop_back(); - break; - case cmPOW: - x = qPow(x, y); - m_vRPN.pop_back(); - break; - case cmASSIGN: - Q_UNREACHABLE(); - break; - case cmBO: - Q_UNREACHABLE(); - break; - case cmBC: - Q_UNREACHABLE(); - break; - case cmIF: - Q_UNREACHABLE(); - break; - case cmELSE: - Q_UNREACHABLE(); - break; - case cmENDIF: - Q_UNREACHABLE(); - break; - case cmARG_SEP: - Q_UNREACHABLE(); - break; - case cmVAR: - Q_UNREACHABLE(); - break; - case cmVAL: - Q_UNREACHABLE(); - break; - case cmVARPOW2: - Q_UNREACHABLE(); - break; - case cmVARPOW3: - Q_UNREACHABLE(); - break; - case cmVARPOW4: - Q_UNREACHABLE(); - break; - case cmVARMUL: - Q_UNREACHABLE(); - break; - case cmPOW2: - Q_UNREACHABLE(); - break; - case cmFUNC: - Q_UNREACHABLE(); - break; - case cmFUNC_STR: - Q_UNREACHABLE(); - break; - case cmFUNC_BULK: - Q_UNREACHABLE(); - break; - case cmSTRING: - Q_UNREACHABLE(); - break; - case cmOPRT_BIN: - Q_UNREACHABLE(); - break; - case cmOPRT_POSTFIX: - Q_UNREACHABLE(); - break; - case cmOPRT_INFIX: - Q_UNREACHABLE(); - break; - case cmEND: - Q_UNREACHABLE(); - break; - case cmUNKNOWN: - Q_UNREACHABLE(); - break; - default: - break; - } // switch opcode -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Add an operator identifier to bytecode. - * - * Operator entries in byte code consist of: - *
    - *
  • value array position of the result
  • - *
  • the operator code according to ParserToken::ECmdCode
  • - *
- * - * @sa ParserToken::ECmdCode - */ -void QmuParserByteCode::AddOp(ECmdCode a_Oprt) -{ - bool bOptimized = false; - - if (m_bEnableOptimizer) - { - std::size_t sz = m_vRPN.size(); - - // Check for foldable constants like: - // cmVAL cmVAL cmADD - // where cmADD can stand fopr any binary operator applied to - // two constant values. - if (sz>=2 && m_vRPN[sz-2].Cmd == cmVAL && m_vRPN[sz-1].Cmd == cmVAL) - { - ConstantFolding(a_Oprt); - bOptimized = true; - } - else - { - switch(a_Oprt) - { - case cmPOW: - // Optimization for ploynomials of low order - if (m_vRPN[sz-2].Cmd == cmVAR && m_vRPN[sz-1].Cmd == cmVAL) - { - if (qFuzzyCompare(m_vRPN[sz-1].Val.data2, 2)) - { - m_vRPN[sz-2].Cmd = cmVARPOW2; - } - else if (qFuzzyCompare(m_vRPN[sz-1].Val.data2, 3)) - { - m_vRPN[sz-2].Cmd = cmVARPOW3; - } - else if (qFuzzyCompare(m_vRPN[sz-1].Val.data2, 4)) - { - m_vRPN[sz-2].Cmd = cmVARPOW4; - } - else - { - break; - } - m_vRPN.pop_back(); - bOptimized = true; - } - break; - - case cmSUB: - case cmADD: - // Simple optimization based on pattern recognition for a shitload of different - // bytecode combinations of addition/subtraction - if ( (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAL) || - (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVAR) || - (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVARMUL) || - (m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVAL) || - (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAR && - m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) || - (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVARMUL - && m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) || - (m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVAR && - m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) || - (m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVARMUL && - m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) ) - { - assert( (m_vRPN[sz-2].Val.ptr==NULL && m_vRPN[sz-1].Val.ptr!=NULL) || - (m_vRPN[sz-2].Val.ptr!=NULL && m_vRPN[sz-1].Val.ptr==NULL) || - (m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) ); - - m_vRPN[sz-2].Cmd = cmVARMUL; - m_vRPN[sz-2].Val.ptr = reinterpret_cast( - reinterpret_cast(m_vRPN[sz-2].Val.ptr) | - reinterpret_cast(m_vRPN[sz-1].Val.ptr)); // variable - m_vRPN[sz-2].Val.data2 += ((a_Oprt==cmSUB) ? -1 : 1) * m_vRPN[sz-1].Val.data2; // offset - m_vRPN[sz-2].Val.data += ((a_Oprt==cmSUB) ? -1 : 1) * m_vRPN[sz-1].Val.data; // multiplikatior - m_vRPN.pop_back(); - bOptimized = true; - } - break; - case cmMUL: - if ( (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAL) || - (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVAR) ) - { - m_vRPN[sz-2].Cmd = cmVARMUL; - m_vRPN[sz-2].Val.ptr = reinterpret_cast( - reinterpret_cast(m_vRPN[sz-2].Val.ptr) | - reinterpret_cast(m_vRPN[sz-1].Val.ptr)); - m_vRPN[sz-2].Val.data = m_vRPN[sz-2].Val.data2 + m_vRPN[sz-1].Val.data2; - m_vRPN[sz-2].Val.data2 = 0; - m_vRPN.pop_back(); - bOptimized = true; - } - else if ( (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVARMUL) || - (m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVAL) ) - { - // Optimization: 2*(3*b+1) or (3*b+1)*2 -> 6*b+2 - m_vRPN[sz-2].Cmd = cmVARMUL; - m_vRPN[sz-2].Val.ptr = reinterpret_cast( - reinterpret_cast(m_vRPN[sz-2].Val.ptr) | - reinterpret_cast(m_vRPN[sz-1].Val.ptr)); - if (m_vRPN[sz-1].Cmd == cmVAL) - { - m_vRPN[sz-2].Val.data *= m_vRPN[sz-1].Val.data2; - m_vRPN[sz-2].Val.data2 *= m_vRPN[sz-1].Val.data2; - } - else - { - m_vRPN[sz-2].Val.data = m_vRPN[sz-1].Val.data * m_vRPN[sz-2].Val.data2; - m_vRPN[sz-2].Val.data2 = m_vRPN[sz-1].Val.data2 * m_vRPN[sz-2].Val.data2; - } - m_vRPN.pop_back(); - bOptimized = true; - } - else if (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAR && - m_vRPN[sz-1].Val.ptr == m_vRPN[sz-2].Val.ptr) - { - // Optimization: a*a -> a^2 - m_vRPN[sz-2].Cmd = cmVARPOW2; - m_vRPN.pop_back(); - bOptimized = true; - } - break; - case cmDIV: - if (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVARMUL && - (qFuzzyCompare(m_vRPN[sz-1].Val.data2+1, 1+0)==false)) - { - // Optimization: 4*a/2 -> 2*a - m_vRPN[sz-2].Val.data /= m_vRPN[sz-1].Val.data2; - m_vRPN[sz-2].Val.data2 /= m_vRPN[sz-1].Val.data2; - m_vRPN.pop_back(); - bOptimized = true; - } - break; - case cmLE: - Q_UNREACHABLE(); - break; - case cmGE: - Q_UNREACHABLE(); - break; - case cmNEQ: - Q_UNREACHABLE(); - break; - case cmEQ: - Q_UNREACHABLE(); - break; - case cmLT: - Q_UNREACHABLE(); - break; - case cmGT: - Q_UNREACHABLE(); - break; - case cmLAND: - Q_UNREACHABLE(); - break; - case cmLOR: - Q_UNREACHABLE(); - break; - case cmASSIGN: - Q_UNREACHABLE(); - break; - case cmBO: - Q_UNREACHABLE(); - break; - case cmBC: - Q_UNREACHABLE(); - break; - case cmIF: - Q_UNREACHABLE(); - break; - case cmELSE: - Q_UNREACHABLE(); - break; - case cmENDIF: - Q_UNREACHABLE(); - break; - case cmARG_SEP: - Q_UNREACHABLE(); - break; - case cmVAR: - Q_UNREACHABLE(); - break; - case cmVAL: - Q_UNREACHABLE(); - break; - case cmVARPOW2: - Q_UNREACHABLE(); - break; - case cmVARPOW3: - Q_UNREACHABLE(); - break; - case cmVARPOW4: - Q_UNREACHABLE(); - break; - case cmVARMUL: - Q_UNREACHABLE(); - break; - case cmPOW2: - Q_UNREACHABLE(); - break; - case cmFUNC: - Q_UNREACHABLE(); - break; - case cmFUNC_STR: - Q_UNREACHABLE(); - break; - case cmFUNC_BULK: - Q_UNREACHABLE(); - break; - case cmSTRING: - Q_UNREACHABLE(); - break; - case cmOPRT_BIN: - Q_UNREACHABLE(); - break; - case cmOPRT_POSTFIX: - Q_UNREACHABLE(); - break; - case cmOPRT_INFIX: - Q_UNREACHABLE(); - break; - case cmEND: - Q_UNREACHABLE(); - break; - case cmUNKNOWN: - Q_UNREACHABLE(); - break; - default: - break; - - } // switch a_Oprt - } - } - - // If optimization can't be applied just write the value - if (!bOptimized) - { - --m_iStackPos; - SToken tok; - tok.Cmd = a_Oprt; - m_vRPN.push_back(tok); - } -} - -//---------------------------------------------------------------------------------------------------------------------- -void QmuParserByteCode::AddIfElse(ECmdCode a_Oprt) -{ - SToken tok; - tok.Cmd = a_Oprt; - m_vRPN.push_back(tok); -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Add an assignement operator - * - * Operator entries in byte code consist of: - *
    - *
  • cmASSIGN code
  • - *
  • the pointer of the destination variable
  • - *
- * - * @sa ParserToken::ECmdCode - */ -void QmuParserByteCode::AddAssignOp(qreal *a_pVar) -{ - --m_iStackPos; - - SToken tok; - tok.Cmd = cmASSIGN; - tok.Val.ptr = a_pVar; - m_vRPN.push_back(tok); -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Add function to bytecode. - * - * @param a_iArgc Number of arguments, negative numbers indicate multiarg functions. - * @param a_pFun Pointer to function callback. - */ -void QmuParserByteCode::AddFun(generic_fun_type a_pFun, int a_iArgc) -{ - if (a_iArgc>=0) - { - m_iStackPos = m_iStackPos - a_iArgc + 1; - } - else - { - // function with unlimited number of arguments - m_iStackPos = m_iStackPos + a_iArgc + 1; - } - m_iMaxStackSize = qMax(m_iMaxStackSize, static_cast(m_iStackPos)); - - SToken tok; - tok.Cmd = cmFUNC; - tok.Fun.argc = a_iArgc; - tok.Fun.ptr = a_pFun; - m_vRPN.push_back(tok); -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Add a bulk function to bytecode. - * - * @param a_iArgc Number of arguments, negative numbers indicate multiarg functions. - * @param a_pFun Pointer to function callback. - */ -void QmuParserByteCode::AddBulkFun(generic_fun_type a_pFun, int a_iArgc) -{ - m_iStackPos = m_iStackPos - a_iArgc + 1; - m_iMaxStackSize = qMax(m_iMaxStackSize, static_cast(m_iStackPos)); - - SToken tok; - tok.Cmd = cmFUNC_BULK; - tok.Fun.argc = a_iArgc; - tok.Fun.ptr = a_pFun; - m_vRPN.push_back(tok); -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Add Strung function entry to the parser bytecode. - * @throw nothrow - * - * A string function entry consists of the stack position of the return value, followed by a cmSTRFUNC code, the - * function pointer and an index into the string buffer maintained by the parser. - */ -void QmuParserByteCode::AddStrFun(generic_fun_type a_pFun, int a_iArgc, int a_iIdx) -{ - m_iStackPos = m_iStackPos - a_iArgc + 1; - - SToken tok; - tok.Cmd = cmFUNC_STR; - tok.Fun.argc = a_iArgc; - tok.Fun.idx = a_iIdx; - tok.Fun.ptr = a_pFun; - m_vRPN.push_back(tok); - - m_iMaxStackSize = qMax(m_iMaxStackSize, static_cast(m_iStackPos)); -} - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Add end marker to bytecode. - * - * @throw nothrow - */ -void QmuParserByteCode::Finalize() -{ - SToken tok; - tok.Cmd = cmEND; - m_vRPN.push_back(tok); - rpn_type(m_vRPN).swap(m_vRPN); // shrink bytecode vector to fit - - // Determine the if-then-else jump offsets - QStack stIf, stElse; - int idx; - for (int i=0; i + ** + ** Permission is hereby granted, free of charge, to any person obtaining a copy of this + ** software and associated documentation files (the "Software"), to deal in the Software + ** without restriction, including without limitation the rights to use, copy, modify, + ** merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + ** permit persons to whom the Software is furnished to do so, subject to the following conditions: + ** + ** The above copyright notice and this permission notice shall be included in all copies or + ** substantial portions of the Software. + ** + ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + ** NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + ** DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ** + ******************************************************************************************************/ + +#include "qmuparserbytecode.h" + +#include +#include +#include +#include +#include + +#include "qmuparserdef.h" +#include "qmuparsererror.h" +#include "qmuparsertoken.h" + + +namespace qmu +{ +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Bytecode default constructor. + */ +QmuParserByteCode::QmuParserByteCode() + :m_iStackPos(0), m_iMaxStackSize(0), m_vRPN(), m_bEnableOptimizer(true) +{ + m_vRPN.reserve(50); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Copy constructor. + * + * Implemented in Terms of Assign(const QParserByteCode &a_ByteCode) + */ +QmuParserByteCode::QmuParserByteCode(const QmuParserByteCode &a_ByteCode) + :m_iStackPos(a_ByteCode.m_iStackPos), m_iMaxStackSize(a_ByteCode.m_iMaxStackSize), m_vRPN(a_ByteCode.m_vRPN), + m_bEnableOptimizer(true) +{ + Assign(a_ByteCode); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Assignment operator. + * + * Implemented in Terms of Assign(const QParserByteCode &a_ByteCode) + */ +QmuParserByteCode& QmuParserByteCode::operator=(const QmuParserByteCode &a_ByteCode) +{ + Assign(a_ByteCode); + return *this; +} + +//--------------------------------------------------------------------------------------------------------------------- +void QmuParserByteCode::EnableOptimizer(bool bStat) +{ + m_bEnableOptimizer = bStat; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Copy state of another object to this. + * + * @throw nowthrow + */ +void QmuParserByteCode::Assign(const QmuParserByteCode &a_ByteCode) +{ + if (this==&a_ByteCode) + { + return; + } + + m_iStackPos = a_ByteCode.m_iStackPos; + m_vRPN = a_ByteCode.m_vRPN; + m_iMaxStackSize = a_ByteCode.m_iMaxStackSize; +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Add a Variable pointer to bytecode. + * @param a_pVar Pointer to be added. + * @throw nothrow + */ +void QmuParserByteCode::AddVar(qreal *a_pVar) +{ + ++m_iStackPos; + m_iMaxStackSize = qMax(m_iMaxStackSize, static_cast(m_iStackPos)); + + // optimization does not apply + SToken tok; + tok.Cmd = cmVAR; + tok.Val.ptr = a_pVar; + tok.Val.data = 1; + tok.Val.data2 = 0; + m_vRPN.push_back(tok); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Add a Variable pointer to bytecode. + * + * Value entries in byte code consist of: + *
    + *
  • value array position of the value
  • + *
  • the operator code according to ParserToken::cmVAL
  • + *
  • the value stored in #mc_iSizeVal number of bytecode entries.
  • + *
+ * + * @param a_pVal Value to be added. + * @throw nothrow + */ +void QmuParserByteCode::AddVal(qreal a_fVal) +{ + ++m_iStackPos; + m_iMaxStackSize = qMax(m_iMaxStackSize, static_cast(m_iStackPos)); + + // If optimization does not apply + SToken tok; + tok.Cmd = cmVAL; + tok.Val.ptr = NULL; + tok.Val.data = 0; + tok.Val.data2 = a_fVal; + m_vRPN.push_back(tok); +} + +//--------------------------------------------------------------------------------------------------------------------- +void QmuParserByteCode::ConstantFolding(ECmdCode a_Oprt) +{ + std::size_t sz = m_vRPN.size(); + qreal &x = m_vRPN[sz-2].Val.data2, + &y = m_vRPN[sz-1].Val.data2; + switch (a_Oprt) + { + case cmLAND: + x = static_cast(x) && static_cast(y); + m_vRPN.pop_back(); + break; + case cmLOR: + x = static_cast(x) || static_cast(y); + m_vRPN.pop_back(); + break; + case cmLT: + x = x < y; + m_vRPN.pop_back(); + break; + case cmGT: + x = x > y; + m_vRPN.pop_back(); + break; + case cmLE: + x = x <= y; + m_vRPN.pop_back(); + break; + case cmGE: + x = x >= y; + m_vRPN.pop_back(); + break; + case cmNEQ: + x = (qFuzzyCompare(x, y) == false); + m_vRPN.pop_back(); + break; + case cmEQ: + x = qFuzzyCompare(x, y); + m_vRPN.pop_back(); + break; + case cmADD: + x = x + y; + m_vRPN.pop_back(); + break; + case cmSUB: + x = x - y; + m_vRPN.pop_back(); + break; + case cmMUL: + x = x * y; + m_vRPN.pop_back(); + break; + case cmDIV: + #if defined(MUP_MATH_EXCEPTIONS) + if (y==0) + { + throw ParserError(ecDIV_BY_ZERO, "0"); + } + #endif + x = x / y; + m_vRPN.pop_back(); + break; + case cmPOW: + x = qPow(x, y); + m_vRPN.pop_back(); + break; + case cmASSIGN: + Q_UNREACHABLE(); + break; + case cmBO: + Q_UNREACHABLE(); + break; + case cmBC: + Q_UNREACHABLE(); + break; + case cmIF: + Q_UNREACHABLE(); + break; + case cmELSE: + Q_UNREACHABLE(); + break; + case cmENDIF: + Q_UNREACHABLE(); + break; + case cmARG_SEP: + Q_UNREACHABLE(); + break; + case cmVAR: + Q_UNREACHABLE(); + break; + case cmVAL: + Q_UNREACHABLE(); + break; + case cmVARPOW2: + Q_UNREACHABLE(); + break; + case cmVARPOW3: + Q_UNREACHABLE(); + break; + case cmVARPOW4: + Q_UNREACHABLE(); + break; + case cmVARMUL: + Q_UNREACHABLE(); + break; + case cmPOW2: + Q_UNREACHABLE(); + break; + case cmFUNC: + Q_UNREACHABLE(); + break; + case cmFUNC_STR: + Q_UNREACHABLE(); + break; + case cmFUNC_BULK: + Q_UNREACHABLE(); + break; + case cmSTRING: + Q_UNREACHABLE(); + break; + case cmOPRT_BIN: + Q_UNREACHABLE(); + break; + case cmOPRT_POSTFIX: + Q_UNREACHABLE(); + break; + case cmOPRT_INFIX: + Q_UNREACHABLE(); + break; + case cmEND: + Q_UNREACHABLE(); + break; + case cmUNKNOWN: + Q_UNREACHABLE(); + break; + default: + break; + } // switch opcode +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Add an operator identifier to bytecode. + * + * Operator entries in byte code consist of: + *
    + *
  • value array position of the result
  • + *
  • the operator code according to ParserToken::ECmdCode
  • + *
+ * + * @sa ParserToken::ECmdCode + */ +void QmuParserByteCode::AddOp(ECmdCode a_Oprt) +{ + bool bOptimized = false; + + if (m_bEnableOptimizer) + { + std::size_t sz = m_vRPN.size(); + + // Check for foldable constants like: + // cmVAL cmVAL cmADD + // where cmADD can stand fopr any binary operator applied to + // two constant values. + if (sz>=2 && m_vRPN[sz-2].Cmd == cmVAL && m_vRPN[sz-1].Cmd == cmVAL) + { + ConstantFolding(a_Oprt); + bOptimized = true; + } + else + { + switch (a_Oprt) + { + case cmPOW: + // Optimization for ploynomials of low order + if (m_vRPN[sz-2].Cmd == cmVAR && m_vRPN[sz-1].Cmd == cmVAL) + { + if (qFuzzyCompare(m_vRPN[sz-1].Val.data2, 2)) + { + m_vRPN[sz-2].Cmd = cmVARPOW2; + } + else if (qFuzzyCompare(m_vRPN[sz-1].Val.data2, 3)) + { + m_vRPN[sz-2].Cmd = cmVARPOW3; + } + else if (qFuzzyCompare(m_vRPN[sz-1].Val.data2, 4)) + { + m_vRPN[sz-2].Cmd = cmVARPOW4; + } + else + { + break; + } + m_vRPN.pop_back(); + bOptimized = true; + } + break; + + case cmSUB: + case cmADD: + // Simple optimization based on pattern recognition for a shitload of different + // bytecode combinations of addition/subtraction + if ( (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAL) || + (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVAR) || + (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVARMUL) || + (m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVAL) || + (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAR && + m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) || + (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVARMUL + && m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) || + (m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVAR && + m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) || + (m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVARMUL && + m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) ) + { + assert( (m_vRPN[sz-2].Val.ptr==NULL && m_vRPN[sz-1].Val.ptr!=NULL) || + (m_vRPN[sz-2].Val.ptr!=NULL && m_vRPN[sz-1].Val.ptr==NULL) || + (m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) ); + + m_vRPN[sz-2].Cmd = cmVARMUL; + m_vRPN[sz-2].Val.ptr = reinterpret_cast( + reinterpret_cast(m_vRPN[sz-2].Val.ptr) | + reinterpret_cast(m_vRPN[sz-1].Val.ptr)); // variable + m_vRPN[sz-2].Val.data2 += ((a_Oprt==cmSUB) ? -1 : 1) * m_vRPN[sz-1].Val.data2; // offset + m_vRPN[sz-2].Val.data += ((a_Oprt==cmSUB) ? -1 : 1) * m_vRPN[sz-1].Val.data; // multiplikatior + m_vRPN.pop_back(); + bOptimized = true; + } + break; + case cmMUL: + if ( (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAL) || + (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVAR) ) + { + m_vRPN[sz-2].Cmd = cmVARMUL; + m_vRPN[sz-2].Val.ptr = reinterpret_cast( + reinterpret_cast(m_vRPN[sz-2].Val.ptr) | + reinterpret_cast(m_vRPN[sz-1].Val.ptr)); + m_vRPN[sz-2].Val.data = m_vRPN[sz-2].Val.data2 + m_vRPN[sz-1].Val.data2; + m_vRPN[sz-2].Val.data2 = 0; + m_vRPN.pop_back(); + bOptimized = true; + } + else if ( (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVARMUL) || + (m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVAL) ) + { + // Optimization: 2*(3*b+1) or (3*b+1)*2 -> 6*b+2 + m_vRPN[sz-2].Cmd = cmVARMUL; + m_vRPN[sz-2].Val.ptr = reinterpret_cast( + reinterpret_cast(m_vRPN[sz-2].Val.ptr) | + reinterpret_cast(m_vRPN[sz-1].Val.ptr)); + if (m_vRPN[sz-1].Cmd == cmVAL) + { + m_vRPN[sz-2].Val.data *= m_vRPN[sz-1].Val.data2; + m_vRPN[sz-2].Val.data2 *= m_vRPN[sz-1].Val.data2; + } + else + { + m_vRPN[sz-2].Val.data = m_vRPN[sz-1].Val.data * m_vRPN[sz-2].Val.data2; + m_vRPN[sz-2].Val.data2 = m_vRPN[sz-1].Val.data2 * m_vRPN[sz-2].Val.data2; + } + m_vRPN.pop_back(); + bOptimized = true; + } + else if (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAR && + m_vRPN[sz-1].Val.ptr == m_vRPN[sz-2].Val.ptr) + { + // Optimization: a*a -> a^2 + m_vRPN[sz-2].Cmd = cmVARPOW2; + m_vRPN.pop_back(); + bOptimized = true; + } + break; + case cmDIV: + if (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVARMUL && + (qFuzzyCompare(m_vRPN[sz-1].Val.data2+1, 1+0)==false)) + { + // Optimization: 4*a/2 -> 2*a + m_vRPN[sz-2].Val.data /= m_vRPN[sz-1].Val.data2; + m_vRPN[sz-2].Val.data2 /= m_vRPN[sz-1].Val.data2; + m_vRPN.pop_back(); + bOptimized = true; + } + break; + case cmLE: + Q_UNREACHABLE(); + break; + case cmGE: + Q_UNREACHABLE(); + break; + case cmNEQ: + Q_UNREACHABLE(); + break; + case cmEQ: + Q_UNREACHABLE(); + break; + case cmLT: + Q_UNREACHABLE(); + break; + case cmGT: + Q_UNREACHABLE(); + break; + case cmLAND: + Q_UNREACHABLE(); + break; + case cmLOR: + Q_UNREACHABLE(); + break; + case cmASSIGN: + Q_UNREACHABLE(); + break; + case cmBO: + Q_UNREACHABLE(); + break; + case cmBC: + Q_UNREACHABLE(); + break; + case cmIF: + Q_UNREACHABLE(); + break; + case cmELSE: + Q_UNREACHABLE(); + break; + case cmENDIF: + Q_UNREACHABLE(); + break; + case cmARG_SEP: + Q_UNREACHABLE(); + break; + case cmVAR: + Q_UNREACHABLE(); + break; + case cmVAL: + Q_UNREACHABLE(); + break; + case cmVARPOW2: + Q_UNREACHABLE(); + break; + case cmVARPOW3: + Q_UNREACHABLE(); + break; + case cmVARPOW4: + Q_UNREACHABLE(); + break; + case cmVARMUL: + Q_UNREACHABLE(); + break; + case cmPOW2: + Q_UNREACHABLE(); + break; + case cmFUNC: + Q_UNREACHABLE(); + break; + case cmFUNC_STR: + Q_UNREACHABLE(); + break; + case cmFUNC_BULK: + Q_UNREACHABLE(); + break; + case cmSTRING: + Q_UNREACHABLE(); + break; + case cmOPRT_BIN: + Q_UNREACHABLE(); + break; + case cmOPRT_POSTFIX: + Q_UNREACHABLE(); + break; + case cmOPRT_INFIX: + Q_UNREACHABLE(); + break; + case cmEND: + Q_UNREACHABLE(); + break; + case cmUNKNOWN: + Q_UNREACHABLE(); + break; + default: + break; + + } // switch a_Oprt + } + } + + // If optimization can't be applied just write the value + if (bOptimized == false) + { + --m_iStackPos; + SToken tok; + tok.Cmd = a_Oprt; + m_vRPN.push_back(tok); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void QmuParserByteCode::AddIfElse(ECmdCode a_Oprt) +{ + SToken tok; + tok.Cmd = a_Oprt; + m_vRPN.push_back(tok); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Add an assignement operator + * + * Operator entries in byte code consist of: + *
    + *
  • cmASSIGN code
  • + *
  • the pointer of the destination variable
  • + *
+ * + * @sa ParserToken::ECmdCode + */ +void QmuParserByteCode::AddAssignOp(qreal *a_pVar) +{ + --m_iStackPos; + + SToken tok; + tok.Cmd = cmASSIGN; + tok.Val.ptr = a_pVar; + m_vRPN.push_back(tok); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Add function to bytecode. + * + * @param a_iArgc Number of arguments, negative numbers indicate multiarg functions. + * @param a_pFun Pointer to function callback. + */ +void QmuParserByteCode::AddFun(generic_fun_type a_pFun, int a_iArgc) +{ + if (a_iArgc>=0) + { + m_iStackPos = m_iStackPos - a_iArgc + 1; + } + else + { + // function with unlimited number of arguments + m_iStackPos = m_iStackPos + a_iArgc + 1; + } + m_iMaxStackSize = qMax(m_iMaxStackSize, static_cast(m_iStackPos)); + + SToken tok; + tok.Cmd = cmFUNC; + tok.Fun.argc = a_iArgc; + tok.Fun.ptr = a_pFun; + m_vRPN.push_back(tok); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Add a bulk function to bytecode. + * + * @param a_iArgc Number of arguments, negative numbers indicate multiarg functions. + * @param a_pFun Pointer to function callback. + */ +void QmuParserByteCode::AddBulkFun(generic_fun_type a_pFun, int a_iArgc) +{ + m_iStackPos = m_iStackPos - a_iArgc + 1; + m_iMaxStackSize = qMax(m_iMaxStackSize, static_cast(m_iStackPos)); + + SToken tok; + tok.Cmd = cmFUNC_BULK; + tok.Fun.argc = a_iArgc; + tok.Fun.ptr = a_pFun; + m_vRPN.push_back(tok); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Add Strung function entry to the parser bytecode. + * @throw nothrow + * + * A string function entry consists of the stack position of the return value, followed by a cmSTRFUNC code, the + * function pointer and an index into the string buffer maintained by the parser. + */ +void QmuParserByteCode::AddStrFun(generic_fun_type a_pFun, int a_iArgc, int a_iIdx) +{ + m_iStackPos = m_iStackPos - a_iArgc + 1; + + SToken tok; + tok.Cmd = cmFUNC_STR; + tok.Fun.argc = a_iArgc; + tok.Fun.idx = a_iIdx; + tok.Fun.ptr = a_pFun; + m_vRPN.push_back(tok); + + m_iMaxStackSize = qMax(m_iMaxStackSize, static_cast(m_iStackPos)); +} + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Add end marker to bytecode. + * + * @throw nothrow + */ +void QmuParserByteCode::Finalize() +{ + SToken tok; + tok.Cmd = cmEND; + m_vRPN.push_back(tok); + rpn_type(m_vRPN).swap(m_vRPN); // shrink bytecode vector to fit + + // Determine the if-then-else jump offsets + QStack stIf, stElse; + int idx; + for (int i=0; i - ** - ** Permission is hereby granted, free of charge, to any person obtaining a copy of this - ** software and associated documentation files (the "Software"), to deal in the Software - ** without restriction, including without limitation the rights to use, copy, modify, - ** merge, publish, distribute, sublicense, and/or sell copies of the Software, and to - ** permit persons to whom the Software is furnished to do so, subject to the following conditions: - ** - ** The above copyright notice and this permission notice shall be included in all copies or - ** substantial portions of the Software. - ** - ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT - ** NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - ** DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ** - ******************************************************************************************************/ - -#ifndef QMUPARSERBYTECODE_H -#define QMUPARSERBYTECODE_H - -#include "qmuparserdef.h" -#include "qmuparsererror.h" -#include "qmuparsertoken.h" - -/** - * @file - * @brief Definition of the parser bytecode class. - */ - -namespace qmu -{ -struct SToken -{ - ECmdCode Cmd; - int StackPos; - - union - { - struct //SValData - { - qreal *ptr; - qreal data; - qreal data2; - } Val; - - struct //SFunData - { - // Note: generic_fun_type is merely a placeholder. The real type could be - // anything between gun_type1 and fun_type9. I can't use a void - // pointer due to constraints in the ANSI standard which allows - // data pointers and function pointers to differ in size. - generic_fun_type ptr; - int argc; - int idx; - } Fun; - - struct //SOprtData - { - qreal *ptr; - int offset; - } Oprt; - }; -}; - - -/** - * @brief Bytecode implementation of the Math Parser. - * - * The bytecode contains the formula converted to revers polish notation stored in a continious - * memory area. Associated with this data are operator codes, variable pointers, constant - * values and function pointers. Those are necessary in order to calculate the result. - * All those data items will be casted to the underlying datatype of the bytecode. - * - * @author (C) 2004-2013 Ingo Berg - */ -class QmuParserByteCode -{ -private: - /** @brief Token type for internal use only. */ - typedef QmuParserToken token_type; - - /** @brief Token vector for storing the RPN. */ - typedef QVector rpn_type; - - /** @brief Position in the Calculation array. */ - unsigned m_iStackPos; - - /** @brief Maximum size needed for the stack. */ - std::size_t m_iMaxStackSize; - - /** @brief The actual rpn storage. */ - rpn_type m_vRPN; - - bool m_bEnableOptimizer; - - void ConstantFolding(ECmdCode a_Oprt); -public: - QmuParserByteCode(); - QmuParserByteCode(const QmuParserByteCode &a_ByteCode); - QmuParserByteCode& operator=(const QmuParserByteCode &a_ByteCode); - void Assign(const QmuParserByteCode &a_ByteCode); - void AddVar(qreal *a_pVar); - void AddVal(qreal a_fVal); - void AddOp(ECmdCode a_Oprt); - void AddIfElse(ECmdCode a_Oprt); - void AddAssignOp(qreal *a_pVar); - void AddFun(generic_fun_type a_pFun, int a_iArgc); - void AddBulkFun(generic_fun_type a_pFun, int a_iArgc); - void AddStrFun(generic_fun_type a_pFun, int a_iArgc, int a_iIdx); - void EnableOptimizer(bool bStat); - void Finalize(); - void clear(); - std::size_t GetMaxStackSize() const; - std::size_t GetSize() const; - const SToken* GetBase() const; - void AsciiDump(); -}; -} // namespace qmu -#endif - - +/*************************************************************************************************** + ** + ** Original work Copyright (C) 2013 Ingo Berg + ** Modified work Copyright 2014 Roman Telezhynskyi + ** + ** Permission is hereby granted, free of charge, to any person obtaining a copy of this + ** software and associated documentation files (the "Software"), to deal in the Software + ** without restriction, including without limitation the rights to use, copy, modify, + ** merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + ** permit persons to whom the Software is furnished to do so, subject to the following conditions: + ** + ** The above copyright notice and this permission notice shall be included in all copies or + ** substantial portions of the Software. + ** + ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + ** NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + ** DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ** + ******************************************************************************************************/ + +#ifndef QMUPARSERBYTECODE_H +#define QMUPARSERBYTECODE_H + +#include "qmuparserdef.h" +#include "qmuparsererror.h" +#include "qmuparsertoken.h" + +/** + * @file + * @brief Definition of the parser bytecode class. + */ + +namespace qmu +{ +struct SToken +{ + ECmdCode Cmd; + int StackPos; + + union // + { + struct //SValData + { + qreal *ptr; + qreal data; + qreal data2; + } Val; + + struct //SFunData + { + // Note: generic_fun_type is merely a placeholder. The real type could be + // anything between gun_type1 and fun_type9. I can't use a void + // pointer due to constraints in the ANSI standard which allows + // data pointers and function pointers to differ in size. + generic_fun_type ptr; + int argc; + int idx; + } Fun; + + struct //SOprtData + { + qreal *ptr; + int offset; + } Oprt; + }; +}; + + +/** + * @brief Bytecode implementation of the Math Parser. + * + * The bytecode contains the formula converted to revers polish notation stored in a continious + * memory area. Associated with this data are operator codes, variable pointers, constant + * values and function pointers. Those are necessary in order to calculate the result. + * All those data items will be casted to the underlying datatype of the bytecode. + * + * @author (C) 2004-2013 Ingo Berg + */ +class QmuParserByteCode +{ +private: + /** @brief Token type for internal use only. */ + typedef QmuParserToken token_type; + + /** @brief Token vector for storing the RPN. */ + typedef QVector rpn_type; + + /** @brief Position in the Calculation array. */ + unsigned m_iStackPos; + + /** @brief Maximum size needed for the stack. */ + std::size_t m_iMaxStackSize; + + /** @brief The actual rpn storage. */ + rpn_type m_vRPN; + + bool m_bEnableOptimizer; + + void ConstantFolding(ECmdCode a_Oprt); +public: + QmuParserByteCode(); + QmuParserByteCode(const QmuParserByteCode &a_ByteCode); + QmuParserByteCode& operator=(const QmuParserByteCode &a_ByteCode); + void Assign(const QmuParserByteCode &a_ByteCode); + void AddVar(qreal *a_pVar); + void AddVal(qreal a_fVal); + void AddOp(ECmdCode a_Oprt); + void AddIfElse(ECmdCode a_Oprt); + void AddAssignOp(qreal *a_pVar); + void AddFun(generic_fun_type a_pFun, int a_iArgc); + void AddBulkFun(generic_fun_type a_pFun, int a_iArgc); + void AddStrFun(generic_fun_type a_pFun, int a_iArgc, int a_iIdx); + void EnableOptimizer(bool bStat); + void Finalize(); + void clear(); + std::size_t GetMaxStackSize() const; + std::size_t GetSize() const; + const SToken* GetBase() const; + void AsciiDump(); +}; +} // namespace qmu +#endif diff --git a/src/libs/qmuparser/qmuparsercallback.cpp b/src/libs/qmuparser/qmuparsercallback.cpp index cf6455863..139d91092 100644 --- a/src/libs/qmuparser/qmuparsercallback.cpp +++ b/src/libs/qmuparser/qmuparsercallback.cpp @@ -29,27 +29,27 @@ namespace qmu { -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- //Supressing specific warnings on gcc/g++ http://www.mr-edd.co.uk/blog/supressing_gcc_warnings #ifdef __GNUC__ __extension__ #endif QmuParserCallback::QmuParserCallback ( fun_type0 a_pFun, bool a_bAllowOpti ) - : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 0 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), - m_iCode ( cmFUNC ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) + : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 0 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), + m_iCode ( cmFUNC ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) {} -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- #ifdef __GNUC__ __extension__ #endif QmuParserCallback::QmuParserCallback ( fun_type1 a_pFun, bool a_bAllowOpti, int a_iPrec, ECmdCode a_iCode ) - : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 1 ), m_iPri ( a_iPrec ), m_eOprtAsct ( oaNONE ), - m_iCode ( a_iCode ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) + : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 1 ), m_iPri ( a_iPrec ), m_eOprtAsct ( oaNONE ), + m_iCode ( a_iCode ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) {} -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Constructor for constructing funcstion callbacks taking two arguments. * @throw nothrow @@ -58,11 +58,11 @@ QmuParserCallback::QmuParserCallback ( fun_type1 a_pFun, bool a_bAllowOpti, int __extension__ #endif QmuParserCallback::QmuParserCallback ( fun_type2 a_pFun, bool a_bAllowOpti ) - : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 2 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), - m_iCode ( cmFUNC ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) + : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 2 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), + m_iCode ( cmFUNC ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) {} -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Constructor for constructing binary operator callbacks. * @param a_pFun Pointer to a static function taking two arguments @@ -75,104 +75,104 @@ QmuParserCallback::QmuParserCallback ( fun_type2 a_pFun, bool a_bAllowOpti ) __extension__ #endif QmuParserCallback::QmuParserCallback ( fun_type2 a_pFun, bool a_bAllowOpti, int a_iPrec, - EOprtAssociativity a_eOprtAsct ) - : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 2 ), m_iPri ( a_iPrec ), m_eOprtAsct ( a_eOprtAsct ), - m_iCode ( cmOPRT_BIN ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) + EOprtAssociativity a_eOprtAsct ) + : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 2 ), m_iPri ( a_iPrec ), m_eOprtAsct ( a_eOprtAsct ), + m_iCode ( cmOPRT_BIN ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) {} -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- #ifdef __GNUC__ __extension__ #endif QmuParserCallback::QmuParserCallback ( fun_type3 a_pFun, bool a_bAllowOpti ) - : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 3 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), - m_iCode ( cmFUNC ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) + : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 3 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), + m_iCode ( cmFUNC ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) {} -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- #ifdef __GNUC__ __extension__ #endif QmuParserCallback::QmuParserCallback ( fun_type4 a_pFun, bool a_bAllowOpti ) - : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 4 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), - m_iCode ( cmFUNC ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) + : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 4 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), + m_iCode ( cmFUNC ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) {} -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- #ifdef __GNUC__ __extension__ #endif QmuParserCallback::QmuParserCallback ( fun_type5 a_pFun, bool a_bAllowOpti ) - : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 5 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), - m_iCode ( cmFUNC ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) + : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 5 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), + m_iCode ( cmFUNC ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) {} -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- #ifdef __GNUC__ __extension__ #endif QmuParserCallback::QmuParserCallback ( fun_type6 a_pFun, bool a_bAllowOpti ) - : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 6 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), - m_iCode ( cmFUNC ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) + : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 6 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), + m_iCode ( cmFUNC ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) {} -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- #ifdef __GNUC__ __extension__ #endif QmuParserCallback::QmuParserCallback ( fun_type7 a_pFun, bool a_bAllowOpti ) - : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 7 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), - m_iCode ( cmFUNC ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) + : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 7 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), + m_iCode ( cmFUNC ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) {} -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- #ifdef __GNUC__ __extension__ #endif QmuParserCallback::QmuParserCallback ( fun_type8 a_pFun, bool a_bAllowOpti ) - : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 8 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), - m_iCode ( cmFUNC ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) + : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 8 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), + m_iCode ( cmFUNC ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) {} -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- #ifdef __GNUC__ __extension__ #endif QmuParserCallback::QmuParserCallback ( fun_type9 a_pFun, bool a_bAllowOpti ) - : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 9 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), - m_iCode ( cmFUNC ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) + : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 9 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), + m_iCode ( cmFUNC ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) {} -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- #ifdef __GNUC__ __extension__ #endif QmuParserCallback::QmuParserCallback ( fun_type10 a_pFun, bool a_bAllowOpti ) - : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 10 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), - m_iCode ( cmFUNC ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) + : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 10 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), + m_iCode ( cmFUNC ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) {} -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- #ifdef __GNUC__ __extension__ #endif QmuParserCallback::QmuParserCallback ( bulkfun_type0 a_pFun, bool a_bAllowOpti ) - : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 0 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), - m_iCode ( cmFUNC_BULK ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) + : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 0 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), + m_iCode ( cmFUNC_BULK ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) {} -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- #ifdef __GNUC__ __extension__ #endif QmuParserCallback::QmuParserCallback ( bulkfun_type1 a_pFun, bool a_bAllowOpti ) - : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 1 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), - m_iCode ( cmFUNC_BULK ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) + : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 1 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), + m_iCode ( cmFUNC_BULK ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) {} -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Constructor for constructing funcstion callbacks taking two arguments. * @throw nothrow @@ -181,156 +181,156 @@ QmuParserCallback::QmuParserCallback ( bulkfun_type1 a_pFun, bool a_bAllowOpti ) __extension__ #endif QmuParserCallback::QmuParserCallback ( bulkfun_type2 a_pFun, bool a_bAllowOpti ) - : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 2 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), - m_iCode ( cmFUNC_BULK ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) + : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 2 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), + m_iCode ( cmFUNC_BULK ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) {} -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- #ifdef __GNUC__ __extension__ #endif QmuParserCallback::QmuParserCallback ( bulkfun_type3 a_pFun, bool a_bAllowOpti ) - : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 3 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), - m_iCode ( cmFUNC_BULK ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) + : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 3 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), + m_iCode ( cmFUNC_BULK ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) {} -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- #ifdef __GNUC__ __extension__ #endif QmuParserCallback::QmuParserCallback ( bulkfun_type4 a_pFun, bool a_bAllowOpti ) - : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 4 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), - m_iCode ( cmFUNC_BULK ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) + : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 4 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), + m_iCode ( cmFUNC_BULK ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) {} -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- #ifdef __GNUC__ __extension__ #endif QmuParserCallback::QmuParserCallback ( bulkfun_type5 a_pFun, bool a_bAllowOpti ) - : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 5 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), - m_iCode ( cmFUNC_BULK ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) + : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 5 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), + m_iCode ( cmFUNC_BULK ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) {} -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- #ifdef __GNUC__ __extension__ #endif QmuParserCallback::QmuParserCallback ( bulkfun_type6 a_pFun, bool a_bAllowOpti ) - : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 6 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), - m_iCode ( cmFUNC_BULK ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) + : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 6 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), + m_iCode ( cmFUNC_BULK ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) {} -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- #ifdef __GNUC__ __extension__ #endif QmuParserCallback::QmuParserCallback ( bulkfun_type7 a_pFun, bool a_bAllowOpti ) - : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 7 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), - m_iCode ( cmFUNC_BULK ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) + : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 7 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), + m_iCode ( cmFUNC_BULK ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) {} -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- #ifdef __GNUC__ __extension__ #endif QmuParserCallback::QmuParserCallback ( bulkfun_type8 a_pFun, bool a_bAllowOpti ) - : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 8 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), - m_iCode ( cmFUNC_BULK ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) + : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 8 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), + m_iCode ( cmFUNC_BULK ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) {} -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- #ifdef __GNUC__ __extension__ #endif QmuParserCallback::QmuParserCallback ( bulkfun_type9 a_pFun, bool a_bAllowOpti ) - : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 9 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), - m_iCode ( cmFUNC_BULK ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) + : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 9 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), + m_iCode ( cmFUNC_BULK ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) {} -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- #ifdef __GNUC__ __extension__ #endif QmuParserCallback::QmuParserCallback ( bulkfun_type10 a_pFun, bool a_bAllowOpti ) - : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 10 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), - m_iCode ( cmFUNC_BULK ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) + : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 10 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), + m_iCode ( cmFUNC_BULK ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) {} -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- #ifdef __GNUC__ __extension__ #endif QmuParserCallback::QmuParserCallback ( multfun_type a_pFun, bool a_bAllowOpti ) - : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( -1 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), - m_iCode ( cmFUNC ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) + : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( -1 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), + m_iCode ( cmFUNC ), m_iType ( tpDBL ), m_bAllowOpti ( a_bAllowOpti ) {} -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- #ifdef __GNUC__ __extension__ #endif QmuParserCallback::QmuParserCallback ( strfun_type1 a_pFun, bool a_bAllowOpti ) - : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 0 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), - m_iCode ( cmFUNC_STR ), m_iType ( tpSTR ), m_bAllowOpti ( a_bAllowOpti ) + : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 0 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), + m_iCode ( cmFUNC_STR ), m_iType ( tpSTR ), m_bAllowOpti ( a_bAllowOpti ) {} -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- #ifdef __GNUC__ __extension__ #endif QmuParserCallback::QmuParserCallback ( strfun_type2 a_pFun, bool a_bAllowOpti ) - : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 1 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), - m_iCode ( cmFUNC_STR ), m_iType ( tpSTR ), m_bAllowOpti ( a_bAllowOpti ) + : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 1 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), + m_iCode ( cmFUNC_STR ), m_iType ( tpSTR ), m_bAllowOpti ( a_bAllowOpti ) {} -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- #ifdef __GNUC__ __extension__ #endif QmuParserCallback::QmuParserCallback ( strfun_type3 a_pFun, bool a_bAllowOpti ) - : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 2 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), - m_iCode ( cmFUNC_STR ), m_iType ( tpSTR ), m_bAllowOpti ( a_bAllowOpti ) + : m_pFun ( reinterpret_cast ( a_pFun ) ), m_iArgc ( 2 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), + m_iCode ( cmFUNC_STR ), m_iType ( tpSTR ), m_bAllowOpti ( a_bAllowOpti ) {} -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Default constructor. * @throw nothrow */ QmuParserCallback::QmuParserCallback() - : m_pFun ( 0 ), m_iArgc ( 0 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), m_iCode ( cmUNKNOWN ), m_iType ( tpVOID ), - m_bAllowOpti ( 0 ) + : m_pFun ( 0 ), m_iArgc ( 0 ), m_iPri ( -1 ), m_eOprtAsct ( oaNONE ), m_iCode ( cmUNKNOWN ), m_iType ( tpVOID ), + m_bAllowOpti ( 0 ) {} -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Copy constructor. * @throw nothrow */ QmuParserCallback::QmuParserCallback ( const QmuParserCallback &ref ) - : m_pFun ( ref.m_pFun ), m_iArgc ( ref.m_iArgc ), m_iPri ( ref.m_iPri ), m_eOprtAsct ( ref.m_eOprtAsct ), - m_iCode ( ref.m_iCode ), m_iType ( ref.m_iType ), m_bAllowOpti ( ref.m_bAllowOpti ) + : m_pFun ( ref.m_pFun ), m_iArgc ( ref.m_iArgc ), m_iPri ( ref.m_iPri ), m_eOprtAsct ( ref.m_eOprtAsct ), + m_iCode ( ref.m_iCode ), m_iType ( ref.m_iType ), m_bAllowOpti ( ref.m_bAllowOpti ) { - m_pFun = ref.m_pFun; - m_iArgc = ref.m_iArgc; - m_bAllowOpti = ref.m_bAllowOpti; - m_iCode = ref.m_iCode; - m_iType = ref.m_iType; - m_iPri = ref.m_iPri; - m_eOprtAsct = ref.m_eOprtAsct; + m_pFun = ref.m_pFun; + m_iArgc = ref.m_iArgc; + m_bAllowOpti = ref.m_bAllowOpti; + m_iCode = ref.m_iCode; + m_iType = ref.m_iType; + m_iPri = ref.m_iPri; + m_eOprtAsct = ref.m_eOprtAsct; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Clone this instance and return a pointer to the new instance. */ QmuParserCallback* QmuParserCallback::Clone() const { - return new QmuParserCallback ( *this ); + return new QmuParserCallback ( *this ); } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Return tru if the function is conservative. * @@ -339,10 +339,10 @@ QmuParserCallback* QmuParserCallback::Clone() const */ bool QmuParserCallback::IsOptimizable() const { - return m_bAllowOpti; + return m_bAllowOpti; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Get the callback address for the parser function. * @@ -353,25 +353,25 @@ bool QmuParserCallback::IsOptimizable() const */ void* QmuParserCallback::GetAddr() const { - return m_pFun; + return m_pFun; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Return the callback code. */ ECmdCode QmuParserCallback::GetCode() const { - return m_iCode; + return m_iCode; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- ETypeCode QmuParserCallback::GetType() const { - return m_iType; + return m_iType; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Return the operator precedence. * @throw nothrown @@ -380,10 +380,10 @@ ETypeCode QmuParserCallback::GetType() const */ int QmuParserCallback::GetPri() const { - return m_iPri; + return m_iPri; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Return the operators associativity. * @throw nothrown @@ -392,15 +392,15 @@ int QmuParserCallback::GetPri() const */ EOprtAssociativity QmuParserCallback::GetAssociativity() const { - return m_eOprtAsct; + return m_eOprtAsct; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Returns the number of function Arguments. */ int QmuParserCallback::GetArgc() const { - return m_iArgc; + return m_iArgc; } } // namespace qmu diff --git a/src/libs/qmuparser/qmuparsercallback.h b/src/libs/qmuparser/qmuparsercallback.h index 2ebb4c5f3..2c876bf79 100644 --- a/src/libs/qmuparser/qmuparsercallback.h +++ b/src/libs/qmuparser/qmuparsercallback.h @@ -1,115 +1,114 @@ -/*************************************************************************************************** - ** - ** Original work Copyright (C) 2013 Ingo Berg - ** Modified work Copyright 2014 Roman Telezhynskyi - ** - ** Permission is hereby granted, free of charge, to any person obtaining a copy of this - ** software and associated documentation files (the "Software"), to deal in the Software - ** without restriction, including without limitation the rights to use, copy, modify, - ** merge, publish, distribute, sublicense, and/or sell copies of the Software, and to - ** permit persons to whom the Software is furnished to do so, subject to the following conditions: - ** - ** The above copyright notice and this permission notice shall be included in all copies or - ** substantial portions of the Software. - ** - ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT - ** NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - ** DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ** - ******************************************************************************************************/ - -#ifndef QMUPARSERCALLBACK_H -#define QMUPARSERCALLBACK_H - -#include "qmuparserdef.h" - -/** - * @file - * @brief Definition of the parser callback class. - */ - -namespace qmu -{ - -/** - * @brief Encapsulation of prototypes for a numerical parser function. - * - * Encapsulates the prototyp for numerical parser functions. The class stores the number of arguments for parser - * functions as well as additional flags indication the function is non optimizeable. The pointer to the callback - * function pointer is stored as void* and needs to be casted according to the argument count. Negative argument counts - * indicate a parser function with a variable number of arguments. - * - * @author (C) 2004-2011 Ingo Berg - */ -class QmuParserCallback -{ -public: - QmuParserCallback(fun_type0 a_pFun, bool a_bAllowOpti); - QmuParserCallback(fun_type1 a_pFun, bool a_bAllowOpti, int a_iPrec = -1, ECmdCode a_iCode=cmFUNC); - QmuParserCallback(fun_type2 a_pFun, bool a_bAllowOpti, int a_iPrec, EOprtAssociativity a_eAssociativity); - QmuParserCallback(fun_type2 a_pFun, bool a_bAllowOpti); - QmuParserCallback(fun_type3 a_pFun, bool a_bAllowOpti); - QmuParserCallback(fun_type4 a_pFun, bool a_bAllowOpti); - QmuParserCallback(fun_type5 a_pFun, bool a_bAllowOpti); - QmuParserCallback(fun_type6 a_pFun, bool a_bAllowOpti); - QmuParserCallback(fun_type7 a_pFun, bool a_bAllowOpti); - QmuParserCallback(fun_type8 a_pFun, bool a_bAllowOpti); - QmuParserCallback(fun_type9 a_pFun, bool a_bAllowOpti); - QmuParserCallback(fun_type10 a_pFun, bool a_bAllowOpti); - - QmuParserCallback(bulkfun_type0 a_pFun, bool a_bAllowOpti); - QmuParserCallback(bulkfun_type1 a_pFun, bool a_bAllowOpti); - QmuParserCallback(bulkfun_type2 a_pFun, bool a_bAllowOpti); - QmuParserCallback(bulkfun_type3 a_pFun, bool a_bAllowOpti); - QmuParserCallback(bulkfun_type4 a_pFun, bool a_bAllowOpti); - QmuParserCallback(bulkfun_type5 a_pFun, bool a_bAllowOpti); - QmuParserCallback(bulkfun_type6 a_pFun, bool a_bAllowOpti); - QmuParserCallback(bulkfun_type7 a_pFun, bool a_bAllowOpti); - QmuParserCallback(bulkfun_type8 a_pFun, bool a_bAllowOpti); - QmuParserCallback(bulkfun_type9 a_pFun, bool a_bAllowOpti); - QmuParserCallback(bulkfun_type10 a_pFun, bool a_bAllowOpti); - - QmuParserCallback(multfun_type a_pFun, bool a_bAllowOpti); - QmuParserCallback(strfun_type1 a_pFun, bool a_bAllowOpti); - QmuParserCallback(strfun_type2 a_pFun, bool a_bAllowOpti); - QmuParserCallback(strfun_type3 a_pFun, bool a_bAllowOpti); - QmuParserCallback(); - QmuParserCallback(const QmuParserCallback &a_Fun); - - QmuParserCallback* Clone() const; - bool IsOptimizable() const; - void* GetAddr() const; - ECmdCode GetCode() const; - ETypeCode GetType() const; - int GetPri() const; - EOprtAssociativity GetAssociativity() const; - int GetArgc() const; -private: - void *m_pFun; ///< Pointer to the callback function, casted to void - - /** - * @brief Number of numeric function arguments - * - * This number is negative for functions with variable number of arguments. in this cases - * they represent the actual number of arguments found. - */ - int m_iArgc; - int m_iPri; ///< Valid only for binary and infix operators; Operator precedence. - EOprtAssociativity m_eOprtAsct; ///< Operator associativity; Valid only for binary operators - ECmdCode m_iCode; - ETypeCode m_iType; - bool m_bAllowOpti; ///< Flag indication optimizeability -}; - -//---------------------------------------------------------------------------------------------------------------------- -/** - * @brief Container for Callback objects. - */ -typedef std::map funmap_type; - -} // namespace qmu - -#endif - +/*************************************************************************************************** + ** + ** Original work Copyright (C) 2013 Ingo Berg + ** Modified work Copyright 2014 Roman Telezhynskyi + ** + ** Permission is hereby granted, free of charge, to any person obtaining a copy of this + ** software and associated documentation files (the "Software"), to deal in the Software + ** without restriction, including without limitation the rights to use, copy, modify, + ** merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + ** permit persons to whom the Software is furnished to do so, subject to the following conditions: + ** + ** The above copyright notice and this permission notice shall be included in all copies or + ** substantial portions of the Software. + ** + ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + ** NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + ** DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ** + ******************************************************************************************************/ + +#ifndef QMUPARSERCALLBACK_H +#define QMUPARSERCALLBACK_H + +#include "qmuparserdef.h" + +/** + * @file + * @brief Definition of the parser callback class. + */ + +namespace qmu +{ + +/** + * @brief Encapsulation of prototypes for a numerical parser function. + * + * Encapsulates the prototyp for numerical parser functions. The class stores the number of arguments for parser + * functions as well as additional flags indication the function is non optimizeable. The pointer to the callback + * function pointer is stored as void* and needs to be casted according to the argument count. Negative argument counts + * indicate a parser function with a variable number of arguments. + * + * @author (C) 2004-2011 Ingo Berg + */ +class QmuParserCallback +{ +public: + QmuParserCallback(fun_type0 a_pFun, bool a_bAllowOpti); + QmuParserCallback(fun_type1 a_pFun, bool a_bAllowOpti, int a_iPrec = -1, ECmdCode a_iCode=cmFUNC); + QmuParserCallback(fun_type2 a_pFun, bool a_bAllowOpti, int a_iPrec, EOprtAssociativity a_eAssociativity); + QmuParserCallback(fun_type2 a_pFun, bool a_bAllowOpti); + QmuParserCallback(fun_type3 a_pFun, bool a_bAllowOpti); + QmuParserCallback(fun_type4 a_pFun, bool a_bAllowOpti); + QmuParserCallback(fun_type5 a_pFun, bool a_bAllowOpti); + QmuParserCallback(fun_type6 a_pFun, bool a_bAllowOpti); + QmuParserCallback(fun_type7 a_pFun, bool a_bAllowOpti); + QmuParserCallback(fun_type8 a_pFun, bool a_bAllowOpti); + QmuParserCallback(fun_type9 a_pFun, bool a_bAllowOpti); + QmuParserCallback(fun_type10 a_pFun, bool a_bAllowOpti); + + QmuParserCallback(bulkfun_type0 a_pFun, bool a_bAllowOpti); + QmuParserCallback(bulkfun_type1 a_pFun, bool a_bAllowOpti); + QmuParserCallback(bulkfun_type2 a_pFun, bool a_bAllowOpti); + QmuParserCallback(bulkfun_type3 a_pFun, bool a_bAllowOpti); + QmuParserCallback(bulkfun_type4 a_pFun, bool a_bAllowOpti); + QmuParserCallback(bulkfun_type5 a_pFun, bool a_bAllowOpti); + QmuParserCallback(bulkfun_type6 a_pFun, bool a_bAllowOpti); + QmuParserCallback(bulkfun_type7 a_pFun, bool a_bAllowOpti); + QmuParserCallback(bulkfun_type8 a_pFun, bool a_bAllowOpti); + QmuParserCallback(bulkfun_type9 a_pFun, bool a_bAllowOpti); + QmuParserCallback(bulkfun_type10 a_pFun, bool a_bAllowOpti); + + QmuParserCallback(multfun_type a_pFun, bool a_bAllowOpti); + QmuParserCallback(strfun_type1 a_pFun, bool a_bAllowOpti); + QmuParserCallback(strfun_type2 a_pFun, bool a_bAllowOpti); + QmuParserCallback(strfun_type3 a_pFun, bool a_bAllowOpti); + QmuParserCallback(); + QmuParserCallback(const QmuParserCallback &a_Fun); + + QmuParserCallback* Clone() const; + bool IsOptimizable() const; + void* GetAddr() const; + ECmdCode GetCode() const; + ETypeCode GetType() const; + int GetPri() const; + EOprtAssociativity GetAssociativity() const; + int GetArgc() const; +private: + void *m_pFun; ///< Pointer to the callback function, casted to void + + /** + * @brief Number of numeric function arguments + * + * This number is negative for functions with variable number of arguments. in this cases + * they represent the actual number of arguments found. + */ + int m_iArgc; + int m_iPri; ///< Valid only for binary and infix operators; Operator precedence. + EOprtAssociativity m_eOprtAsct; ///< Operator associativity; Valid only for binary operators + ECmdCode m_iCode; + ETypeCode m_iType; + bool m_bAllowOpti; ///< Flag indication optimizeability +}; + +//--------------------------------------------------------------------------------------------------------------------- +/** + * @brief Container for Callback objects. + */ +typedef std::map funmap_type; + +} // namespace qmu + +#endif diff --git a/src/libs/qmuparser/qmuparserdef.h b/src/libs/qmuparser/qmuparserdef.h index 4edd3f390..6f4b2aa0d 100644 --- a/src/libs/qmuparser/qmuparserdef.h +++ b/src/libs/qmuparser/qmuparserdef.h @@ -47,11 +47,11 @@ //#define QMUP_USE_OPENMP #if defined(_UNICODE) - /** @brief Definition of the basic parser string type. */ - #define QMUP_STRING_TYPE std::wstring + /** @brief Definition of the basic parser string type. */ + #define QMUP_STRING_TYPE std::wstring #else - /** @brief Definition of the basic parser string type. */ - #define QMUP_STRING_TYPE std::string + /** @brief Definition of the basic parser string type. */ + #define QMUP_STRING_TYPE std::string #endif namespace qmu @@ -272,4 +272,3 @@ typedef qreal* ( *facfun_type ) ( const QString &, void* ); } // end of namespace #endif - diff --git a/src/libs/qmuparser/qmuparsererror.cpp b/src/libs/qmuparser/qmuparsererror.cpp index 543d60d9f..ab5c237cb 100644 --- a/src/libs/qmuparser/qmuparsererror.cpp +++ b/src/libs/qmuparser/qmuparsererror.cpp @@ -28,116 +28,116 @@ namespace qmu { const QmuParserErrorMsg QmuParserErrorMsg::m_Instance; -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- const QmuParserErrorMsg& QmuParserErrorMsg::Instance() { - return m_Instance; + return m_Instance; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- QString QmuParserErrorMsg::operator[] ( unsigned a_iIdx ) const { - return ( a_iIdx < static_cast( m_vErrMsg.size() ) ) ? m_vErrMsg[a_iIdx] : QString(); + return ( a_iIdx < static_cast( m_vErrMsg.size() ) ) ? m_vErrMsg[a_iIdx] : QString(); } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- QmuParserErrorMsg::~QmuParserErrorMsg() {} -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- QmuParserErrorMsg::QmuParserErrorMsg() - : m_vErrMsg ( 0 ) + : m_vErrMsg ( 0 ) { - m_vErrMsg.resize ( ecCOUNT ); + m_vErrMsg.resize ( ecCOUNT ); - m_vErrMsg[ecUNASSIGNABLE_TOKEN] = "Unexpected token \"$TOK$\" found at position $POS$."; - m_vErrMsg[ecINTERNAL_ERROR] = "Internal error"; - m_vErrMsg[ecINVALID_NAME] = "Invalid function-, variable- or constant name: \"$TOK$\"."; - m_vErrMsg[ecINVALID_BINOP_IDENT] = "Invalid binary operator identifier: \"$TOK$\"."; - m_vErrMsg[ecINVALID_INFIX_IDENT] = "Invalid infix operator identifier: \"$TOK$\"."; - m_vErrMsg[ecINVALID_POSTFIX_IDENT] = "Invalid postfix operator identifier: \"$TOK$\"."; - m_vErrMsg[ecINVALID_FUN_PTR] = "Invalid pointer to callback function."; - m_vErrMsg[ecEMPTY_EXPRESSION] = "Expression is empty."; - m_vErrMsg[ecINVALID_VAR_PTR] = "Invalid pointer to variable."; - m_vErrMsg[ecUNEXPECTED_OPERATOR] = "Unexpected operator \"$TOK$\" found at position $POS$"; - m_vErrMsg[ecUNEXPECTED_EOF] = "Unexpected end of expression at position $POS$"; - m_vErrMsg[ecUNEXPECTED_ARG_SEP] = "Unexpected argument separator at position $POS$"; - m_vErrMsg[ecUNEXPECTED_PARENS] = "Unexpected parenthesis \"$TOK$\" at position $POS$"; - m_vErrMsg[ecUNEXPECTED_FUN] = "Unexpected function \"$TOK$\" at position $POS$"; - m_vErrMsg[ecUNEXPECTED_VAL] = "Unexpected value \"$TOK$\" found at position $POS$"; - m_vErrMsg[ecUNEXPECTED_VAR] = "Unexpected variable \"$TOK$\" found at position $POS$"; - m_vErrMsg[ecUNEXPECTED_ARG] = "Function arguments used without a function (position: $POS$)"; - m_vErrMsg[ecMISSING_PARENS] = "Missing parenthesis"; - m_vErrMsg[ecTOO_MANY_PARAMS] = "Too many parameters for function \"$TOK$\" at expression position $POS$"; - m_vErrMsg[ecTOO_FEW_PARAMS] = "Too few parameters for function \"$TOK$\" at expression position $POS$"; - m_vErrMsg[ecDIV_BY_ZERO] = "Divide by zero"; - m_vErrMsg[ecDOMAIN_ERROR] = "Domain error"; - m_vErrMsg[ecNAME_CONFLICT] = "Name conflict"; - m_vErrMsg[ecOPT_PRI] = "Invalid value for operator priority (must be greater or equal to zero)."; - m_vErrMsg[ecBUILTIN_OVERLOAD] = "user defined binary operator \"$TOK$\" conflicts with a built in operator."; - m_vErrMsg[ecUNEXPECTED_STR] = "Unexpected string token found at position $POS$."; - m_vErrMsg[ecUNTERMINATED_STRING] = "Unterminated string starting at position $POS$."; - m_vErrMsg[ecSTRING_EXPECTED] = "String function called with a non string type of argument."; - m_vErrMsg[ecVAL_EXPECTED] = "String value used where a numerical argument is expected."; - m_vErrMsg[ecOPRT_TYPE_CONFLICT] = "No suitable overload for operator \"$TOK$\" at position $POS$."; - m_vErrMsg[ecSTR_RESULT] = "Function result is a string."; - m_vErrMsg[ecGENERIC] = "Parser error."; - m_vErrMsg[ecLOCALE] = "Decimal separator is identic to function argument separator."; - m_vErrMsg[ecUNEXPECTED_CONDITIONAL] = "The \"$TOK$\" operator must be preceeded by a closing bracket."; - m_vErrMsg[ecMISSING_ELSE_CLAUSE] = "If-then-else operator is missing an else clause"; - m_vErrMsg[ecMISPLACED_COLON] = "Misplaced colon at position $POS$"; + m_vErrMsg[ecUNASSIGNABLE_TOKEN] = "Unexpected token \"$TOK$\" found at position $POS$."; + m_vErrMsg[ecINTERNAL_ERROR] = "Internal error"; + m_vErrMsg[ecINVALID_NAME] = "Invalid function-, variable- or constant name: \"$TOK$\"."; + m_vErrMsg[ecINVALID_BINOP_IDENT] = "Invalid binary operator identifier: \"$TOK$\"."; + m_vErrMsg[ecINVALID_INFIX_IDENT] = "Invalid infix operator identifier: \"$TOK$\"."; + m_vErrMsg[ecINVALID_POSTFIX_IDENT] = "Invalid postfix operator identifier: \"$TOK$\"."; + m_vErrMsg[ecINVALID_FUN_PTR] = "Invalid pointer to callback function."; + m_vErrMsg[ecEMPTY_EXPRESSION] = "Expression is empty."; + m_vErrMsg[ecINVALID_VAR_PTR] = "Invalid pointer to variable."; + m_vErrMsg[ecUNEXPECTED_OPERATOR] = "Unexpected operator \"$TOK$\" found at position $POS$"; + m_vErrMsg[ecUNEXPECTED_EOF] = "Unexpected end of expression at position $POS$"; + m_vErrMsg[ecUNEXPECTED_ARG_SEP] = "Unexpected argument separator at position $POS$"; + m_vErrMsg[ecUNEXPECTED_PARENS] = "Unexpected parenthesis \"$TOK$\" at position $POS$"; + m_vErrMsg[ecUNEXPECTED_FUN] = "Unexpected function \"$TOK$\" at position $POS$"; + m_vErrMsg[ecUNEXPECTED_VAL] = "Unexpected value \"$TOK$\" found at position $POS$"; + m_vErrMsg[ecUNEXPECTED_VAR] = "Unexpected variable \"$TOK$\" found at position $POS$"; + m_vErrMsg[ecUNEXPECTED_ARG] = "Function arguments used without a function (position: $POS$)"; + m_vErrMsg[ecMISSING_PARENS] = "Missing parenthesis"; + m_vErrMsg[ecTOO_MANY_PARAMS] = "Too many parameters for function \"$TOK$\" at expression position $POS$"; + m_vErrMsg[ecTOO_FEW_PARAMS] = "Too few parameters for function \"$TOK$\" at expression position $POS$"; + m_vErrMsg[ecDIV_BY_ZERO] = "Divide by zero"; + m_vErrMsg[ecDOMAIN_ERROR] = "Domain error"; + m_vErrMsg[ecNAME_CONFLICT] = "Name conflict"; + m_vErrMsg[ecOPT_PRI] = "Invalid value for operator priority (must be greater or equal to zero)."; + m_vErrMsg[ecBUILTIN_OVERLOAD] = "user defined binary operator \"$TOK$\" conflicts with a built in operator."; + m_vErrMsg[ecUNEXPECTED_STR] = "Unexpected string token found at position $POS$."; + m_vErrMsg[ecUNTERMINATED_STRING] = "Unterminated string starting at position $POS$."; + m_vErrMsg[ecSTRING_EXPECTED] = "String function called with a non string type of argument."; + m_vErrMsg[ecVAL_EXPECTED] = "String value used where a numerical argument is expected."; + m_vErrMsg[ecOPRT_TYPE_CONFLICT] = "No suitable overload for operator \"$TOK$\" at position $POS$."; + m_vErrMsg[ecSTR_RESULT] = "Function result is a string."; + m_vErrMsg[ecGENERIC] = "Parser error."; + m_vErrMsg[ecLOCALE] = "Decimal separator is identic to function argument separator."; + m_vErrMsg[ecUNEXPECTED_CONDITIONAL] = "The \"$TOK$\" operator must be preceeded by a closing bracket."; + m_vErrMsg[ecMISSING_ELSE_CLAUSE] = "If-then-else operator is missing an else clause"; + m_vErrMsg[ecMISPLACED_COLON] = "Misplaced colon at position $POS$"; #if defined(_DEBUG) - for ( int i = 0; i < ecCOUNT; ++i ) - { - if ( !m_vErrMsg[i].length() ) - { - assert ( false ); - } - } + for ( int i = 0; i < ecCOUNT; ++i ) + { + if ( m_vErrMsg[i].length() == false) + { + assert ( false ); + } + } #endif } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- // // QParserError class // -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Default constructor. */ QmuParserError::QmuParserError() - : m_strMsg(), m_strFormula(), m_strTok(), m_iPos ( -1 ), m_iErrc ( ecUNDEFINED ), - m_ErrMsg ( QmuParserErrorMsg::Instance() ) + : m_strMsg(), m_strFormula(), m_strTok(), m_iPos ( -1 ), m_iErrc ( ecUNDEFINED ), + m_ErrMsg ( QmuParserErrorMsg::Instance() ) { } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief This Constructor is used for internal exceptions only. * * It does not contain any information but the error code. */ QmuParserError::QmuParserError ( EErrorCodes a_iErrc ) - : m_strMsg(), m_strFormula(), m_strTok(), m_iPos ( -1 ), m_iErrc ( a_iErrc ), - m_ErrMsg ( QmuParserErrorMsg::Instance() ) + : m_strMsg(), m_strFormula(), m_strTok(), m_iPos ( -1 ), m_iErrc ( a_iErrc ), + m_ErrMsg ( QmuParserErrorMsg::Instance() ) { - m_strMsg = m_ErrMsg[m_iErrc]; - ReplaceSubString ( m_strMsg, "$POS$", QString().setNum ( m_iPos ) ); - ReplaceSubString ( m_strMsg, "$TOK$", m_strTok ); + m_strMsg = m_ErrMsg[m_iErrc]; + ReplaceSubString ( m_strMsg, "$POS$", QString().setNum ( m_iPos ) ); + ReplaceSubString ( m_strMsg, "$TOK$", m_strTok ); } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Construct an error from a message text. */ QmuParserError::QmuParserError ( const QString &sMsg ) - : m_strMsg(sMsg), m_strFormula(), m_strTok(), m_iPos ( -1 ), m_iErrc ( ecUNDEFINED ), - m_ErrMsg ( QmuParserErrorMsg::Instance() ) + : m_strMsg(sMsg), m_strFormula(), m_strTok(), m_iPos ( -1 ), m_iErrc ( ecUNDEFINED ), + m_ErrMsg ( QmuParserErrorMsg::Instance() ) {} -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Construct an error object. * @param [in] a_iErrc the error code. @@ -149,15 +149,15 @@ QmuParserError::QmuParserError ( EErrorCodes iErrc, const QString &sTok, const QString &sExpr, int iPos ) - : m_strMsg(), m_strFormula ( sExpr ), m_strTok ( sTok ), m_iPos ( iPos ), m_iErrc ( iErrc ), - m_ErrMsg ( QmuParserErrorMsg::Instance() ) + : m_strMsg(), m_strFormula ( sExpr ), m_strTok ( sTok ), m_iPos ( iPos ), m_iErrc ( iErrc ), + m_ErrMsg ( QmuParserErrorMsg::Instance() ) { - m_strMsg = m_ErrMsg[m_iErrc]; - ReplaceSubString ( m_strMsg, "$POS$", QString().setNum ( m_iPos ) ); - ReplaceSubString ( m_strMsg, "$TOK$", m_strTok ); + m_strMsg = m_ErrMsg[m_iErrc]; + ReplaceSubString ( m_strMsg, "$POS$", QString().setNum ( m_iPos ) ); + ReplaceSubString ( m_strMsg, "$TOK$", m_strTok ); } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Construct an error object. * @param [in] iErrc the error code. @@ -165,58 +165,58 @@ QmuParserError::QmuParserError ( EErrorCodes iErrc, * @param [in] sTok The token string related to this error. */ QmuParserError::QmuParserError ( EErrorCodes iErrc, int iPos, const QString &sTok ) - : m_strMsg(), m_strFormula(), m_strTok ( sTok ), m_iPos ( iPos ), m_iErrc ( iErrc ), - m_ErrMsg ( QmuParserErrorMsg::Instance() ) + : m_strMsg(), m_strFormula(), m_strTok ( sTok ), m_iPos ( iPos ), m_iErrc ( iErrc ), + m_ErrMsg ( QmuParserErrorMsg::Instance() ) { - m_strMsg = m_ErrMsg[m_iErrc]; - ReplaceSubString ( m_strMsg, "$POS$", QString().setNum ( m_iPos ) ); - ReplaceSubString ( m_strMsg, "$TOK$", m_strTok ); + m_strMsg = m_ErrMsg[m_iErrc]; + ReplaceSubString ( m_strMsg, "$POS$", QString().setNum ( m_iPos ) ); + ReplaceSubString ( m_strMsg, "$TOK$", m_strTok ); } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** @brief Construct an error object. * @param [in] szMsg The error message text. * @param [in] iPos the position related to the error. * @param [in] sTok The token string related to this error. */ QmuParserError::QmuParserError ( const QString &szMsg, int iPos, const QString &sTok ) - : m_strMsg ( szMsg ), m_strFormula(), m_strTok ( sTok ), m_iPos ( iPos ), m_iErrc ( ecGENERIC ), - m_ErrMsg ( QmuParserErrorMsg::Instance() ) + : m_strMsg ( szMsg ), m_strFormula(), m_strTok ( sTok ), m_iPos ( iPos ), m_iErrc ( ecGENERIC ), + m_ErrMsg ( QmuParserErrorMsg::Instance() ) { - ReplaceSubString ( m_strMsg, "$POS$", QString().setNum ( m_iPos ) ); - ReplaceSubString ( m_strMsg, "$TOK$", m_strTok ); + ReplaceSubString ( m_strMsg, "$POS$", QString().setNum ( m_iPos ) ); + ReplaceSubString ( m_strMsg, "$TOK$", m_strTok ); } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** @brief Copy constructor. */ QmuParserError::QmuParserError ( const QmuParserError &a_Obj ) - : m_strMsg ( a_Obj.m_strMsg ), m_strFormula ( a_Obj.m_strFormula ), m_strTok ( a_Obj.m_strTok ), - m_iPos ( a_Obj.m_iPos ), m_iErrc ( a_Obj.m_iErrc ), m_ErrMsg ( QmuParserErrorMsg::Instance() ) + : m_strMsg ( a_Obj.m_strMsg ), m_strFormula ( a_Obj.m_strFormula ), m_strTok ( a_Obj.m_strTok ), + m_iPos ( a_Obj.m_iPos ), m_iErrc ( a_Obj.m_iErrc ), m_ErrMsg ( QmuParserErrorMsg::Instance() ) { } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** @brief Assignment operator. */ QmuParserError& QmuParserError::operator= ( const QmuParserError &a_Obj ) { - if ( this == &a_Obj ) - { - return *this; - } + if ( this == &a_Obj ) + { + return *this; + } - m_strMsg = a_Obj.m_strMsg; - m_strFormula = a_Obj.m_strFormula; - m_strTok = a_Obj.m_strTok; - m_iPos = a_Obj.m_iPos; - m_iErrc = a_Obj.m_iErrc; - return *this; + m_strMsg = a_Obj.m_strMsg; + m_strFormula = a_Obj.m_strFormula; + m_strTok = a_Obj.m_strTok; + m_iPos = a_Obj.m_iPos; + m_iErrc = a_Obj.m_iErrc; + return *this; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- QmuParserError::~QmuParserError() {} -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Replace all ocuurences of a substring with another string. * @param strFind The string that shall be replaced. @@ -224,65 +224,67 @@ QmuParserError::~QmuParserError() */ void QmuParserError::ReplaceSubString ( QString &strSource, const QString &strFind, const QString &strReplaceWith ) { - QString strResult; - int iPos ( 0 ), iNext ( 0 ); + QString strResult; + int iPos ( 0 ), iNext ( 0 ); - for ( ;; ) - { - iNext = strSource.indexOf ( strFind, iPos ); - strResult.append ( strSource.mid ( iPos, iNext - iPos ) ); + for ( ;; ) + { + iNext = strSource.indexOf ( strFind, iPos ); + strResult.append ( strSource.mid ( iPos, iNext - iPos ) ); - if ( iNext == -1 ) - break; + if ( iNext == -1 ) + { + break; + } - strResult.append ( strReplaceWith ); - iPos = iNext + strFind.length(); - } + strResult.append ( strReplaceWith ); + iPos = iNext + strFind.length(); + } - strSource.swap ( strResult ); + strSource.swap ( strResult ); } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Reset the erro object. */ void QmuParserError::Reset() { - m_strMsg.clear(); - m_strFormula.clear(); - m_strTok.clear(); - m_iPos = -1; - m_iErrc = ecUNDEFINED; + m_strMsg.clear(); + m_strFormula.clear(); + m_strTok.clear(); + m_iPos = -1; + m_iErrc = ecUNDEFINED; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Set the expression related to this error. */ void QmuParserError::SetFormula ( const QString &a_strFormula ) { - m_strFormula = a_strFormula; + m_strFormula = a_strFormula; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief gets the expression related tp this error. */ const QString& QmuParserError::GetExpr() const { - return m_strFormula; + return m_strFormula; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Returns the message string for this error. */ const QString& QmuParserError::GetMsg() const { - return m_strMsg; + return m_strMsg; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Return the formula position related to the error. * @@ -290,24 +292,24 @@ const QString& QmuParserError::GetMsg() const */ std::size_t QmuParserError::GetPos() const { - return m_iPos; + return m_iPos; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Return string related with this token (if available). */ const QString& QmuParserError::GetToken() const { - return m_strTok; + return m_strTok; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Return the error code. */ EErrorCodes QmuParserError::GetCode() const { - return m_iErrc; + return m_iErrc; } } // namespace qmu diff --git a/src/libs/qmuparser/qmuparsererror.h b/src/libs/qmuparser/qmuparsererror.h index 0ed154df6..645fba258 100644 --- a/src/libs/qmuparser/qmuparsererror.h +++ b/src/libs/qmuparser/qmuparsererror.h @@ -97,18 +97,18 @@ enum EErrorCodes class QmuParserErrorMsg { public: - typedef QmuParserErrorMsg self_type; + typedef QmuParserErrorMsg self_type; - QmuParserErrorMsg(); - ~QmuParserErrorMsg(); + QmuParserErrorMsg(); + ~QmuParserErrorMsg(); - static const QmuParserErrorMsg& Instance(); - QString operator[] ( unsigned a_iIdx ) const; + static const QmuParserErrorMsg& Instance(); + QString operator[] ( unsigned a_iIdx ) const; private: - Q_DISABLE_COPY(QmuParserErrorMsg) - QVector m_vErrMsg; ///< A vector with the predefined error messages - static const self_type m_Instance; ///< The instance pointer + Q_DISABLE_COPY(QmuParserErrorMsg) + QVector m_vErrMsg; ///< A vector with the predefined error messages + static const self_type m_Instance; ///< The instance pointer }; //--------------------------------------------------------------------------- @@ -121,38 +121,37 @@ class QmuParserError { public: - QmuParserError(); - explicit QmuParserError ( EErrorCodes a_iErrc ); - explicit QmuParserError ( const QString &sMsg ); - QmuParserError ( EErrorCodes a_iErrc, const QString &sTok, const QString &sFormula = QString(), int a_iPos = -1 ); - QmuParserError ( EErrorCodes a_iErrc, int a_iPos, const QString &sTok ); - QmuParserError ( const QString &a_szMsg, int a_iPos, const QString &sTok = QString() ); - QmuParserError ( const QmuParserError &a_Obj ); - QmuParserError& operator= ( const QmuParserError &a_Obj ); - ~QmuParserError(); + QmuParserError(); + explicit QmuParserError ( EErrorCodes a_iErrc ); + explicit QmuParserError ( const QString &sMsg ); + QmuParserError ( EErrorCodes a_iErrc, const QString &sTok, const QString &sFormula = QString(), int a_iPos = -1 ); + QmuParserError ( EErrorCodes a_iErrc, int a_iPos, const QString &sTok ); + QmuParserError ( const QString &a_szMsg, int a_iPos, const QString &sTok = QString() ); + QmuParserError ( const QmuParserError &a_Obj ); + QmuParserError& operator= ( const QmuParserError &a_Obj ); + ~QmuParserError(); - void SetFormula ( const QString &a_strFormula ); - const QString& GetExpr() const; - const QString& GetMsg() const; - std::size_t GetPos() const; - const QString& GetToken() const; - EErrorCodes GetCode() const; + void SetFormula ( const QString &a_strFormula ); + const QString& GetExpr() const; + const QString& GetMsg() const; + std::size_t GetPos() const; + const QString& GetToken() const; + EErrorCodes GetCode() const; private: - QString m_strMsg; ///< The message string - QString m_strFormula; ///< Formula string - QString m_strTok; ///< Token related with the error - int m_iPos; ///< Formula position related to the error - EErrorCodes m_iErrc; ///< Error code - const QmuParserErrorMsg &m_ErrMsg; - /** - * @brief Replace all ocuurences of a substring with another string. - */ - void ReplaceSubString ( QString &strSource, const QString &strFind, const QString &strReplaceWith ); - void Reset(); + QString m_strMsg; ///< The message string + QString m_strFormula; ///< Formula string + QString m_strTok; ///< Token related with the error + int m_iPos; ///< Formula position related to the error + EErrorCodes m_iErrc; ///< Error code + const QmuParserErrorMsg &m_ErrMsg; + /** + * @brief Replace all ocuurences of a substring with another string. + */ + void ReplaceSubString ( QString &strSource, const QString &strFind, const QString &strReplaceWith ); + void Reset(); }; } // namespace qmu #endif - diff --git a/src/libs/qmuparser/qmuparserfixes.h b/src/libs/qmuparser/qmuparserfixes.h index be7056930..85b4298cd 100644 --- a/src/libs/qmuparser/qmuparserfixes.h +++ b/src/libs/qmuparser/qmuparserfixes.h @@ -1,59 +1,57 @@ -/*************************************************************************************************** - ** - ** Original work Copyright (C) 2013 Ingo Berg - ** Modified work Copyright 2014 Roman Telezhynskyi - ** - ** Permission is hereby granted, free of charge, to any person obtaining a copy of this - ** software and associated documentation files (the "Software"), to deal in the Software - ** without restriction, including without limitation the rights to use, copy, modify, - ** merge, publish, distribute, sublicense, and/or sell copies of the Software, and to - ** permit persons to whom the Software is furnished to do so, subject to the following conditions: - ** - ** The above copyright notice and this permission notice shall be included in all copies or - ** substantial portions of the Software. - ** - ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT - ** NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - ** DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ** - ******************************************************************************************************/ - -#ifndef QMUPARSERFIXES_H -#define QMUPARSERFIXES_H - -/** @file - @brief This file contains compatibility fixes for some platforms. -*/ - -// -// Compatibility fixes -// - -//--------------------------------------------------------------------------- -// -// Intel Compiler -// -//--------------------------------------------------------------------------- - -#ifdef __INTEL_COMPILER - -// remark #981: operands are evaluated in unspecified order -// disabled -> completely pointless if the functions do not have side effects -// -#pragma warning(disable:981) - -// remark #383: value copied to temporary, reference to temporary used -#pragma warning(disable:383) - -// remark #1572: floating-point equality and inequality comparisons are unreliable -// disabled -> everyone knows it, the parser passes this problem -// deliberately to the user -#pragma warning(disable:1572) - -#endif - -#endif // include guard - - +/*************************************************************************************************** + ** + ** Original work Copyright (C) 2013 Ingo Berg + ** Modified work Copyright 2014 Roman Telezhynskyi + ** + ** Permission is hereby granted, free of charge, to any person obtaining a copy of this + ** software and associated documentation files (the "Software"), to deal in the Software + ** without restriction, including without limitation the rights to use, copy, modify, + ** merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + ** permit persons to whom the Software is furnished to do so, subject to the following conditions: + ** + ** The above copyright notice and this permission notice shall be included in all copies or + ** substantial portions of the Software. + ** + ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + ** NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + ** DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ** + ******************************************************************************************************/ + +#ifndef QMUPARSERFIXES_H +#define QMUPARSERFIXES_H + +/** @file + @brief This file contains compatibility fixes for some platforms. +*/ + +// +// Compatibility fixes +// + +//--------------------------------------------------------------------------- +// +// Intel Compiler +// +//--------------------------------------------------------------------------- + +#ifdef __INTEL_COMPILER + +// remark #981: operands are evaluated in unspecified order +// disabled -> completely pointless if the functions do not have side effects +// +#pragma warning(disable:981) + +// remark #383: value copied to temporary, reference to temporary used +#pragma warning(disable:383) + +// remark #1572: floating-point equality and inequality comparisons are unreliable +// disabled -> everyone knows it, the parser passes this problem +// deliberately to the user +#pragma warning(disable:1572) + +#endif + +#endif // include guard diff --git a/src/libs/qmuparser/qmuparsertest.cpp b/src/libs/qmuparser/qmuparsertest.cpp index fa6fcb4b1..95305cdc5 100644 --- a/src/libs/qmuparser/qmuparsertest.cpp +++ b/src/libs/qmuparser/qmuparsertest.cpp @@ -41,1179 +41,1177 @@ namespace Test { int QmuParserTester::c_iCount = 0; -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- QmuParserTester::QmuParserTester() - : m_vTestFun() + : m_vTestFun() { - AddTest ( &QmuParserTester::TestNames ); - AddTest ( &QmuParserTester::TestSyntax ); - AddTest ( &QmuParserTester::TestPostFix ); - AddTest ( &QmuParserTester::TestInfixOprt ); - AddTest ( &QmuParserTester::TestVarConst ); - AddTest ( &QmuParserTester::TestMultiArg ); - AddTest ( &QmuParserTester::TestExpression ); - AddTest ( &QmuParserTester::TestIfThenElse ); - AddTest ( &QmuParserTester::TestInterface ); - AddTest ( &QmuParserTester::TestBinOprt ); - AddTest ( &QmuParserTester::TestException ); - AddTest ( &QmuParserTester::TestStrArg ); + AddTest ( &QmuParserTester::TestNames ); + AddTest ( &QmuParserTester::TestSyntax ); + AddTest ( &QmuParserTester::TestPostFix ); + AddTest ( &QmuParserTester::TestInfixOprt ); + AddTest ( &QmuParserTester::TestVarConst ); + AddTest ( &QmuParserTester::TestMultiArg ); + AddTest ( &QmuParserTester::TestExpression ); + AddTest ( &QmuParserTester::TestIfThenElse ); + AddTest ( &QmuParserTester::TestInterface ); + AddTest ( &QmuParserTester::TestBinOprt ); + AddTest ( &QmuParserTester::TestException ); + AddTest ( &QmuParserTester::TestStrArg ); - QmuParserTester::c_iCount = 0; + QmuParserTester::c_iCount = 0; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- int QmuParserTester::IsHexVal ( const QString &a_szExpr, int *a_iPos, qreal *a_fVal ) { - if ( a_szExpr[1] == 0 || ( a_szExpr[0] != '0' || a_szExpr[1] != 'x' ) ) - { - return 0; - } + if ( a_szExpr[1] == 0 || ( a_szExpr[0] != '0' || a_szExpr[1] != 'x' ) ) + { + return 0; + } - unsigned iVal ( 0 ); - bool ok = false; - iVal = a_szExpr.toUInt ( &ok, 16 ); + unsigned iVal ( 0 ); + bool ok = false; + iVal = a_szExpr.toUInt ( &ok, 16 ); - if ( ok ) - { - int nPos = a_szExpr.indexOf ( QString().setNum ( iVal, 16 ) ); - if ( nPos == 0 ) - { - return 1; - } + if ( ok ) + { + int nPos = a_szExpr.indexOf ( QString().setNum ( iVal, 16 ) ); + if ( nPos == 0 ) + { + return 1; + } - *a_iPos += 2 + nPos; - *a_fVal = static_cast(iVal); - return 1; - } - else - { - return 0; - } + *a_iPos += 2 + nPos; + *a_fVal = static_cast(iVal); + return 1; + } + else + { + return 0; + } } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- int QmuParserTester::TestInterface() { - int iStat = 0; - qDebug() << "testing member functions..."; + int iStat = 0; + qDebug() << "testing member functions..."; - // Test RemoveVar - qreal afVal[3] = {1, 2, 3}; - QmuParser p; + // Test RemoveVar + qreal afVal[3] = {1, 2, 3}; + QmuParser p; - try - { - p.DefineVar ( "a", &afVal[0] ); - p.DefineVar ( "b", &afVal[1] ); - p.DefineVar ( "c", &afVal[2] ); - p.SetExpr ( "a+b+c" ); - p.Eval(); - } - catch ( ... ) - { - iStat += 1; // this is not supposed to happen - } + try + { + p.DefineVar ( "a", &afVal[0] ); + p.DefineVar ( "b", &afVal[1] ); + p.DefineVar ( "c", &afVal[2] ); + p.SetExpr ( "a+b+c" ); + p.Eval(); + } + catch ( ... ) + { + iStat += 1; // this is not supposed to happen + } - try - { - p.RemoveVar ( "c" ); - p.Eval(); - iStat += 1; // not supposed to reach this, nonexisting variable "c" deleted... - } - catch ( ... ) - { - // failure is expected... - } + try + { + p.RemoveVar ( "c" ); + p.Eval(); + iStat += 1; // not supposed to reach this, nonexisting variable "c" deleted... + } + catch ( ... ) + { + // failure is expected... + } - if ( iStat == 0 ) - { - qDebug() << "passed"; - } - else - { - qDebug() << "\n failed with " << iStat << " errors"; - } + if ( iStat == 0 ) + { + qDebug() << "passed"; + } + else + { + qDebug() << "\n failed with " << iStat << " errors"; + } - return iStat; + return iStat; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- int QmuParserTester::TestStrArg() { - int iStat = 0; - qDebug() << "testing string arguments..."; + int iStat = 0; + qDebug() << "testing string arguments..."; - iStat += EqnTest ( "valueof(\"\")", 123, true ); // empty string arguments caused a crash - iStat += EqnTest ( "valueof(\"aaa\")+valueof(\"bbb\") ", 246, true ); - iStat += EqnTest ( "2*(valueof(\"aaa\")-23)+valueof(\"bbb\")", 323, true ); - // use in expressions with variables - iStat += EqnTest ( "a*(atof(\"10\")-b)", 8, true ); - iStat += EqnTest ( "a-(atof(\"10\")*b)", -19, true ); - // string + numeric arguments - iStat += EqnTest ( "strfun1(\"100\")", 100, true ); - iStat += EqnTest ( "strfun2(\"100\",1)", 101, true ); - iStat += EqnTest ( "strfun3(\"99\",1,2)", 102, true ); + iStat += EqnTest ( "valueof(\"\")", 123, true ); // empty string arguments caused a crash + iStat += EqnTest ( "valueof(\"aaa\")+valueof(\"bbb\") ", 246, true ); + iStat += EqnTest ( "2*(valueof(\"aaa\")-23)+valueof(\"bbb\")", 323, true ); + // use in expressions with variables + iStat += EqnTest ( "a*(atof(\"10\")-b)", 8, true ); + iStat += EqnTest ( "a-(atof(\"10\")*b)", -19, true ); + // string + numeric arguments + iStat += EqnTest ( "strfun1(\"100\")", 100, true ); + iStat += EqnTest ( "strfun2(\"100\",1)", 101, true ); + iStat += EqnTest ( "strfun3(\"99\",1,2)", 102, true ); - if ( iStat == 0 ) - { - qDebug() << "passed"; - } - else - { - qDebug() << "\n failed with " << iStat << " errors"; - } + if ( iStat == 0 ) + { + qDebug() << "passed"; + } + else + { + qDebug() << "\n failed with " << iStat << " errors"; + } - return iStat; + return iStat; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- int QmuParserTester::TestBinOprt() { - int iStat = 0; - qDebug() << "testing binary operators..."; + int iStat = 0; + qDebug() << "testing binary operators..."; - // built in operators - // xor operator - //iStat += EqnTest("1 xor 2", 3, true); - //iStat += EqnTest("a xor b", 3, true); // with a=1 and b=2 - //iStat += EqnTest("1 xor 2 xor 3", 0, true); - //iStat += EqnTest("a xor b xor 3", 0, true); // with a=1 and b=2 - //iStat += EqnTest("a xor b xor c", 0, true); // with a=1 and b=2 - //iStat += EqnTest("(1 xor 2) xor 3", 0, true); - //iStat += EqnTest("(a xor b) xor c", 0, true); // with a=1 and b=2 - //iStat += EqnTest("(a) xor (b) xor c", 0, true); // with a=1 and b=2 - //iStat += EqnTest("1 or 2"), 3, true; - //iStat += EqnTest("a or b"), 3, true; // with a=1 and b=2 - iStat += EqnTest ( "a++b", 3, true ); - iStat += EqnTest ( "a ++ b", 3, true ); - iStat += EqnTest ( "1++2", 3, true ); - iStat += EqnTest ( "1 ++ 2", 3, true ); - iStat += EqnTest ( "a add b", 3, true ); - iStat += EqnTest ( "1 add 2", 3, true ); - iStat += EqnTest ( "aa", 1, true ); - iStat += EqnTest ( "a>a", 0, true ); - iStat += EqnTest ( "aa", 0, true ); - iStat += EqnTest ( "a<=a", 1, true ); - iStat += EqnTest ( "a<=b", 1, true ); - iStat += EqnTest ( "b<=a", 0, true ); - iStat += EqnTest ( "a>=a", 1, true ); - iStat += EqnTest ( "b>=a", 1, true ); - iStat += EqnTest ( "a>=b", 0, true ); + // built in operators + // xor operator + //iStat += EqnTest("1 xor 2", 3, true); + //iStat += EqnTest("a xor b", 3, true); // with a=1 and b=2 + //iStat += EqnTest("1 xor 2 xor 3", 0, true); + //iStat += EqnTest("a xor b xor 3", 0, true); // with a=1 and b=2 + //iStat += EqnTest("a xor b xor c", 0, true); // with a=1 and b=2 + //iStat += EqnTest("(1 xor 2) xor 3", 0, true); + //iStat += EqnTest("(a xor b) xor c", 0, true); // with a=1 and b=2 + //iStat += EqnTest("(a) xor (b) xor c", 0, true); // with a=1 and b=2 + //iStat += EqnTest("1 or 2"), 3, true; + //iStat += EqnTest("a or b"), 3, true; // with a=1 and b=2 + iStat += EqnTest ( "a++b", 3, true ); + iStat += EqnTest ( "a ++ b", 3, true ); + iStat += EqnTest ( "1++2", 3, true ); + iStat += EqnTest ( "1 ++ 2", 3, true ); + iStat += EqnTest ( "a add b", 3, true ); + iStat += EqnTest ( "1 add 2", 3, true ); + iStat += EqnTest ( "aa", 1, true ); + iStat += EqnTest ( "a>a", 0, true ); + iStat += EqnTest ( "aa", 0, true ); + iStat += EqnTest ( "a<=a", 1, true ); + iStat += EqnTest ( "a<=b", 1, true ); + iStat += EqnTest ( "b<=a", 0, true ); + iStat += EqnTest ( "a>=a", 1, true ); + iStat += EqnTest ( "b>=a", 1, true ); + iStat += EqnTest ( "a>=b", 0, true ); - // Test logical operators, expecially if user defined "&" and the internal "&&" collide - iStat += EqnTest ( "1 && 1", 1, true ); - iStat += EqnTest ( "1 && 0", 0, true ); - iStat += EqnTest ( "(aa)", 1, true ); - iStat += EqnTest ( "(ab)", 0, true ); - //iStat += EqnTest("12 and 255", 12, true); - //iStat += EqnTest("12 and 0", 0, true); - iStat += EqnTest ( "12 & 255", 12, true ); - iStat += EqnTest ( "12 & 0", 0, true ); - iStat += EqnTest ( "12&255", 12, true ); - iStat += EqnTest ( "12&0", 0, true ); + // Test logical operators, expecially if user defined "&" and the internal "&&" collide + iStat += EqnTest ( "1 && 1", 1, true ); + iStat += EqnTest ( "1 && 0", 0, true ); + iStat += EqnTest ( "(aa)", 1, true ); + iStat += EqnTest ( "(ab)", 0, true ); + //iStat += EqnTest("12 and 255", 12, true); + //iStat += EqnTest("12 and 0", 0, true); + iStat += EqnTest ( "12 & 255", 12, true ); + iStat += EqnTest ( "12 & 0", 0, true ); + iStat += EqnTest ( "12&255", 12, true ); + iStat += EqnTest ( "12&0", 0, true ); - // Assignement operator - iStat += EqnTest ( "a = b", 2, true ); - iStat += EqnTest ( "a = sin(b)", 0.909297, true ); - iStat += EqnTest ( "a = 1+sin(b)", 1.909297, true ); - iStat += EqnTest ( "(a=b)*2", 4, true ); - iStat += EqnTest ( "2*(a=b)", 4, true ); - iStat += EqnTest ( "2*(a=b+1)", 6, true ); - iStat += EqnTest ( "(a=b+1)*2", 6, true ); + // Assignement operator + iStat += EqnTest ( "a = b", 2, true ); + iStat += EqnTest ( "a = sin(b)", 0.909297, true ); + iStat += EqnTest ( "a = 1+sin(b)", 1.909297, true ); + iStat += EqnTest ( "(a=b)*2", 4, true ); + iStat += EqnTest ( "2*(a=b)", 4, true ); + iStat += EqnTest ( "2*(a=b+1)", 6, true ); + iStat += EqnTest ( "(a=b+1)*2", 6, true ); - iStat += EqnTest ( "2^2^3", 256, true ); - iStat += EqnTest ( "1/2/3", 1.0 / 6.0, true ); + iStat += EqnTest ( "2^2^3", 256, true ); + iStat += EqnTest ( "1/2/3", 1.0 / 6.0, true ); - // reference: http://www.wolframalpha.com/input/?i=3%2B4*2%2F%281-5%29^2^3 - iStat += EqnTest ( "3+4*2/(1-5)^2^3", 3.0001220703125, true ); + // reference: http://www.wolframalpha.com/input/?i=3%2B4*2%2F%281-5%29^2^3 + iStat += EqnTest ( "3+4*2/(1-5)^2^3", 3.0001220703125, true ); - if ( iStat == 0 ) - { - qDebug() << "passed"; - } - else - { - qDebug() << "\n failed with " << iStat << " errors"; - } + if ( iStat == 0 ) + { + qDebug() << "passed"; + } + else + { + qDebug() << "\n failed with " << iStat << " errors"; + } - return iStat; + return iStat; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** @brief Check muParser name restriction enforcement. */ int QmuParserTester::TestNames() { - int iStat = 0, - iErr = 0; + int iStat = 0, + iErr = 0; - qDebug() << "testing name restriction enforcement..."; + qDebug() << "testing name restriction enforcement..."; - QmuParser p; + QmuParser p; #define PARSER_THROWCHECK(DOMAIN, FAIL, EXPR, ARG) \ iErr = 0; \ QmuParserTester::c_iCount++; \ try \ { \ - p.Define##DOMAIN(EXPR, ARG); \ + p.Define##DOMAIN(EXPR, ARG); \ } \ - catch(QmuParser::exception_type&) \ + catch (QmuParser::exception_type&) \ { \ iErr = (FAIL==false) ? 0 : 1; \ } \ iStat += iErr; - // constant names - PARSER_THROWCHECK ( Const, false, "0a", 1 ) - PARSER_THROWCHECK ( Const, false, "9a", 1 ) - PARSER_THROWCHECK ( Const, false, "+a", 1 ) - PARSER_THROWCHECK ( Const, false, "-a", 1 ) - PARSER_THROWCHECK ( Const, false, "a-", 1 ) - PARSER_THROWCHECK ( Const, false, "a*", 1 ) - PARSER_THROWCHECK ( Const, false, "a?", 1 ) - PARSER_THROWCHECK ( Const, true, "a", 1 ) - PARSER_THROWCHECK ( Const, true, "a_min", 1 ) - PARSER_THROWCHECK ( Const, true, "a_min0", 1 ) - PARSER_THROWCHECK ( Const, true, "a_min9", 1 ) - // variable names - qreal a; - p.ClearConst(); - PARSER_THROWCHECK ( Var, false, "123abc", &a ) - PARSER_THROWCHECK ( Var, false, "9a", &a ) - PARSER_THROWCHECK ( Var, false, "0a", &a ) - PARSER_THROWCHECK ( Var, false, "+a", &a ) - PARSER_THROWCHECK ( Var, false, "-a", &a ) - PARSER_THROWCHECK ( Var, false, "?a", &a ) - PARSER_THROWCHECK ( Var, false, "!a", &a ) - PARSER_THROWCHECK ( Var, false, "a+", &a ) - PARSER_THROWCHECK ( Var, false, "a-", &a ) - PARSER_THROWCHECK ( Var, false, "a*", &a ) - PARSER_THROWCHECK ( Var, false, "a?", &a ) - PARSER_THROWCHECK ( Var, true, "a", &a ) - PARSER_THROWCHECK ( Var, true, "a_min", &a ) - PARSER_THROWCHECK ( Var, true, "a_min0", &a ) - PARSER_THROWCHECK ( Var, true, "a_min9", &a ) - PARSER_THROWCHECK ( Var, false, "a_min9", 0 ) - // Postfix operators - // fail - PARSER_THROWCHECK ( PostfixOprt, false, "(k", f1of1 ) - PARSER_THROWCHECK ( PostfixOprt, false, "9+", f1of1 ) - PARSER_THROWCHECK ( PostfixOprt, false, "+", 0 ) - // pass - PARSER_THROWCHECK ( PostfixOprt, true, "-a", f1of1 ) - PARSER_THROWCHECK ( PostfixOprt, true, "?a", f1of1 ) - PARSER_THROWCHECK ( PostfixOprt, true, "_", f1of1 ) - PARSER_THROWCHECK ( PostfixOprt, true, "#", f1of1 ) - PARSER_THROWCHECK ( PostfixOprt, true, "&&", f1of1 ) - PARSER_THROWCHECK ( PostfixOprt, true, "||", f1of1 ) - PARSER_THROWCHECK ( PostfixOprt, true, "&", f1of1 ) - PARSER_THROWCHECK ( PostfixOprt, true, "|", f1of1 ) - PARSER_THROWCHECK ( PostfixOprt, true, "++", f1of1 ) - PARSER_THROWCHECK ( PostfixOprt, true, "--", f1of1 ) - PARSER_THROWCHECK ( PostfixOprt, true, "?>", f1of1 ) - PARSER_THROWCHECK ( PostfixOprt, true, "?<", f1of1 ) - PARSER_THROWCHECK ( PostfixOprt, true, "**", f1of1 ) - PARSER_THROWCHECK ( PostfixOprt, true, "xor", f1of1 ) - PARSER_THROWCHECK ( PostfixOprt, true, "and", f1of1 ) - PARSER_THROWCHECK ( PostfixOprt, true, "or", f1of1 ) - PARSER_THROWCHECK ( PostfixOprt, true, "not", f1of1 ) - PARSER_THROWCHECK ( PostfixOprt, true, "!", f1of1 ) - // Binary operator - // The following must fail with builtin operators activated - // p.EnableBuiltInOp(true); -> this is the default - p.ClearPostfixOprt(); - PARSER_THROWCHECK ( Oprt, false, "+", f1of2 ) - PARSER_THROWCHECK ( Oprt, false, "-", f1of2 ) - PARSER_THROWCHECK ( Oprt, false, "*", f1of2 ) - PARSER_THROWCHECK ( Oprt, false, "/", f1of2 ) - PARSER_THROWCHECK ( Oprt, false, "^", f1of2 ) - PARSER_THROWCHECK ( Oprt, false, "&&", f1of2 ) - PARSER_THROWCHECK ( Oprt, false, "||", f1of2 ) - // without activated built in operators it should work - p.EnableBuiltInOprt ( false ); - PARSER_THROWCHECK ( Oprt, true, "+", f1of2 ) - PARSER_THROWCHECK ( Oprt, true, "-", f1of2 ) - PARSER_THROWCHECK ( Oprt, true, "*", f1of2 ) - PARSER_THROWCHECK ( Oprt, true, "/", f1of2 ) - PARSER_THROWCHECK ( Oprt, true, "^", f1of2 ) - PARSER_THROWCHECK ( Oprt, true, "&&", f1of2 ) - PARSER_THROWCHECK ( Oprt, true, "||", f1of2 ) + // constant names + PARSER_THROWCHECK ( Const, false, "0a", 1 ) + PARSER_THROWCHECK ( Const, false, "9a", 1 ) + PARSER_THROWCHECK ( Const, false, "+a", 1 ) + PARSER_THROWCHECK ( Const, false, "-a", 1 ) + PARSER_THROWCHECK ( Const, false, "a-", 1 ) + PARSER_THROWCHECK ( Const, false, "a*", 1 ) + PARSER_THROWCHECK ( Const, false, "a?", 1 ) + PARSER_THROWCHECK ( Const, true, "a", 1 ) + PARSER_THROWCHECK ( Const, true, "a_min", 1 ) + PARSER_THROWCHECK ( Const, true, "a_min0", 1 ) + PARSER_THROWCHECK ( Const, true, "a_min9", 1 ) + // variable names + qreal a; + p.ClearConst(); + PARSER_THROWCHECK ( Var, false, "123abc", &a ) + PARSER_THROWCHECK ( Var, false, "9a", &a ) + PARSER_THROWCHECK ( Var, false, "0a", &a ) + PARSER_THROWCHECK ( Var, false, "+a", &a ) + PARSER_THROWCHECK ( Var, false, "-a", &a ) + PARSER_THROWCHECK ( Var, false, "?a", &a ) + PARSER_THROWCHECK ( Var, false, "!a", &a ) + PARSER_THROWCHECK ( Var, false, "a+", &a ) + PARSER_THROWCHECK ( Var, false, "a-", &a ) + PARSER_THROWCHECK ( Var, false, "a*", &a ) + PARSER_THROWCHECK ( Var, false, "a?", &a ) + PARSER_THROWCHECK ( Var, true, "a", &a ) + PARSER_THROWCHECK ( Var, true, "a_min", &a ) + PARSER_THROWCHECK ( Var, true, "a_min0", &a ) + PARSER_THROWCHECK ( Var, true, "a_min9", &a ) + PARSER_THROWCHECK ( Var, false, "a_min9", 0 ) + // Postfix operators + // fail + PARSER_THROWCHECK ( PostfixOprt, false, "(k", f1of1 ) + PARSER_THROWCHECK ( PostfixOprt, false, "9+", f1of1 ) + PARSER_THROWCHECK ( PostfixOprt, false, "+", 0 ) + // pass + PARSER_THROWCHECK ( PostfixOprt, true, "-a", f1of1 ) + PARSER_THROWCHECK ( PostfixOprt, true, "?a", f1of1 ) + PARSER_THROWCHECK ( PostfixOprt, true, "_", f1of1 ) + PARSER_THROWCHECK ( PostfixOprt, true, "#", f1of1 ) + PARSER_THROWCHECK ( PostfixOprt, true, "&&", f1of1 ) + PARSER_THROWCHECK ( PostfixOprt, true, "||", f1of1 ) + PARSER_THROWCHECK ( PostfixOprt, true, "&", f1of1 ) + PARSER_THROWCHECK ( PostfixOprt, true, "|", f1of1 ) + PARSER_THROWCHECK ( PostfixOprt, true, "++", f1of1 ) + PARSER_THROWCHECK ( PostfixOprt, true, "--", f1of1 ) + PARSER_THROWCHECK ( PostfixOprt, true, "?>", f1of1 ) + PARSER_THROWCHECK ( PostfixOprt, true, "?<", f1of1 ) + PARSER_THROWCHECK ( PostfixOprt, true, "**", f1of1 ) + PARSER_THROWCHECK ( PostfixOprt, true, "xor", f1of1 ) + PARSER_THROWCHECK ( PostfixOprt, true, "and", f1of1 ) + PARSER_THROWCHECK ( PostfixOprt, true, "or", f1of1 ) + PARSER_THROWCHECK ( PostfixOprt, true, "not", f1of1 ) + PARSER_THROWCHECK ( PostfixOprt, true, "!", f1of1 ) + // Binary operator + // The following must fail with builtin operators activated + // p.EnableBuiltInOp(true); -> this is the default + p.ClearPostfixOprt(); + PARSER_THROWCHECK ( Oprt, false, "+", f1of2 ) + PARSER_THROWCHECK ( Oprt, false, "-", f1of2 ) + PARSER_THROWCHECK ( Oprt, false, "*", f1of2 ) + PARSER_THROWCHECK ( Oprt, false, "/", f1of2 ) + PARSER_THROWCHECK ( Oprt, false, "^", f1of2 ) + PARSER_THROWCHECK ( Oprt, false, "&&", f1of2 ) + PARSER_THROWCHECK ( Oprt, false, "||", f1of2 ) + // without activated built in operators it should work + p.EnableBuiltInOprt ( false ); + PARSER_THROWCHECK ( Oprt, true, "+", f1of2 ) + PARSER_THROWCHECK ( Oprt, true, "-", f1of2 ) + PARSER_THROWCHECK ( Oprt, true, "*", f1of2 ) + PARSER_THROWCHECK ( Oprt, true, "/", f1of2 ) + PARSER_THROWCHECK ( Oprt, true, "^", f1of2 ) + PARSER_THROWCHECK ( Oprt, true, "&&", f1of2 ) + PARSER_THROWCHECK ( Oprt, true, "||", f1of2 ) #undef PARSER_THROWCHECK - if ( iStat == 0 ) - { - qDebug() << "passed"; - } - else - { - qDebug() << "\n failed with " << iStat << " errors"; - } + if ( iStat == 0 ) + { + qDebug() << "passed"; + } + else + { + qDebug() << "\n failed with " << iStat << " errors"; + } - return iStat; + return iStat; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- int QmuParserTester::TestSyntax() { - int iStat = 0; - qDebug() << "testing syntax engine..."; + int iStat = 0; + qDebug() << "testing syntax engine..."; - iStat += ThrowTest ( "1,", ecUNEXPECTED_EOF ); // incomplete hex definition - iStat += ThrowTest ( "a,", ecUNEXPECTED_EOF ); // incomplete hex definition - iStat += ThrowTest ( "sin(8),", ecUNEXPECTED_EOF ); // incomplete hex definition - iStat += ThrowTest ( "(sin(8)),", ecUNEXPECTED_EOF ); // incomplete hex definition - iStat += ThrowTest ( "a{m},", ecUNEXPECTED_EOF ); // incomplete hex definition + iStat += ThrowTest ( "1,", ecUNEXPECTED_EOF ); // incomplete hex definition + iStat += ThrowTest ( "a,", ecUNEXPECTED_EOF ); // incomplete hex definition + iStat += ThrowTest ( "sin(8),", ecUNEXPECTED_EOF ); // incomplete hex definition + iStat += ThrowTest ( "(sin(8)),", ecUNEXPECTED_EOF ); // incomplete hex definition + iStat += ThrowTest ( "a{m},", ecUNEXPECTED_EOF ); // incomplete hex definition - iStat += EqnTest ( "(1+ 2*a)", 3, true ); // Spaces within formula - iStat += EqnTest ( "sqrt((4))", 2, true ); // Multiple brackets - iStat += EqnTest ( "sqrt((2)+2)", 2, true ); // Multiple brackets - iStat += EqnTest ( "sqrt(2+(2))", 2, true ); // Multiple brackets - iStat += EqnTest ( "sqrt(a+(3))", 2, true ); // Multiple brackets - iStat += EqnTest ( "sqrt((3)+a)", 2, true ); // Multiple brackets - iStat += EqnTest ( "order(1,2)", 1, true ); // May not cause name collision with operator "or" - iStat += EqnTest ( "(2+", 0, false ); // missing closing bracket - iStat += EqnTest ( "2++4", 0, false ); // unexpected operator - iStat += EqnTest ( "2+-4", 0, false ); // unexpected operator - iStat += EqnTest ( "(2+)", 0, false ); // unexpected closing bracket - iStat += EqnTest ( "--2", 0, false ); // double sign - iStat += EqnTest ( "ksdfj", 0, false ); // unknown token - iStat += EqnTest ( "()", 0, false ); // empty bracket without a function - iStat += EqnTest ( "5+()", 0, false ); // empty bracket without a function - iStat += EqnTest ( "sin(cos)", 0, false ); // unexpected function - iStat += EqnTest ( "5t6", 0, false ); // unknown token - iStat += EqnTest ( "5 t 6", 0, false ); // unknown token - iStat += EqnTest ( "8*", 0, false ); // unexpected end of formula - iStat += EqnTest ( ",3", 0, false ); // unexpected comma - iStat += EqnTest ( "3,5", 0, false ); // unexpected comma - iStat += EqnTest ( "sin(8,8)", 0, false ); // too many function args - iStat += EqnTest ( "(7,8)", 0, false ); // too many function args - iStat += EqnTest ( "sin)", 0, false ); // unexpected closing bracket - iStat += EqnTest ( "a)", 0, false ); // unexpected closing bracket - iStat += EqnTest ( "pi)", 0, false ); // unexpected closing bracket - iStat += EqnTest ( "sin(())", 0, false ); // unexpected closing bracket - iStat += EqnTest ( "sin()", 0, false ); // unexpected closing bracket + iStat += EqnTest ( "(1+ 2*a)", 3, true ); // Spaces within formula + iStat += EqnTest ( "sqrt((4))", 2, true ); // Multiple brackets + iStat += EqnTest ( "sqrt((2)+2)", 2, true ); // Multiple brackets + iStat += EqnTest ( "sqrt(2+(2))", 2, true ); // Multiple brackets + iStat += EqnTest ( "sqrt(a+(3))", 2, true ); // Multiple brackets + iStat += EqnTest ( "sqrt((3)+a)", 2, true ); // Multiple brackets + iStat += EqnTest ( "order(1,2)", 1, true ); // May not cause name collision with operator "or" + iStat += EqnTest ( "(2+", 0, false ); // missing closing bracket + iStat += EqnTest ( "2++4", 0, false ); // unexpected operator + iStat += EqnTest ( "2+-4", 0, false ); // unexpected operator + iStat += EqnTest ( "(2+)", 0, false ); // unexpected closing bracket + iStat += EqnTest ( "--2", 0, false ); // double sign + iStat += EqnTest ( "ksdfj", 0, false ); // unknown token + iStat += EqnTest ( "()", 0, false ); // empty bracket without a function + iStat += EqnTest ( "5+()", 0, false ); // empty bracket without a function + iStat += EqnTest ( "sin(cos)", 0, false ); // unexpected function + iStat += EqnTest ( "5t6", 0, false ); // unknown token + iStat += EqnTest ( "5 t 6", 0, false ); // unknown token + iStat += EqnTest ( "8*", 0, false ); // unexpected end of formula + iStat += EqnTest ( ",3", 0, false ); // unexpected comma + iStat += EqnTest ( "3,5", 0, false ); // unexpected comma + iStat += EqnTest ( "sin(8,8)", 0, false ); // too many function args + iStat += EqnTest ( "(7,8)", 0, false ); // too many function args + iStat += EqnTest ( "sin)", 0, false ); // unexpected closing bracket + iStat += EqnTest ( "a)", 0, false ); // unexpected closing bracket + iStat += EqnTest ( "pi)", 0, false ); // unexpected closing bracket + iStat += EqnTest ( "sin(())", 0, false ); // unexpected closing bracket + iStat += EqnTest ( "sin()", 0, false ); // unexpected closing bracket - if ( iStat == 0 ) - { - qDebug() << "passed"; - } - else - { - qDebug() << "\n failed with " << iStat << " errors"; - } + if ( iStat == 0 ) + { + qDebug() << "passed"; + } + else + { + qDebug() << "\n failed with " << iStat << " errors"; + } - return iStat; + return iStat; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- int QmuParserTester::TestVarConst() { - int iStat = 0; - qDebug() << "testing variable/constant detection..."; + int iStat = 0; + qDebug() << "testing variable/constant detection..."; - // Test if the result changes when a variable changes - iStat += EqnTestWithVarChange ( "a", 1, 1, 2, 2 ); - iStat += EqnTestWithVarChange ( "2*a", 2, 4, 3, 6 ); + // Test if the result changes when a variable changes + iStat += EqnTestWithVarChange ( "a", 1, 1, 2, 2 ); + iStat += EqnTestWithVarChange ( "2*a", 2, 4, 3, 6 ); - // distinguish constants with same basename - iStat += EqnTest ( "const", 1, true ); - iStat += EqnTest ( "const1", 2, true ); - iStat += EqnTest ( "const2", 3, true ); - iStat += EqnTest ( "2*const", 2, true ); - iStat += EqnTest ( "2*const1", 4, true ); - iStat += EqnTest ( "2*const2", 6, true ); - iStat += EqnTest ( "2*const+1", 3, true ); - iStat += EqnTest ( "2*const1+1", 5, true ); - iStat += EqnTest ( "2*const2+1", 7, true ); - iStat += EqnTest ( "const", 0, false ); - iStat += EqnTest ( "const1", 0, false ); - iStat += EqnTest ( "const2", 0, false ); + // distinguish constants with same basename + iStat += EqnTest ( "const", 1, true ); + iStat += EqnTest ( "const1", 2, true ); + iStat += EqnTest ( "const2", 3, true ); + iStat += EqnTest ( "2*const", 2, true ); + iStat += EqnTest ( "2*const1", 4, true ); + iStat += EqnTest ( "2*const2", 6, true ); + iStat += EqnTest ( "2*const+1", 3, true ); + iStat += EqnTest ( "2*const1+1", 5, true ); + iStat += EqnTest ( "2*const2+1", 7, true ); + iStat += EqnTest ( "const", 0, false ); + iStat += EqnTest ( "const1", 0, false ); + iStat += EqnTest ( "const2", 0, false ); - // distinguish variables with same basename - iStat += EqnTest ( "a", 1, true ); - iStat += EqnTest ( "aa", 2, true ); - iStat += EqnTest ( "2*a", 2, true ); - iStat += EqnTest ( "2*aa", 4, true ); - iStat += EqnTest ( "2*a-1", 1, true ); - iStat += EqnTest ( "2*aa-1", 3, true ); + // distinguish variables with same basename + iStat += EqnTest ( "a", 1, true ); + iStat += EqnTest ( "aa", 2, true ); + iStat += EqnTest ( "2*a", 2, true ); + iStat += EqnTest ( "2*aa", 4, true ); + iStat += EqnTest ( "2*a-1", 1, true ); + iStat += EqnTest ( "2*aa-1", 3, true ); - // custom value recognition - iStat += EqnTest ( "0xff", 255, true ); - iStat += EqnTest ( "0x97 + 0xff", 406, true ); + // custom value recognition + iStat += EqnTest ( "0xff", 255, true ); + iStat += EqnTest ( "0x97 + 0xff", 406, true ); - // Finally test querying of used variables - try - { - int idx; - qmu::QmuParser p; - qreal vVarVal[] = { 1, 2, 3, 4, 5}; - p.DefineVar ( "a", &vVarVal[0] ); - p.DefineVar ( "b", &vVarVal[1] ); - p.DefineVar ( "c", &vVarVal[2] ); - p.DefineVar ( "d", &vVarVal[3] ); - p.DefineVar ( "e", &vVarVal[4] ); + // Finally test querying of used variables + try + { + int idx; + qmu::QmuParser p; + qreal vVarVal[] = { 1, 2, 3, 4, 5}; + p.DefineVar ( "a", &vVarVal[0] ); + p.DefineVar ( "b", &vVarVal[1] ); + p.DefineVar ( "c", &vVarVal[2] ); + p.DefineVar ( "d", &vVarVal[3] ); + p.DefineVar ( "e", &vVarVal[4] ); - // Test lookup of defined variables - // 4 used variables - p.SetExpr ( "a+b+c+d" ); - qmu::varmap_type UsedVar = p.GetUsedVar(); - int iCount = static_cast(UsedVar.size()); - if ( iCount != 4 ) - { - throw false; - } + // Test lookup of defined variables + // 4 used variables + p.SetExpr ( "a+b+c+d" ); + qmu::varmap_type UsedVar = p.GetUsedVar(); + int iCount = static_cast(UsedVar.size()); + if ( iCount != 4 ) + { + throw false; + } - // the next check will fail if the parser - // erroneousely creates new variables internally - if ( p.GetVar().size() != 5 ) - { - throw false; - } + // the next check will fail if the parser + // erroneousely creates new variables internally + if ( p.GetVar().size() != 5 ) + { + throw false; + } - qmu::varmap_type::const_iterator item = UsedVar.begin(); - for ( idx = 0; item != UsedVar.end(); ++item ) - { - if ( &vVarVal[idx++] != item->second ) - { - throw false; - } - } + qmu::varmap_type::const_iterator item = UsedVar.begin(); + for ( idx = 0; item != UsedVar.end(); ++item ) + { + if ( &vVarVal[idx++] != item->second ) + { + throw false; + } + } - // Test lookup of undefined variables - p.SetExpr ( "undef1+undef2+undef3" ); - UsedVar = p.GetUsedVar(); - iCount = static_cast(UsedVar.size()); - if ( iCount != 3 ) - { - throw false; - } + // Test lookup of undefined variables + p.SetExpr ( "undef1+undef2+undef3" ); + UsedVar = p.GetUsedVar(); + iCount = static_cast(UsedVar.size()); + if ( iCount != 3 ) + { + throw false; + } - // the next check will fail if the parser - // erroneousely creates new variables internally - if ( p.GetVar().size() != 5 ) - { - throw false; - } + // the next check will fail if the parser + // erroneousely creates new variables internally + if ( p.GetVar().size() != 5 ) + { + throw false; + } - for ( item = UsedVar.begin(); item != UsedVar.end(); ++item ) - { - if ( item->second != 0 ) - { - throw false; // all pointers to undefined variables must be null - } - } + for ( item = UsedVar.begin(); item != UsedVar.end(); ++item ) + { + if ( item->second != 0 ) + { + throw false; // all pointers to undefined variables must be null + } + } - // 1 used variables - p.SetExpr ( "a+b" ); - UsedVar = p.GetUsedVar(); - iCount = static_cast(UsedVar.size()); - if ( iCount != 2 ) - { - throw false; - } - item = UsedVar.begin(); - for ( idx = 0; item != UsedVar.end(); ++item ) - { - if ( &vVarVal[idx++] != item->second ) - { - throw false; - } - } + // 1 used variables + p.SetExpr ( "a+b" ); + UsedVar = p.GetUsedVar(); + iCount = static_cast(UsedVar.size()); + if ( iCount != 2 ) + { + throw false; + } + item = UsedVar.begin(); + for ( idx = 0; item != UsedVar.end(); ++item ) + { + if ( &vVarVal[idx++] != item->second ) + { + throw false; + } + } - } - catch ( ... ) - { - iStat += 1; - } + } + catch ( ... ) + { + iStat += 1; + } - if ( iStat == 0 ) - { - qDebug() << "passed"; - } - else - { - qDebug() << "\n failed with " << iStat << " errors"; - } + if ( iStat == 0 ) + { + qDebug() << "passed"; + } + else + { + qDebug() << "\n failed with " << iStat << " errors"; + } - return iStat; + return iStat; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- int QmuParserTester::TestMultiArg() { - int iStat = 0; - qDebug() << "testing multiarg functions..."; + int iStat = 0; + qDebug() << "testing multiarg functions..."; - // Compound expressions - iStat += EqnTest ( "1,2,3", 3, true ); - iStat += EqnTest ( "a,b,c", 3, true ); - iStat += EqnTest ( "a=10,b=20,c=a*b", 200, true ); - iStat += EqnTest ( "1,\n2,\n3", 3, true ); - iStat += EqnTest ( "a,\nb,\nc", 3, true ); - iStat += EqnTest ( "a=10,\nb=20,\nc=a*b", 200, true ); - iStat += EqnTest ( "1,\r\n2,\r\n3", 3, true ); - iStat += EqnTest ( "a,\r\nb,\r\nc", 3, true ); - iStat += EqnTest ( "a=10,\r\nb=20,\r\nc=a*b", 200, true ); + // Compound expressions + iStat += EqnTest ( "1,2,3", 3, true ); + iStat += EqnTest ( "a,b,c", 3, true ); + iStat += EqnTest ( "a=10,b=20,c=a*b", 200, true ); + iStat += EqnTest ( "1,\n2,\n3", 3, true ); + iStat += EqnTest ( "a,\nb,\nc", 3, true ); + iStat += EqnTest ( "a=10,\nb=20,\nc=a*b", 200, true ); + iStat += EqnTest ( "1,\r\n2,\r\n3", 3, true ); + iStat += EqnTest ( "a,\r\nb,\r\nc", 3, true ); + iStat += EqnTest ( "a=10,\r\nb=20,\r\nc=a*b", 200, true ); - // picking the right argument - iStat += EqnTest ( "f1of1(1)", 1, true ); - iStat += EqnTest ( "f1of2(1, 2)", 1, true ); - iStat += EqnTest ( "f2of2(1, 2)", 2, true ); - iStat += EqnTest ( "f1of3(1, 2, 3)", 1, true ); - iStat += EqnTest ( "f2of3(1, 2, 3)", 2, true ); - iStat += EqnTest ( "f3of3(1, 2, 3)", 3, true ); - iStat += EqnTest ( "f1of4(1, 2, 3, 4)", 1, true ); - iStat += EqnTest ( "f2of4(1, 2, 3, 4)", 2, true ); - iStat += EqnTest ( "f3of4(1, 2, 3, 4)", 3, true ); - iStat += EqnTest ( "f4of4(1, 2, 3, 4)", 4, true ); - iStat += EqnTest ( "f1of5(1, 2, 3, 4, 5)", 1, true ); - iStat += EqnTest ( "f2of5(1, 2, 3, 4, 5)", 2, true ); - iStat += EqnTest ( "f3of5(1, 2, 3, 4, 5)", 3, true ); - iStat += EqnTest ( "f4of5(1, 2, 3, 4, 5)", 4, true ); - iStat += EqnTest ( "f5of5(1, 2, 3, 4, 5)", 5, true ); - // Too few arguments / Too many arguments - iStat += EqnTest ( "1+ping()", 11, true ); - iStat += EqnTest ( "ping()+1", 11, true ); - iStat += EqnTest ( "2*ping()", 20, true ); - iStat += EqnTest ( "ping()*2", 20, true ); - iStat += EqnTest ( "ping(1,2)", 0, false ); - iStat += EqnTest ( "1+ping(1,2)", 0, false ); - iStat += EqnTest ( "f1of1(1,2)", 0, false ); - iStat += EqnTest ( "f1of1()", 0, false ); - iStat += EqnTest ( "f1of2(1, 2, 3)", 0, false ); - iStat += EqnTest ( "f1of2(1)", 0, false ); - iStat += EqnTest ( "f1of3(1, 2, 3, 4)", 0, false ); - iStat += EqnTest ( "f1of3(1)", 0, false ); - iStat += EqnTest ( "f1of4(1, 2, 3, 4, 5)", 0, false ); - iStat += EqnTest ( "f1of4(1)", 0, false ); - iStat += EqnTest ( "(1,2,3)", 0, false ); - iStat += EqnTest ( "1,2,3", 0, false ); - iStat += EqnTest ( "(1*a,2,3)", 0, false ); - iStat += EqnTest ( "1,2*a,3", 0, false ); + // picking the right argument + iStat += EqnTest ( "f1of1(1)", 1, true ); + iStat += EqnTest ( "f1of2(1, 2)", 1, true ); + iStat += EqnTest ( "f2of2(1, 2)", 2, true ); + iStat += EqnTest ( "f1of3(1, 2, 3)", 1, true ); + iStat += EqnTest ( "f2of3(1, 2, 3)", 2, true ); + iStat += EqnTest ( "f3of3(1, 2, 3)", 3, true ); + iStat += EqnTest ( "f1of4(1, 2, 3, 4)", 1, true ); + iStat += EqnTest ( "f2of4(1, 2, 3, 4)", 2, true ); + iStat += EqnTest ( "f3of4(1, 2, 3, 4)", 3, true ); + iStat += EqnTest ( "f4of4(1, 2, 3, 4)", 4, true ); + iStat += EqnTest ( "f1of5(1, 2, 3, 4, 5)", 1, true ); + iStat += EqnTest ( "f2of5(1, 2, 3, 4, 5)", 2, true ); + iStat += EqnTest ( "f3of5(1, 2, 3, 4, 5)", 3, true ); + iStat += EqnTest ( "f4of5(1, 2, 3, 4, 5)", 4, true ); + iStat += EqnTest ( "f5of5(1, 2, 3, 4, 5)", 5, true ); + // Too few arguments / Too many arguments + iStat += EqnTest ( "1+ping()", 11, true ); + iStat += EqnTest ( "ping()+1", 11, true ); + iStat += EqnTest ( "2*ping()", 20, true ); + iStat += EqnTest ( "ping()*2", 20, true ); + iStat += EqnTest ( "ping(1,2)", 0, false ); + iStat += EqnTest ( "1+ping(1,2)", 0, false ); + iStat += EqnTest ( "f1of1(1,2)", 0, false ); + iStat += EqnTest ( "f1of1()", 0, false ); + iStat += EqnTest ( "f1of2(1, 2, 3)", 0, false ); + iStat += EqnTest ( "f1of2(1)", 0, false ); + iStat += EqnTest ( "f1of3(1, 2, 3, 4)", 0, false ); + iStat += EqnTest ( "f1of3(1)", 0, false ); + iStat += EqnTest ( "f1of4(1, 2, 3, 4, 5)", 0, false ); + iStat += EqnTest ( "f1of4(1)", 0, false ); + iStat += EqnTest ( "(1,2,3)", 0, false ); + iStat += EqnTest ( "1,2,3", 0, false ); + iStat += EqnTest ( "(1*a,2,3)", 0, false ); + iStat += EqnTest ( "1,2*a,3", 0, false ); - // correct calculation of arguments - iStat += EqnTest ( "min(a, 1)", 1, true ); - iStat += EqnTest ( "min(3*2, 1)", 1, true ); - iStat += EqnTest ( "min(3*2, 1)", 6, false ); - iStat += EqnTest ( "firstArg(2,3,4)", 2, true ); - iStat += EqnTest ( "lastArg(2,3,4)", 4, true ); - iStat += EqnTest ( "min(3*a+1, 1)", 1, true ); - iStat += EqnTest ( "max(3*a+1, 1)", 4, true ); - iStat += EqnTest ( "max(3*a+1, 1)*2", 8, true ); - iStat += EqnTest ( "2*max(3*a+1, 1)+2", 10, true ); + // correct calculation of arguments + iStat += EqnTest ( "min(a, 1)", 1, true ); + iStat += EqnTest ( "min(3*2, 1)", 1, true ); + iStat += EqnTest ( "min(3*2, 1)", 6, false ); + iStat += EqnTest ( "firstArg(2,3,4)", 2, true ); + iStat += EqnTest ( "lastArg(2,3,4)", 4, true ); + iStat += EqnTest ( "min(3*a+1, 1)", 1, true ); + iStat += EqnTest ( "max(3*a+1, 1)", 4, true ); + iStat += EqnTest ( "max(3*a+1, 1)*2", 8, true ); + iStat += EqnTest ( "2*max(3*a+1, 1)+2", 10, true ); - // functions with Variable argument count - iStat += EqnTest ( "sum(a)", 1, true ); - iStat += EqnTest ( "sum(1,2,3)", 6, true ); - iStat += EqnTest ( "sum(a,b,c)", 6, true ); - iStat += EqnTest ( "sum(1,-max(1,2),3)*2", 4, true ); - iStat += EqnTest ( "2*sum(1,2,3)", 12, true ); - iStat += EqnTest ( "2*sum(1,2,3)+2", 14, true ); - iStat += EqnTest ( "2*sum(-1,2,3)+2", 10, true ); - iStat += EqnTest ( "2*sum(-1,2,-(-a))+2", 6, true ); - iStat += EqnTest ( "2*sum(-1,10,-a)+2", 18, true ); - iStat += EqnTest ( "2*sum(1,2,3)*2", 24, true ); - iStat += EqnTest ( "sum(1,-max(1,2),3)*2", 4, true ); - iStat += EqnTest ( "sum(1*3, 4, a+2)", 10, true ); - iStat += EqnTest ( "sum(1*3, 2*sum(1,2,2), a+2)", 16, true ); - iStat += EqnTest ( "sum(1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2)", 24, true ); + // functions with Variable argument count + iStat += EqnTest ( "sum(a)", 1, true ); + iStat += EqnTest ( "sum(1,2,3)", 6, true ); + iStat += EqnTest ( "sum(a,b,c)", 6, true ); + iStat += EqnTest ( "sum(1,-max(1,2),3)*2", 4, true ); + iStat += EqnTest ( "2*sum(1,2,3)", 12, true ); + iStat += EqnTest ( "2*sum(1,2,3)+2", 14, true ); + iStat += EqnTest ( "2*sum(-1,2,3)+2", 10, true ); + iStat += EqnTest ( "2*sum(-1,2,-(-a))+2", 6, true ); + iStat += EqnTest ( "2*sum(-1,10,-a)+2", 18, true ); + iStat += EqnTest ( "2*sum(1,2,3)*2", 24, true ); + iStat += EqnTest ( "sum(1,-max(1,2),3)*2", 4, true ); + iStat += EqnTest ( "sum(1*3, 4, a+2)", 10, true ); + iStat += EqnTest ( "sum(1*3, 2*sum(1,2,2), a+2)", 16, true ); + iStat += EqnTest ( "sum(1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2)", 24, true ); - // some failures - iStat += EqnTest ( "sum()", 0, false ); - iStat += EqnTest ( "sum(,)", 0, false ); - iStat += EqnTest ( "sum(1,2,)", 0, false ); - iStat += EqnTest ( "sum(,1,2)", 0, false ); + // some failures + iStat += EqnTest ( "sum()", 0, false ); + iStat += EqnTest ( "sum(,)", 0, false ); + iStat += EqnTest ( "sum(1,2,)", 0, false ); + iStat += EqnTest ( "sum(,1,2)", 0, false ); - if ( iStat == 0 ) - { - qDebug() << "passed"; - } - else - { - qDebug() << "\n failed with " << iStat << " errors"; - } + if ( iStat == 0 ) + { + qDebug() << "passed"; + } + else + { + qDebug() << "\n failed with " << iStat << " errors"; + } - return iStat; + return iStat; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- int QmuParserTester::TestInfixOprt() { - int iStat ( 0 ); - qDebug() << "testing infix operators..."; + int iStat ( 0 ); + qDebug() << "testing infix operators..."; - iStat += EqnTest ( "-1", -1, true ); - iStat += EqnTest ( "-(-1)", 1, true ); - iStat += EqnTest ( "-(-1)*2", 2, true ); - iStat += EqnTest ( "-(-2)*sqrt(4)", 4, true ); - iStat += EqnTest ( "-_pi", -M_PI, true ); - iStat += EqnTest ( "-a", -1, true ); - iStat += EqnTest ( "-(a)", -1, true ); - iStat += EqnTest ( "-(-a)", 1, true ); - iStat += EqnTest ( "-(-a)*2", 2, true ); - iStat += EqnTest ( "-(8)", -8, true ); - iStat += EqnTest ( "-8", -8, true ); - iStat += EqnTest ( "-(2+1)", -3, true ); - iStat += EqnTest ( "-(f1of1(1+2*3)+1*2)", -9, true ); - iStat += EqnTest ( "-(-f1of1(1+2*3)+1*2)", 5, true ); - iStat += EqnTest ( "-sin(8)", -0.989358, true ); - iStat += EqnTest ( "3-(-a)", 4, true ); - iStat += EqnTest ( "3--a", 4, true ); - iStat += EqnTest ( "-1*3", -3, true ); + iStat += EqnTest ( "-1", -1, true ); + iStat += EqnTest ( "-(-1)", 1, true ); + iStat += EqnTest ( "-(-1)*2", 2, true ); + iStat += EqnTest ( "-(-2)*sqrt(4)", 4, true ); + iStat += EqnTest ( "-_pi", -M_PI, true ); + iStat += EqnTest ( "-a", -1, true ); + iStat += EqnTest ( "-(a)", -1, true ); + iStat += EqnTest ( "-(-a)", 1, true ); + iStat += EqnTest ( "-(-a)*2", 2, true ); + iStat += EqnTest ( "-(8)", -8, true ); + iStat += EqnTest ( "-8", -8, true ); + iStat += EqnTest ( "-(2+1)", -3, true ); + iStat += EqnTest ( "-(f1of1(1+2*3)+1*2)", -9, true ); + iStat += EqnTest ( "-(-f1of1(1+2*3)+1*2)", 5, true ); + iStat += EqnTest ( "-sin(8)", -0.989358, true ); + iStat += EqnTest ( "3-(-a)", 4, true ); + iStat += EqnTest ( "3--a", 4, true ); + iStat += EqnTest ( "-1*3", -3, true ); - // Postfix / infix priorities - iStat += EqnTest ( "~2#", 8, true ); - iStat += EqnTest ( "~f1of1(2)#", 8, true ); - iStat += EqnTest ( "~(b)#", 8, true ); - iStat += EqnTest ( "(~b)#", 12, true ); - iStat += EqnTest ( "~(2#)", 8, true ); - iStat += EqnTest ( "~(f1of1(2)#)", 8, true ); - // - iStat += EqnTest ( "-2^2", -4, true ); - iStat += EqnTest ( "-(a+b)^2", -9, true ); - iStat += EqnTest ( "(-3)^2", 9, true ); - iStat += EqnTest ( "-(-2^2)", 4, true ); - iStat += EqnTest ( "3+-3^2", -6, true ); - // The following assumes use of sqr as postfix operator ("") together - // with a sign operator of low priority: - iStat += EqnTest ( "-2'", -4, true ); - iStat += EqnTest ( "-(1+1)'", -4, true ); - iStat += EqnTest ( "2+-(1+1)'", -2, true ); - iStat += EqnTest ( "2+-2'", -2, true ); - // This is the classic behaviour of the infix sign operator (here: "$") which is - // now deprecated: - iStat += EqnTest ( "$2^2", 4, true ); - iStat += EqnTest ( "$(a+b)^2", 9, true ); - iStat += EqnTest ( "($3)^2", 9, true ); - iStat += EqnTest ( "$($2^2)", -4, true ); - iStat += EqnTest ( "3+$3^2", 12, true ); + // Postfix / infix priorities + iStat += EqnTest ( "~2#", 8, true ); + iStat += EqnTest ( "~f1of1(2)#", 8, true ); + iStat += EqnTest ( "~(b)#", 8, true ); + iStat += EqnTest ( "(~b)#", 12, true ); + iStat += EqnTest ( "~(2#)", 8, true ); + iStat += EqnTest ( "~(f1of1(2)#)", 8, true ); + // + iStat += EqnTest ( "-2^2", -4, true ); + iStat += EqnTest ( "-(a+b)^2", -9, true ); + iStat += EqnTest ( "(-3)^2", 9, true ); + iStat += EqnTest ( "-(-2^2)", 4, true ); + iStat += EqnTest ( "3+-3^2", -6, true ); + // The following assumes use of sqr as postfix operator ("") together + // with a sign operator of low priority: + iStat += EqnTest ( "-2'", -4, true ); + iStat += EqnTest ( "-(1+1)'", -4, true ); + iStat += EqnTest ( "2+-(1+1)'", -2, true ); + iStat += EqnTest ( "2+-2'", -2, true ); + // This is the classic behaviour of the infix sign operator (here: "$") which is + // now deprecated: + iStat += EqnTest ( "$2^2", 4, true ); + iStat += EqnTest ( "$(a+b)^2", 9, true ); + iStat += EqnTest ( "($3)^2", 9, true ); + iStat += EqnTest ( "$($2^2)", -4, true ); + iStat += EqnTest ( "3+$3^2", 12, true ); - // infix operators sharing the first few characters - iStat += EqnTest ( "~ 123", 123 + 2, true ); - iStat += EqnTest ( "~~ 123", 123 + 2, true ); + // infix operators sharing the first few characters + iStat += EqnTest ( "~ 123", 123 + 2, true ); + iStat += EqnTest ( "~~ 123", 123 + 2, true ); - if ( iStat == 0 ) - { - qDebug() << "passed"; - } - else - { - qDebug() << "\n failed with " << iStat << " errors"; - } + if ( iStat == 0 ) + { + qDebug() << "passed"; + } + else + { + qDebug() << "\n failed with " << iStat << " errors"; + } - return iStat; + return iStat; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- int QmuParserTester::TestPostFix() { - int iStat = 0; - qDebug() << "testing postfix operators..."; + int iStat = 0; + qDebug() << "testing postfix operators..."; - // application - iStat += EqnTest ( "3{m}+5", 5.003, true ); - iStat += EqnTest ( "1000{m}", 1, true ); - iStat += EqnTest ( "1000 {m}", 1, true ); - iStat += EqnTest ( "(a){m}", 1e-3, true ); - iStat += EqnTest ( "a{m}", 1e-3, true ); - iStat += EqnTest ( "a {m}", 1e-3, true ); - iStat += EqnTest ( "-(a){m}", -1e-3, true ); - iStat += EqnTest ( "-2{m}", -2e-3, true ); - iStat += EqnTest ( "-2 {m}", -2e-3, true ); - iStat += EqnTest ( "f1of1(1000){m}", 1, true ); - iStat += EqnTest ( "-f1of1(1000){m}", -1, true ); - iStat += EqnTest ( "-f1of1(-1000){m}", 1, true ); - iStat += EqnTest ( "f4of4(0,0,0,1000){m}", 1, true ); - iStat += EqnTest ( "2+(a*1000){m}", 3, true ); + // application + iStat += EqnTest ( "3{m}+5", 5.003, true ); + iStat += EqnTest ( "1000{m}", 1, true ); + iStat += EqnTest ( "1000 {m}", 1, true ); + iStat += EqnTest ( "(a){m}", 1e-3, true ); + iStat += EqnTest ( "a{m}", 1e-3, true ); + iStat += EqnTest ( "a {m}", 1e-3, true ); + iStat += EqnTest ( "-(a){m}", -1e-3, true ); + iStat += EqnTest ( "-2{m}", -2e-3, true ); + iStat += EqnTest ( "-2 {m}", -2e-3, true ); + iStat += EqnTest ( "f1of1(1000){m}", 1, true ); + iStat += EqnTest ( "-f1of1(1000){m}", -1, true ); + iStat += EqnTest ( "-f1of1(-1000){m}", 1, true ); + iStat += EqnTest ( "f4of4(0,0,0,1000){m}", 1, true ); + iStat += EqnTest ( "2+(a*1000){m}", 3, true ); - // can postfix operators "m" und "meg" be told apart properly? - iStat += EqnTest ( "2*3000meg+2", 2 * 3e9 + 2, true ); + // can postfix operators "m" und "meg" be told apart properly? + iStat += EqnTest ( "2*3000meg+2", 2 * 3e9 + 2, true ); - // some incorrect results - iStat += EqnTest ( "1000{m}", 0.1, false ); - iStat += EqnTest ( "(a){m}", 2, false ); - // failure due to syntax checking - iStat += ThrowTest ( "0x", ecUNASSIGNABLE_TOKEN ); // incomplete hex definition - iStat += ThrowTest ( "3+", ecUNEXPECTED_EOF ); - iStat += ThrowTest ( "4 + {m}", ecUNASSIGNABLE_TOKEN ); - iStat += ThrowTest ( "{m}4", ecUNASSIGNABLE_TOKEN ); - iStat += ThrowTest ( "sin({m})", ecUNASSIGNABLE_TOKEN ); - iStat += ThrowTest ( "{m} {m}", ecUNASSIGNABLE_TOKEN ); - iStat += ThrowTest ( "{m}(8)", ecUNASSIGNABLE_TOKEN ); - iStat += ThrowTest ( "4,{m}", ecUNASSIGNABLE_TOKEN ); - iStat += ThrowTest ( "-{m}", ecUNASSIGNABLE_TOKEN ); - iStat += ThrowTest ( "2(-{m})", ecUNEXPECTED_PARENS ); - iStat += ThrowTest ( "2({m})", ecUNEXPECTED_PARENS ); + // some incorrect results + iStat += EqnTest ( "1000{m}", 0.1, false ); + iStat += EqnTest ( "(a){m}", 2, false ); + // failure due to syntax checking + iStat += ThrowTest ( "0x", ecUNASSIGNABLE_TOKEN ); // incomplete hex definition + iStat += ThrowTest ( "3+", ecUNEXPECTED_EOF ); + iStat += ThrowTest ( "4 + {m}", ecUNASSIGNABLE_TOKEN ); + iStat += ThrowTest ( "{m}4", ecUNASSIGNABLE_TOKEN ); + iStat += ThrowTest ( "sin({m})", ecUNASSIGNABLE_TOKEN ); + iStat += ThrowTest ( "{m} {m}", ecUNASSIGNABLE_TOKEN ); + iStat += ThrowTest ( "{m}(8)", ecUNASSIGNABLE_TOKEN ); + iStat += ThrowTest ( "4,{m}", ecUNASSIGNABLE_TOKEN ); + iStat += ThrowTest ( "-{m}", ecUNASSIGNABLE_TOKEN ); + iStat += ThrowTest ( "2(-{m})", ecUNEXPECTED_PARENS ); + iStat += ThrowTest ( "2({m})", ecUNEXPECTED_PARENS ); - iStat += ThrowTest ( "multi*1.0", ecUNASSIGNABLE_TOKEN ); + iStat += ThrowTest ( "multi*1.0", ecUNASSIGNABLE_TOKEN ); - if ( iStat == 0 ) - { - qDebug() << "passed"; - } - else - { - qDebug() << "\n failed with " << iStat << " errors"; - } + if ( iStat == 0 ) + { + qDebug() << "passed"; + } + else + { + qDebug() << "\n failed with " << iStat << " errors"; + } - return iStat; + return iStat; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- int QmuParserTester::TestExpression() { - int iStat = 0; - qDebug() << "testing expression samples..."; + int iStat = 0; + qDebug() << "testing expression samples..."; - qreal b = 2; + qreal b = 2; - // Optimization - iStat += EqnTest ( "2*b*5", 20, true ); - iStat += EqnTest ( "2*b*5 + 4*b", 28, true ); - iStat += EqnTest ( "2*a/3", 2.0 / 3.0, true ); + // Optimization + iStat += EqnTest ( "2*b*5", 20, true ); + iStat += EqnTest ( "2*b*5 + 4*b", 28, true ); + iStat += EqnTest ( "2*a/3", 2.0 / 3.0, true ); - // Addition auf cmVARMUL - iStat += EqnTest ( "3+b", b + 3, true ); - iStat += EqnTest ( "b+3", b + 3, true ); - iStat += EqnTest ( "b*3+2", b * 3 + 2, true ); - iStat += EqnTest ( "3*b+2", b * 3 + 2, true ); - iStat += EqnTest ( "2+b*3", b * 3 + 2, true ); - iStat += EqnTest ( "2+3*b", b * 3 + 2, true ); - iStat += EqnTest ( "b+3*b", b + 3 * b, true ); - iStat += EqnTest ( "3*b+b", b + 3 * b, true ); + // Addition auf cmVARMUL + iStat += EqnTest ( "3+b", b + 3, true ); + iStat += EqnTest ( "b+3", b + 3, true ); + iStat += EqnTest ( "b*3+2", b * 3 + 2, true ); + iStat += EqnTest ( "3*b+2", b * 3 + 2, true ); + iStat += EqnTest ( "2+b*3", b * 3 + 2, true ); + iStat += EqnTest ( "2+3*b", b * 3 + 2, true ); + iStat += EqnTest ( "b+3*b", b + 3 * b, true ); + iStat += EqnTest ( "3*b+b", b + 3 * b, true ); - iStat += EqnTest ( "2+b*3+b", 2 + b * 3 + b, true ); - iStat += EqnTest ( "b+2+b*3", b + 2 + b * 3, true ); + iStat += EqnTest ( "2+b*3+b", 2 + b * 3 + b, true ); + iStat += EqnTest ( "b+2+b*3", b + 2 + b * 3, true ); - iStat += EqnTest ( "(2*b+1)*4", ( 2 * b + 1 ) * 4, true ); - iStat += EqnTest ( "4*(2*b+1)", ( 2 * b + 1 ) * 4, true ); + iStat += EqnTest ( "(2*b+1)*4", ( 2 * b + 1 ) * 4, true ); + iStat += EqnTest ( "4*(2*b+1)", ( 2 * b + 1 ) * 4, true ); - // operator precedencs - iStat += EqnTest ( "1+2-3*4/5^6", 2.99923, true ); - iStat += EqnTest ( "1^2/3*4-5+6", 2.33333333, true ); - iStat += EqnTest ( "1+2*3", 7, true ); - iStat += EqnTest ( "1+2*3", 7, true ); - iStat += EqnTest ( "(1+2)*3", 9, true ); - iStat += EqnTest ( "(1+2)*(-3)", -9, true ); - iStat += EqnTest ( "2/4", 0.5, true ); + // operator precedencs + iStat += EqnTest ( "1+2-3*4/5^6", 2.99923, true ); + iStat += EqnTest ( "1^2/3*4-5+6", 2.33333333, true ); + iStat += EqnTest ( "1+2*3", 7, true ); + iStat += EqnTest ( "1+2*3", 7, true ); + iStat += EqnTest ( "(1+2)*3", 9, true ); + iStat += EqnTest ( "(1+2)*(-3)", -9, true ); + iStat += EqnTest ( "2/4", 0.5, true ); - iStat += EqnTest ( "exp(ln(7))", 7, true ); - iStat += EqnTest ( "e^ln(7)", 7, true ); - iStat += EqnTest ( "e^(ln(7))", 7, true ); - iStat += EqnTest ( "(e^(ln(7)))", 7, true ); - iStat += EqnTest ( "1-(e^(ln(7)))", -6, true ); - iStat += EqnTest ( "2*(e^(ln(7)))", 14, true ); - iStat += EqnTest ( "10^log(5)", 5, true ); - iStat += EqnTest ( "10^log10(5)", 5, true ); - iStat += EqnTest ( "2^log2(4)", 4, true ); - iStat += EqnTest ( "-(sin(0)+1)", -1, true ); - iStat += EqnTest ( "-(2^1.1)", -2.14354692, true ); + iStat += EqnTest ( "exp(ln(7))", 7, true ); + iStat += EqnTest ( "e^ln(7)", 7, true ); + iStat += EqnTest ( "e^(ln(7))", 7, true ); + iStat += EqnTest ( "(e^(ln(7)))", 7, true ); + iStat += EqnTest ( "1-(e^(ln(7)))", -6, true ); + iStat += EqnTest ( "2*(e^(ln(7)))", 14, true ); + iStat += EqnTest ( "10^log(5)", 5, true ); + iStat += EqnTest ( "10^log10(5)", 5, true ); + iStat += EqnTest ( "2^log2(4)", 4, true ); + iStat += EqnTest ( "-(sin(0)+1)", -1, true ); + iStat += EqnTest ( "-(2^1.1)", -2.14354692, true ); - iStat += EqnTest ( "(cos(2.41)/b)", -0.372056, true ); - iStat += EqnTest ( "(1*(2*(3*(4*(5*(6*(a+b)))))))", 2160, true ); - iStat += EqnTest ( "(1*(2*(3*(4*(5*(6*(7*(a+b))))))))", 15120, true ); - iStat += EqnTest ( "(a/((((b+(((e*(((((pi*((((3.45*((pi+a)+pi))+b)+b)*a))+0.68)+e)+a)/a))+a)+b))+b)*a)-pi))", - 0.00377999, true ); + iStat += EqnTest ( "(cos(2.41)/b)", -0.372056, true ); + iStat += EqnTest ( "(1*(2*(3*(4*(5*(6*(a+b)))))))", 2160, true ); + iStat += EqnTest ( "(1*(2*(3*(4*(5*(6*(7*(a+b))))))))", 15120, true ); + iStat += EqnTest ( "(a/((((b+(((e*(((((pi*((((3.45*((pi+a)+pi))+b)+b)*a))+0.68)+e)+a)/a))+a)+b))+b)*a)-pi))", + 0.00377999, true ); - // long formula (Reference: Matlab) - iStat += EqnTest ( - "(((-9))-e/(((((((pi-(((-7)+(-3)/4/e))))/(((-5))-2)-((pi+(-0))*(sqrt((e+e))*(-8))*(((-pi)+(-pi)-(-9)*(6*5))" - "/(-e)-e))/2)/((((sqrt(2/(-e)+6)-(4-2))+((5/(-2))/(1*(-pi)+3))/8)*pi*((pi/((-2)/(-6)*1*(-1))*(-6)+(-e)))))/" - "((e+(-2)+(-e)*((((-3)*9+(-e)))+(-9)))))))-((((e-7+(((5/pi-(3/1+pi)))))/e)/(-5))/(sqrt((((((1+(-7))))+((((-" - "e)*(-e)))-8))*(-5)/((-e)))*(-6)-((((((-2)-(-9)-(-e)-1)/3))))/(sqrt((8+(e-((-6))+(9*(-9))))*(((3+2-8))*(7+6" - "+(-5))+((0/(-e)*(-pi))+7)))+(((((-e)/e/e)+((-6)*5)*e+(3+(-5)/pi))))+pi))/sqrt((((9))+((((pi))-8+2))+pi))/e" - "*4)*((-5)/(((-pi))*(sqrt(e)))))-(((((((-e)*(e)-pi))/4+(pi)*(-9)))))))+(-pi)", -12.23016549, true ); + // long formula (Reference: Matlab) + iStat += EqnTest ( + "(((-9))-e/(((((((pi-(((-7)+(-3)/4/e))))/(((-5))-2)-((pi+(-0))*(sqrt((e+e))*(-8))*(((-pi)+(-pi)-(-9)*(6*5))" + "/(-e)-e))/2)/((((sqrt(2/(-e)+6)-(4-2))+((5/(-2))/(1*(-pi)+3))/8)*pi*((pi/((-2)/(-6)*1*(-1))*(-6)+(-e)))))/" + "((e+(-2)+(-e)*((((-3)*9+(-e)))+(-9)))))))-((((e-7+(((5/pi-(3/1+pi)))))/e)/(-5))/(sqrt((((((1+(-7))))+((((-" + "e)*(-e)))-8))*(-5)/((-e)))*(-6)-((((((-2)-(-9)-(-e)-1)/3))))/(sqrt((8+(e-((-6))+(9*(-9))))*(((3+2-8))*(7+6" + "+(-5))+((0/(-e)*(-pi))+7)))+(((((-e)/e/e)+((-6)*5)*e+(3+(-5)/pi))))+pi))/sqrt((((9))+((((pi))-8+2))+pi))/e" + "*4)*((-5)/(((-pi))*(sqrt(e)))))-(((((((-e)*(e)-pi))/4+(pi)*(-9)))))))+(-pi)", -12.23016549, true ); - // long formula (Reference: Matlab) - iStat += EqnTest ( - "(atan(sin((((((((((((((((pi/cos((a/((((0.53-b)-pi)*e)/b))))+2.51)+a)-0.54)/0.98)+b)*b)+e)/a)+b)+a)+b)+pi)/e" - ")+a)))*2.77)", -2.16995656, true ); + // long formula (Reference: Matlab) + iStat += EqnTest ( + "(atan(sin((((((((((((((((pi/cos((a/((((0.53-b)-pi)*e)/b))))+2.51)+a)-0.54)/0.98)+b)*b)+e)/a)+b)+a)+b)+pi)/e" + ")+a)))*2.77)", -2.16995656, true ); - // long formula (Reference: Matlab) - iStat += EqnTest ( "1+2-3*4/5^6*(2*(1-5+(3*7^9)*(4+6*7-3)))+12", -7995810.09926, true ); + // long formula (Reference: Matlab) + iStat += EqnTest ( "1+2-3*4/5^6*(2*(1-5+(3*7^9)*(4+6*7-3)))+12", -7995810.09926, true ); - if ( iStat == 0 ) - { - qDebug() << "passed"; - } - else - { - qDebug() << "\n failed with " << iStat << " errors"; - } + if ( iStat == 0 ) + { + qDebug() << "passed"; + } + else + { + qDebug() << "\n failed with " << iStat << " errors"; + } - return iStat; + return iStat; } - - -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- int QmuParserTester::TestIfThenElse() { - int iStat = 0; - qDebug() << "testing if-then-else operator..."; + int iStat = 0; + qDebug() << "testing if-then-else operator..."; - // Test error detection - iStat += ThrowTest ( ":3", ecUNEXPECTED_CONDITIONAL ); - iStat += ThrowTest ( "? 1 : 2", ecUNEXPECTED_CONDITIONAL ); - iStat += ThrowTest ( "(ab) ? 10 : 11", 11, true ); - iStat += EqnTest ( "(ab) ? c : d", -2, true ); + iStat += EqnTest ( "1 ? 128 : 255", 128, true ); + iStat += EqnTest ( "1<2 ? 128 : 255", 128, true ); + iStat += EqnTest ( "ab) ? 10 : 11", 11, true ); + iStat += EqnTest ( "(ab) ? c : d", -2, true ); - iStat += EqnTest ( "(a>b) ? 1 : 0", 0, true ); - iStat += EqnTest ( "((a>b) ? 1 : 0) ? 1 : 2", 2, true ); - iStat += EqnTest ( "((a>b) ? 1 : 0) ? 1 : sum((a>b) ? 1 : 2)", 2, true ); - iStat += EqnTest ( "((a>b) ? 0 : 1) ? 1 : sum((a>b) ? 1 : 2)", 1, true ); + iStat += EqnTest ( "(a>b) ? 1 : 0", 0, true ); + iStat += EqnTest ( "((a>b) ? 1 : 0) ? 1 : 2", 2, true ); + iStat += EqnTest ( "((a>b) ? 1 : 0) ? 1 : sum((a>b) ? 1 : 2)", 2, true ); + iStat += EqnTest ( "((a>b) ? 0 : 1) ? 1 : sum((a>b) ? 1 : 2)", 1, true ); - iStat += EqnTest ( "sum((a>b) ? 1 : 2)", 2, true ); - iStat += EqnTest ( "sum((1) ? 1 : 2)", 1, true ); - iStat += EqnTest ( "sum((a>b) ? 1 : 2, 100)", 102, true ); - iStat += EqnTest ( "sum((1) ? 1 : 2, 100)", 101, true ); - iStat += EqnTest ( "sum(3, (a>b) ? 3 : 10)", 13, true ); - iStat += EqnTest ( "sum(3, (ab) ? 3 : 10)", 130, true ); - iStat += EqnTest ( "10*sum(3, (ab) ? 3 : 10)*10", 130, true ); - iStat += EqnTest ( "sum(3, (ab) ? sum(3, (ab) ? sum(3, (ab) ? sum(3, (ab) ? 1 : 2)", 2, true ); + iStat += EqnTest ( "sum((1) ? 1 : 2)", 1, true ); + iStat += EqnTest ( "sum((a>b) ? 1 : 2, 100)", 102, true ); + iStat += EqnTest ( "sum((1) ? 1 : 2, 100)", 101, true ); + iStat += EqnTest ( "sum(3, (a>b) ? 3 : 10)", 13, true ); + iStat += EqnTest ( "sum(3, (ab) ? 3 : 10)", 130, true ); + iStat += EqnTest ( "10*sum(3, (ab) ? 3 : 10)*10", 130, true ); + iStat += EqnTest ( "sum(3, (ab) ? sum(3, (ab) ? sum(3, (ab) ? sum(3, (ab)&&(a2)&&(1<2) ? 128 : 255", 255, true ); - iStat += EqnTest ( "((1<2)&&(1<2)) ? 128 : 255", 128, true ); - iStat += EqnTest ( "((1>2)&&(1<2)) ? 128 : 255", 255, true ); - iStat += EqnTest ( "((ab)&&(ab)&&(a2)&&(1<2) ? 128 : 255", 255, true ); + iStat += EqnTest ( "((1<2)&&(1<2)) ? 128 : 255", 128, true ); + iStat += EqnTest ( "((1>2)&&(1<2)) ? 128 : 255", 255, true ); + iStat += EqnTest ( "((ab)&&(a0 ? 1>2 ? 128 : 255 : 1>0 ? 32 : 64", 255, true ); - iStat += EqnTest ( "1>0 ? 1>2 ? 128 : 255 :(1>0 ? 32 : 64)", 255, true ); - iStat += EqnTest ( "1>0 ? 1>0 ? 128 : 255 : 1>2 ? 32 : 64", 128, true ); - iStat += EqnTest ( "1>0 ? 1>0 ? 128 : 255 :(1>2 ? 32 : 64)", 128, true ); - iStat += EqnTest ( "1>2 ? 1>2 ? 128 : 255 : 1>0 ? 32 : 64", 32, true ); - iStat += EqnTest ( "1>2 ? 1>0 ? 128 : 255 : 1>2 ? 32 : 64", 64, true ); - iStat += EqnTest ( "1>0 ? 50 : 1>0 ? 128 : 255", 50, true ); - iStat += EqnTest ( "1>0 ? 50 : (1>0 ? 128 : 255)", 50, true ); - iStat += EqnTest ( "1>0 ? 1>0 ? 128 : 255 : 50", 128, true ); - iStat += EqnTest ( "1>2 ? 1>2 ? 128 : 255 : 1>0 ? 32 : 1>2 ? 64 : 16", 32, true ); - iStat += EqnTest ( "1>2 ? 1>2 ? 128 : 255 : 1>0 ? 32 :(1>2 ? 64 : 16)", 32, true ); - iStat += EqnTest ( "1>0 ? 1>2 ? 128 : 255 : 1>0 ? 32 :1>2 ? 64 : 16", 255, true ); - iStat += EqnTest ( "1>0 ? 1>2 ? 128 : 255 : (1>0 ? 32 :1>2 ? 64 : 16)", 255, true ); - iStat += EqnTest ( "1 ? 0 ? 128 : 255 : 1 ? 32 : 64", 255, true ); + iStat += EqnTest ( "1>0 ? 1>2 ? 128 : 255 : 1>0 ? 32 : 64", 255, true ); + iStat += EqnTest ( "1>0 ? 1>2 ? 128 : 255 :(1>0 ? 32 : 64)", 255, true ); + iStat += EqnTest ( "1>0 ? 1>0 ? 128 : 255 : 1>2 ? 32 : 64", 128, true ); + iStat += EqnTest ( "1>0 ? 1>0 ? 128 : 255 :(1>2 ? 32 : 64)", 128, true ); + iStat += EqnTest ( "1>2 ? 1>2 ? 128 : 255 : 1>0 ? 32 : 64", 32, true ); + iStat += EqnTest ( "1>2 ? 1>0 ? 128 : 255 : 1>2 ? 32 : 64", 64, true ); + iStat += EqnTest ( "1>0 ? 50 : 1>0 ? 128 : 255", 50, true ); + iStat += EqnTest ( "1>0 ? 50 : (1>0 ? 128 : 255)", 50, true ); + iStat += EqnTest ( "1>0 ? 1>0 ? 128 : 255 : 50", 128, true ); + iStat += EqnTest ( "1>2 ? 1>2 ? 128 : 255 : 1>0 ? 32 : 1>2 ? 64 : 16", 32, true ); + iStat += EqnTest ( "1>2 ? 1>2 ? 128 : 255 : 1>0 ? 32 :(1>2 ? 64 : 16)", 32, true ); + iStat += EqnTest ( "1>0 ? 1>2 ? 128 : 255 : 1>0 ? 32 :1>2 ? 64 : 16", 255, true ); + iStat += EqnTest ( "1>0 ? 1>2 ? 128 : 255 : (1>0 ? 32 :1>2 ? 64 : 16)", 255, true ); + iStat += EqnTest ( "1 ? 0 ? 128 : 255 : 1 ? 32 : 64", 255, true ); - // assignment operators - iStat += EqnTest ( "a= 0 ? 128 : 255, a", 255, true ); - iStat += EqnTest ( "a=((a>b)&&(ab)&&(a - // this is now legal, for reference see: - // https://sourceforge.net/forum/message.php?msg_id=7411373 - // iStat += ThrowTest( "sin=9"), ecUNEXPECTED_OPERATOR); - //
+ // + // this is now legal, for reference see: + // https://sourceforge.net/forum/message.php?msg_id=7411373 + // iStat += ThrowTest( "sin=9"), ecUNEXPECTED_OPERATOR); + // - iStat += ThrowTest ( "(8)=5", ecUNEXPECTED_OPERATOR ); - iStat += ThrowTest ( "(a)=5", ecUNEXPECTED_OPERATOR ); - iStat += ThrowTest ( "a=\"tttt\"", ecOPRT_TYPE_CONFLICT ); + iStat += ThrowTest ( "(8)=5", ecUNEXPECTED_OPERATOR ); + iStat += ThrowTest ( "(a)=5", ecUNEXPECTED_OPERATOR ); + iStat += ThrowTest ( "a=\"tttt\"", ecOPRT_TYPE_CONFLICT ); - if ( iStat == 0 ) - { - qDebug() << "passed" ; - } - else - { - qDebug() << "\n failed with " << iStat << " errors" ; - } + if ( iStat == 0 ) + { + qDebug() << "passed"; + } + else + { + qDebug() << "\n failed with " << iStat << " errors"; + } - return iStat; + return iStat; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- void QmuParserTester::AddTest ( testfun_type a_pFun ) { - m_vTestFun.push_back ( a_pFun ); + m_vTestFun.push_back ( a_pFun ); } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- void QmuParserTester::Run() { - int iStat = 0; - try - { - for ( int i = 0; i < m_vTestFun.size(); ++i ) - { - iStat += ( this->*m_vTestFun[i] ) (); - } - } - catch ( QmuParser::exception_type &e ) - { - qDebug() << "\n" << e.GetMsg() ; - qDebug() << e.GetToken() ; - Abort(); - } - catch ( std::exception &e ) - { - qDebug() << e.what() ; - Abort(); - } - catch ( ... ) - { - qDebug() << "Internal error"; - Abort(); - } + int iStat = 0; + try + { + for ( int i = 0; i < m_vTestFun.size(); ++i ) + { + iStat += ( this->*m_vTestFun[i] ) (); + } + } + catch ( QmuParser::exception_type &e ) + { + qDebug() << "\n" << e.GetMsg(); + qDebug() << e.GetToken(); + Abort(); + } + catch ( std::exception &e ) + { + qDebug() << e.what(); + Abort(); + } + catch ( ... ) + { + qDebug() << "Internal error"; + Abort(); + } - if ( iStat == 0 ) - { - qDebug() << "Test passed (" << QmuParserTester::c_iCount << " expressions)" ; - } - else - { - qDebug() << "Test failed with " << iStat - << " errors (" << QmuParserTester::c_iCount - << " expressions)" ; - } - QmuParserTester::c_iCount = 0; + if ( iStat == 0 ) + { + qDebug() << "Test passed (" << QmuParserTester::c_iCount << " expressions)"; + } + else + { + qDebug() << "Test failed with " << iStat + << " errors (" << QmuParserTester::c_iCount + << " expressions)"; + } + QmuParserTester::c_iCount = 0; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- int QmuParserTester::ThrowTest ( const QString &a_str, int a_iErrc, bool a_bFail ) { - QmuParserTester::c_iCount++; + QmuParserTester::c_iCount++; - try - { - qreal fVal[] = {1, 1, 1}; - QmuParser p; + try + { + qreal fVal[] = {1, 1, 1}; + QmuParser p; - p.DefineVar ( "a", &fVal[0] ); - p.DefineVar ( "b", &fVal[1] ); - p.DefineVar ( "c", &fVal[2] ); - p.DefinePostfixOprt ( "{m}", Milli ); - p.DefinePostfixOprt ( "m", Milli ); - p.DefineFun ( "ping", Ping ); - p.DefineFun ( "valueof", ValueOf ); - p.DefineFun ( "strfun1", StrFun1 ); - p.DefineFun ( "strfun2", StrFun2 ); - p.DefineFun ( "strfun3", StrFun3 ); - p.SetExpr ( a_str ); - p.Eval(); - } - catch ( QmuParserError &e ) - { - // output the formula in case of an failed test - if ( a_bFail == false || ( a_bFail == true && a_iErrc != e.GetCode() ) ) - { - qDebug() << "\n " - << "Expression: " << a_str - << " Code:" << e.GetCode() << "(" << e.GetMsg() << ")" - << " Expected:" << a_iErrc; - } + p.DefineVar ( "a", &fVal[0] ); + p.DefineVar ( "b", &fVal[1] ); + p.DefineVar ( "c", &fVal[2] ); + p.DefinePostfixOprt ( "{m}", Milli ); + p.DefinePostfixOprt ( "m", Milli ); + p.DefineFun ( "ping", Ping ); + p.DefineFun ( "valueof", ValueOf ); + p.DefineFun ( "strfun1", StrFun1 ); + p.DefineFun ( "strfun2", StrFun2 ); + p.DefineFun ( "strfun3", StrFun3 ); + p.SetExpr ( a_str ); + p.Eval(); + } + catch ( QmuParserError &e ) + { + // output the formula in case of an failed test + if ( a_bFail == false || ( a_bFail == true && a_iErrc != e.GetCode() ) ) + { + qDebug() << "\n " + << "Expression: " << a_str + << " Code:" << e.GetCode() << "(" << e.GetMsg() << ")" + << " Expected:" << a_iErrc; + } - return ( a_iErrc == e.GetCode() ) ? 0 : 1; - } + return ( a_iErrc == e.GetCode() ) ? 0 : 1; + } - // if a_bFail==false no exception is expected - bool bRet ( ( a_bFail == false ) ? 0 : 1 ); - if ( bRet == 1 ) - { - qDebug() << "\n " - << "Expression: " << a_str - << " did evaluate; Expected error:" << a_iErrc; - } + // if a_bFail==false no exception is expected + bool bRet ( ( a_bFail == false ) ? 0 : 1 ); + if ( bRet == 1 ) + { + qDebug() << "\n " + << "Expression: " << a_str + << " did evaluate; Expected error:" << a_iErrc; + } - return bRet; + return bRet; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Evaluate a tet expression. * * @return 1 in case of a failure, 0 otherwise. */ int QmuParserTester::EqnTestWithVarChange ( const QString &a_str, double a_fVar1, double a_fRes1, double a_fVar2, - double a_fRes2 ) + double a_fRes2 ) { - QmuParserTester::c_iCount++; - qreal fVal[2] = { -999, -999 }; // should be equalinitially + QmuParserTester::c_iCount++; + qreal fVal[2] = { -999, -999 }; // should be equalinitially - try - { - QmuParser p; + try + { + QmuParser p; - // variable - qreal var = 0; - p.DefineVar ( "a", &var ); - p.SetExpr ( a_str ); + // variable + qreal var = 0; + p.DefineVar ( "a", &var ); + p.SetExpr ( a_str ); - var = a_fVar1; - fVal[0] = p.Eval(); + var = a_fVar1; + fVal[0] = p.Eval(); - var = a_fVar2; - fVal[1] = p.Eval(); + var = a_fVar2; + fVal[1] = p.Eval(); - if ( fabs ( a_fRes1 - fVal[0] ) > 0.0000000001 ) - { - throw std::runtime_error ( "incorrect result (first pass)" ); - } + if ( fabs ( a_fRes1 - fVal[0] ) > 0.0000000001 ) + { + throw std::runtime_error ( "incorrect result (first pass)" ); + } - if ( fabs ( a_fRes2 - fVal[1] ) > 0.0000000001 ) - { - throw std::runtime_error ( "incorrect result (second pass)" ); - } - } - catch ( QmuParser::exception_type &e ) - { - qDebug() << "\n fail: " << a_str << " (" << e.GetMsg() << ")"; - return 1; - } - catch ( std::exception &e ) - { - qDebug() << "\n fail: " << a_str << " (" << e.what() << ")"; - return 1; // always return a failure since this exception is not expected - } - catch ( ... ) - { - qDebug() << "\n fail: " << a_str << " (unexpected exception)"; - return 1; // exceptions other than ParserException are not allowed - } + if ( fabs ( a_fRes2 - fVal[1] ) > 0.0000000001 ) + { + throw std::runtime_error ( "incorrect result (second pass)" ); + } + } + catch ( QmuParser::exception_type &e ) + { + qDebug() << "\n fail: " << a_str << " (" << e.GetMsg() << ")"; + return 1; + } + catch ( std::exception &e ) + { + qDebug() << "\n fail: " << a_str << " (" << e.what() << ")"; + return 1; // always return a failure since this exception is not expected + } + catch ( ... ) + { + qDebug() << "\n fail: " << a_str << " (unexpected exception)"; + return 1; // exceptions other than ParserException are not allowed + } - return 0; + return 0; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Evaluate a tet expression. * @@ -1221,196 +1219,196 @@ int QmuParserTester::EqnTestWithVarChange ( const QString &a_str, double a_fVar1 */ int QmuParserTester::EqnTest ( const QString &a_str, double a_fRes, bool a_fPass ) { - QmuParserTester::c_iCount++; - int iRet ( 0 ); - qreal fVal[5] = { -999, -998, -997, -996, -995}; // initially should be different + QmuParserTester::c_iCount++; + int iRet ( 0 ); + qreal fVal[5] = { -999, -998, -997, -996, -995}; // initially should be different - try - { - std::unique_ptr p1; - QmuParser p2, p3; // three parser objects - // they will be used for testing copy and assihnment operators - // p1 is a pointer since i'm going to delete it in order to test if - // parsers after copy construction still refer to members of it. - // !! If this is the case this function will crash !! + try + { + std::unique_ptr p1; + QmuParser p2, p3; // three parser objects + // they will be used for testing copy and assihnment operators + // p1 is a pointer since i'm going to delete it in order to test if + // parsers after copy construction still refer to members of it. + // !! If this is the case this function will crash !! - p1.reset ( new qmu::QmuParser() ); - // Add constants - p1->DefineConst ( "pi", ( qreal ) M_PI ); - p1->DefineConst ( "e", ( qreal ) M_E ); - p1->DefineConst ( "const", 1 ); - p1->DefineConst ( "const1", 2 ); - p1->DefineConst ( "const2", 3 ); - // variables - qreal vVarVal[] = { 1, 2, 3, -2}; - p1->DefineVar ( "a", &vVarVal[0] ); - p1->DefineVar ( "aa", &vVarVal[1] ); - p1->DefineVar ( "b", &vVarVal[1] ); - p1->DefineVar ( "c", &vVarVal[2] ); - p1->DefineVar ( "d", &vVarVal[3] ); + p1.reset ( new qmu::QmuParser() ); + // Add constants + p1->DefineConst ( "pi", ( qreal ) M_PI ); + p1->DefineConst ( "e", ( qreal ) M_E ); + p1->DefineConst ( "const", 1 ); + p1->DefineConst ( "const1", 2 ); + p1->DefineConst ( "const2", 3 ); + // variables + qreal vVarVal[] = { 1, 2, 3, -2}; + p1->DefineVar ( "a", &vVarVal[0] ); + p1->DefineVar ( "aa", &vVarVal[1] ); + p1->DefineVar ( "b", &vVarVal[1] ); + p1->DefineVar ( "c", &vVarVal[2] ); + p1->DefineVar ( "d", &vVarVal[3] ); - // custom value ident functions - p1->AddValIdent ( &QmuParserTester::IsHexVal ); + // custom value ident functions + p1->AddValIdent ( &QmuParserTester::IsHexVal ); - // functions - p1->DefineFun ( "ping", Ping ); - p1->DefineFun ( "f1of1", f1of1 ); // one parameter - p1->DefineFun ( "f1of2", f1of2 ); // two parameter - p1->DefineFun ( "f2of2", f2of2 ); - p1->DefineFun ( "f1of3", f1of3 ); // three parameter - p1->DefineFun ( "f2of3", f2of3 ); - p1->DefineFun ( "f3of3", f3of3 ); - p1->DefineFun ( "f1of4", f1of4 ); // four parameter - p1->DefineFun ( "f2of4", f2of4 ); - p1->DefineFun ( "f3of4", f3of4 ); - p1->DefineFun ( "f4of4", f4of4 ); - p1->DefineFun ( "f1of5", f1of5 ); // five parameter - p1->DefineFun ( "f2of5", f2of5 ); - p1->DefineFun ( "f3of5", f3of5 ); - p1->DefineFun ( "f4of5", f4of5 ); - p1->DefineFun ( "f5of5", f5of5 ); + // functions + p1->DefineFun ( "ping", Ping ); + p1->DefineFun ( "f1of1", f1of1 ); // one parameter + p1->DefineFun ( "f1of2", f1of2 ); // two parameter + p1->DefineFun ( "f2of2", f2of2 ); + p1->DefineFun ( "f1of3", f1of3 ); // three parameter + p1->DefineFun ( "f2of3", f2of3 ); + p1->DefineFun ( "f3of3", f3of3 ); + p1->DefineFun ( "f1of4", f1of4 ); // four parameter + p1->DefineFun ( "f2of4", f2of4 ); + p1->DefineFun ( "f3of4", f3of4 ); + p1->DefineFun ( "f4of4", f4of4 ); + p1->DefineFun ( "f1of5", f1of5 ); // five parameter + p1->DefineFun ( "f2of5", f2of5 ); + p1->DefineFun ( "f3of5", f3of5 ); + p1->DefineFun ( "f4of5", f4of5 ); + p1->DefineFun ( "f5of5", f5of5 ); - // binary operators - p1->DefineOprt ( "add", add, 0 ); - p1->DefineOprt ( "++", add, 0 ); - p1->DefineOprt ( "&", land, prLAND ); + // binary operators + p1->DefineOprt ( "add", add, 0 ); + p1->DefineOprt ( "++", add, 0 ); + p1->DefineOprt ( "&", land, prLAND ); - // sample functions - p1->DefineFun ( "min", Min ); - p1->DefineFun ( "max", Max ); - p1->DefineFun ( "sum", Sum ); - p1->DefineFun ( "valueof", ValueOf ); - p1->DefineFun ( "atof", StrToFloat ); - p1->DefineFun ( "strfun1", StrFun1 ); - p1->DefineFun ( "strfun2", StrFun2 ); - p1->DefineFun ( "strfun3", StrFun3 ); - p1->DefineFun ( "lastArg", LastArg ); - p1->DefineFun ( "firstArg", FirstArg ); - p1->DefineFun ( "order", FirstArg ); + // sample functions + p1->DefineFun ( "min", Min ); + p1->DefineFun ( "max", Max ); + p1->DefineFun ( "sum", Sum ); + p1->DefineFun ( "valueof", ValueOf ); + p1->DefineFun ( "atof", StrToFloat ); + p1->DefineFun ( "strfun1", StrFun1 ); + p1->DefineFun ( "strfun2", StrFun2 ); + p1->DefineFun ( "strfun3", StrFun3 ); + p1->DefineFun ( "lastArg", LastArg ); + p1->DefineFun ( "firstArg", FirstArg ); + p1->DefineFun ( "order", FirstArg ); - // infix / postfix operator - // Note: Identifiers used here do not have any meaning - // they are mere placeholders to test certain features. - p1->DefineInfixOprt ( "$", sign, prPOW + 1 ); // sign with high priority - p1->DefineInfixOprt ( "~", plus2 ); // high priority - p1->DefineInfixOprt ( "~~", plus2 ); - p1->DefinePostfixOprt ( "{m}", Milli ); - p1->DefinePostfixOprt ( "{M}", Mega ); - p1->DefinePostfixOprt ( "m", Milli ); - p1->DefinePostfixOprt ( "meg", Mega ); - p1->DefinePostfixOprt ( "#", times3 ); - p1->DefinePostfixOprt ( "'", sqr ); - p1->SetExpr ( a_str ); + // infix / postfix operator + // Note: Identifiers used here do not have any meaning + // they are mere placeholders to test certain features. + p1->DefineInfixOprt ( "$", sign, prPOW + 1 ); // sign with high priority + p1->DefineInfixOprt ( "~", plus2 ); // high priority + p1->DefineInfixOprt ( "~~", plus2 ); + p1->DefinePostfixOprt ( "{m}", Milli ); + p1->DefinePostfixOprt ( "{M}", Mega ); + p1->DefinePostfixOprt ( "m", Milli ); + p1->DefinePostfixOprt ( "meg", Mega ); + p1->DefinePostfixOprt ( "#", times3 ); + p1->DefinePostfixOprt ( "'", sqr ); + p1->SetExpr ( a_str ); - // Test bytecode integrity - // String parsing and bytecode parsing must yield the same result - fVal[0] = p1->Eval(); // result from stringparsing - fVal[1] = p1->Eval(); // result from bytecode - if ( qFuzzyCompare( fVal[0], fVal[1] ) == false ) - { - throw QmuParser::exception_type ( "Bytecode / string parsing mismatch." ); - } + // Test bytecode integrity + // String parsing and bytecode parsing must yield the same result + fVal[0] = p1->Eval(); // result from stringparsing + fVal[1] = p1->Eval(); // result from bytecode + if ( qFuzzyCompare( fVal[0], fVal[1] ) == false ) + { + throw QmuParser::exception_type ( "Bytecode / string parsing mismatch." ); + } - // Test copy and assignement operators - try - { - // Test copy constructor - QVector vParser; - vParser.push_back ( * ( p1.get() ) ); - qmu::QmuParser p2 = vParser[0]; // take parser from vector + // Test copy and assignement operators + try + { + // Test copy constructor + QVector vParser; + vParser.push_back ( * ( p1.get() ) ); + qmu::QmuParser p2 = vParser[0]; // take parser from vector - // destroy the originals from p2 - vParser.clear(); // delete the vector - p1.reset ( 0 ); + // destroy the originals from p2 + vParser.clear(); // delete the vector + p1.reset ( 0 ); - fVal[2] = p2.Eval(); + fVal[2] = p2.Eval(); - // Test assignement operator - // additionally disable Optimizer this time - qmu::QmuParser p3; - p3 = p2; - p3.EnableOptimizer ( false ); - fVal[3] = p3.Eval(); + // Test assignement operator + // additionally disable Optimizer this time + qmu::QmuParser p3; + p3 = p2; + p3.EnableOptimizer ( false ); + fVal[3] = p3.Eval(); - // Test Eval function for multiple return values - // use p2 since it has the optimizer enabled! - int nNum; - qreal *v = p2.Eval ( nNum ); - fVal[4] = v[nNum - 1]; - } - catch ( std::exception &e ) - { - qDebug() << "\n " << e.what() << "\n"; - } + // Test Eval function for multiple return values + // use p2 since it has the optimizer enabled! + int nNum; + qreal *v = p2.Eval ( nNum ); + fVal[4] = v[nNum - 1]; + } + catch ( std::exception &e ) + { + qDebug() << "\n " << e.what() << "\n"; + } - // limited floating point accuracy requires the following test - bool bCloseEnough ( true ); - for ( unsigned i = 0; i < sizeof ( fVal ) / sizeof ( qreal ); ++i ) - { - bCloseEnough &= ( fabs ( a_fRes - fVal[i] ) <= fabs ( fVal[i] * 0.00001 ) ); + // limited floating point accuracy requires the following test + bool bCloseEnough ( true ); + for ( unsigned i = 0; i < sizeof ( fVal ) / sizeof ( qreal ); ++i ) + { + bCloseEnough &= ( fabs ( a_fRes - fVal[i] ) <= fabs ( fVal[i] * 0.00001 ) ); - // The tests equations never result in infinity, if they do thats a bug. - // reference: - // http://sourceforge.net/projects/muparser/forums/forum/462843/topic/5037825 - if ( numeric_limits::has_infinity ) - { - bCloseEnough &= (qFuzzyCompare( fabs ( fVal[i] ), numeric_limits::infinity())==false ); - } - } + // The tests equations never result in infinity, if they do thats a bug. + // reference: + // http://sourceforge.net/projects/muparser/forums/forum/462843/topic/5037825 + if ( numeric_limits::has_infinity ) + { + bCloseEnough &= (qFuzzyCompare( fabs ( fVal[i] ), numeric_limits::infinity())==false ); + } + } - iRet = ( ( bCloseEnough && a_fPass ) || ( !bCloseEnough && !a_fPass ) ) ? 0 : 1; + iRet = ( ( bCloseEnough && a_fPass ) || ( bCloseEnough == false && a_fPass == false) ) ? 0 : 1; - if ( iRet == 1 ) - { - qDebug() << "\n fail: " << a_str - << " (incorrect result; expected: " << a_fRes - << " ;calculated: " << fVal[0] << "," - << fVal[1] << "," - << fVal[2] << "," - << fVal[3] << "," - << fVal[4] << ")."; - } - } - catch ( QmuParser::exception_type &e ) - { - if ( a_fPass ) - { - if ( (qFuzzyCompare(fVal[0], fVal[2])==false) && (qFuzzyCompare(fVal[0], -999)==false) && - (qFuzzyCompare(fVal[1], -998 )==false)) - { - qDebug() << "\n fail: " << a_str << " (copy construction)"; - } - else - { - qDebug() << "\n fail: " << a_str << " (" << e.GetMsg() << ")"; - } - return 1; - } - } - catch ( std::exception &e ) - { - qDebug() << "\n fail: " << a_str << " (" << e.what() << ")"; - return 1; // always return a failure since this exception is not expected - } - catch ( ... ) - { - qDebug() << "\n fail: " << a_str << " (unexpected exception)"; - return 1; // exceptions other than ParserException are not allowed - } + if ( iRet == 1 ) + { + qDebug() << "\n fail: " << a_str + << " (incorrect result; expected: " << a_fRes + << " ;calculated: " << fVal[0] << "," + << fVal[1] << "," + << fVal[2] << "," + << fVal[3] << "," + << fVal[4] << ")."; + } + } + catch ( QmuParser::exception_type &e ) + { + if ( a_fPass ) + { + if ( (qFuzzyCompare(fVal[0], fVal[2])==false) && (qFuzzyCompare(fVal[0], -999)==false) && + (qFuzzyCompare(fVal[1], -998 )==false)) + { + qDebug() << "\n fail: " << a_str << " (copy construction)"; + } + else + { + qDebug() << "\n fail: " << a_str << " (" << e.GetMsg() << ")"; + } + return 1; + } + } + catch ( std::exception &e ) + { + qDebug() << "\n fail: " << a_str << " (" << e.what() << ")"; + return 1; // always return a failure since this exception is not expected + } + catch ( ... ) + { + qDebug() << "\n fail: " << a_str << " (unexpected exception)"; + return 1; // exceptions other than ParserException are not allowed + } - return iRet; + return iRet; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Internal error in test class Test is going to be aborted. */ void Q_NORETURN QmuParserTester::Abort() const { - qDebug() << "Test failed (internal error in test class)" ; - while ( !getchar() ); - exit ( -1 ); + qDebug() << "Test failed (internal error in test class)"; + while ( getchar() == false); + exit ( -1 ); } } // namespace test } // namespace qmu diff --git a/src/libs/qmuparser/qmuparsertest.h b/src/libs/qmuparser/qmuparsertest.h index aaf5ab48d..648e6fb9c 100644 --- a/src/libs/qmuparser/qmuparsertest.h +++ b/src/libs/qmuparser/qmuparsertest.h @@ -41,7 +41,7 @@ namespace qmu */ namespace Test { -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Test cases for unit testing. * @@ -50,253 +50,251 @@ namespace Test class QmuParserTester // final { public: - typedef int ( QmuParserTester::*testfun_type ) (); + typedef int ( QmuParserTester::*testfun_type ) (); - QmuParserTester(); - void Run(); + QmuParserTester(); + void Run(); private: - QVector m_vTestFun; - static int c_iCount; + QVector m_vTestFun; + static int c_iCount; - void AddTest ( testfun_type a_pFun ); + void AddTest ( testfun_type a_pFun ); - // Test Double Parser - int EqnTest ( const QString &a_str, double a_fRes, bool a_fPass ); - int EqnTestWithVarChange ( const QString &a_str, double a_fRes1, double a_fVar1, double a_fRes2, double a_fVar2 ); - int ThrowTest ( const QString &a_str, int a_iErrc, bool a_bFail = true ); + // Test Double Parser + int EqnTest ( const QString &a_str, double a_fRes, bool a_fPass ); + int EqnTestWithVarChange ( const QString &a_str, double a_fRes1, double a_fVar1, double a_fRes2, double a_fVar2 ); + int ThrowTest ( const QString &a_str, int a_iErrc, bool a_bFail = true ); - // Multiarg callbacks - static qreal f1of1 ( qreal v ) - { - return v; - } + // Multiarg callbacks + static qreal f1of1 ( qreal v ) + { + return v; + } - static qreal f1of2 ( qreal v, qreal ) - { - return v; - } + static qreal f1of2 ( qreal v, qreal ) + { + return v; + } - static qreal f2of2 ( qreal , qreal v ) - { - return v; - } + static qreal f2of2 ( qreal, qreal v ) + { + return v; + } - static qreal f1of3 ( qreal v, qreal , qreal ) - { - return v; - } + static qreal f1of3 ( qreal v, qreal, qreal ) + { + return v; + } - static qreal f2of3 ( qreal , qreal v, qreal ) - { - return v; - } + static qreal f2of3 ( qreal, qreal v, qreal ) + { + return v; + } - static qreal f3of3 ( qreal , qreal , qreal v ) - { - return v; - } + static qreal f3of3 ( qreal, qreal, qreal v ) + { + return v; + } - static qreal f1of4 ( qreal v, qreal, qreal , qreal ) - { - return v; - } + static qreal f1of4 ( qreal v, qreal, qreal, qreal ) + { + return v; + } - static qreal f2of4 ( qreal , qreal v, qreal , qreal ) - { - return v; - } + static qreal f2of4 ( qreal, qreal v, qreal, qreal ) + { + return v; + } - static qreal f3of4 ( qreal , qreal, qreal v, qreal ) - { - return v; - } + static qreal f3of4 ( qreal, qreal, qreal v, qreal ) + { + return v; + } - static qreal f4of4 ( qreal , qreal, qreal , qreal v ) - { - return v; - } + static qreal f4of4 ( qreal, qreal, qreal, qreal v ) + { + return v; + } - static qreal f1of5 ( qreal v, qreal, qreal , qreal , qreal ) - { - return v; - } + static qreal f1of5 ( qreal v, qreal, qreal, qreal, qreal ) + { + return v; + } - static qreal f2of5 ( qreal , qreal v, qreal , qreal , qreal ) - { - return v; - } + static qreal f2of5 ( qreal, qreal v, qreal, qreal, qreal ) + { + return v; + } - static qreal f3of5 ( qreal , qreal, qreal v, qreal , qreal ) - { - return v; - } + static qreal f3of5 ( qreal, qreal, qreal v, qreal, qreal ) + { + return v; + } - static qreal f4of5 ( qreal , qreal, qreal , qreal v, qreal ) - { - return v; - } + static qreal f4of5 ( qreal, qreal, qreal, qreal v, qreal ) + { + return v; + } - static qreal f5of5 ( qreal , qreal, qreal , qreal , qreal v ) - { - return v; - } + static qreal f5of5 ( qreal, qreal, qreal, qreal, qreal v ) + { + return v; + } - static qreal Min ( qreal a_fVal1, qreal a_fVal2 ) - { - return ( a_fVal1 < a_fVal2 ) ? a_fVal1 : a_fVal2; - } + static qreal Min ( qreal a_fVal1, qreal a_fVal2 ) + { + return ( a_fVal1 < a_fVal2 ) ? a_fVal1 : a_fVal2; + } - static qreal Max ( qreal a_fVal1, qreal a_fVal2 ) - { - return ( a_fVal1 > a_fVal2 ) ? a_fVal1 : a_fVal2; - } + static qreal Max ( qreal a_fVal1, qreal a_fVal2 ) + { + return ( a_fVal1 > a_fVal2 ) ? a_fVal1 : a_fVal2; + } - static qreal plus2 ( qreal v1 ) - { - return v1 + 2; - } + static qreal plus2 ( qreal v1 ) + { + return v1 + 2; + } - static qreal times3 ( qreal v1 ) - { - return v1 * 3; - } + static qreal times3 ( qreal v1 ) + { + return v1 * 3; + } - static qreal sqr ( qreal v1 ) - { - return v1 * v1; - } + static qreal sqr ( qreal v1 ) + { + return v1 * v1; + } - static qreal sign ( qreal v ) - { - return -v; - } + static qreal sign ( qreal v ) + { + return -v; + } - static qreal add ( qreal v1, qreal v2 ) - { - return v1 + v2; - } + static qreal add ( qreal v1, qreal v2 ) + { + return v1 + v2; + } - static qreal land ( qreal v1, qreal v2 ) - { - return static_cast( v1 ) & static_cast( v2 ); - } + static qreal land ( qreal v1, qreal v2 ) + { + return static_cast( v1 ) & static_cast( v2 ); + } - static qreal FirstArg ( const qreal* a_afArg, int a_iArgc ) - { - if ( !a_iArgc ) - { - throw qmu::QmuParser::exception_type ( "too few arguments for function FirstArg." ); - } + static qreal FirstArg ( const qreal* a_afArg, int a_iArgc ) + { + if ( a_iArgc == false) + { + throw qmu::QmuParser::exception_type ( "too few arguments for function FirstArg." ); + } - return a_afArg[0]; - } + return a_afArg[0]; + } - static qreal LastArg ( const qreal* a_afArg, int a_iArgc ) - { - if ( !a_iArgc ) - { - throw qmu::QmuParser::exception_type ( "too few arguments for function LastArg." ); - } + static qreal LastArg ( const qreal* a_afArg, int a_iArgc ) + { + if ( a_iArgc == false) + { + throw qmu::QmuParser::exception_type ( "too few arguments for function LastArg." ); + } - return a_afArg[a_iArgc - 1]; - } + return a_afArg[a_iArgc - 1]; + } - static qreal Sum ( const qreal* a_afArg, int a_iArgc ) - { - if ( !a_iArgc ) - { - throw qmu::QmuParser::exception_type ( "too few arguments for function sum." ); - } + static qreal Sum ( const qreal* a_afArg, int a_iArgc ) + { + if ( a_iArgc == false) + { + throw qmu::QmuParser::exception_type ( "too few arguments for function sum." ); + } - qreal fRes = 0; - for ( int i = 0; i < a_iArgc; ++i ) - { - fRes += a_afArg[i]; - } - return fRes; - } + qreal fRes = 0; + for ( int i = 0; i < a_iArgc; ++i ) + { + fRes += a_afArg[i]; + } + return fRes; + } - static qreal Rnd ( qreal v ) - { - return static_cast( ( 1 + ( v * qrand() / ( RAND_MAX + 1.0 ) ) ) ); - } + static qreal Rnd ( qreal v ) + { + return static_cast( ( 1 + ( v * qrand() / ( RAND_MAX + 1.0 ) ) ) ); + } - static qreal RndWithString ( const char_type* ) - { - return static_cast( ( 1 + ( 1000.0f * static_cast(qrand()) / ( RAND_MAX + 1.0 ) ) ) ); - } + static qreal RndWithString ( const char_type* ) + { + return static_cast( ( 1 + ( 1000.0f * static_cast(qrand()) / ( RAND_MAX + 1.0 ) ) ) ); + } - static qreal Ping() - { - return 10; - } + static qreal Ping() + { + return 10; + } - static qreal ValueOf ( const QString & ) - { - return 123; - } + static qreal ValueOf ( const QString & ) + { + return 123; + } - static qreal StrFun1 ( const QString & v1 ) - { - int val = v1.toInt(); - return static_cast(val); - } + static qreal StrFun1 ( const QString & v1 ) + { + int val = v1.toInt(); + return static_cast(val); + } - static qreal StrFun2 ( const QString & v1, qreal v2 ) - { - int val = v1.toInt(); - return static_cast( val + v2 ); - } + static qreal StrFun2 ( const QString & v1, qreal v2 ) + { + int val = v1.toInt(); + return static_cast( val + v2 ); + } - static qreal StrFun3 ( const QString & v1, qreal v2, qreal v3 ) - { - int val = v1.toInt(); - return val + v2 + v3; - } + static qreal StrFun3 ( const QString & v1, qreal v2, qreal v3 ) + { + int val = v1.toInt(); + return val + v2 + v3; + } - static qreal StrToFloat ( const QString & a_szMsg ) - { - qreal val = a_szMsg.toDouble(); - return val; - } + static qreal StrToFloat ( const QString & a_szMsg ) + { + qreal val = a_szMsg.toDouble(); + return val; + } - // postfix operator callback - static qreal Mega ( qreal a_fVal ) - { - return a_fVal * static_cast( 1e6 ); - } + // postfix operator callback + static qreal Mega ( qreal a_fVal ) + { + return a_fVal * static_cast( 1e6 ); + } - static qreal Micro ( qreal a_fVal ) - { - return a_fVal * static_cast( 1e-6 ); - } + static qreal Micro ( qreal a_fVal ) + { + return a_fVal * static_cast( 1e-6 ); + } - static qreal Milli ( qreal a_fVal ) - { - return a_fVal / static_cast( 1e3 ); - } + static qreal Milli ( qreal a_fVal ) + { + return a_fVal / static_cast( 1e3 ); + } - // Custom value recognition - static int IsHexVal ( const QString &a_szExpr, int *a_iPos, qreal *a_fVal ); + // Custom value recognition + static int IsHexVal ( const QString &a_szExpr, int *a_iPos, qreal *a_fVal ); - int TestNames(); - int TestSyntax(); - int TestMultiArg(); - int TestPostFix(); - int TestExpression(); - int TestInfixOprt(); - int TestBinOprt(); - int TestVarConst(); - int TestInterface(); - int TestException(); - int TestStrArg(); - int TestIfThenElse(); + int TestNames(); + int TestSyntax(); + int TestMultiArg(); + int TestPostFix(); + int TestExpression(); + int TestInfixOprt(); + int TestBinOprt(); + int TestVarConst(); + int TestInterface(); + int TestException(); + int TestStrArg(); + int TestIfThenElse(); - void Abort() const; + void Abort() const; }; } // namespace Test } // namespace qmu #endif - - diff --git a/src/libs/qmuparser/qmuparsertoken.h b/src/libs/qmuparser/qmuparsertoken.h index a1ef34a13..815de0194 100644 --- a/src/libs/qmuparser/qmuparsertoken.h +++ b/src/libs/qmuparser/qmuparsertoken.h @@ -50,7 +50,7 @@ namespace qmu *
  • functions with a string as argument
  • *
  • prefix operators
  • *
  • infix operators
  • - *
  • binary operator
  • + *
  • binary operator
  • * * * @author (C) 2004-2013 Ingo Berg @@ -59,458 +59,470 @@ template class QmuParserToken { public: - //--------------------------------------------------------------------------- - /** - * @brief Constructor (default). - * - * Sets token to an neutral state of type cmUNKNOWN. - * @throw nothrow - * @sa ECmdCode - */ - QmuParserToken() - : m_iCode ( cmUNKNOWN ), m_iType ( tpVOID ), m_pTok ( 0 ), m_iIdx ( -1 ), m_strTok(), m_strVal(), m_fVal(), - m_pCallback() - {} + //--------------------------------------------------------------------------- + /** + * @brief Constructor (default). + * + * Sets token to an neutral state of type cmUNKNOWN. + * @throw nothrow + * @sa ECmdCode + */ + QmuParserToken() + : m_iCode ( cmUNKNOWN ), m_iType ( tpVOID ), m_pTok ( 0 ), m_iIdx ( -1 ), m_strTok(), m_strVal(), m_fVal(), + m_pCallback() + {} - //------------------------------------------------------------------------------ - /** - * @brief Create token from another one. - * - * Implemented by calling Assign(...) - * @throw nothrow - * @post m_iType==cmUNKNOWN - * @sa #Assign - */ - QmuParserToken ( const QmuParserToken &a_Tok ) - : m_iCode ( a_Tok.m_iCode ), m_iType ( a_Tok.m_iType ), m_pTok ( a_Tok.m_pTok ), m_iIdx ( a_Tok.m_iIdx ), - m_strTok( a_Tok.m_strTok ), m_strVal(a_Tok.m_strVal), m_fVal(a_Tok.m_fVal), m_pCallback() - { - Assign ( a_Tok ); - } + //------------------------------------------------------------------------------ + /** + * @brief Create token from another one. + * + * Implemented by calling Assign(...) + * @throw nothrow + * @post m_iType==cmUNKNOWN + * @sa #Assign + */ + QmuParserToken ( const QmuParserToken &a_Tok ) + : m_iCode ( a_Tok.m_iCode ), m_iType ( a_Tok.m_iType ), m_pTok ( a_Tok.m_pTok ), m_iIdx ( a_Tok.m_iIdx ), + m_strTok( a_Tok.m_strTok ), m_strVal(a_Tok.m_strVal), m_fVal(a_Tok.m_fVal), m_pCallback() + { + Assign ( a_Tok ); + } - //------------------------------------------------------------------------------ - /** - * @brief Assignement operator. - * - * Copy token state from another token and return this. - * Implemented by calling Assign(...). - * @throw nothrow - */ - QmuParserToken& operator= ( const QmuParserToken &a_Tok ) - { - Assign ( a_Tok ); - return *this; - } + //------------------------------------------------------------------------------ + /** + * @brief Assignement operator. + * + * Copy token state from another token and return this. + * Implemented by calling Assign(...). + * @throw nothrow + */ + QmuParserToken& operator= ( const QmuParserToken &a_Tok ) + { + Assign ( a_Tok ); + return *this; + } - //------------------------------------------------------------------------------ - /** - * @brief Copy token information from argument. - * - * @throw nothrow - */ - void Assign ( const QmuParserToken &a_Tok ) - { - m_iCode = a_Tok.m_iCode; - m_pTok = a_Tok.m_pTok; - m_strTok = a_Tok.m_strTok; - m_iIdx = a_Tok.m_iIdx; - m_strVal = a_Tok.m_strVal; - m_iType = a_Tok.m_iType; - m_fVal = a_Tok.m_fVal; - // create new callback object if a_Tok has one - m_pCallback.reset ( a_Tok.m_pCallback.get() ? a_Tok.m_pCallback->Clone() : 0 ); - } + //------------------------------------------------------------------------------ + /** + * @brief Copy token information from argument. + * + * @throw nothrow + */ + void Assign ( const QmuParserToken &a_Tok ) + { + m_iCode = a_Tok.m_iCode; + m_pTok = a_Tok.m_pTok; + m_strTok = a_Tok.m_strTok; + m_iIdx = a_Tok.m_iIdx; + m_strVal = a_Tok.m_strVal; + m_iType = a_Tok.m_iType; + m_fVal = a_Tok.m_fVal; + // create new callback object if a_Tok has one + m_pCallback.reset ( a_Tok.m_pCallback.get() ? a_Tok.m_pCallback->Clone() : 0 ); + } - //------------------------------------------------------------------------------ - /** - * @brief Assign a token type. - * - * Token may not be of type value, variable or function. Those have seperate set functions. - * - * @pre [assert] a_iType!=cmVAR - * @pre [assert] a_iType!=cmVAL - * @pre [assert] a_iType!=cmFUNC - * @post m_fVal = 0 - * @post m_pTok = 0 - */ - QmuParserToken& Set ( ECmdCode a_iType, const TString &a_strTok = TString() ) - { - // The following types cant be set this way, they have special Set functions - assert ( a_iType != cmVAR ); - assert ( a_iType != cmVAL ); - assert ( a_iType != cmFUNC ); + //------------------------------------------------------------------------------ + /** + * @brief Assign a token type. + * + * Token may not be of type value, variable or function. Those have seperate set functions. + * + * @pre [assert] a_iType!=cmVAR + * @pre [assert] a_iType!=cmVAL + * @pre [assert] a_iType!=cmFUNC + * @post m_fVal = 0 + * @post m_pTok = 0 + */ + QmuParserToken& Set ( ECmdCode a_iType, const TString &a_strTok = TString() ) + { + // The following types cant be set this way, they have special Set functions + assert ( a_iType != cmVAR ); + assert ( a_iType != cmVAL ); + assert ( a_iType != cmFUNC ); - m_iCode = a_iType; - m_iType = tpVOID; - m_pTok = 0; - m_strTok = a_strTok; - m_iIdx = -1; + m_iCode = a_iType; + m_iType = tpVOID; + m_pTok = 0; + m_strTok = a_strTok; + m_iIdx = -1; - return *this; - } + return *this; + } - //------------------------------------------------------------------------------ - /** - * @brief Set Callback type. - */ - QmuParserToken& Set ( const QmuParserCallback &a_pCallback, const TString &a_sTok ) - { - assert ( a_pCallback.GetAddr() ); + //------------------------------------------------------------------------------ + /** + * @brief Set Callback type. + */ + QmuParserToken& Set ( const QmuParserCallback &a_pCallback, const TString &a_sTok ) + { + assert ( a_pCallback.GetAddr() ); - m_iCode = a_pCallback.GetCode(); - m_iType = tpVOID; - m_strTok = a_sTok; - m_pCallback.reset ( new QmuParserCallback ( a_pCallback ) ); + m_iCode = a_pCallback.GetCode(); + m_iType = tpVOID; + m_strTok = a_sTok; + m_pCallback.reset ( new QmuParserCallback ( a_pCallback ) ); - m_pTok = 0; - m_iIdx = -1; + m_pTok = 0; + m_iIdx = -1; - return *this; - } + return *this; + } - //------------------------------------------------------------------------------ - /** - * @brief Make this token a value token. - * - * Member variables not necessary for value tokens will be invalidated. - * @throw nothrow - */ - QmuParserToken& SetVal ( TBase a_fVal, const TString &a_strTok = TString() ) - { - m_iCode = cmVAL; - m_iType = tpDBL; - m_fVal = a_fVal; - m_strTok = a_strTok; - m_iIdx = -1; + //------------------------------------------------------------------------------ + /** + * @brief Make this token a value token. + * + * Member variables not necessary for value tokens will be invalidated. + * @throw nothrow + */ + QmuParserToken& SetVal ( TBase a_fVal, const TString &a_strTok = TString() ) + { + m_iCode = cmVAL; + m_iType = tpDBL; + m_fVal = a_fVal; + m_strTok = a_strTok; + m_iIdx = -1; - m_pTok = 0; - m_pCallback.reset ( 0 ); + m_pTok = 0; + m_pCallback.reset ( 0 ); - return *this; - } + return *this; + } - //------------------------------------------------------------------------------ - /** - * @brief make this token a variable token. - * - * Member variables not necessary for variable tokens will be invalidated. - * @throw nothrow - */ - QmuParserToken& SetVar ( TBase *a_pVar, const TString &a_strTok ) - { - m_iCode = cmVAR; - m_iType = tpDBL; - m_strTok = a_strTok; - m_iIdx = -1; - m_pTok = reinterpret_cast ( a_pVar ); - m_pCallback.reset ( 0 ); - return *this; - } + //------------------------------------------------------------------------------ + /** + * @brief make this token a variable token. + * + * Member variables not necessary for variable tokens will be invalidated. + * @throw nothrow + */ + QmuParserToken& SetVar ( TBase *a_pVar, const TString &a_strTok ) + { + m_iCode = cmVAR; + m_iType = tpDBL; + m_strTok = a_strTok; + m_iIdx = -1; + m_pTok = reinterpret_cast ( a_pVar ); + m_pCallback.reset ( 0 ); + return *this; + } - //------------------------------------------------------------------------------ - /** - * @brief Make this token a variable token. - * - * Member variables not necessary for variable tokens will be invalidated. - * @throw nothrow - */ - QmuParserToken& SetString ( const TString &a_strTok, std::size_t a_iSize ) - { - m_iCode = cmSTRING; - m_iType = tpSTR; - m_strTok = a_strTok; - m_iIdx = static_cast ( a_iSize ); + //------------------------------------------------------------------------------ + /** + * @brief Make this token a variable token. + * + * Member variables not necessary for variable tokens will be invalidated. + * @throw nothrow + */ + QmuParserToken& SetString ( const TString &a_strTok, std::size_t a_iSize ) + { + m_iCode = cmSTRING; + m_iType = tpSTR; + m_strTok = a_strTok; + m_iIdx = static_cast ( a_iSize ); - m_pTok = 0; - m_pCallback.reset ( 0 ); - return *this; - } + m_pTok = 0; + m_pCallback.reset ( 0 ); + return *this; + } - //------------------------------------------------------------------------------ - /** - * @brief Set an index associated with the token related data. - * - * In cmSTRFUNC - This is the index to a string table in the main parser. - * @param a_iIdx The index the string function result will take in the bytecode parser. - * @throw exception_type if #a_iIdx<0 or #m_iType!=cmSTRING - */ - void SetIdx ( int a_iIdx ) - { - if ( m_iCode != cmSTRING || a_iIdx < 0 ) - throw QmuParserError ( ecINTERNAL_ERROR ); + //------------------------------------------------------------------------------ + /** + * @brief Set an index associated with the token related data. + * + * In cmSTRFUNC - This is the index to a string table in the main parser. + * @param a_iIdx The index the string function result will take in the bytecode parser. + * @throw exception_type if #a_iIdx<0 or #m_iType!=cmSTRING + */ + void SetIdx ( int a_iIdx ) + { + if ( m_iCode != cmSTRING || a_iIdx < 0 ) + { + throw QmuParserError ( ecINTERNAL_ERROR ); + } - m_iIdx = a_iIdx; - } + m_iIdx = a_iIdx; + } - //------------------------------------------------------------------------------ - /** - * @brief Return Index associated with the token related data. - * - * In cmSTRFUNC - This is the index to a string table in the main parser. - * - * @throw exception_type if #m_iIdx<0 or #m_iType!=cmSTRING - * @return The index the result will take in the Bytecode calculatin array (#m_iIdx). - */ - int GetIdx() const - { - if ( m_iIdx < 0 || m_iCode != cmSTRING ) - throw QmuParserError ( ecINTERNAL_ERROR ); + //------------------------------------------------------------------------------ + /** + * @brief Return Index associated with the token related data. + * + * In cmSTRFUNC - This is the index to a string table in the main parser. + * + * @throw exception_type if #m_iIdx<0 or #m_iType!=cmSTRING + * @return The index the result will take in the Bytecode calculatin array (#m_iIdx). + */ + int GetIdx() const + { + if ( m_iIdx < 0 || m_iCode != cmSTRING ) + { + throw QmuParserError ( ecINTERNAL_ERROR ); + } - return m_iIdx; - } + return m_iIdx; + } - //------------------------------------------------------------------------------ - /** - * @brief Return the token type. - * - * @return #m_iType - * @throw nothrow - */ - ECmdCode GetCode() const - { - if ( m_pCallback.get() ) - { - return m_pCallback->GetCode(); - } - else - { - return m_iCode; - } - } + //------------------------------------------------------------------------------ + /** + * @brief Return the token type. + * + * @return #m_iType + * @throw nothrow + */ + ECmdCode GetCode() const + { + if ( m_pCallback.get() ) + { + return m_pCallback->GetCode(); + } + else + { + return m_iCode; + } + } - //------------------------------------------------------------------------------ - ETypeCode GetType() const - { - if ( m_pCallback.get() ) - { - return m_pCallback->GetType(); - } - else - { - return m_iType; - } - } + //------------------------------------------------------------------------------ + ETypeCode GetType() const + { + if ( m_pCallback.get() ) + { + return m_pCallback->GetType(); + } + else + { + return m_iType; + } + } - //------------------------------------------------------------------------------ - int GetPri() const - { - if ( !m_pCallback.get() ) - throw QmuParserError ( ecINTERNAL_ERROR ); + //------------------------------------------------------------------------------ + int GetPri() const + { + if ( m_pCallback.get() == false) + { + throw QmuParserError ( ecINTERNAL_ERROR ); + } - if ( m_pCallback->GetCode() != cmOPRT_BIN && m_pCallback->GetCode() != cmOPRT_INFIX ) - throw QmuParserError ( ecINTERNAL_ERROR ); + if ( m_pCallback->GetCode() != cmOPRT_BIN && m_pCallback->GetCode() != cmOPRT_INFIX ) + { + throw QmuParserError ( ecINTERNAL_ERROR ); + } - return m_pCallback->GetPri(); - } + return m_pCallback->GetPri(); + } - //------------------------------------------------------------------------------ - EOprtAssociativity GetAssociativity() const - { - if ( m_pCallback.get() == NULL || m_pCallback->GetCode() != cmOPRT_BIN ) - throw QmuParserError ( ecINTERNAL_ERROR ); + //------------------------------------------------------------------------------ + EOprtAssociativity GetAssociativity() const + { + if ( m_pCallback.get() == NULL || m_pCallback->GetCode() != cmOPRT_BIN ) + { + throw QmuParserError ( ecINTERNAL_ERROR ); + } - return m_pCallback->GetAssociativity(); - } + return m_pCallback->GetAssociativity(); + } - //------------------------------------------------------------------------------ - /** - * @brief Return the address of the callback function assoziated with function and operator tokens. - * - * @return The pointer stored in #m_pTok. - * @throw exception_type if token type is non of: - *
      - *
    • cmFUNC
    • - *
    • cmSTRFUNC
    • - *
    • cmPOSTOP
    • - *
    • cmINFIXOP
    • - *
    • cmOPRT_BIN
    • - *
    - * @sa ECmdCode - */ - generic_fun_type GetFuncAddr() const - { - return ( m_pCallback.get() ) ? reinterpret_cast ( m_pCallback->GetAddr() ) : - reinterpret_cast (0); - } + //------------------------------------------------------------------------------ + /** + * @brief Return the address of the callback function assoziated with function and operator tokens. + * + * @return The pointer stored in #m_pTok. + * @throw exception_type if token type is non of: + *
      + *
    • cmFUNC
    • + *
    • cmSTRFUNC
    • + *
    • cmPOSTOP
    • + *
    • cmINFIXOP
    • + *
    • cmOPRT_BIN
    • + *
    + * @sa ECmdCode + */ + generic_fun_type GetFuncAddr() const + { + return ( m_pCallback.get() ) ? reinterpret_cast ( m_pCallback->GetAddr() ) : + reinterpret_cast (0); + } - //------------------------------------------------------------------------------ - /** - * @brief Get value of the token. - * - * Only applicable to variable and value tokens. - * @throw exception_type if token is no value/variable token. - */ - TBase GetVal() const - { - switch ( m_iCode ) - { - case cmVAL: - return m_fVal; - case cmVAR: - return * ( reinterpret_cast(m_pTok) ); - case cmLE: - Q_UNREACHABLE(); - break; - case cmGE: - Q_UNREACHABLE(); - break; - case cmNEQ: - Q_UNREACHABLE(); - break; - case cmEQ: - Q_UNREACHABLE(); - break; - case cmLT: - Q_UNREACHABLE(); - break; - case cmGT: - Q_UNREACHABLE(); - break; - case cmADD: - Q_UNREACHABLE(); - break; - case cmSUB: - Q_UNREACHABLE(); - break; - case cmMUL: - Q_UNREACHABLE(); - break; - case cmDIV: - Q_UNREACHABLE(); - break; - case cmPOW: - Q_UNREACHABLE(); - break; - case cmLAND: - Q_UNREACHABLE(); - break; - case cmLOR: - Q_UNREACHABLE(); - break; - case cmASSIGN: - Q_UNREACHABLE(); - break; - case cmBO: - Q_UNREACHABLE(); - break; - case cmBC: - Q_UNREACHABLE(); - break; - case cmIF: - Q_UNREACHABLE(); - break; - case cmELSE: - Q_UNREACHABLE(); - break; - case cmENDIF: - Q_UNREACHABLE(); - break; - case cmARG_SEP: - Q_UNREACHABLE(); - break; - case cmVARPOW2: - Q_UNREACHABLE(); - break; - case cmVARPOW3: - Q_UNREACHABLE(); - break; - case cmVARPOW4: - Q_UNREACHABLE(); - break; - case cmVARMUL: - Q_UNREACHABLE(); - break; - case cmPOW2: - Q_UNREACHABLE(); - break; - case cmFUNC: - Q_UNREACHABLE(); - break; - case cmFUNC_STR: - Q_UNREACHABLE(); - break; - case cmFUNC_BULK: - Q_UNREACHABLE(); - break; - case cmSTRING: - Q_UNREACHABLE(); - break; - case cmOPRT_BIN: - Q_UNREACHABLE(); - break; - case cmOPRT_POSTFIX: - Q_UNREACHABLE(); - break; - case cmOPRT_INFIX: - Q_UNREACHABLE(); - break; - case cmEND: - Q_UNREACHABLE(); - break; - case cmUNKNOWN: - Q_UNREACHABLE(); - break; - default: - throw QmuParserError ( ecVAL_EXPECTED ); - } - } + //------------------------------------------------------------------------------ + /** + * @brief Get value of the token. + * + * Only applicable to variable and value tokens. + * @throw exception_type if token is no value/variable token. + */ + TBase GetVal() const + { + switch ( m_iCode ) + { + case cmVAL: + return m_fVal; + case cmVAR: + return * ( reinterpret_cast(m_pTok) ); + case cmLE: + Q_UNREACHABLE(); + break; + case cmGE: + Q_UNREACHABLE(); + break; + case cmNEQ: + Q_UNREACHABLE(); + break; + case cmEQ: + Q_UNREACHABLE(); + break; + case cmLT: + Q_UNREACHABLE(); + break; + case cmGT: + Q_UNREACHABLE(); + break; + case cmADD: + Q_UNREACHABLE(); + break; + case cmSUB: + Q_UNREACHABLE(); + break; + case cmMUL: + Q_UNREACHABLE(); + break; + case cmDIV: + Q_UNREACHABLE(); + break; + case cmPOW: + Q_UNREACHABLE(); + break; + case cmLAND: + Q_UNREACHABLE(); + break; + case cmLOR: + Q_UNREACHABLE(); + break; + case cmASSIGN: + Q_UNREACHABLE(); + break; + case cmBO: + Q_UNREACHABLE(); + break; + case cmBC: + Q_UNREACHABLE(); + break; + case cmIF: + Q_UNREACHABLE(); + break; + case cmELSE: + Q_UNREACHABLE(); + break; + case cmENDIF: + Q_UNREACHABLE(); + break; + case cmARG_SEP: + Q_UNREACHABLE(); + break; + case cmVARPOW2: + Q_UNREACHABLE(); + break; + case cmVARPOW3: + Q_UNREACHABLE(); + break; + case cmVARPOW4: + Q_UNREACHABLE(); + break; + case cmVARMUL: + Q_UNREACHABLE(); + break; + case cmPOW2: + Q_UNREACHABLE(); + break; + case cmFUNC: + Q_UNREACHABLE(); + break; + case cmFUNC_STR: + Q_UNREACHABLE(); + break; + case cmFUNC_BULK: + Q_UNREACHABLE(); + break; + case cmSTRING: + Q_UNREACHABLE(); + break; + case cmOPRT_BIN: + Q_UNREACHABLE(); + break; + case cmOPRT_POSTFIX: + Q_UNREACHABLE(); + break; + case cmOPRT_INFIX: + Q_UNREACHABLE(); + break; + case cmEND: + Q_UNREACHABLE(); + break; + case cmUNKNOWN: + Q_UNREACHABLE(); + break; + default: + throw QmuParserError ( ecVAL_EXPECTED ); + } + } - //------------------------------------------------------------------------------ - /** - * @brief Get address of a variable token. - * - * Valid only if m_iType==CmdVar. - * @throw exception_type if token is no variable token. - */ - TBase* GetVar() const - { - if ( m_iCode != cmVAR ) - { - throw QmuParserError ( ecINTERNAL_ERROR ); - } + //------------------------------------------------------------------------------ + /** + * @brief Get address of a variable token. + * + * Valid only if m_iType==CmdVar. + * @throw exception_type if token is no variable token. + */ + TBase* GetVar() const + { + if ( m_iCode != cmVAR ) + { + throw QmuParserError ( ecINTERNAL_ERROR ); + } - return reinterpret_cast( m_pTok ); - } + return reinterpret_cast( m_pTok ); + } - //------------------------------------------------------------------------------ - /** - * @brief Return the number of function arguments. - * - * Valid only if m_iType==CmdFUNC. - */ - int GetArgCount() const - { - assert ( m_pCallback.get() ); + //------------------------------------------------------------------------------ + /** + * @brief Return the number of function arguments. + * + * Valid only if m_iType==CmdFUNC. + */ + int GetArgCount() const + { + assert ( m_pCallback.get() ); - if ( !m_pCallback->GetAddr() ) - throw QmuParserError ( ecINTERNAL_ERROR ); + if ( m_pCallback->GetAddr() == false) + { + throw QmuParserError ( ecINTERNAL_ERROR ); + } - return m_pCallback->GetArgc(); - } + return m_pCallback->GetArgc(); + } - //------------------------------------------------------------------------------ - /** - * @brief Return the token identifier. - * - * If #m_iType is cmSTRING the token identifier is the value of the string argument - * for a string function. - * @return #m_strTok - * @throw nothrow - * @sa m_strTok - */ - const TString& GetAsString() const - { - return m_strTok; - } + //------------------------------------------------------------------------------ + /** + * @brief Return the token identifier. + * + * If #m_iType is cmSTRING the token identifier is the value of the string argument + * for a string function. + * @return #m_strTok + * @throw nothrow + * @sa m_strTok + */ + const TString& GetAsString() const + { + return m_strTok; + } private: - ECmdCode m_iCode; ///< Type of the token; The token type is a constant of type #ECmdCode. - ETypeCode m_iType; - void *m_pTok; ///< Stores Token pointer; not applicable for all tokens - int m_iIdx; ///< An otional index to an external buffer storing the token data - TString m_strTok; ///< Token string - TString m_strVal; ///< Value for string variables - qreal m_fVal; ///< the value - std::unique_ptr m_pCallback; + ECmdCode m_iCode; ///< Type of the token; The token type is a constant of type #ECmdCode. + ETypeCode m_iType; + void *m_pTok; ///< Stores Token pointer; not applicable for all tokens + int m_iIdx; ///< An otional index to an external buffer storing the token data + TString m_strTok; ///< Token string + TString m_strVal; ///< Value for string variables + qreal m_fVal; ///< the value + std::unique_ptr m_pCallback; }; } // namespace qmu diff --git a/src/libs/qmuparser/qmuparsertokenreader.cpp b/src/libs/qmuparser/qmuparsertokenreader.cpp index 6ba7a541d..485bdbda0 100644 --- a/src/libs/qmuparser/qmuparsertokenreader.cpp +++ b/src/libs/qmuparser/qmuparsertokenreader.cpp @@ -36,7 +36,7 @@ namespace qmu // Forward declaration class QmuParserBase; -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Copy constructor. * @@ -44,17 +44,17 @@ class QmuParserBase; * @throw nothrow */ QmuParserTokenReader::QmuParserTokenReader ( const QmuParserTokenReader &a_Reader ) - :m_pParser( a_Reader.m_pParser ), m_strFormula( a_Reader.m_strFormula ), m_iPos( a_Reader.m_iPos ), - m_iSynFlags( a_Reader.m_iSynFlags ), m_bIgnoreUndefVar( a_Reader.m_bIgnoreUndefVar ), - m_pFunDef( a_Reader.m_pFunDef ), m_pPostOprtDef( a_Reader.m_pPostOprtDef ), - m_pInfixOprtDef( a_Reader.m_pInfixOprtDef ), m_pOprtDef( a_Reader.m_pOprtDef), - m_pConstDef( a_Reader.m_pConstDef ), m_pStrVarDef( a_Reader.m_pStrVarDef ), m_pVarDef( a_Reader.m_pVarDef ), - m_pFactory( a_Reader.m_pFactory ), m_pFactoryData( a_Reader.m_pFactoryData ), m_vIdentFun( a_Reader.m_vIdentFun ), - m_UsedVar( a_Reader.m_UsedVar ), m_fZero(0), m_iBrackets( a_Reader.m_iBrackets ), m_lastTok(), - m_cArgSep( a_Reader.m_cArgSep ) + :m_pParser( a_Reader.m_pParser ), m_strFormula( a_Reader.m_strFormula ), m_iPos( a_Reader.m_iPos ), + m_iSynFlags( a_Reader.m_iSynFlags ), m_bIgnoreUndefVar( a_Reader.m_bIgnoreUndefVar ), + m_pFunDef( a_Reader.m_pFunDef ), m_pPostOprtDef( a_Reader.m_pPostOprtDef ), + m_pInfixOprtDef( a_Reader.m_pInfixOprtDef ), m_pOprtDef( a_Reader.m_pOprtDef), + m_pConstDef( a_Reader.m_pConstDef ), m_pStrVarDef( a_Reader.m_pStrVarDef ), m_pVarDef( a_Reader.m_pVarDef ), + m_pFactory( a_Reader.m_pFactory ), m_pFactoryData( a_Reader.m_pFactoryData ), m_vIdentFun( a_Reader.m_vIdentFun ), + m_UsedVar( a_Reader.m_UsedVar ), m_fZero(0), m_iBrackets( a_Reader.m_iBrackets ), m_lastTok(), + m_cArgSep( a_Reader.m_cArgSep ) {} -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Assignement operator. * @@ -65,15 +65,15 @@ QmuParserTokenReader::QmuParserTokenReader ( const QmuParserTokenReader &a_Reade */ QmuParserTokenReader& QmuParserTokenReader::operator= ( const QmuParserTokenReader &a_Reader ) { - if ( &a_Reader != this ) - { - Assign ( a_Reader ); - } + if ( &a_Reader != this ) + { + Assign ( a_Reader ); + } - return *this; + return *this; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Assign state of a token reader to this token reader. * @@ -82,28 +82,28 @@ QmuParserTokenReader& QmuParserTokenReader::operator= ( const QmuParserTokenRead */ void QmuParserTokenReader::Assign ( const QmuParserTokenReader &a_Reader ) { - m_pParser = a_Reader.m_pParser; - m_strFormula = a_Reader.m_strFormula; - m_iPos = a_Reader.m_iPos; - m_iSynFlags = a_Reader.m_iSynFlags; + m_pParser = a_Reader.m_pParser; + m_strFormula = a_Reader.m_strFormula; + m_iPos = a_Reader.m_iPos; + m_iSynFlags = a_Reader.m_iSynFlags; - m_UsedVar = a_Reader.m_UsedVar; - m_pFunDef = a_Reader.m_pFunDef; - m_pConstDef = a_Reader.m_pConstDef; - m_pVarDef = a_Reader.m_pVarDef; - m_pStrVarDef = a_Reader.m_pStrVarDef; - m_pPostOprtDef = a_Reader.m_pPostOprtDef; - m_pInfixOprtDef = a_Reader.m_pInfixOprtDef; - m_pOprtDef = a_Reader.m_pOprtDef; - m_bIgnoreUndefVar = a_Reader.m_bIgnoreUndefVar; - m_vIdentFun = a_Reader.m_vIdentFun; - m_pFactory = a_Reader.m_pFactory; - m_pFactoryData = a_Reader.m_pFactoryData; - m_iBrackets = a_Reader.m_iBrackets; - m_cArgSep = a_Reader.m_cArgSep; + m_UsedVar = a_Reader.m_UsedVar; + m_pFunDef = a_Reader.m_pFunDef; + m_pConstDef = a_Reader.m_pConstDef; + m_pVarDef = a_Reader.m_pVarDef; + m_pStrVarDef = a_Reader.m_pStrVarDef; + m_pPostOprtDef = a_Reader.m_pPostOprtDef; + m_pInfixOprtDef = a_Reader.m_pInfixOprtDef; + m_pOprtDef = a_Reader.m_pOprtDef; + m_bIgnoreUndefVar = a_Reader.m_bIgnoreUndefVar; + m_vIdentFun = a_Reader.m_vIdentFun; + m_pFactory = a_Reader.m_pFactory; + m_pFactoryData = a_Reader.m_pFactoryData; + m_iBrackets = a_Reader.m_iBrackets; + m_cArgSep = a_Reader.m_cArgSep; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Constructor. * @@ -114,16 +114,16 @@ void QmuParserTokenReader::Assign ( const QmuParserTokenReader &a_Reader ) * @param a_pParent Parent parser object of the token reader. */ QmuParserTokenReader::QmuParserTokenReader ( QmuParserBase *a_pParent ) - : m_pParser ( a_pParent ), m_strFormula(), m_iPos ( 0 ), m_iSynFlags ( 0 ), m_bIgnoreUndefVar ( false ), - m_pFunDef ( NULL ), m_pPostOprtDef ( NULL ), m_pInfixOprtDef ( NULL ), m_pOprtDef ( NULL ), m_pConstDef ( NULL ), - m_pStrVarDef ( NULL ), m_pVarDef ( NULL ), m_pFactory ( NULL ), m_pFactoryData ( NULL ), m_vIdentFun(), - m_UsedVar(), m_fZero ( 0 ), m_iBrackets ( 0 ), m_lastTok(), m_cArgSep ( ',' ) + : m_pParser ( a_pParent ), m_strFormula(), m_iPos ( 0 ), m_iSynFlags ( 0 ), m_bIgnoreUndefVar ( false ), + m_pFunDef ( NULL ), m_pPostOprtDef ( NULL ), m_pInfixOprtDef ( NULL ), m_pOprtDef ( NULL ), m_pConstDef ( NULL ), + m_pStrVarDef ( NULL ), m_pVarDef ( NULL ), m_pFactory ( NULL ), m_pFactoryData ( NULL ), m_vIdentFun(), + m_UsedVar(), m_fZero ( 0 ), m_iBrackets ( 0 ), m_lastTok(), m_cArgSep ( ',' ) { - assert ( m_pParser ); - SetParent ( m_pParser ); + assert ( m_pParser ); + SetParent ( m_pParser ); } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Create instance of a QParserTokenReader identical with this and return its pointer. * @@ -134,38 +134,38 @@ QmuParserTokenReader::QmuParserTokenReader ( QmuParserBase *a_pParent ) */ QmuParserTokenReader* QmuParserTokenReader::Clone ( QmuParserBase *a_pParent ) const { - std::unique_ptr ptr ( new QmuParserTokenReader ( *this ) ); - ptr->SetParent ( a_pParent ); - return ptr.release(); + std::unique_ptr ptr ( new QmuParserTokenReader ( *this ) ); + ptr->SetParent ( a_pParent ); + return ptr.release(); } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- QmuParserTokenReader::token_type& QmuParserTokenReader::SaveBeforeReturn ( const token_type &tok ) { - m_lastTok = tok; - return m_lastTok; + m_lastTok = tok; + return m_lastTok; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- void QmuParserTokenReader::AddValIdent ( identfun_type a_pCallback ) { - // Use push_front is used to give user defined callbacks a higher priority than - // the built in ones. Otherwise reading hex numbers would not work - // since the "0" in "0xff" would always be read first making parsing of - // the rest impossible. - // reference: - // http://sourceforge.net/projects/muparser/forums/forum/462843/topic/4824956 - m_vIdentFun.push_front ( a_pCallback ); + // Use push_front is used to give user defined callbacks a higher priority than + // the built in ones. Otherwise reading hex numbers would not work + // since the "0" in "0xff" would always be read first making parsing of + // the rest impossible. + // reference: + // http://sourceforge.net/projects/muparser/forums/forum/462843/topic/4824956 + m_vIdentFun.push_front ( a_pCallback ); } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- void QmuParserTokenReader::SetVarCreator ( facfun_type a_pFactory, void *pUserData ) { - m_pFactory = a_pFactory; - m_pFactoryData = pUserData; + m_pFactory = a_pFactory; + m_pFactoryData = pUserData; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Return the current position of the token reader in the formula string. * @@ -174,10 +174,10 @@ void QmuParserTokenReader::SetVarCreator ( facfun_type a_pFactory, void *pUserDa */ int QmuParserTokenReader::GetPos() const { - return m_iPos; + return m_iPos; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Return a reference to the formula. * @@ -186,19 +186,19 @@ int QmuParserTokenReader::GetPos() const */ const QString& QmuParserTokenReader::GetExpr() const { - return m_strFormula; + return m_strFormula; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Return a map containing the used variables only. */ varmap_type& QmuParserTokenReader::GetUsedVar() { - return m_UsedVar; + return m_UsedVar; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Initialize the token Reader. * @@ -207,11 +207,11 @@ varmap_type& QmuParserTokenReader::GetUsedVar() */ void QmuParserTokenReader::SetFormula ( const QString &a_strFormula ) { - m_strFormula = a_strFormula; - ReInit(); + m_strFormula = a_strFormula; + ReInit(); } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Set Flag that contronls behaviour in case of undefined variables beeing found. * @@ -222,10 +222,10 @@ void QmuParserTokenReader::SetFormula ( const QString &a_strFormula ) */ void QmuParserTokenReader::IgnoreUndefVar ( bool bIgnore ) { - m_bIgnoreUndefVar = bIgnore; + m_bIgnoreUndefVar = bIgnore; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Reset the token reader to the start of the formula. * @@ -236,87 +236,120 @@ void QmuParserTokenReader::IgnoreUndefVar ( bool bIgnore ) */ void QmuParserTokenReader::ReInit() { - m_iPos = 0; - m_iSynFlags = sfSTART_OF_LINE; - m_iBrackets = 0; - m_UsedVar.clear(); - m_lastTok = token_type(); + m_iPos = 0; + m_iSynFlags = sfSTART_OF_LINE; + m_iBrackets = 0; + m_UsedVar.clear(); + m_lastTok = token_type(); } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Read the next token from the string. */ QmuParserTokenReader::token_type QmuParserTokenReader::ReadNextToken() { - assert ( m_pParser ); + assert ( m_pParser ); #if defined(_UNICODE) - const char_type *szFormula = m_strFormula.toStdWString().c_str(); + const char_type *szFormula = m_strFormula.toStdWString().c_str(); #else - const char_type *szFormula = m_strFormula.toStdString().c_str(); + const char_type *szFormula = m_strFormula.toStdString().c_str(); #endif - token_type tok; + token_type tok; - // Ignore all non printable characters when reading the expression - while ( szFormula[m_iPos] > 0 && szFormula[m_iPos] <= 0x20 ) - { - ++m_iPos; - } + // Ignore all non printable characters when reading the expression + while ( szFormula[m_iPos] > 0 && szFormula[m_iPos] <= 0x20 ) + { + ++m_iPos; + } - if ( IsEOF ( tok ) ) return SaveBeforeReturn ( tok ); // Check for end of formula - if ( IsOprt ( tok ) ) return SaveBeforeReturn ( tok ); // Check for user defined binary operator - if ( IsFunTok ( tok ) ) return SaveBeforeReturn ( tok ); // Check for function token - if ( IsBuiltIn ( tok ) ) return SaveBeforeReturn ( tok ); // Check built in operators / tokens - if ( IsArgSep ( tok ) ) return SaveBeforeReturn ( tok ); // Check for function argument separators - if ( IsValTok ( tok ) ) return SaveBeforeReturn ( tok ); // Check for values / constant tokens - if ( IsVarTok ( tok ) ) return SaveBeforeReturn ( tok ); // Check for variable tokens - if ( IsStrVarTok ( tok ) ) return SaveBeforeReturn ( tok ); // Check for string variables - if ( IsString ( tok ) ) return SaveBeforeReturn ( tok ); // Check for String tokens - if ( IsInfixOpTok ( tok ) ) return SaveBeforeReturn ( tok ); // Check for unary operators - if ( IsPostOpTok ( tok ) ) return SaveBeforeReturn ( tok ); // Check for unary operators + if ( IsEOF ( tok ) ) + { + return SaveBeforeReturn ( tok ); // Check for end of formula + } + if ( IsOprt ( tok ) ) + { + return SaveBeforeReturn ( tok ); // Check for user defined binary operator + } + if ( IsFunTok ( tok ) ) + { + return SaveBeforeReturn ( tok ); // Check for function token + } + if ( IsBuiltIn ( tok ) ) + { + return SaveBeforeReturn ( tok ); // Check built in operators / tokens + } + if ( IsArgSep ( tok ) ) + { + return SaveBeforeReturn ( tok ); // Check for function argument separators + } + if ( IsValTok ( tok ) ) + { + return SaveBeforeReturn ( tok ); // Check for values / constant tokens + } + if ( IsVarTok ( tok ) ) + { + return SaveBeforeReturn ( tok ); // Check for variable tokens + } + if ( IsStrVarTok ( tok ) ) + { + return SaveBeforeReturn ( tok ); // Check for string variables + } + if ( IsString ( tok ) ) + { + return SaveBeforeReturn ( tok ); // Check for String tokens + } + if ( IsInfixOpTok ( tok ) ) + { + return SaveBeforeReturn ( tok ); // Check for unary operators + } + if ( IsPostOpTok ( tok ) ) + { + return SaveBeforeReturn ( tok ); // Check for unary operators + } - // Check String for undefined variable token. Done only if a - // flag is set indicating to ignore undefined variables. - // This is a way to conditionally avoid an error if - // undefined variables occur. - // (The GetUsedVar function must suppress the error for - // undefined variables in order to collect all variable - // names including the undefined ones.) - if ( ( m_bIgnoreUndefVar || m_pFactory ) && IsUndefVarTok ( tok ) ) - { - return SaveBeforeReturn ( tok ); - } + // Check String for undefined variable token. Done only if a + // flag is set indicating to ignore undefined variables. + // This is a way to conditionally avoid an error if + // undefined variables occur. + // (The GetUsedVar function must suppress the error for + // undefined variables in order to collect all variable + // names including the undefined ones.) + if ( ( m_bIgnoreUndefVar || m_pFactory ) && IsUndefVarTok ( tok ) ) + { + return SaveBeforeReturn ( tok ); + } - // Check for unknown token - // - // !!! From this point on there is no exit without an exception possible... - // - QString strTok; - int iEnd = ExtractToken ( m_pParser->ValidNameChars(), strTok, m_iPos ); - if ( iEnd != m_iPos ) - { - Error ( ecUNASSIGNABLE_TOKEN, m_iPos, strTok ); - } + // Check for unknown token + // + // !!! From this point on there is no exit without an exception possible... + // + QString strTok; + int iEnd = ExtractToken ( m_pParser->ValidNameChars(), strTok, m_iPos ); + if ( iEnd != m_iPos ) + { + Error ( ecUNASSIGNABLE_TOKEN, m_iPos, strTok ); + } - Error ( ecUNASSIGNABLE_TOKEN, m_iPos, m_strFormula.mid ( m_iPos ) ); - return token_type(); // never reached + Error ( ecUNASSIGNABLE_TOKEN, m_iPos, m_strFormula.mid ( m_iPos ) ); + return token_type(); // never reached } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- void QmuParserTokenReader::SetParent ( QmuParserBase *a_pParent ) { - m_pParser = a_pParent; - m_pFunDef = &a_pParent->m_FunDef; - m_pOprtDef = &a_pParent->m_OprtDef; - m_pInfixOprtDef = &a_pParent->m_InfixOprtDef; - m_pPostOprtDef = &a_pParent->m_PostOprtDef; - m_pVarDef = &a_pParent->m_VarDef; - m_pStrVarDef = &a_pParent->m_StrVarDef; - m_pConstDef = &a_pParent->m_ConstDef; + m_pParser = a_pParent; + m_pFunDef = &a_pParent->m_FunDef; + m_pOprtDef = &a_pParent->m_OprtDef; + m_pInfixOprtDef = &a_pParent->m_InfixOprtDef; + m_pPostOprtDef = &a_pParent->m_PostOprtDef; + m_pVarDef = &a_pParent->m_VarDef; + m_pStrVarDef = &a_pParent->m_StrVarDef; + m_pConstDef = &a_pParent->m_ConstDef; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Extract all characters that belong to a certain charset. * @@ -329,34 +362,36 @@ void QmuParserTokenReader::SetParent ( QmuParserBase *a_pParent ) int QmuParserTokenReader::ExtractToken ( const QString &a_szCharSet, QString &a_sTok, int a_iPos ) const { #if defined(_UNICODE) - const std::wstring m_strFormulaStd = m_strFormula.toStdWString(); - const std::wstring a_szCharSetstd = a_szCharSet.toStdWString(); + const std::wstring m_strFormulaStd = m_strFormula.toStdWString(); + const std::wstring a_szCharSetstd = a_szCharSet.toStdWString(); #else - const std::string m_strFormulaStd = m_strFormula.toStdString(); - const std::string a_szCharSetStd = a_szCharSet.toStdString(); + const std::string m_strFormulaStd = m_strFormula.toStdString(); + const std::string a_szCharSetStd = a_szCharSet.toStdString(); #endif - int iEnd = static_cast(m_strFormulaStd.find_first_not_of ( a_szCharSetStd, a_iPos )); + int iEnd = static_cast(m_strFormulaStd.find_first_not_of ( a_szCharSetStd, a_iPos )); - if ( iEnd == static_cast(string_type::npos) ) - { - iEnd = static_cast(m_strFormulaStd.length()); - } + if ( iEnd == static_cast(string_type::npos) ) + { + iEnd = static_cast(m_strFormulaStd.length()); + } - // Assign token string if there was something found - if ( a_iPos != iEnd ) - { + // Assign token string if there was something found + if ( a_iPos != iEnd ) + { #if defined(_UNICODE) - a_sTok = QString().fromStdWString ( std::wstring ( m_strFormulaStd.begin() + a_iPos, m_strFormulaStd.begin() + iEnd ) ); + a_sTok = QString().fromStdWString ( std::wstring ( m_strFormulaStd.begin() + a_iPos, + m_strFormulaStd.begin() + iEnd ) ); #else - a_sTok = QString().fromStdString ( std::string ( m_strFormulaStd.begin() + a_iPos, m_strFormulaStd.begin() + iEnd ) ); + a_sTok = QString().fromStdString ( std::string ( m_strFormulaStd.begin() + a_iPos, + m_strFormulaStd.begin() + iEnd ) ); #endif - } + } - return iEnd; + return iEnd; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Check Expression for the presence of a binary operator token. * @@ -367,38 +402,39 @@ int QmuParserTokenReader::ExtractToken ( const QString &a_szCharSet, QString &a_ int QmuParserTokenReader::ExtractOperatorToken ( QString &a_sTok, int a_iPos ) const { #if defined(_UNICODE) - const std::wstring m_strFormulaStd = m_strFormula.toStdWString(); - const std::wstring oprtCharsStd = m_pParser->ValidInfixOprtChars().toStdWString(); + const std::wstring m_strFormulaStd = m_strFormula.toStdWString(); + const std::wstring oprtCharsStd = m_pParser->ValidInfixOprtChars().toStdWString(); #else - const std::string m_strFormulaStd = m_strFormula.toStdString(); - const std::string oprtCharsStd = m_pParser->ValidInfixOprtChars().toStdString(); + const std::string m_strFormulaStd = m_strFormula.toStdString(); + const std::string oprtCharsStd = m_pParser->ValidInfixOprtChars().toStdString(); #endif - int iEnd = static_cast( m_strFormulaStd.find_first_not_of ( oprtCharsStd, a_iPos ) ); - if ( iEnd == static_cast( string_type::npos ) ) - { - iEnd = static_cast( m_strFormulaStd.length() ); - } + int iEnd = static_cast( m_strFormulaStd.find_first_not_of ( oprtCharsStd, a_iPos ) ); + if ( iEnd == static_cast( string_type::npos ) ) + { + iEnd = static_cast( m_strFormulaStd.length() ); + } - // Assign token string if there was something found - if ( a_iPos != iEnd ) - { + // Assign token string if there was something found + if ( a_iPos != iEnd ) + { #if defined(_UNICODE) - a_sTok = QString().fromStdWString ( string_type ( m_strFormulaStd.begin() + a_iPos, - m_strFormulaStd.begin() + iEnd ) ); + a_sTok = QString().fromStdWString ( string_type ( m_strFormulaStd.begin() + a_iPos, + m_strFormulaStd.begin() + iEnd ) ); #else - a_sTok = QString().fromStdString ( string_type ( m_strFormulaStd.begin() + a_iPos, m_strFormulaStd.begin() + iEnd ) ); + a_sTok = QString().fromStdString ( string_type ( m_strFormulaStd.begin() + a_iPos, + m_strFormulaStd.begin() + iEnd ) ); #endif - return iEnd; - } - else - { - // There is still the chance of having to deal with an operator consisting exclusively - // of alphabetic characters. - return ExtractToken ( QMUP_CHARS, a_sTok, a_iPos ); - } + return iEnd; + } + else + { + // There is still the chance of having to deal with an operator consisting exclusively + // of alphabetic characters. + return ExtractToken ( QMUP_CHARS, a_sTok, a_iPos ); + } } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Check if a built in operator or other token can be found * @param a_Tok [out] Operator token if one is found. This can either be a binary operator or an infix operator token. @@ -406,131 +442,152 @@ int QmuParserTokenReader::ExtractOperatorToken ( QString &a_sTok, int a_iPos ) c */ bool QmuParserTokenReader::IsBuiltIn ( token_type &a_Tok ) { - const QStringList pOprtDef = m_pParser->GetOprtDef(); + const QStringList pOprtDef = m_pParser->GetOprtDef(); - // Compare token with function and operator strings - // check string for operator/function - for ( int i = 0; i < pOprtDef.size(); ++i ) - { - int len = pOprtDef.at ( i ).length(); - if ( pOprtDef.at ( i ) == m_strFormula.mid ( m_iPos, m_iPos + len ) ) - { - switch ( i ) - { - //case cmAND: - //case cmOR: - //case cmXOR: - case cmLAND: - case cmLOR: - case cmLT: - case cmGT: - case cmLE: - case cmGE: - case cmNEQ: - case cmEQ: - case cmADD: - case cmSUB: - case cmMUL: - case cmDIV: - case cmPOW: - case cmASSIGN: - //if (len!=sTok.length()) - // continue; + // Compare token with function and operator strings + // check string for operator/function + for ( int i = 0; i < pOprtDef.size(); ++i ) + { + int len = pOprtDef.at ( i ).length(); + if ( pOprtDef.at ( i ) == m_strFormula.mid ( m_iPos, m_iPos + len ) ) + { + switch ( i ) + { + //case cmAND: + //case cmOR: + //case cmXOR: + case cmLAND: + case cmLOR: + case cmLT: + case cmGT: + case cmLE: + case cmGE: + case cmNEQ: + case cmEQ: + case cmADD: + case cmSUB: + case cmMUL: + case cmDIV: + case cmPOW: + case cmASSIGN: + //if (len!=sTok.length()) + // continue; - // The assignement operator need special treatment - if ( i == cmASSIGN && m_iSynFlags & noASSIGN ) - Error ( ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef.at ( i ) ); + // The assignement operator need special treatment + if ( i == cmASSIGN && m_iSynFlags & noASSIGN ) + { + Error ( ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef.at ( i ) ); + } - if ( !m_pParser->HasBuiltInOprt() ) continue; - if ( m_iSynFlags & noOPT ) - { - // Maybe its an infix operator not an operator - // Both operator types can share characters in - // their identifiers - if ( IsInfixOpTok ( a_Tok ) ) - return true; + if ( m_pParser->HasBuiltInOprt() == false) + { + continue; + } + if ( m_iSynFlags & noOPT ) + { + // Maybe its an infix operator not an operator + // Both operator types can share characters in + // their identifiers + if ( IsInfixOpTok ( a_Tok ) ) + { + return true; + } - Error ( ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef.at ( i ) ); - } + Error ( ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef.at ( i ) ); + } - m_iSynFlags = noBC | noOPT | noARG_SEP | noPOSTOP | noASSIGN | noIF | noELSE; - m_iSynFlags |= ( ( i != cmEND ) && ( i != cmBC ) ) ? noEND : 0; - break; + m_iSynFlags = noBC | noOPT | noARG_SEP | noPOSTOP | noASSIGN | noIF | noELSE; + m_iSynFlags |= ( ( i != cmEND ) && ( i != cmBC ) ) ? noEND : 0; + break; - case cmBO: - if ( m_iSynFlags & noBO ) - Error ( ecUNEXPECTED_PARENS, m_iPos, pOprtDef.at ( i ) ); + case cmBO: + if ( m_iSynFlags & noBO ) + { + Error ( ecUNEXPECTED_PARENS, m_iPos, pOprtDef.at ( i ) ); + } - if ( m_lastTok.GetCode() == cmFUNC ) - m_iSynFlags = noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN | noIF | noELSE; - else - m_iSynFlags = noBC | noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN | noIF | noELSE; + if ( m_lastTok.GetCode() == cmFUNC ) + { + m_iSynFlags = noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN | noIF | noELSE; + } + else + { + m_iSynFlags = noBC | noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN | noIF | noELSE; + } - ++m_iBrackets; - break; + ++m_iBrackets; + break; - case cmBC: - if ( m_iSynFlags & noBC ) - Error ( ecUNEXPECTED_PARENS, m_iPos, pOprtDef.at ( i ) ); + case cmBC: + if ( m_iSynFlags & noBC ) + { + Error ( ecUNEXPECTED_PARENS, m_iPos, pOprtDef.at ( i ) ); + } - m_iSynFlags = noBO | noVAR | noVAL | noFUN | noINFIXOP | noSTR | noASSIGN; + m_iSynFlags = noBO | noVAR | noVAL | noFUN | noINFIXOP | noSTR | noASSIGN; - if ( --m_iBrackets < 0 ) - Error ( ecUNEXPECTED_PARENS, m_iPos, pOprtDef.at ( i ) ); - break; + if ( --m_iBrackets < 0 ) + { + Error ( ecUNEXPECTED_PARENS, m_iPos, pOprtDef.at ( i ) ); + } + break; - case cmELSE: - if ( m_iSynFlags & noELSE ) - Error ( ecUNEXPECTED_CONDITIONAL, m_iPos, pOprtDef.at ( i ) ); + case cmELSE: + if ( m_iSynFlags & noELSE ) + { + Error ( ecUNEXPECTED_CONDITIONAL, m_iPos, pOprtDef.at ( i ) ); + } - m_iSynFlags = noBC | noPOSTOP | noEND | noOPT | noIF | noELSE; - break; + m_iSynFlags = noBC | noPOSTOP | noEND | noOPT | noIF | noELSE; + break; - case cmIF: - if ( m_iSynFlags & noIF ) - Error ( ecUNEXPECTED_CONDITIONAL, m_iPos, pOprtDef.at ( i ) ); + case cmIF: + if ( m_iSynFlags & noIF ) + { + Error ( ecUNEXPECTED_CONDITIONAL, m_iPos, pOprtDef.at ( i ) ); + } - m_iSynFlags = noBC | noPOSTOP | noEND | noOPT | noIF | noELSE; - break; + m_iSynFlags = noBC | noPOSTOP | noEND | noOPT | noIF | noELSE; + break; - default: // The operator is listed in c_DefaultOprt, but not here. This is a bad thing... - Error ( ecINTERNAL_ERROR ); - } // switch operator id + default: // The operator is listed in c_DefaultOprt, but not here. This is a bad thing... + Error ( ecINTERNAL_ERROR ); + } // switch operator id - m_iPos += len; - a_Tok.Set ( static_cast(i), pOprtDef.at ( i ) ); - return true; - } // if operator string found - } // end of for all operator strings + m_iPos += len; + a_Tok.Set ( static_cast(i), pOprtDef.at ( i ) ); + return true; + } // if operator string found + } // end of for all operator strings - return false; + return false; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- bool QmuParserTokenReader::IsArgSep ( token_type &a_Tok ) { - if ( m_strFormula.at ( m_iPos ) == m_cArgSep ) - { - // copy the separator into null terminated string - QString szSep; - szSep[0] = m_cArgSep; - szSep[1] = 0; + if ( m_strFormula.at ( m_iPos ) == m_cArgSep ) + { + // copy the separator into null terminated string + QString szSep; + szSep[0] = m_cArgSep; + szSep[1] = 0; - if ( m_iSynFlags & noARG_SEP ) - { - Error ( ecUNEXPECTED_ARG_SEP, m_iPos, szSep ); - } + if ( m_iSynFlags & noARG_SEP ) + { + Error ( ecUNEXPECTED_ARG_SEP, m_iPos, szSep ); + } - m_iSynFlags = noBC | noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN; - m_iPos++; - a_Tok.Set ( cmARG_SEP, szSep ); - return true; - } + m_iSynFlags = noBC | noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN; + m_iPos++; + a_Tok.Set ( cmARG_SEP, szSep ); + return true; + } - return false; + return false; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Check for End of Formula. * @@ -542,72 +599,82 @@ bool QmuParserTokenReader::IsArgSep ( token_type &a_Tok ) bool QmuParserTokenReader::IsEOF ( token_type &a_Tok ) { #if defined(_UNICODE) - const char_type* szFormula = m_strFormula.toStdWString().c_str(); + const char_type* szFormula = m_strFormula.toStdWString().c_str(); #else - const char_type* szFormula = m_strFormula.toStdString().c_str(); + const char_type* szFormula = m_strFormula.toStdString().c_str(); #endif - // check for EOF - if ( !szFormula[m_iPos] /*|| szFormula[m_iPos] == '\n'*/ ) - { - if ( m_iSynFlags & noEND ) - Error ( ecUNEXPECTED_EOF, m_iPos ); + // check for EOF + if ( szFormula[m_iPos] == false /*|| szFormula[m_iPos] == '\n'*/ ) + { + if ( m_iSynFlags & noEND ) + { + Error ( ecUNEXPECTED_EOF, m_iPos ); + } - if ( m_iBrackets > 0 ) - Error ( ecMISSING_PARENS, m_iPos, ")" ); + if ( m_iBrackets > 0 ) + { + Error ( ecMISSING_PARENS, m_iPos, ")" ); + } - m_iSynFlags = 0; - a_Tok.Set ( cmEND ); - return true; - } + m_iSynFlags = 0; + a_Tok.Set ( cmEND ); + return true; + } - return false; + return false; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Check if a string position contains a unary infix operator. * @return true if a function token has been found false otherwise. */ bool QmuParserTokenReader::IsInfixOpTok ( token_type &a_Tok ) { - QString sTok; - int iEnd = ExtractToken ( m_pParser->ValidInfixOprtChars(), sTok, m_iPos ); - if ( iEnd == m_iPos ) - return false; + QString sTok; + int iEnd = ExtractToken ( m_pParser->ValidInfixOprtChars(), sTok, m_iPos ); + if ( iEnd == m_iPos ) + { + return false; + } - // iteraterate over all postfix operator strings - funmap_type::const_reverse_iterator it = m_pInfixOprtDef->rbegin(); - for ( ; it != m_pInfixOprtDef->rend(); ++it ) - { - if ( sTok.indexOf ( it->first ) != 0 ) - continue; + // iteraterate over all postfix operator strings + funmap_type::const_reverse_iterator it = m_pInfixOprtDef->rbegin(); + for ( ; it != m_pInfixOprtDef->rend(); ++it ) + { + if ( sTok.indexOf ( it->first ) != 0 ) + { + continue; + } - a_Tok.Set ( it->second, it->first ); - m_iPos += static_cast(it->first.length()); + a_Tok.Set ( it->second, it->first ); + m_iPos += static_cast(it->first.length()); - if ( m_iSynFlags & noINFIXOP ) - Error ( ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString() ); + if ( m_iSynFlags & noINFIXOP ) + { + Error ( ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString() ); + } - m_iSynFlags = noPOSTOP | noINFIXOP | noOPT | noBC | noSTR | noASSIGN; - return true; - } + m_iSynFlags = noPOSTOP | noINFIXOP | noOPT | noBC | noSTR | noASSIGN; + return true; + } - return false; + return false; - /* - a_Tok.Set(item->second, sTok); - m_iPos = (int)iEnd; + /* + a_Tok.Set(item->second, sTok); + m_iPos = (int)iEnd; - if (m_iSynFlags & noINFIXOP) - Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString()); + if (m_iSynFlags & noINFIXOP) + Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString()); - m_iSynFlags = noPOSTOP | noINFIXOP | noOPT | noBC | noSTR | noASSIGN; - return true; - */ + m_iSynFlags = noPOSTOP | noINFIXOP | noOPT | noBC | noSTR | noASSIGN; + return true; + */ } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Check whether the token at a given position is a function token. * @param a_Tok [out] If a value token is found it will be placed here. @@ -617,30 +684,38 @@ bool QmuParserTokenReader::IsInfixOpTok ( token_type &a_Tok ) */ bool QmuParserTokenReader::IsFunTok ( token_type &a_Tok ) { - QString strTok; - int iEnd = ExtractToken ( m_pParser->ValidNameChars(), strTok, m_iPos ); - if ( iEnd == m_iPos ) - return false; + QString strTok; + int iEnd = ExtractToken ( m_pParser->ValidNameChars(), strTok, m_iPos ); + if ( iEnd == m_iPos ) + { + return false; + } - funmap_type::const_iterator item = m_pFunDef->find ( strTok ); - if ( item == m_pFunDef->end() ) - return false; + funmap_type::const_iterator item = m_pFunDef->find ( strTok ); + if ( item == m_pFunDef->end() ) + { + return false; + } - // Check if the next sign is an opening bracket - if ( m_strFormula.at ( iEnd ) != '(' ) - return false; + // Check if the next sign is an opening bracket + if ( m_strFormula.at ( iEnd ) != '(' ) + { + return false; + } - a_Tok.Set ( item->second, strTok ); + a_Tok.Set ( item->second, strTok ); - m_iPos = iEnd; - if ( m_iSynFlags & noFUN ) - Error ( ecUNEXPECTED_FUN, m_iPos - static_cast(a_Tok.GetAsString().length()), a_Tok.GetAsString() ); + m_iPos = iEnd; + if ( m_iSynFlags & noFUN ) + { + Error ( ecUNEXPECTED_FUN, m_iPos - static_cast(a_Tok.GetAsString().length()), a_Tok.GetAsString() ); + } - m_iSynFlags = noANY ^ noBO; - return true; + m_iSynFlags = noANY ^ noBO; + return true; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Check if a string position contains a binary operator. * @param a_Tok [out] Operator token if one is found. This can either be a binary operator or an infix operator token. @@ -648,112 +723,124 @@ bool QmuParserTokenReader::IsFunTok ( token_type &a_Tok ) */ bool QmuParserTokenReader::IsOprt ( token_type &a_Tok ) { - QString strTok; + QString strTok; - int iEnd = ExtractOperatorToken ( strTok, m_iPos ); - if ( iEnd == m_iPos ) - return false; + int iEnd = ExtractOperatorToken ( strTok, m_iPos ); + if ( iEnd == m_iPos ) + { + return false; + } - // Check if the operator is a built in operator, if so ignore it here - const QStringList pOprtDef = m_pParser->GetOprtDef(); - QStringList::const_iterator constIterator; - for ( constIterator = pOprtDef.constBegin(); m_pParser->HasBuiltInOprt() && constIterator != pOprtDef.constEnd(); - ++constIterator ) - { - if ( ( *constIterator ) == strTok ) - return false; - } + // Check if the operator is a built in operator, if so ignore it here + const QStringList pOprtDef = m_pParser->GetOprtDef(); + QStringList::const_iterator constIterator; + for ( constIterator = pOprtDef.constBegin(); m_pParser->HasBuiltInOprt() && constIterator != pOprtDef.constEnd(); + ++constIterator ) + { + if ( ( *constIterator ) == strTok ) + { + return false; + } + } - // Note: - // All tokens in oprt_bin_maptype are have been sorted by their length - // Long operators must come first! Otherwise short names (like: "add") that - // are part of long token names (like: "add123") will be found instead - // of the long ones. - // Length sorting is done with ascending length so we use a reverse iterator here. - funmap_type::const_reverse_iterator it = m_pOprtDef->rbegin(); - for ( ; it != m_pOprtDef->rend(); ++it ) - { - const QString &sID = it->first; - if ( sID == m_strFormula.mid ( m_iPos, m_iPos + sID.length() ) ) - { - a_Tok.Set ( it->second, strTok ); + // Note: + // All tokens in oprt_bin_maptype are have been sorted by their length + // Long operators must come first! Otherwise short names (like: "add") that + // are part of long token names (like: "add123") will be found instead + // of the long ones. + // Length sorting is done with ascending length so we use a reverse iterator here. + funmap_type::const_reverse_iterator it = m_pOprtDef->rbegin(); + for ( ; it != m_pOprtDef->rend(); ++it ) + { + const QString &sID = it->first; + if ( sID == m_strFormula.mid ( m_iPos, m_iPos + sID.length() ) ) + { + a_Tok.Set ( it->second, strTok ); - // operator was found - if ( m_iSynFlags & noOPT ) - { - // An operator was found but is not expected to occur at - // this position of the formula, maybe it is an infix - // operator, not a binary operator. Both operator types - // can share characters in their identifiers. - if ( IsInfixOpTok ( a_Tok ) ) - return true; - else - { - // nope, no infix operator - return false; - //Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString()); - } + // operator was found + if ( m_iSynFlags & noOPT ) + { + // An operator was found but is not expected to occur at + // this position of the formula, maybe it is an infix + // operator, not a binary operator. Both operator types + // can share characters in their identifiers. + if ( IsInfixOpTok ( a_Tok ) ) + { + return true; + } + else + { + // nope, no infix operator + return false; + //Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString()); + } - } + } - m_iPos += sID.length(); - m_iSynFlags = noBC | noOPT | noARG_SEP | noPOSTOP | noEND | noBC | noASSIGN; - return true; - } - } + m_iPos += sID.length(); + m_iSynFlags = noBC | noOPT | noARG_SEP | noPOSTOP | noEND | noBC | noASSIGN; + return true; + } + } - return false; + return false; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Check if a string position contains a unary post value operator. */ bool QmuParserTokenReader::IsPostOpTok ( token_type &a_Tok ) { - // Do not check for postfix operators if they are not allowed at - // the current expression index. - // - // This will fix the bug reported here: - // - // http://sourceforge.net/tracker/index.php?func=detail&aid=3343891&group_id=137191&atid=737979 - // - if ( m_iSynFlags & noPOSTOP ) - return false; - // + // Do not check for postfix operators if they are not allowed at + // the current expression index. + // + // This will fix the bug reported here: + // + // http://sourceforge.net/tracker/index.php?func=detail&aid=3343891&group_id=137191&atid=737979 + // + if ( m_iSynFlags & noPOSTOP ) + { + return false; + } + // - // Tricky problem with equations like "3m+5": - // m is a postfix operator, + is a valid sign for postfix operators and - // for binary operators parser detects "m+" as operator string and - // finds no matching postfix operator. - // - // This is a special case so this routine slightly differs from the other - // token readers. + // Tricky problem with equations like "3m+5": + // m is a postfix operator, + is a valid sign for postfix operators and + // for binary operators parser detects "m+" as operator string and + // finds no matching postfix operator. + // + // This is a special case so this routine slightly differs from the other + // token readers. - // Test if there could be a postfix operator - QString sTok; - int iEnd = ExtractToken ( m_pParser->ValidOprtChars(), sTok, m_iPos ); - if ( iEnd == m_iPos ) - return false; + // Test if there could be a postfix operator + QString sTok; + int iEnd = ExtractToken ( m_pParser->ValidOprtChars(), sTok, m_iPos ); + if ( iEnd == m_iPos ) + { + return false; + } - // iteraterate over all postfix operator strings - funmap_type::const_reverse_iterator it = m_pPostOprtDef->rbegin(); - for ( ; it != m_pPostOprtDef->rend(); ++it ) - { - if ( sTok.indexOf ( it->first ) != 0 ) - continue; + // iteraterate over all postfix operator strings + funmap_type::const_reverse_iterator it = m_pPostOprtDef->rbegin(); + for ( ; it != m_pPostOprtDef->rend(); ++it ) + { + if ( sTok.indexOf ( it->first ) != 0 ) + { + continue; + } - a_Tok.Set ( it->second, sTok ); - m_iPos += it->first.length(); + a_Tok.Set ( it->second, sTok ); + m_iPos += it->first.length(); - m_iSynFlags = noVAL | noVAR | noFUN | noBO | noPOSTOP | noSTR | noASSIGN; - return true; - } + m_iSynFlags = noVAL | noVAR | noFUN | noBO | noPOSTOP | noSTR | noASSIGN; + return true; + } - return false; + return false; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Check whether the token at a given position is a value token. * @@ -764,54 +851,58 @@ bool QmuParserTokenReader::IsPostOpTok ( token_type &a_Tok ) */ bool QmuParserTokenReader::IsValTok ( token_type &a_Tok ) { - assert ( m_pConstDef ); - assert ( m_pParser ); + assert ( m_pConstDef ); + assert ( m_pParser ); - QString strTok; - qreal fVal ( 0 ); - int iEnd ( 0 ); + QString strTok; + qreal fVal ( 0 ); + int iEnd ( 0 ); - // 2.) Check for user defined constant - // Read everything that could be a constant name - iEnd = ExtractToken ( m_pParser->ValidNameChars(), strTok, m_iPos ); - if ( iEnd != m_iPos ) - { - valmap_type::const_iterator item = m_pConstDef->find ( strTok ); - if ( item != m_pConstDef->end() ) - { - m_iPos = iEnd; - a_Tok.SetVal ( item->second, strTok ); + // 2.) Check for user defined constant + // Read everything that could be a constant name + iEnd = ExtractToken ( m_pParser->ValidNameChars(), strTok, m_iPos ); + if ( iEnd != m_iPos ) + { + valmap_type::const_iterator item = m_pConstDef->find ( strTok ); + if ( item != m_pConstDef->end() ) + { + m_iPos = iEnd; + a_Tok.SetVal ( item->second, strTok ); - if ( m_iSynFlags & noVAL ) - Error ( ecUNEXPECTED_VAL, m_iPos - strTok.length(), strTok ); + if ( m_iSynFlags & noVAL ) + { + Error ( ecUNEXPECTED_VAL, m_iPos - strTok.length(), strTok ); + } - m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN; - return true; - } - } + m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN; + return true; + } + } - // 3.call the value recognition functions provided by the user - // Call user defined value recognition functions - std::list::const_iterator item = m_vIdentFun.begin(); - for ( item = m_vIdentFun.begin(); item != m_vIdentFun.end(); ++item ) - { - int iStart = m_iPos; - if ( ( *item ) ( m_strFormula.mid ( m_iPos ), &m_iPos, &fVal ) == 1 ) - { - strTok = m_strFormula.mid ( iStart, m_iPos ); - if ( m_iSynFlags & noVAL ) - Error ( ecUNEXPECTED_VAL, m_iPos - strTok.length(), strTok ); + // 3.call the value recognition functions provided by the user + // Call user defined value recognition functions + std::list::const_iterator item = m_vIdentFun.begin(); + for ( item = m_vIdentFun.begin(); item != m_vIdentFun.end(); ++item ) + { + int iStart = m_iPos; + if ( ( *item ) ( m_strFormula.mid ( m_iPos ), &m_iPos, &fVal ) == 1 ) + { + strTok = m_strFormula.mid ( iStart, m_iPos ); + if ( m_iSynFlags & noVAL ) + { + Error ( ecUNEXPECTED_VAL, m_iPos - strTok.length(), strTok ); + } - a_Tok.SetVal ( fVal, strTok ); - m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN; - return true; - } - } + a_Tok.SetVal ( fVal, strTok ); + m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN; + return true; + } + } - return false; + return false; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Check wheter a token at a given position is a variable token. * @param a_Tok [out] If a variable token has been found it will be placed here. @@ -819,64 +910,82 @@ bool QmuParserTokenReader::IsValTok ( token_type &a_Tok ) */ bool QmuParserTokenReader::IsVarTok ( token_type &a_Tok ) { - if ( !m_pVarDef->size() ) - return false; + if ( m_pVarDef->size() == false) + { + return false; + } - QString strTok; - int iEnd = ExtractToken ( m_pParser->ValidNameChars(), strTok, m_iPos ); - if ( iEnd == m_iPos ) - return false; + QString strTok; + int iEnd = ExtractToken ( m_pParser->ValidNameChars(), strTok, m_iPos ); + if ( iEnd == m_iPos ) + { + return false; + } - varmap_type::const_iterator item = m_pVarDef->find ( strTok ); - if ( item == m_pVarDef->end() ) - return false; + varmap_type::const_iterator item = m_pVarDef->find ( strTok ); + if ( item == m_pVarDef->end() ) + { + return false; + } - if ( m_iSynFlags & noVAR ) - Error ( ecUNEXPECTED_VAR, m_iPos, strTok ); + if ( m_iSynFlags & noVAR ) + { + Error ( ecUNEXPECTED_VAR, m_iPos, strTok ); + } - m_pParser->OnDetectVar ( m_strFormula, m_iPos, iEnd ); + m_pParser->OnDetectVar ( m_strFormula, m_iPos, iEnd ); - m_iPos = iEnd; - a_Tok.SetVar ( item->second, strTok ); - m_UsedVar[item->first] = item->second; // Add variable to used-var-list + m_iPos = iEnd; + a_Tok.SetVar ( item->second, strTok ); + m_UsedVar[item->first] = item->second; // Add variable to used-var-list - m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR; + m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR; // Zur Info hier die SynFlags von IsVal(): // m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN; - return true; + return true; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- bool QmuParserTokenReader::IsStrVarTok ( token_type &a_Tok ) { - if ( !m_pStrVarDef || !m_pStrVarDef->size() ) - return false; + if ( m_pStrVarDef == false || m_pStrVarDef->size() == false) + { + return false; + } - QString strTok; - int iEnd = ExtractToken ( m_pParser->ValidNameChars(), strTok, m_iPos ); - if ( iEnd == m_iPos ) - return false; + QString strTok; + int iEnd = ExtractToken ( m_pParser->ValidNameChars(), strTok, m_iPos ); + if ( iEnd == m_iPos ) + { + return false; + } - strmap_type::const_iterator item = m_pStrVarDef->find ( strTok ); - if ( item == m_pStrVarDef->end() ) - return false; + strmap_type::const_iterator item = m_pStrVarDef->find ( strTok ); + if ( item == m_pStrVarDef->end() ) + { + return false; + } - if ( m_iSynFlags & noSTR ) - Error ( ecUNEXPECTED_VAR, m_iPos, strTok ); + if ( m_iSynFlags & noSTR ) + { + Error ( ecUNEXPECTED_VAR, m_iPos, strTok ); + } - m_iPos = iEnd; - if ( !m_pParser->m_vStringVarBuf.size() ) - Error ( ecINTERNAL_ERROR ); + m_iPos = iEnd; + if ( m_pParser->m_vStringVarBuf.size() == false) + { + Error ( ecINTERNAL_ERROR ); + } - a_Tok.SetString ( m_pParser->m_vStringVarBuf[item->second], m_pParser->m_vStringVarBuf.size() ); + a_Tok.SetString ( m_pParser->m_vStringVarBuf[item->second], m_pParser->m_vStringVarBuf.size() ); - m_iSynFlags = noANY ^ ( noBC | noOPT | noEND | noARG_SEP ); - return true; + m_iSynFlags = noANY ^ ( noBC | noOPT | noEND | noARG_SEP ); + return true; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Check wheter a token at a given position is an undefined variable. * @@ -886,52 +995,52 @@ bool QmuParserTokenReader::IsStrVarTok ( token_type &a_Tok ) */ bool QmuParserTokenReader::IsUndefVarTok ( token_type &a_Tok ) { - QString strTok; - int iEnd ( ExtractToken ( m_pParser->ValidNameChars(), strTok, m_iPos ) ); - if ( iEnd == m_iPos ) - { - return false; - } + QString strTok; + int iEnd ( ExtractToken ( m_pParser->ValidNameChars(), strTok, m_iPos ) ); + if ( iEnd == m_iPos ) + { + return false; + } - if ( m_iSynFlags & noVAR ) - { - // 20061021 added token string strTok instead of a_Tok.GetAsString() as the - // token identifier. - // related bug report: - // http://sourceforge.net/tracker/index.php?func=detail&aid=1578779&group_id=137191&atid=737979 - Error ( ecUNEXPECTED_VAR, m_iPos - a_Tok.GetAsString().length(), strTok ); - } + if ( m_iSynFlags & noVAR ) + { + // 20061021 added token string strTok instead of a_Tok.GetAsString() as the + // token identifier. + // related bug report: + // http://sourceforge.net/tracker/index.php?func=detail&aid=1578779&group_id=137191&atid=737979 + Error ( ecUNEXPECTED_VAR, m_iPos - a_Tok.GetAsString().length(), strTok ); + } - // If a factory is available implicitely create new variables - if ( m_pFactory ) - { - qreal *fVar = m_pFactory ( strTok, m_pFactoryData ); - a_Tok.SetVar ( fVar, strTok ); + // If a factory is available implicitely create new variables + if ( m_pFactory ) + { + qreal *fVar = m_pFactory ( strTok, m_pFactoryData ); + a_Tok.SetVar ( fVar, strTok ); - // Do not use m_pParser->DefineVar( strTok, fVar ); - // in order to define the new variable, it will clear the - // m_UsedVar array which will kill previousely defined variables - // from the list - // This is safe because the new variable can never override an existing one - // because they are checked first! - ( *m_pVarDef ) [strTok] = fVar; - m_UsedVar[strTok] = fVar; // Add variable to used-var-list - } - else - { - a_Tok.SetVar ( &m_fZero, strTok ); - m_UsedVar[strTok] = 0; // Add variable to used-var-list - } + // Do not use m_pParser->DefineVar( strTok, fVar ); + // in order to define the new variable, it will clear the + // m_UsedVar array which will kill previousely defined variables + // from the list + // This is safe because the new variable can never override an existing one + // because they are checked first! + ( *m_pVarDef ) [strTok] = fVar; + m_UsedVar[strTok] = fVar; // Add variable to used-var-list + } + else + { + a_Tok.SetVar ( &m_fZero, strTok ); + m_UsedVar[strTok] = 0; // Add variable to used-var-list + } - m_iPos = iEnd; + m_iPos = iEnd; - // Call the variable factory in order to let it define a new parser variable - m_iSynFlags = noVAL | noVAR | noFUN | noBO | noPOSTOP | noINFIXOP | noSTR; - return true; + // Call the variable factory in order to let it define a new parser variable + m_iSynFlags = noVAL | noVAR | noFUN | noBO | noPOSTOP | noINFIXOP | noSTR; + return true; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Check wheter a token at a given position is a string. * @param a_Tok [out] If a variable token has been found it will be placed here. @@ -941,38 +1050,47 @@ bool QmuParserTokenReader::IsUndefVarTok ( token_type &a_Tok ) */ bool QmuParserTokenReader::IsString ( token_type &a_Tok ) { - if ( m_strFormula[m_iPos] != '"' ) - return false; + if ( m_strFormula[m_iPos] != '"' ) + { + return false; + } - QString strBuf ( m_strFormula[m_iPos + 1] ); - int iEnd ( 0 ), iSkip ( 0 ); + QString strBuf ( m_strFormula[m_iPos + 1] ); + int iEnd ( 0 ), iSkip ( 0 ); - // parser over escaped '\"' end replace them with '"' - for ( iEnd = strBuf.indexOf ( "\"" ); iEnd != 0 && iEnd != -1; iEnd = strBuf.indexOf ( "\"", iEnd ) ) - { - if ( strBuf[iEnd - 1] != '\\' ) break; - strBuf.replace ( iEnd - 1, 2, "\"" ); - iSkip++; - } + // parser over escaped '\"' end replace them with '"' + for ( iEnd = strBuf.indexOf ( "\"" ); iEnd != 0 && iEnd != -1; iEnd = strBuf.indexOf ( "\"", iEnd ) ) + { + if ( strBuf[iEnd - 1] != '\\' ) + { + break; + } + strBuf.replace ( iEnd - 1, 2, "\"" ); + iSkip++; + } - if ( iEnd == -1 ) - Error ( ecUNTERMINATED_STRING, m_iPos, "\"" ); + if ( iEnd == -1 ) + { + Error ( ecUNTERMINATED_STRING, m_iPos, "\"" ); + } - QString strTok = strBuf.mid ( 0, iEnd ); + QString strTok = strBuf.mid ( 0, iEnd ); - if ( m_iSynFlags & noSTR ) - Error ( ecUNEXPECTED_STR, m_iPos, strTok ); + if ( m_iSynFlags & noSTR ) + { + Error ( ecUNEXPECTED_STR, m_iPos, strTok ); + } - m_pParser->m_vStringBuf.push_back ( strTok ); // Store string in internal buffer - a_Tok.SetString ( strTok, m_pParser->m_vStringBuf.size() ); + m_pParser->m_vStringBuf.push_back ( strTok ); // Store string in internal buffer + a_Tok.SetString ( strTok, m_pParser->m_vStringBuf.size() ); - m_iPos += strTok.length() + 2 + iSkip; // +2 wg Anfhrungszeichen; +iSkip fr entfernte escape zeichen - m_iSynFlags = noANY ^ ( noARG_SEP | noBC | noOPT | noEND ); + m_iPos += strTok.length() + 2 + iSkip; // +2 wg Anfhrungszeichen; +iSkip fr entfernte escape zeichen + m_iSynFlags = noANY ^ ( noARG_SEP | noBC | noOPT | noEND ); - return true; + return true; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- /** * @brief Create an error containing the parse error position. * @@ -985,19 +1103,18 @@ bool QmuParserTokenReader::IsString ( token_type &a_Tok ) */ void QmuParserTokenReader::Error ( EErrorCodes a_iErrc, int a_iPos, const QString &a_sTok ) const { - m_pParser->Error ( a_iErrc, a_iPos, a_sTok ); + m_pParser->Error ( a_iErrc, a_iPos, a_sTok ); } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- void QmuParserTokenReader::SetArgSep ( char_type cArgSep ) { - m_cArgSep = cArgSep; + m_cArgSep = cArgSep; } -//---------------------------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------------------------- QChar QmuParserTokenReader::GetArgSep() const { - return m_cArgSep; + return m_cArgSep; } } // namespace qmu - diff --git a/src/libs/qmuparser/qmuparsertokenreader.h b/src/libs/qmuparser/qmuparsertokenreader.h index 8abf62de6..8bf7a3efc 100644 --- a/src/libs/qmuparser/qmuparsertokenreader.h +++ b/src/libs/qmuparser/qmuparsertokenreader.h @@ -1,156 +1,154 @@ -/*************************************************************************************************** - ** - ** Original work Copyright (C) 2013 Ingo Berg - ** Modified work Copyright 2014 Roman Telezhynskyi - ** - ** Permission is hereby granted, free of charge, to any person obtaining a copy of this - ** software and associated documentation files (the "Software"), to deal in the Software - ** without restriction, including without limitation the rights to use, copy, modify, - ** merge, publish, distribute, sublicense, and/or sell copies of the Software, and to - ** permit persons to whom the Software is furnished to do so, subject to the following conditions: - ** - ** The above copyright notice and this permission notice shall be included in all copies or - ** substantial portions of the Software. - ** - ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT - ** NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - ** DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ** - ******************************************************************************************************/ - -#ifndef QMUPARSERTOKENREADER_H -#define QMUPARSERTOKENREADER_H - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "qmuparserdef.h" -#include "qmuparsertoken.h" - -/** @file - @brief This file contains the parser token reader definition. -*/ - - -namespace qmu -{ - // Forward declaration - class QmuParserBase; - - /** @brief Token reader for the ParserBase class. - - */ - class QmuParserTokenReader - { - private: - - typedef QmuParserToken token_type; - - public: - - QmuParserTokenReader(QmuParserBase *a_pParent); - QmuParserTokenReader* Clone(QmuParserBase *a_pParent) const; - - void AddValIdent(identfun_type a_pCallback); - void SetVarCreator(facfun_type a_pFactory, void *pUserData); - void SetFormula(const QString &a_strFormula); - void SetArgSep(char_type cArgSep); - - int GetPos() const; - const QString &GetExpr() const; - varmap_type& GetUsedVar(); - QChar GetArgSep() const; - - void IgnoreUndefVar(bool bIgnore); - void ReInit(); - token_type ReadNextToken(); - - private: - - /** @brief Syntax codes. - - The syntax codes control the syntax check done during the first time parsing of - the expression string. They are flags that indicate which tokens are allowed next - if certain tokens are identified. - */ - enum ESynCodes - { - noBO = 1 << 0, ///< to avoid i.e. "cos(7)(" - noBC = 1 << 1, ///< to avoid i.e. "sin)" or "()" - noVAL = 1 << 2, ///< to avoid i.e. "tan 2" or "sin(8)3.14" - noVAR = 1 << 3, ///< to avoid i.e. "sin a" or "sin(8)a" - noARG_SEP = 1 << 4, ///< to avoid i.e. ",," or "+," ... - noFUN = 1 << 5, ///< to avoid i.e. "sqrt cos" or "(1)sin" - noOPT = 1 << 6, ///< to avoid i.e. "(+)" - noPOSTOP = 1 << 7, ///< to avoid i.e. "(5!!)" "sin!" - noINFIXOP = 1 << 8, ///< to avoid i.e. "++4" "!!4" - noEND = 1 << 9, ///< to avoid unexpected end of formula - noSTR = 1 << 10, ///< to block numeric arguments on string functions - noASSIGN = 1 << 11, ///< to block assignement to constant i.e. "4=7" - noIF = 1 << 12, - noELSE = 1 << 13, - sfSTART_OF_LINE = noOPT | noBC | noPOSTOP | noASSIGN | noIF | noELSE | noARG_SEP, - noANY = ~0 ///< All of he above flags set - }; - - QmuParserTokenReader(const QmuParserTokenReader &a_Reader); - QmuParserTokenReader& operator=(const QmuParserTokenReader &a_Reader); - void Assign(const QmuParserTokenReader &a_Reader); - - void SetParent(QmuParserBase *a_pParent); - int ExtractToken(const QString &a_szCharSet, QString &a_strTok, int a_iPos) const; - int ExtractOperatorToken(QString &a_sTok, int a_iPos) const; - - bool IsBuiltIn(token_type &a_Tok); - bool IsArgSep(token_type &a_Tok); - bool IsEOF(token_type &a_Tok); - bool IsInfixOpTok(token_type &a_Tok); - bool IsFunTok(token_type &a_Tok); - bool IsPostOpTok(token_type &a_Tok); - bool IsOprt(token_type &a_Tok); - bool IsValTok(token_type &a_Tok); - bool IsVarTok(token_type &a_Tok); - bool IsStrVarTok(token_type &a_Tok); - bool IsUndefVarTok(token_type &a_Tok); - bool IsString(token_type &a_Tok); - void Error(EErrorCodes a_iErrc, - int a_iPos = -1, - const QString &a_sTok = QString() ) const; - - token_type& SaveBeforeReturn(const token_type &tok); - - QmuParserBase *m_pParser; - QString m_strFormula; - int m_iPos; - int m_iSynFlags; - bool m_bIgnoreUndefVar; - - const funmap_type *m_pFunDef; - const funmap_type *m_pPostOprtDef; - const funmap_type *m_pInfixOprtDef; - const funmap_type *m_pOprtDef; - const valmap_type *m_pConstDef; - const strmap_type *m_pStrVarDef; - varmap_type *m_pVarDef; ///< The only non const pointer to parser internals - facfun_type m_pFactory; - void *m_pFactoryData; - std::list m_vIdentFun; ///< Value token identification function - varmap_type m_UsedVar; - qreal m_fZero; ///< Dummy value of zero, referenced by undefined variables - int m_iBrackets; - token_type m_lastTok; - QChar m_cArgSep; ///< The character used for separating function arguments - }; -} // namespace qmu - -#endif - - +/*************************************************************************************************** + ** + ** Original work Copyright (C) 2013 Ingo Berg + ** Modified work Copyright 2014 Roman Telezhynskyi + ** + ** Permission is hereby granted, free of charge, to any person obtaining a copy of this + ** software and associated documentation files (the "Software"), to deal in the Software + ** without restriction, including without limitation the rights to use, copy, modify, + ** merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + ** permit persons to whom the Software is furnished to do so, subject to the following conditions: + ** + ** The above copyright notice and this permission notice shall be included in all copies or + ** substantial portions of the Software. + ** + ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + ** NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + ** DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ** + ******************************************************************************************************/ + +#ifndef QMUPARSERTOKENREADER_H +#define QMUPARSERTOKENREADER_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qmuparserdef.h" +#include "qmuparsertoken.h" + +/** @file + @brief This file contains the parser token reader definition. +*/ + + +namespace qmu +{ + // Forward declaration + class QmuParserBase; + + /** @brief Token reader for the ParserBase class. + + */ + class QmuParserTokenReader + { + private: + + typedef QmuParserToken token_type; + + public: + + QmuParserTokenReader(QmuParserBase *a_pParent); + QmuParserTokenReader* Clone(QmuParserBase *a_pParent) const; + + void AddValIdent(identfun_type a_pCallback); + void SetVarCreator(facfun_type a_pFactory, void *pUserData); + void SetFormula(const QString &a_strFormula); + void SetArgSep(char_type cArgSep); + + int GetPos() const; + const QString &GetExpr() const; + varmap_type& GetUsedVar(); + QChar GetArgSep() const; + + void IgnoreUndefVar(bool bIgnore); + void ReInit(); + token_type ReadNextToken(); + + private: + /** + * @brief Syntax codes. + * + * The syntax codes control the syntax check done during the first time parsing of + * the expression string. They are flags that indicate which tokens are allowed next + * if certain tokens are identified. + */ + enum ESynCodes + { + noBO = 1 << 0, ///< to avoid i.e. "cos(7)(" + noBC = 1 << 1, ///< to avoid i.e. "sin)" or "()" + noVAL = 1 << 2, ///< to avoid i.e. "tan 2" or "sin(8)3.14" + noVAR = 1 << 3, ///< to avoid i.e. "sin a" or "sin(8)a" + noARG_SEP = 1 << 4, ///< to avoid i.e. ",," or "+," ... + noFUN = 1 << 5, ///< to avoid i.e. "sqrt cos" or "(1)sin" + noOPT = 1 << 6, ///< to avoid i.e. "(+)" + noPOSTOP = 1 << 7, ///< to avoid i.e. "(5!!)" "sin!" + noINFIXOP = 1 << 8, ///< to avoid i.e. "++4" "!!4" + noEND = 1 << 9, ///< to avoid unexpected end of formula + noSTR = 1 << 10, ///< to block numeric arguments on string functions + noASSIGN = 1 << 11, ///< to block assignement to constant i.e. "4=7" + noIF = 1 << 12, + noELSE = 1 << 13, + sfSTART_OF_LINE = noOPT | noBC | noPOSTOP | noASSIGN | noIF | noELSE | noARG_SEP, + noANY = ~0 ///< All of he above flags set + }; + + QmuParserTokenReader(const QmuParserTokenReader &a_Reader); + QmuParserTokenReader& operator=(const QmuParserTokenReader &a_Reader); + void Assign(const QmuParserTokenReader &a_Reader); + + void SetParent(QmuParserBase *a_pParent); + int ExtractToken(const QString &a_szCharSet, QString &a_strTok, int a_iPos) const; + int ExtractOperatorToken(QString &a_sTok, int a_iPos) const; + + bool IsBuiltIn(token_type &a_Tok); + bool IsArgSep(token_type &a_Tok); + bool IsEOF(token_type &a_Tok); + bool IsInfixOpTok(token_type &a_Tok); + bool IsFunTok(token_type &a_Tok); + bool IsPostOpTok(token_type &a_Tok); + bool IsOprt(token_type &a_Tok); + bool IsValTok(token_type &a_Tok); + bool IsVarTok(token_type &a_Tok); + bool IsStrVarTok(token_type &a_Tok); + bool IsUndefVarTok(token_type &a_Tok); + bool IsString(token_type &a_Tok); + void Error(EErrorCodes a_iErrc, + int a_iPos = -1, + const QString &a_sTok = QString() ) const; + + token_type& SaveBeforeReturn(const token_type &tok); + + QmuParserBase *m_pParser; + QString m_strFormula; + int m_iPos; + int m_iSynFlags; + bool m_bIgnoreUndefVar; + + const funmap_type *m_pFunDef; + const funmap_type *m_pPostOprtDef; + const funmap_type *m_pInfixOprtDef; + const funmap_type *m_pOprtDef; + const valmap_type *m_pConstDef; + const strmap_type *m_pStrVarDef; + varmap_type *m_pVarDef; ///< The only non const pointer to parser internals + facfun_type m_pFactory; + void *m_pFactoryData; + std::list m_vIdentFun; ///< Value token identification function + varmap_type m_UsedVar; + qreal m_fZero; ///< Dummy value of zero, referenced by undefined variables + int m_iBrackets; + token_type m_lastTok; + QChar m_cArgSep; ///< The character used for separating function arguments + }; +} // namespace qmu + +#endif