KiCad PCB EDA Suite
NUMERIC_EVALUATOR Class Reference

#include <numeric_evaluator.h>

Classes

struct  Token
 
struct  TokenStat
 

Public Member Functions

 NUMERIC_EVALUATOR (EDA_UNITS aUnits)
 
 ~NUMERIC_EVALUATOR ()
 
void Clear ()
 
void parseError (const char *s)
 
void parseOk ()
 
void parseSetResult (double)
 
bool IsValid () const
 
wxString Result () const
 
bool Process (const wxString &aString)
 
wxString OriginalText () const
 
void SetVar (const wxString &aString, double aValue)
 
double GetVar (const wxString &aString)
 
void RemoveVar (const wxString &aString)
 
void ClearVar ()
 

Protected Member Functions

void newString (const wxString &aString)
 
Token getToken ()
 
void parse (int token, numEval::TokenType value)
 

Private Types

enum class  Unit {
  Invalid , MM , CM , Inch ,
  Mil
}
 

Private Attributes

void * m_parser
 
struct NUMERIC_EVALUATOR::TokenStat m_token
 
char m_localeDecimalSeparator
 
bool m_parseError
 
bool m_parseFinished
 
Unit m_defaultUnits
 
wxString m_originalText
 
std::map< wxString, double > m_varMap
 

Detailed Description

Definition at line 94 of file numeric_evaluator.h.

Member Enumeration Documentation

◆ Unit

enum class NUMERIC_EVALUATOR::Unit
strongprivate
Enumerator
Invalid 
MM 
CM 
Inch 
Mil 

Definition at line 96 of file numeric_evaluator.h.

96{ Invalid, MM, CM, Inch, Mil };

Constructor & Destructor Documentation

◆ NUMERIC_EVALUATOR()

NUMERIC_EVALUATOR::NUMERIC_EVALUATOR ( EDA_UNITS  aUnits)

Definition at line 47 of file numeric_evaluator.cpp.

48{
49 struct lconv* lc = localeconv();
50 m_localeDecimalSeparator = *lc->decimal_point;
51
52 m_parseError = false;
53 m_parseFinished = false;
54
55 m_parser = numEval::ParseAlloc( malloc );
56
57 switch( aUnits )
58 {
62 default: m_defaultUnits = Unit::MM; break;
63 }
64}

References Inch, INCHES, m_defaultUnits, m_localeDecimalSeparator, m_parseError, m_parseFinished, m_parser, Mil, MILLIMETRES, MILS, and MM.

◆ ~NUMERIC_EVALUATOR()

NUMERIC_EVALUATOR::~NUMERIC_EVALUATOR ( )

Definition at line 67 of file numeric_evaluator.cpp.

68{
69 numEval::ParseFree( m_parser, free );
70
71 // Allow explicit call to destructor
72 m_parser = nullptr;
73
74 Clear();
75}

References Clear(), and m_parser.

Member Function Documentation

◆ Clear()

void NUMERIC_EVALUATOR::Clear ( )

◆ ClearVar()

void NUMERIC_EVALUATOR::ClearVar ( )
inline

Definition at line 137 of file numeric_evaluator.h.

137{ m_varMap.clear(); }
std::map< wxString, double > m_varMap

References m_varMap.

◆ getToken()

NUMERIC_EVALUATOR::Token NUMERIC_EVALUATOR::getToken ( )
protected

Definition at line 173 of file numeric_evaluator.cpp.

174{
175 Token retval;
176 size_t idx;
177
178 retval.token = ENDS;
179 retval.value.dValue = 0;
180 retval.value.valid = false;
181 retval.value.text[0] = 0;
182
183 if( m_token.token == nullptr )
184 return retval;
185
186 if( m_token.input == nullptr )
187 return retval;
188
189 if( m_token.pos >= m_token.inputLen )
190 return retval;
191
192 auto isDecimalSeparator = [ & ]( char ch ) -> bool {
193 return ( ch == m_localeDecimalSeparator || ch == '.' || ch == ',' );
194 };
195
196 // Lambda: get value as string, store into clToken.token and update current index.
197 auto extractNumber = [ & ]() {
198 bool haveSeparator = false;
199 idx = 0;
200 auto ch = m_token.input[ m_token.pos ];
201
202 do
203 {
204 if( isDecimalSeparator( ch ) && haveSeparator )
205 break;
206
207 m_token.token[ idx++ ] = ch;
208
209 if( isDecimalSeparator( ch ) )
210 haveSeparator = true;
211
212 ch = m_token.input[ ++m_token.pos ];
213 } while( isdigit( ch ) || isDecimalSeparator( ch ) );
214
215 m_token.token[ idx ] = 0;
216
217 // Ensure that the systems decimal separator is used
218 for( int i = strlen( m_token.token ); i; i-- )
219 {
220 if( isDecimalSeparator( m_token.token[ i - 1 ] ) )
222 }
223 };
224
225 // Lamda: Get unit for current token.
226 // Valid units are ", in, mm, mil and thou. Returns Unit::Invalid otherwise.
227 auto checkUnit = [ this ]() -> Unit {
228 char ch = m_token.input[ m_token.pos ];
229
230 if( ch == '"' )
231 {
232 m_token.pos++;
233 return Unit::Inch;
234 }
235
236 // Do not use strcasecmp() as it is not available on all platforms
237 const char* cptr = &m_token.input[ m_token.pos ];
238 const auto sizeLeft = m_token.inputLen - m_token.pos;
239
240 if( sizeLeft >= 2 && ch == 'm' && cptr[ 1 ] == 'm' && !isalnum( cptr[ 2 ] ) )
241 {
242 m_token.pos += 2;
243 return Unit::MM;
244 }
245
246 if( sizeLeft >= 2 && ch == 'c' && cptr[ 1 ] == 'm' && !isalnum( cptr[ 2 ] ) )
247 {
248 m_token.pos += 2;
249 return Unit::CM;
250 }
251
252 if( sizeLeft >= 2 && ch == 'i' && cptr[ 1 ] == 'n' && !isalnum( cptr[ 2 ] ) )
253 {
254 m_token.pos += 2;
255 return Unit::Inch;
256 }
257
258 if( sizeLeft >= 3 && ch == 'm' && cptr[ 1 ] == 'i' && cptr[ 2 ] == 'l'
259 && !isalnum( cptr[ 3 ] ) )
260 {
261 m_token.pos += 3;
262 return Unit::Mil;
263 }
264
265 if( sizeLeft >= 4 && ch == 't' && cptr[ 1 ] == 'h' && cptr[ 2 ] == 'o'
266 && cptr[ 3 ] == 'u' && !isalnum( cptr[ 4 ] ) )
267 {
268 m_token.pos += 4;
269 return Unit::Mil;
270 }
271
272 return Unit::Invalid;
273 };
274
275 char ch;
276
277 // Start processing of first/next token: Remove whitespace
278 for( ;; )
279 {
280 ch = m_token.input[ m_token.pos ];
281
282 if( ch == ' ' )
283 m_token.pos++;
284 else
285 break;
286 }
287
288 Unit convertFrom;
289
290 if( ch == 0 )
291 {
292 /* End of input */
293 }
294 else if( isdigit( ch ) || isDecimalSeparator( ch ))
295 {
296 // VALUE
297 extractNumber();
298 retval.token = VALUE;
299 retval.value.dValue = atof( m_token.token );
300 }
301 else if(( convertFrom = checkUnit()) != Unit::Invalid )
302 {
303 // UNIT
304 // Units are appended to a VALUE.
305 // Determine factor to default unit if unit for value is given.
306 // Example: Default is mm, unit is inch: factor is 25.4
307 // The factor is assigned to the terminal UNIT. The actual
308 // conversion is done within a parser action.
309 retval.token = UNIT;
310
311 if( m_defaultUnits == Unit::MM )
312 {
313 switch( convertFrom )
314 {
315 case Unit::Inch: retval.value.dValue = 25.4; break;
316 case Unit::Mil: retval.value.dValue = 25.4 / 1000.0; break;
317 case Unit::MM: retval.value.dValue = 1.0; break;
318 case Unit::CM: retval.value.dValue = 10.0; break;
319 case Unit::Invalid: break;
320 }
321 }
322 else if( m_defaultUnits == Unit::Inch )
323 {
324 switch( convertFrom )
325 {
326 case Unit::Inch: retval.value.dValue = 1.0; break;
327 case Unit::Mil: retval.value.dValue = 1.0 / 1000.0; break;
328 case Unit::MM: retval.value.dValue = 1.0 / 25.4; break;
329 case Unit::CM: retval.value.dValue = 1.0 / 2.54; break;
330 case Unit::Invalid: break;
331 }
332 }
333 else if( m_defaultUnits == Unit::Mil )
334 {
335 switch( convertFrom )
336 {
337 case Unit::Inch: retval.value.dValue = 1.0 * 1000.0; break;
338 case Unit::Mil: retval.value.dValue = 1.0; break;
339 case Unit::MM: retval.value.dValue = 1000.0 / 25.4; break;
340 case Unit::CM: retval.value.dValue = 1000.0 / 2.54; break;
341 case Unit::Invalid: break;
342 }
343 }
344 }
345 else if( isalpha( ch ))
346 {
347 // VAR
348 const char* cptr = &m_token.input[ m_token.pos ];
349 cptr++;
350
351 while( isalnum( *cptr ))
352 cptr++;
353
354 retval.token = VAR;
355 size_t bytesToCopy = cptr - &m_token.input[ m_token.pos ];
356
357 if( bytesToCopy >= sizeof( retval.value.text ) )
358 bytesToCopy = sizeof( retval.value.text ) - 1;
359
360 strncpy( retval.value.text, &m_token.input[ m_token.pos ], bytesToCopy );
361 retval.value.text[ bytesToCopy ] = 0;
362 m_token.pos += cptr - &m_token.input[ m_token.pos ];
363 }
364 else
365 {
366 // Single char tokens
367 switch( ch )
368 {
369 case '+': retval.token = PLUS; break;
370 case '-': retval.token = MINUS; break;
371 case '*': retval.token = MULT; break;
372 case '/': retval.token = DIVIDE; break;
373 case '(': retval.token = PARENL; break;
374 case ')': retval.token = PARENR; break;
375 case '=': retval.token = ASSIGN; break;
376 case ';': retval.token = SEMCOL; break;
377 default: m_parseError = true; break; /* invalid character */
378 }
379
380 m_token.pos++;
381 }
382
383 if( !m_parseError )
384 retval.value.valid = true;
385
386 return retval;
387}

References CM, numEval::TokenType::dValue, Inch, NUMERIC_EVALUATOR::TokenStat::input, NUMERIC_EVALUATOR::TokenStat::inputLen, Invalid, m_defaultUnits, m_localeDecimalSeparator, m_parseError, m_token, Mil, MM, NUMERIC_EVALUATOR::TokenStat::pos, numEval::TokenType::text, NUMERIC_EVALUATOR::Token::token, NUMERIC_EVALUATOR::TokenStat::token, numEval::TokenType::valid, and NUMERIC_EVALUATOR::Token::value.

Referenced by Process().

◆ GetVar()

double NUMERIC_EVALUATOR::GetVar ( const wxString &  aString)

Definition at line 394 of file numeric_evaluator.cpp.

395{
396 if( m_varMap[ aString ] )
397 return m_varMap[ aString ];
398 else
399 return 0.0;
400}

References m_varMap.

◆ IsValid()

bool NUMERIC_EVALUATOR::IsValid ( ) const
inline

Definition at line 113 of file numeric_evaluator.h.

113{ return !m_parseError; }

References m_parseError.

◆ newString()

void NUMERIC_EVALUATOR::newString ( const wxString &  aString)
protected

Definition at line 157 of file numeric_evaluator.cpp.

158{
159 Clear();
160
161 m_originalText = aString;
162
163 m_token.token = reinterpret_cast<decltype( m_token.token )>( malloc( TokenStat::OutLen + 1 ) );
164 strcpy( m_token.token, "0" );
165 m_token.inputLen = aString.length();
166 m_token.pos = 0;
167 m_token.input = aString.mb_str();
168
169 m_parseFinished = false;
170}

References Clear(), NUMERIC_EVALUATOR::TokenStat::input, NUMERIC_EVALUATOR::TokenStat::inputLen, m_originalText, m_parseFinished, m_token, NUMERIC_EVALUATOR::TokenStat::OutLen, NUMERIC_EVALUATOR::TokenStat::pos, and NUMERIC_EVALUATOR::TokenStat::token.

Referenced by Process().

◆ OriginalText()

wxString NUMERIC_EVALUATOR::OriginalText ( ) const

◆ parse()

void NUMERIC_EVALUATOR::parse ( int  token,
numEval::TokenType  value 
)
protected

◆ parseError()

void NUMERIC_EVALUATOR::parseError ( const char *  s)

Definition at line 88 of file numeric_evaluator.cpp.

89{
90 m_parseError = true;
91}

References m_parseError.

◆ parseOk()

void NUMERIC_EVALUATOR::parseOk ( )

Definition at line 94 of file numeric_evaluator.cpp.

95{
96 m_parseFinished = true;
97}

References m_parseFinished.

◆ parseSetResult()

void NUMERIC_EVALUATOR::parseSetResult ( double  val)

Definition at line 100 of file numeric_evaluator.cpp.

101{
102 if( std::isnan( val ) )
103 {
104 // Naively printing this with %g produces "nan" on some platforms
105 // and "-nan(ind)" on others (e.g. MSVC). So force a "standard" string.
106 snprintf( m_token.token, m_token.OutLen, "%s", "NaN" );
107 }
108 else
109 {
110 // Can be printed as a floating point
111 // Warning: DO NOT use a format like %f or %g, because they can create issues.
112 // especially %g can generate an exponent, incompatible with UNIT_BINDER
113 // Use the optimized Double2Str
114 snprintf( m_token.token, m_token.OutLen, "%s", Double2Str( val ).c_str() );
115 }
116}
std::string Double2Str(double aValue)
Print a float number without using scientific notation and no trailing 0 We want to avoid scientific ...

References Double2Str(), m_token, NUMERIC_EVALUATOR::TokenStat::OutLen, and NUMERIC_EVALUATOR::TokenStat::token.

◆ Process()

bool NUMERIC_EVALUATOR::Process ( const wxString &  aString)

Definition at line 125 of file numeric_evaluator.cpp.

126{
127 // Feed parser token after token until end of input.
128
129 newString( aString );
130 m_parseError = false;
131 m_parseFinished = false;
132 Token tok;
133
134 if( aString.IsEmpty() )
135 {
136 m_parseFinished = true;
137 return true;
138 }
139
140 do
141 {
142 tok = getToken();
143 numEval::Parse( m_parser, tok.token, tok.value, this );
144
145 if( m_parseFinished || tok.token == ENDS )
146 {
147 // Reset parser by passing zero as token ID, value is ignored.
148 numEval::Parse( m_parser, 0, tok.value, this );
149 break;
150 }
151 } while( tok.token );
152
153 return !m_parseError;
154}
void newString(const wxString &aString)
PARSE_RESULT Parse(const wxString &aString, NOTATION aNotation=NOTATION::SI, SIM_VALUE::TYPE aValueType=SIM_VALUE::TYPE_FLOAT)
Definition: sim_value.cpp:189

References getToken(), m_parseError, m_parseFinished, m_parser, newString(), SIM_VALUE_PARSER::Parse(), NUMERIC_EVALUATOR::Token::token, and NUMERIC_EVALUATOR::Token::value.

Referenced by TEXT_CTRL_EVAL::evaluate(), UNIT_BINDER::GetDoubleValue(), UNIT_BINDER::GetValue(), and UNIT_BINDER::onKillFocus().

◆ RemoveVar()

void NUMERIC_EVALUATOR::RemoveVar ( const wxString &  aString)
inline

Definition at line 134 of file numeric_evaluator.h.

134{ m_varMap.erase( aString ); }

References m_varMap.

◆ Result()

wxString NUMERIC_EVALUATOR::Result ( ) const
inline

◆ SetVar()

void NUMERIC_EVALUATOR::SetVar ( const wxString &  aString,
double  aValue 
)

Definition at line 389 of file numeric_evaluator.cpp.

390{
391 m_varMap[ aString ] = aValue;
392}

References m_varMap.

Member Data Documentation

◆ m_defaultUnits

Unit NUMERIC_EVALUATOR::m_defaultUnits
private

Definition at line 177 of file numeric_evaluator.h.

Referenced by getToken(), and NUMERIC_EVALUATOR().

◆ m_localeDecimalSeparator

char NUMERIC_EVALUATOR::m_localeDecimalSeparator
private

Definition at line 171 of file numeric_evaluator.h.

Referenced by getToken(), and NUMERIC_EVALUATOR().

◆ m_originalText

wxString NUMERIC_EVALUATOR::m_originalText
private

Definition at line 179 of file numeric_evaluator.h.

Referenced by Clear(), newString(), and OriginalText().

◆ m_parseError

bool NUMERIC_EVALUATOR::m_parseError
private

Definition at line 174 of file numeric_evaluator.h.

Referenced by Clear(), getToken(), IsValid(), NUMERIC_EVALUATOR(), parseError(), and Process().

◆ m_parseFinished

bool NUMERIC_EVALUATOR::m_parseFinished
private

Definition at line 175 of file numeric_evaluator.h.

Referenced by newString(), NUMERIC_EVALUATOR(), parseOk(), and Process().

◆ m_parser

void* NUMERIC_EVALUATOR::m_parser
private

Definition at line 157 of file numeric_evaluator.h.

Referenced by NUMERIC_EVALUATOR(), Process(), and ~NUMERIC_EVALUATOR().

◆ m_token

struct NUMERIC_EVALUATOR::TokenStat NUMERIC_EVALUATOR::m_token
private

◆ m_varMap

std::map<wxString, double> NUMERIC_EVALUATOR::m_varMap
private

Definition at line 181 of file numeric_evaluator.h.

Referenced by ClearVar(), GetVar(), RemoveVar(), and SetVar().


The documentation for this class was generated from the following files: