KiCad PCB EDA Suite
numeric_evaluator.h
Go to the documentation of this file.
1/*
2 This file is part of libeval, a simple math expression evaluator
3
4 Copyright (C) 2017 Michael Geselbracht, [email protected]
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <https://www.gnu.org/licenses/>.
18*/
19
20/*
21An evaluator object is used to replace an input string that represents
22a mathematical expression by its result.
23
24Example: Consider the input "3+4". The result of this expression is "7".
25The NumericEvaluator can be used like this:
26
27 NumericEvaluator eval;
28 eval.process("3+4");
29 printf("3+4", eval.result());
30
31The same example with error checking. Please note that even a valid input string may result
32in an empty output string or "NaN".
33
34 NumericEvaluator eval;
35 bool ret = eval.process("3+4");
36 assert(ret == eval.isValid()); // isValid() reflects return value of process().
37 if (eval.isValid()) printf("3+4=%s\n", eval.result());
38
39Using variables
40Expressions can refer to variables if they were defined by previous expressions.
41A variable can be defined by an expression or by the setVar() method.
42Expressions that define/set variables do not have a result.
43
44 eval.process("x=1; y=2"); // Result is NaN
45 eval.setVar("z", 3);
46 eval.process("x+y+z");
47 printf("x+y+z=%s\n", eval.result());
48
49Input string storage
50An evaluator object can store and retrieve the original input string using a pointer
51as key. This can be used to restore the input string of a text entry field.
52
53 eval.process("25.4-0.7", &eval);
54 printf("%s = %s\n", eval.textInput(&eval), eval.result());
55
56Unit conversion
57The evaluator uses a default unit and constants can be specified with a unit.
58As long as no units are used the default unit is not relevant.
59Supported units are millimeters (mm), Mil (mil) and inch (")
60
61 eval.process("1\"");
62 printf("1\" = %s\n", eval.result());
63 eval.process("12.7 - 0.1\" - 50mil");
64 printf("12.7 - 0.1\" - 50mil = %s\n", eval.result());
65*/
66
67#ifndef NUMERIC_EVALUATOR_H_
68#define NUMERIC_EVALUATOR_H_
69
70#include <cstddef>
71#include <map>
72#include <string>
73
74#include <eda_units.h>
75
76// This namespace is used for the lemon parser
77namespace numEval
78{
79 struct TokenType
80 {
81 union
82 {
83 double dValue;
84 int iValue;
85 };
86
87 bool valid;
88 char text[32];
89 };
90
91} // namespace numEval
92
94{
95 enum class Unit { Invalid, MM, CM, Inch, Mil, Degrees, SI };
96
97public:
100
101 /* clear() should be invoked by the client if a new input string is to be processed. It
102 * will reset the parser. User defined variables are retained.
103 */
104 void Clear();
105
106 void SetDefaultUnits( EDA_UNITS aUnits );
107
108 void LocaleChanged();
109
110 /* Used by the lemon parser */
111 void parseError(const char* s);
112 void parseOk();
113 void parseSetResult(double);
114
115 /* Check if previous invocation of process() was successful */
116 inline bool IsValid() const { return !m_parseError; }
117
118 /* Result of string processing. Undefined if !isValid() */
119 inline wxString Result() const { return wxString::FromUTF8( m_token.token ); }
120
121 /* Evaluate input string.
122 * Result can be retrieved by result().
123 * Returns true if input string could be evaluated, otherwise false.
124 */
125 bool Process( const wxString& aString );
126
127 /* Retrieve the original text before evaluation. */
128 wxString OriginalText() const;
129
130 /* Add/set variable with value */
131 void SetVar( const wxString& aString, double aValue );
132
133 /* Get value of variable. Returns 0.0 if not defined. */
134 double GetVar( const wxString& aString );
135
136 /* Remove single variable */
137 void RemoveVar( const wxString& aString ) { m_varMap.erase( aString ); }
138
139 /* Remove all variables */
140 void ClearVar() { m_varMap.clear(); }
141
142protected:
143 /* Token type used by the tokenizer */
144 struct Token
145 {
146 int token;
148 };
149
150 /* Begin processing of a new input string */
151 void newString( const wxString& aString );
152
153 /* Tokenizer: Next token/value taken from input string. */
154 Token getToken();
155
156 /* Used by processing loop */
157 void parse( int token, numEval::TokenType value );
158
159private:
160 void* m_parser; // the current lemon parser state machine
161
162 /* Token state for input string. */
164 {
166 input( nullptr ),
167 token( nullptr ),
168 inputLen( 0 ),
169 outputLen( 0 ),
170 pos( 0 )
171 {};
172
173 const char* input; // current input string ("var=4")
174 char* token; // output token ("var", type:VAR; "4", type:VALUE)
175 size_t inputLen; // strlen(input)
176 size_t outputLen; // At least 64, up to input length
177 size_t pos; // current index
179
181
182 /* Parse progress. Set by parser actions. */
185
186 Unit m_defaultUnits; // Default unit for values
187
189
190 std::map<wxString, double> m_varMap;
191};
192
193
194#endif /* NUMERIC_EVALUATOR_H_ */
void parse(int token, numEval::TokenType value)
void parseSetResult(double)
wxString OriginalText() const
struct NUMERIC_EVALUATOR::TokenStat m_token
void newString(const wxString &aString)
void parseError(const char *s)
double GetVar(const wxString &aString)
wxString Result() const
NUMERIC_EVALUATOR(EDA_UNITS aUnits)
void RemoveVar(const wxString &aString)
void SetDefaultUnits(EDA_UNITS aUnits)
void SetVar(const wxString &aString, double aValue)
bool Process(const wxString &aString)
std::map< wxString, double > m_varMap
EDA_UNITS
Definition: eda_units.h:43
numEval::TokenType value