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, bool aUseMils=false)
 
 ~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::Metric, 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 
Metric 
Inch 
Mil 

Definition at line 96 of file numeric_evaluator.h.

96 { Invalid, Metric, Inch, Mil };

Constructor & Destructor Documentation

◆ NUMERIC_EVALUATOR()

NUMERIC_EVALUATOR::NUMERIC_EVALUATOR ( EDA_UNITS  aUnits,
bool  aUseMils = false 
)

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  {
58  case EDA_UNITS::INCHES:
59  if( aUseMils )
61  else
63  break;
66  break;
67  default:m_defaultUnits = Unit::Metric;
68  break;
69  }
70 }
void * ParseAlloc(void *(*mallocProc)(size_t))

◆ ~NUMERIC_EVALUATOR()

NUMERIC_EVALUATOR::~NUMERIC_EVALUATOR ( )

Definition at line 73 of file numeric_evaluator.cpp.

74 {
76 
77  // Allow explicit call to destructor
78  m_parser = nullptr;
79 
80  Clear();
81 }
void ParseFree(void *p, void(*freeProc)(void *))

Member Function Documentation

◆ Clear()

void NUMERIC_EVALUATOR::Clear ( )

Definition at line 84 of file numeric_evaluator.cpp.

85 {
86  free( m_token.token );
87  m_token.token = nullptr;
88  m_token.input = nullptr;
89  m_parseError = true;
90  m_originalText = wxEmptyString;
91 }
struct NUMERIC_EVALUATOR::TokenStat m_token

Referenced by UNIT_BINDER::ChangeValue(), TEXT_CTRL_EVAL::SetValue(), and UNIT_BINDER::SetValue().

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

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

◆ GetVar()

double NUMERIC_EVALUATOR::GetVar ( const wxString &  aString)

Definition at line 377 of file numeric_evaluator.cpp.

378 {
379  if( m_varMap[ aString ] )
380  return m_varMap[ aString ];
381  else
382  return 0.0;
383 }
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 160 of file numeric_evaluator.cpp.

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

◆ OriginalText()

wxString NUMERIC_EVALUATOR::OriginalText ( ) const

Definition at line 122 of file numeric_evaluator.cpp.

123 {
124  return m_originalText;
125 }

Referenced by 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 94 of file numeric_evaluator.cpp.

95 {
96  m_parseError = true;
97 }

◆ parseOk()

void NUMERIC_EVALUATOR::parseOk ( )

Definition at line 100 of file numeric_evaluator.cpp.

101 {
102  m_parseFinished = true;
103 }

◆ parseSetResult()

void NUMERIC_EVALUATOR::parseSetResult ( double  val)

Definition at line 106 of file numeric_evaluator.cpp.

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

◆ Process()

bool NUMERIC_EVALUATOR::Process ( const wxString &  aString)

Definition at line 128 of file numeric_evaluator.cpp.

129 {
130  // Feed parser token after token until end of input.
131 
132  newString( aString );
133  m_parseError = false;
134  m_parseFinished = false;
135  Token tok;
136 
137  if( aString.IsEmpty() )
138  {
139  m_parseFinished = true;
140  return true;
141  }
142 
143  do
144  {
145  tok = getToken();
146  numEval::Parse( m_parser, tok.token, tok.value, this );
147 
148  if( m_parseFinished || tok.token == ENDS )
149  {
150  // Reset parser by passing zero as token ID, value is ignored.
151  numEval::Parse( m_parser, 0, tok.value, this );
152  break;
153  }
154  } while( tok.token );
155 
156  return !m_parseError;
157 }
void Parse(void *yyp, int yymajor, ParseTOKENTYPE yyminor ParseARG_PDECL)
#define ENDS
void newString(const wxString &aString)

Referenced by TEXT_CTRL_EVAL::evaluate(), 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::GetValue(), and UNIT_BINDER::onKillFocus().

◆ SetVar()

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

Definition at line 372 of file numeric_evaluator.cpp.

373 {
374  m_varMap[ aString ] = aValue;
375 }
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.

◆ m_localeDecimalSeparator

char NUMERIC_EVALUATOR::m_localeDecimalSeparator
private

Definition at line 171 of file numeric_evaluator.h.

Referenced by numEval::ColorSetBrush().

◆ m_originalText

wxString NUMERIC_EVALUATOR::m_originalText
private

Definition at line 179 of file numeric_evaluator.h.

◆ m_parseError

bool NUMERIC_EVALUATOR::m_parseError
private

Definition at line 174 of file numeric_evaluator.h.

Referenced by IsValid().

◆ m_parseFinished

bool NUMERIC_EVALUATOR::m_parseFinished
private

Definition at line 175 of file numeric_evaluator.h.

◆ m_parser

void* NUMERIC_EVALUATOR::m_parser
private

Definition at line 157 of file numeric_evaluator.h.

◆ 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: