2022-10-10 19:43:11 +00:00
|
|
|
|
/*
|
|
|
|
|
Copyright (C) 2022 Fredrik Öhrström (gpl-3.0-or-later)
|
|
|
|
|
|
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifndef FORMULA_IMPLEMENTATION
|
|
|
|
|
#define FORMULA_IMPLEMENTATION
|
|
|
|
|
|
|
|
|
|
#include"formula.h"
|
|
|
|
|
#include"meters.h"
|
|
|
|
|
|
|
|
|
|
#include<stack>
|
|
|
|
|
|
2022-11-19 13:40:03 +00:00
|
|
|
|
struct FormulaImplementation;
|
|
|
|
|
|
2022-10-10 19:43:11 +00:00
|
|
|
|
struct NumericFormula
|
|
|
|
|
{
|
2022-11-19 13:40:03 +00:00
|
|
|
|
NumericFormula(FormulaImplementation *f, SIUnit u) : formula_(f), siunit_(u) { }
|
2022-11-01 11:14:48 +00:00
|
|
|
|
SIUnit &siunit() { return siunit_; }
|
2022-11-07 20:36:00 +00:00
|
|
|
|
// Calculate the formula and return the value in the given "to" unit.
|
|
|
|
|
virtual double calculate(SIUnit to) = 0;
|
2022-10-10 19:43:11 +00:00
|
|
|
|
virtual string str() = 0;
|
|
|
|
|
virtual string tree() = 0;
|
|
|
|
|
virtual ~NumericFormula() = 0;
|
|
|
|
|
|
2022-11-19 13:40:03 +00:00
|
|
|
|
FormulaImplementation *formula() { return formula_; }
|
|
|
|
|
|
2022-10-10 19:43:11 +00:00
|
|
|
|
private:
|
|
|
|
|
|
2022-11-19 13:40:03 +00:00
|
|
|
|
FormulaImplementation *formula_;
|
2022-11-01 11:14:48 +00:00
|
|
|
|
SIUnit siunit_;
|
2022-10-10 19:43:11 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct NumericFormulaConstant : public NumericFormula
|
|
|
|
|
{
|
2022-11-19 13:40:03 +00:00
|
|
|
|
NumericFormulaConstant(FormulaImplementation *f, Unit u, double c) : NumericFormula(f, u), constant_(c) {}
|
2022-11-07 20:36:00 +00:00
|
|
|
|
double calculate(SIUnit to);
|
2022-10-10 19:43:11 +00:00
|
|
|
|
string str();
|
|
|
|
|
string tree();
|
|
|
|
|
~NumericFormulaConstant();
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
|
|
double constant_;
|
|
|
|
|
};
|
|
|
|
|
|
2022-11-19 13:40:03 +00:00
|
|
|
|
struct NumericFormulaMeterField : public NumericFormula
|
2022-10-10 19:43:11 +00:00
|
|
|
|
{
|
2022-11-23 17:42:59 +00:00
|
|
|
|
NumericFormulaMeterField(FormulaImplementation *f, Unit u, string v, Quantity q)
|
|
|
|
|
: NumericFormula(f, u), vname_(v), quantity_(q) {}
|
2022-11-19 13:40:03 +00:00
|
|
|
|
|
2022-11-07 20:36:00 +00:00
|
|
|
|
double calculate(SIUnit to);
|
2022-10-10 19:43:11 +00:00
|
|
|
|
string str();
|
|
|
|
|
string tree();
|
2022-11-19 13:40:03 +00:00
|
|
|
|
~NumericFormulaMeterField();
|
2022-10-10 19:43:11 +00:00
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
2022-11-23 17:42:59 +00:00
|
|
|
|
string vname_;
|
|
|
|
|
Quantity quantity_;
|
2022-10-10 19:43:11 +00:00
|
|
|
|
};
|
|
|
|
|
|
2022-11-19 13:40:03 +00:00
|
|
|
|
struct NumericFormulaDVEntryField : public NumericFormula
|
|
|
|
|
{
|
|
|
|
|
NumericFormulaDVEntryField(FormulaImplementation *f, Unit u, DVEntryCounterType ct) : NumericFormula(f, u), counter_(ct) {}
|
|
|
|
|
|
|
|
|
|
double calculate(SIUnit to);
|
|
|
|
|
string str();
|
|
|
|
|
string tree();
|
|
|
|
|
~NumericFormulaDVEntryField();
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
|
|
DVEntryCounterType counter_;
|
|
|
|
|
};
|
|
|
|
|
|
2022-11-07 20:36:00 +00:00
|
|
|
|
struct NumericFormulaPair : public NumericFormula
|
|
|
|
|
{
|
2022-11-19 13:40:03 +00:00
|
|
|
|
NumericFormulaPair(FormulaImplementation *f, SIUnit siu,
|
2022-11-07 20:36:00 +00:00
|
|
|
|
unique_ptr<NumericFormula> &a,
|
|
|
|
|
unique_ptr<NumericFormula> &b,
|
|
|
|
|
string name, string op)
|
2022-11-19 13:40:03 +00:00
|
|
|
|
: NumericFormula(f, siu),
|
2022-11-07 20:36:00 +00:00
|
|
|
|
left_(std::move(a)),
|
|
|
|
|
right_(std::move(b)),
|
|
|
|
|
name_(name),
|
|
|
|
|
op_(op)
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
string str();
|
|
|
|
|
string tree();
|
|
|
|
|
~NumericFormulaPair();
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<NumericFormula> left_;
|
|
|
|
|
std::unique_ptr<NumericFormula> right_;
|
|
|
|
|
std::string name_;
|
|
|
|
|
std::string op_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct NumericFormulaAddition : public NumericFormulaPair
|
2022-10-10 19:43:11 +00:00
|
|
|
|
{
|
2022-11-19 13:40:03 +00:00
|
|
|
|
NumericFormulaAddition(FormulaImplementation *f, SIUnit siu,
|
2022-10-10 19:43:11 +00:00
|
|
|
|
unique_ptr<NumericFormula> &a,
|
|
|
|
|
unique_ptr<NumericFormula> &b)
|
2022-11-19 13:40:03 +00:00
|
|
|
|
: NumericFormulaPair(f, siu, a, b, "ADD", "+") {}
|
2022-10-10 19:43:11 +00:00
|
|
|
|
|
2022-11-07 20:36:00 +00:00
|
|
|
|
double calculate(SIUnit to);
|
2022-10-10 19:43:11 +00:00
|
|
|
|
|
|
|
|
|
~NumericFormulaAddition();
|
2022-11-07 20:36:00 +00:00
|
|
|
|
};
|
2022-10-10 19:43:11 +00:00
|
|
|
|
|
2022-11-07 20:36:00 +00:00
|
|
|
|
struct NumericFormulaSubtraction : public NumericFormulaPair
|
|
|
|
|
{
|
2022-11-19 13:40:03 +00:00
|
|
|
|
NumericFormulaSubtraction(FormulaImplementation *f, SIUnit siu,
|
2022-11-07 20:36:00 +00:00
|
|
|
|
unique_ptr<NumericFormula> &a,
|
|
|
|
|
unique_ptr<NumericFormula> &b)
|
2022-11-19 13:40:03 +00:00
|
|
|
|
: NumericFormulaPair(f, siu, a, b, "SUB", "-") {}
|
2022-10-10 19:43:11 +00:00
|
|
|
|
|
2022-11-07 20:36:00 +00:00
|
|
|
|
double calculate(SIUnit to);
|
|
|
|
|
|
|
|
|
|
~NumericFormulaSubtraction();
|
2022-10-10 19:43:11 +00:00
|
|
|
|
};
|
|
|
|
|
|
2022-11-07 20:36:00 +00:00
|
|
|
|
struct NumericFormulaMultiplication : public NumericFormulaPair
|
2022-11-01 11:14:48 +00:00
|
|
|
|
{
|
2022-11-19 13:40:03 +00:00
|
|
|
|
NumericFormulaMultiplication(FormulaImplementation *f, SIUnit siu,
|
2022-11-01 11:14:48 +00:00
|
|
|
|
unique_ptr<NumericFormula> &a,
|
|
|
|
|
unique_ptr<NumericFormula> &b)
|
2022-11-19 13:40:03 +00:00
|
|
|
|
: NumericFormulaPair(f, siu, a, b, "TIMES", "×") {}
|
2022-11-01 11:14:48 +00:00
|
|
|
|
|
2022-11-07 20:36:00 +00:00
|
|
|
|
double calculate(SIUnit to);
|
|
|
|
|
|
|
|
|
|
~NumericFormulaMultiplication();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct NumericFormulaDivision : public NumericFormulaPair
|
|
|
|
|
{
|
2022-11-19 13:40:03 +00:00
|
|
|
|
NumericFormulaDivision(FormulaImplementation *f, SIUnit siu,
|
2022-11-07 20:36:00 +00:00
|
|
|
|
unique_ptr<NumericFormula> &a,
|
|
|
|
|
unique_ptr<NumericFormula> &b)
|
2022-11-19 13:40:03 +00:00
|
|
|
|
: NumericFormulaPair(f, siu, a, b, "DIV", "÷") {}
|
2022-11-07 20:36:00 +00:00
|
|
|
|
|
|
|
|
|
double calculate(SIUnit to);
|
|
|
|
|
|
|
|
|
|
~NumericFormulaDivision();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct NumericFormulaExponentiation : public NumericFormulaPair
|
|
|
|
|
{
|
2022-11-19 13:40:03 +00:00
|
|
|
|
NumericFormulaExponentiation(FormulaImplementation *f, SIUnit siu,
|
2022-11-07 20:36:00 +00:00
|
|
|
|
unique_ptr<NumericFormula> &a,
|
|
|
|
|
unique_ptr<NumericFormula> &b)
|
2022-11-19 13:40:03 +00:00
|
|
|
|
: NumericFormulaPair(f, siu, a, b, "EXP", "^") {}
|
2022-11-07 20:36:00 +00:00
|
|
|
|
|
|
|
|
|
double calculate(SIUnit to);
|
|
|
|
|
|
|
|
|
|
~NumericFormulaExponentiation();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct NumericFormulaSquareRoot : public NumericFormula
|
|
|
|
|
{
|
2022-11-19 13:40:03 +00:00
|
|
|
|
NumericFormulaSquareRoot(FormulaImplementation *f, SIUnit siu,
|
2022-11-07 20:36:00 +00:00
|
|
|
|
unique_ptr<NumericFormula> &inner)
|
2022-11-19 13:40:03 +00:00
|
|
|
|
: NumericFormula(f, siu), inner_(std::move(inner)) {}
|
2022-11-07 20:36:00 +00:00
|
|
|
|
|
|
|
|
|
double calculate(SIUnit to);
|
2022-11-01 11:14:48 +00:00
|
|
|
|
string str();
|
|
|
|
|
string tree();
|
|
|
|
|
|
2022-11-07 20:36:00 +00:00
|
|
|
|
~NumericFormulaSquareRoot();
|
2022-11-01 11:14:48 +00:00
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
2022-11-07 20:36:00 +00:00
|
|
|
|
std::unique_ptr<NumericFormula> inner_;
|
2022-11-01 11:14:48 +00:00
|
|
|
|
};
|
|
|
|
|
|
2022-10-10 19:43:11 +00:00
|
|
|
|
enum class TokenType
|
|
|
|
|
{
|
|
|
|
|
SPACE,
|
|
|
|
|
LPAR,
|
|
|
|
|
RPAR,
|
|
|
|
|
NUMBER,
|
2022-11-26 13:15:14 +00:00
|
|
|
|
DATETIME,
|
|
|
|
|
TIME,
|
2022-10-10 19:43:11 +00:00
|
|
|
|
PLUS,
|
2022-11-07 20:36:00 +00:00
|
|
|
|
MINUS,
|
|
|
|
|
TIMES,
|
|
|
|
|
DIV,
|
|
|
|
|
EXP,
|
|
|
|
|
SQRT,
|
2022-10-10 19:43:11 +00:00
|
|
|
|
UNIT,
|
|
|
|
|
FIELD
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const char *toString(TokenType tt);
|
|
|
|
|
|
|
|
|
|
struct Token
|
|
|
|
|
{
|
|
|
|
|
Token(TokenType t, size_t s, size_t l) : type(t), start(s), len(l) {}
|
|
|
|
|
|
|
|
|
|
TokenType type;
|
|
|
|
|
size_t start;
|
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
|
|
string str(const string &s);
|
|
|
|
|
string vals(const string &s);
|
|
|
|
|
double val(const string &s);
|
|
|
|
|
Unit unit(const string &s);
|
2022-11-01 11:14:48 +00:00
|
|
|
|
|
|
|
|
|
string withMarker(const string &s);
|
2022-10-10 19:43:11 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct FormulaImplementation : public Formula
|
|
|
|
|
{
|
|
|
|
|
bool parse(Meter *m, const string &f);
|
|
|
|
|
bool valid();
|
2022-11-01 11:14:48 +00:00
|
|
|
|
string errors();
|
2022-11-19 13:40:03 +00:00
|
|
|
|
double calculate(Unit to, DVEntry *dve = NULL, Meter *m = NULL);
|
2022-10-10 19:43:11 +00:00
|
|
|
|
void clear();
|
|
|
|
|
string str();
|
|
|
|
|
string tree();
|
2022-11-19 13:40:03 +00:00
|
|
|
|
void setMeter(Meter *m);
|
|
|
|
|
void setDVEntry(DVEntry *dve);
|
2022-10-10 19:43:11 +00:00
|
|
|
|
|
2022-11-19 13:40:03 +00:00
|
|
|
|
// Pushes a constant on the formula builder stack.
|
2022-11-01 11:14:48 +00:00
|
|
|
|
void doConstant(Unit u, double c);
|
2022-11-19 13:40:03 +00:00
|
|
|
|
// Pushes a meter field read on the formula builder stack.
|
|
|
|
|
void doMeterField(Unit u, FieldInfo *fi);
|
|
|
|
|
// Pushes a dve entry field read on the formula builder stack.
|
|
|
|
|
void doDVEntryField(Unit u, DVEntryCounterType ct);
|
|
|
|
|
// Pops the two top nodes of the formula builder stack and pushes an addition on the formula builder stack.
|
2022-11-26 13:15:14 +00:00
|
|
|
|
// The target unit will be the supplied to unit.
|
|
|
|
|
void doAddition(const SIUnit &to);
|
2022-11-19 13:40:03 +00:00
|
|
|
|
// Pops the two top nodes of the formula builder stack and pushes a subtraction on the formula builder stack.
|
2022-11-26 13:15:14 +00:00
|
|
|
|
// The target unit will be the supplied to unit.
|
|
|
|
|
void doSubtraction(const SIUnit &to);
|
2022-11-19 13:40:03 +00:00
|
|
|
|
// Pops the two top nodes of the formula builder stack and pushes a multiplication on the formula builder stack.
|
2022-11-01 11:14:48 +00:00
|
|
|
|
// The target unit will be multiplication of the SI Units.
|
|
|
|
|
void doMultiplication();
|
2022-11-19 13:40:03 +00:00
|
|
|
|
// Pops the two top nodes of the formula builder stack and pushes a division on the formula builder stack.
|
2022-11-07 20:36:00 +00:00
|
|
|
|
// The target unit will be first SIUnit divided by the second SIUnit.
|
|
|
|
|
void doDivision();
|
2022-11-19 13:40:03 +00:00
|
|
|
|
// Pops the two top nodes of the formula builder stack and pushes an exponentiation on the formula builder stack.
|
2022-11-07 20:36:00 +00:00
|
|
|
|
// The target unit will be first SIUnit exponentiated.
|
|
|
|
|
void doExponentiation();
|
2022-11-19 13:40:03 +00:00
|
|
|
|
// Pops the single top node of the formula builder stack and pushes an squareroot on the formula builder stack.
|
2022-11-07 20:36:00 +00:00
|
|
|
|
// The target unit will be SIUnit square rooted.
|
|
|
|
|
void doSquareRoot();
|
2022-10-10 19:43:11 +00:00
|
|
|
|
|
|
|
|
|
~FormulaImplementation();
|
|
|
|
|
|
|
|
|
|
bool tokenize();
|
|
|
|
|
bool go();
|
|
|
|
|
size_t findSpace(size_t i);
|
|
|
|
|
size_t findNumber(size_t i);
|
2022-11-26 13:15:14 +00:00
|
|
|
|
size_t findDateTime(size_t i);
|
|
|
|
|
size_t findTime(size_t i);
|
2022-10-10 19:43:11 +00:00
|
|
|
|
size_t findUnit(size_t i);
|
|
|
|
|
size_t findPlus(size_t i);
|
2022-11-07 20:36:00 +00:00
|
|
|
|
size_t findMinus(size_t i);
|
|
|
|
|
size_t findTimes(size_t i);
|
|
|
|
|
size_t findDiv(size_t i);
|
|
|
|
|
size_t findExp(size_t i);
|
|
|
|
|
size_t findSqrt(size_t i);
|
2022-10-10 19:43:11 +00:00
|
|
|
|
size_t findLPar(size_t i);
|
|
|
|
|
size_t findRPar(size_t i);
|
|
|
|
|
size_t findField(size_t i);
|
|
|
|
|
|
|
|
|
|
Token *LA(size_t i);
|
|
|
|
|
size_t parseOps(size_t i);
|
|
|
|
|
size_t parsePar(size_t i);
|
|
|
|
|
|
|
|
|
|
void handleConstant(Token *number, Token *unit);
|
2022-11-26 13:15:14 +00:00
|
|
|
|
void handleSeconds(Token *number);
|
|
|
|
|
void handleUnixTimestamp(Token *number);
|
2022-11-01 11:14:48 +00:00
|
|
|
|
void handleAddition(Token *add);
|
2022-11-07 20:36:00 +00:00
|
|
|
|
void handleSubtraction(Token *add);
|
2022-11-01 11:14:48 +00:00
|
|
|
|
void handleMultiplication(Token *add);
|
2022-11-07 20:36:00 +00:00
|
|
|
|
void handleDivision(Token *add);
|
|
|
|
|
void handleExponentiation(Token *add);
|
|
|
|
|
void handleSquareRoot(Token *add);
|
2022-10-10 19:43:11 +00:00
|
|
|
|
void handleField(Token *field);
|
|
|
|
|
|
2022-11-01 11:14:48 +00:00
|
|
|
|
void pushOp(NumericFormula *nf);
|
|
|
|
|
std::unique_ptr<NumericFormula> popOp();
|
|
|
|
|
NumericFormula *topOp();
|
|
|
|
|
NumericFormula *top2Op();
|
|
|
|
|
|
2022-11-19 13:40:03 +00:00
|
|
|
|
Meter *meter() { return meter_; }
|
|
|
|
|
DVEntry *dventry() { return dventry_; }
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
2022-10-10 19:43:11 +00:00
|
|
|
|
bool valid_ = true;
|
2022-11-01 11:14:48 +00:00
|
|
|
|
std::vector<std::unique_ptr<NumericFormula>> op_stack_;
|
2022-10-10 19:43:11 +00:00
|
|
|
|
std::vector<Token> tokens_;
|
|
|
|
|
std::string formula_; // To be parsed.
|
2022-11-19 13:40:03 +00:00
|
|
|
|
Meter *meter_; // To be referenced when parsing and calculating.
|
|
|
|
|
DVEntry *dventry_; // To be referenced when calculating.
|
2022-11-01 11:14:48 +00:00
|
|
|
|
|
|
|
|
|
// Any errors during parsing are store here.
|
|
|
|
|
std::vector<std::string> errors_;
|
2022-10-10 19:43:11 +00:00
|
|
|
|
};
|
|
|
|
|
|
2022-11-19 13:40:03 +00:00
|
|
|
|
struct StringInterpolatorImplementation : public StringInterpolator
|
|
|
|
|
{
|
|
|
|
|
// Create a string interpolation from for example: "historic_{storage_counter / - 12 counter}_value"
|
|
|
|
|
// Which for a dventry with storage 13 will "generate historic_1_value"
|
|
|
|
|
bool parse(const std::string &f);
|
|
|
|
|
std::string apply(DVEntry *dve);
|
|
|
|
|
~StringInterpolatorImplementation();
|
|
|
|
|
|
|
|
|
|
// The strings store "historic_" "_value"
|
|
|
|
|
std::vector<std::string> strings_;
|
|
|
|
|
// The formula stores the parsed "storage_counter / - 12 counter" formula.
|
|
|
|
|
std::vector<std::unique_ptr<Formula>> formulas_;
|
|
|
|
|
};
|
|
|
|
|
|
2022-10-10 19:43:11 +00:00
|
|
|
|
#endif
|