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  Unit {
  Unit::Invalid, Unit::MM, Unit::CM, Unit::Inch,
  Unit::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 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 46 of file numeric_evaluator.cpp.

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

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 66 of file numeric_evaluator.cpp.

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

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 169 of file numeric_evaluator.cpp.

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

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, and NUMERIC_EVALUATOR::Token::value.

Referenced by Process().

◆ GetVar()

double NUMERIC_EVALUATOR::GetVar ( const wxString &  aString)

Definition at line 379 of file numeric_evaluator.cpp.

380 {
381  if( m_varMap[ aString ] )
382  return m_varMap[ aString ];
383  else
384  return 0.0;
385 }
std::map< wxString, double > m_varMap

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 153 of file numeric_evaluator.cpp.

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

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

Definition at line 115 of file numeric_evaluator.cpp.

116 {
117  return m_originalText;
118 }

References m_originalText.

Referenced by UNIT_BINDER::GetOriginalText(), UNIT_BINDER::onSetFocus(), and TEXT_CTRL_EVAL::onTextFocusGet().

◆ parse()

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

◆ parseError()

void NUMERIC_EVALUATOR::parseError ( const char *  s)

Definition at line 87 of file numeric_evaluator.cpp.

88 {
89  m_parseError = true;
90 }

References m_parseError.

◆ parseOk()

void NUMERIC_EVALUATOR::parseOk ( )

Definition at line 93 of file numeric_evaluator.cpp.

94 {
95  m_parseFinished = true;
96 }

References m_parseFinished.

◆ parseSetResult()

void NUMERIC_EVALUATOR::parseSetResult ( double  val)

Definition at line 99 of file numeric_evaluator.cpp.

100 {
101  if( std::isnan( val ) )
102  {
103  // Naively printing this with %g produces "nan" on some platforms
104  // and "-nan(ind)" on others (e.g. MSVC). So force a "standard" string.
105  snprintf( m_token.token, m_token.OutLen, "%s", "NaN" );
106  }
107  else
108  {
109  // Can be printed as a floating point
110  snprintf( m_token.token, m_token.OutLen, "%.10g", val );
111  }
112 }
struct NUMERIC_EVALUATOR::TokenStat m_token

References m_token, NUMERIC_EVALUATOR::TokenStat::OutLen, and NUMERIC_EVALUATOR::TokenStat::token.

◆ Process()

bool NUMERIC_EVALUATOR::Process ( const wxString &  aString)

Definition at line 121 of file numeric_evaluator.cpp.

122 {
123  // Feed parser token after token until end of input.
124 
125  newString( aString );
126  m_parseError = false;
127  m_parseFinished = false;
128  Token tok;
129 
130  if( aString.IsEmpty() )
131  {
132  m_parseFinished = true;
133  return true;
134  }
135 
136  do
137  {
138  tok = getToken();
139  numEval::Parse( m_parser, tok.token, tok.value, this );
140 
141  if( m_parseFinished || tok.token == ENDS )
142  {
143  // Reset parser by passing zero as token ID, value is ignored.
144  numEval::Parse( m_parser, 0, tok.value, this );
145  break;
146  }
147  } while( tok.token );
148 
149  return !m_parseError;
150 }
void newString(const wxString &aString)

References getToken(), m_parseError, m_parseFinished, m_parser, newString(), 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 ); }
std::map< wxString, double > m_varMap

References m_varMap.

◆ Result()

wxString NUMERIC_EVALUATOR::Result ( ) const
inline

Definition at line 116 of file numeric_evaluator.h.

116 { return wxString::FromUTF8( m_token.token ); }
struct NUMERIC_EVALUATOR::TokenStat m_token

References m_token, and NUMERIC_EVALUATOR::TokenStat::token.

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

◆ SetVar()

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

Definition at line 374 of file numeric_evaluator.cpp.

375 {
376  m_varMap[ aString ] = aValue;
377 }
std::map< wxString, double > m_varMap

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: