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>
|
|
|
|
|
|
|
|
|
|
struct NumericFormula
|
|
|
|
|
{
|
2022-11-01 11:14:48 +00:00
|
|
|
|
NumericFormula(SIUnit u) : siunit_(u) { }
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
2022-11-01 11:14:48 +00:00
|
|
|
|
SIUnit siunit_;
|
2022-10-10 19:43:11 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct NumericFormulaConstant : public NumericFormula
|
|
|
|
|
{
|
|
|
|
|
NumericFormulaConstant(Unit u, double c) : NumericFormula(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_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct NumericFormulaField : public NumericFormula
|
|
|
|
|
{
|
|
|
|
|
NumericFormulaField(Unit u, Meter *m, FieldInfo *fi) : NumericFormula(u), meter_(m), field_info_(fi) {}
|
2022-11-07 20:36:00 +00:00
|
|
|
|
double calculate(SIUnit to);
|
2022-10-10 19:43:11 +00:00
|
|
|
|
string str();
|
|
|
|
|
string tree();
|
|
|
|
|
~NumericFormulaField();
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
|
|
Meter *meter_;
|
|
|
|
|
FieldInfo *field_info_;
|
|
|
|
|
};
|
|
|
|
|
|
2022-11-07 20:36:00 +00:00
|
|
|
|
struct NumericFormulaPair : public NumericFormula
|
|
|
|
|
{
|
|
|
|
|
NumericFormulaPair(SIUnit siu,
|
|
|
|
|
unique_ptr<NumericFormula> &a,
|
|
|
|
|
unique_ptr<NumericFormula> &b,
|
|
|
|
|
string name, string op)
|
|
|
|
|
: NumericFormula(siu),
|
|
|
|
|
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-01 11:14:48 +00:00
|
|
|
|
NumericFormulaAddition(SIUnit siu,
|
2022-10-10 19:43:11 +00:00
|
|
|
|
unique_ptr<NumericFormula> &a,
|
|
|
|
|
unique_ptr<NumericFormula> &b)
|
2022-11-07 20:36:00 +00:00
|
|
|
|
: NumericFormulaPair(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
|
|
|
|
|
{
|
|
|
|
|
NumericFormulaSubtraction(SIUnit siu,
|
|
|
|
|
unique_ptr<NumericFormula> &a,
|
|
|
|
|
unique_ptr<NumericFormula> &b)
|
|
|
|
|
: NumericFormulaPair(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
|
|
|
|
{
|
|
|
|
|
NumericFormulaMultiplication(SIUnit siu,
|
|
|
|
|
unique_ptr<NumericFormula> &a,
|
|
|
|
|
unique_ptr<NumericFormula> &b)
|
2022-11-07 20:36:00 +00:00
|
|
|
|
: NumericFormulaPair(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
|
|
|
|
|
{
|
|
|
|
|
NumericFormulaDivision(SIUnit siu,
|
|
|
|
|
unique_ptr<NumericFormula> &a,
|
|
|
|
|
unique_ptr<NumericFormula> &b)
|
|
|
|
|
: NumericFormulaPair(siu, a, b, "DIV", "÷") {}
|
|
|
|
|
|
|
|
|
|
double calculate(SIUnit to);
|
|
|
|
|
|
|
|
|
|
~NumericFormulaDivision();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct NumericFormulaExponentiation : public NumericFormulaPair
|
|
|
|
|
{
|
|
|
|
|
NumericFormulaExponentiation(SIUnit siu,
|
|
|
|
|
unique_ptr<NumericFormula> &a,
|
|
|
|
|
unique_ptr<NumericFormula> &b)
|
|
|
|
|
: NumericFormulaPair(siu, a, b, "EXP", "^") {}
|
|
|
|
|
|
|
|
|
|
double calculate(SIUnit to);
|
|
|
|
|
|
|
|
|
|
~NumericFormulaExponentiation();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct NumericFormulaSquareRoot : public NumericFormula
|
|
|
|
|
{
|
|
|
|
|
NumericFormulaSquareRoot(SIUnit siu,
|
|
|
|
|
unique_ptr<NumericFormula> &inner)
|
|
|
|
|
: NumericFormula(siu), inner_(std::move(inner)) {}
|
|
|
|
|
|
|
|
|
|
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,
|
|
|
|
|
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-10-10 19:43:11 +00:00
|
|
|
|
double calculate(Unit to);
|
|
|
|
|
void clear();
|
|
|
|
|
string str();
|
|
|
|
|
string tree();
|
|
|
|
|
|
|
|
|
|
// Pushes a constant on the stack.
|
2022-11-01 11:14:48 +00:00
|
|
|
|
void doConstant(Unit u, double c);
|
|
|
|
|
// Pushes a field read on the stack.
|
|
|
|
|
void doField(Unit u, Meter *m, FieldInfo *fi);
|
2022-11-07 20:36:00 +00:00
|
|
|
|
// Pops the two top nodes of the stack and pushes an addition on the stack.
|
2022-11-01 11:14:48 +00:00
|
|
|
|
// The target unit will be the first unit of the two operands.
|
|
|
|
|
void doAddition();
|
2022-11-07 20:36:00 +00:00
|
|
|
|
// Pops the two top nodes of the stack and pushes a subtraction on the stack.
|
|
|
|
|
// The target unit will be the first unit of the two operands.
|
|
|
|
|
void doSubtraction();
|
|
|
|
|
// Pops the two top nodes of the stack and pushes a multiplication on the stack.
|
2022-11-01 11:14:48 +00:00
|
|
|
|
// The target unit will be multiplication of the SI Units.
|
|
|
|
|
void doMultiplication();
|
2022-11-07 20:36:00 +00:00
|
|
|
|
// Pops the two top nodes of the stack and pushes a division on the stack.
|
|
|
|
|
// The target unit will be first SIUnit divided by the second SIUnit.
|
|
|
|
|
void doDivision();
|
|
|
|
|
// Pops the two top nodes of the stack and pushes an exponentiation on the stack.
|
|
|
|
|
// The target unit will be first SIUnit exponentiated.
|
|
|
|
|
void doExponentiation();
|
|
|
|
|
// Pops the single top node of the stack and pushes an squareroot on the stack.
|
|
|
|
|
// The target unit will be SIUnit square rooted.
|
|
|
|
|
void doSquareRoot();
|
2022-10-10 19:43:11 +00:00
|
|
|
|
|
|
|
|
|
~FormulaImplementation();
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
|
|
bool tokenize();
|
|
|
|
|
bool go();
|
|
|
|
|
size_t findSpace(size_t i);
|
|
|
|
|
size_t findNumber(size_t i);
|
|
|
|
|
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-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-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.
|
|
|
|
|
Meter *meter_; // To be referenced when parsing.
|
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
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#endif
|