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 <base_units.h>
75
76// This namespace is used for the lemon parser
77namespace numEval
78{
79
80 struct TokenType
81 {
82 union
83 {
84 double dValue;
85 int iValue;
86 };
87
88 bool valid;
89 char text[32];
90 };
91
92} // namespace numEval
93
95{
96 enum class Unit { Invalid, MM, CM, Inch, Mil };
97
98public:
101
102 /* clear() should be invoked by the client if a new input string is to be processed. It
103 * will reset the parser. User defined variables are retained.
104 */
105 void Clear();
106
107 /* Used by the lemon parser */
108 void parseError(const char* s);
109 void parseOk();
110 void parseSetResult(double);
111
112 /* Check if previous invocation of process() was successful */
113 inline bool IsValid() const { return !m_parseError; }
114
115 /* Result of string processing. Undefined if !isValid() */
116 inline wxString Result() const { return wxString::FromUTF8( m_token.token ); }
117
118 /* Evaluate input string.
119 * Result can be retrieved by result().
120 * Returns true if input string could be evaluated, otherwise false.
121 */
122 bool Process( const wxString& aString );
123
124 /* Retrieve the original text before evaluation. */
125 wxString OriginalText() const;
126
127 /* Add/set variable with value */
128 void SetVar( const wxString& aString, double aValue );
129
130 /* Get value of variable. Returns 0.0 if not defined. */
131 double GetVar( const wxString& aString );
132
133 /* Remove single variable */
134 void RemoveVar( const wxString& aString ) { m_varMap.erase( aString ); }
135
136 /* Remove all variables */
137 void ClearVar() { m_varMap.clear(); }
138
139protected:
140 /* Token type used by the tokenizer */
141 struct Token
142 {
143 int token;
145 };
146
147 /* Begin processing of a new input string */
148 void newString( const wxString& aString );
149
150 /* Tokenizer: Next token/value taken from input string. */
151 Token getToken();
152
153 /* Used by processing loop */
154 void parse( int token, numEval::TokenType value );
155
156private:
157 void* m_parser; // the current lemon parser state machine
158
159 /* Token state for input string. */
161 {
162 enum { OutLen = 32 };
163 TokenStat() : input( nullptr ), token( nullptr ), inputLen( 0 ), pos( 0 ) { /* empty */ }
164 const char* input; // current input string ("var=4")
165 char* token; // output token ("var", type:VAR; "4", type:VALUE)
166 size_t inputLen; // strlen(input)
167 size_t pos; // current index
168 }
170
172
173 /* Parse progress. Set by parser actions. */
176
177 Unit m_defaultUnits; // Default unit for values
178
180
181 std::map<wxString, double> m_varMap;
182};
183
184
185#endif /* NUMERIC_EVALUATOR_H_ */
Implementation of conversion functions that require both schematic and board internal units.
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 SetVar(const wxString &aString, double aValue)
bool Process(const wxString &aString)
std::map< wxString, double > m_varMap
EDA_UNITS
Definition: eda_units.h:39
numEval::TokenType value