KiCad PCB EDA Suite
libeval_compiler.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) 2007 Michael Geselbracht, mgeselbracht3@gmail.com
5  Copyright (C) 2019-2020 KiCad Developers, see AUTHORS.txt for contributors.
6 
7  This program is free software: you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation, either version 3 of the License, or
10  (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20 
21 #ifndef __LIBEVAL_COMPILER_H
22 #define __LIBEVAL_COMPILER_H
23 
24 #include <cstddef>
25 #include <functional>
26 #include <map>
27 #include <string>
28 #include <stack>
29 
30 #include <base_units.h>
31 #include <wx/intl.h>
32 
33 #if defined(WIN32)
34 // This gets leaked by python headers on MSVC only and will cause chaos
35 #undef COMPILER
36 #endif
37 
38 #define TR_OP_BINARY_MASK 0x200
39 #define TR_OP_UNARY_MASK 0x100
40 
41 #define TR_OP_MUL 0x201
42 #define TR_OP_DIV 0x202
43 #define TR_OP_ADD 0x203
44 #define TR_OP_SUB 0x204
45 #define TR_OP_LESS 0x25
46 #define TR_OP_GREATER 0x206
47 #define TR_OP_LESS_EQUAL 0x207
48 #define TR_OP_GREATER_EQUAL 0x208
49 #define TR_OP_EQUAL 0x209
50 #define TR_OP_NOT_EQUAL 0x20a
51 #define TR_OP_BOOL_AND 0x20b
52 #define TR_OP_BOOL_OR 0x20c
53 #define TR_OP_BOOL_NOT 0x100
54 #define TR_OP_FUNC_CALL 24
55 #define TR_OP_METHOD_CALL 25
56 #define TR_UOP_PUSH_VAR 1
57 #define TR_UOP_PUSH_VALUE 2
58 
59 // This namespace is used for the lemon parser
60 namespace LIBEVAL
61 {
62 
63 class COMPILER;
64 
66 {
67  CST_PARSE = 0,
70 };
71 
73 {
74  bool pendingError = false;
75 
77  wxString message;
78  int srcPos;
79 };
80 
81 
83 {
84  VT_STRING = 1,
88 };
89 
91 {
93  TR_NUMBER = 1,
95  TR_ASSIGN = 3,
97  TR_STRING = 5,
98  TR_UNIT = 6,
101 };
102 
103 class UOP;
104 class UCODE;
105 class CONTEXT;
106 class VAR_REF;
107 
108 typedef std::function<void( CONTEXT*, void* )> FUNC_CALL_REF;
109 
111 {
112  wxString* str;
113  double num;
114  int idx;
115 };
116 
117 // Lemon can't handle c'tors and d'tors, so we provide a poor-man's version.
118 constexpr T_TOKEN_VALUE defaultTokenValue = { nullptr, 0.0, 0 };
119 
120 
121 struct T_TOKEN
122 {
123  int token;
125 };
126 
127 // Lemon can't handle c'tors and d'tors, so we provide a poor-man's version.
129 
130 
132 {
133 public:
135 
136  int op;
139  bool valid;
141  bool isVisited;
142  int srcPos;
143 
144  void SetUop( int aOp, double aValue );
145  void SetUop( int aOp, const wxString& aValue, bool aStringIsWildcard );
146  void SetUop( int aOp, std::unique_ptr<VAR_REF> aRef = nullptr );
147  void SetUop( int aOp, FUNC_CALL_REF aFunc, std::unique_ptr<VAR_REF> aRef = nullptr );
148 };
149 
150 
151 TREE_NODE* newNode( LIBEVAL::COMPILER* compiler, int op,
152  const T_TOKEN_VALUE& value = defaultTokenValue );
153 
155 {
156 public:
158  {
159  }
160 
161  virtual ~UNIT_RESOLVER()
162  {
163  }
164 
165  virtual const std::vector<wxString>& GetSupportedUnits() const
166  {
167  static const std::vector<wxString> nullUnits;
168 
169  return nullUnits;
170  }
171 
172  virtual wxString GetSupportedUnitsMessage() const
173  {
174  return wxEmptyString;
175  }
176 
177  virtual double Convert( const wxString& aString, int unitType ) const
178  {
179  return 0.0;
180  };
181 };
182 
183 
184 class VALUE
185 {
186 public:
187  VALUE() :
188  m_type( VT_UNDEFINED ),
189  m_valueDbl( 0 ),
190  m_stringIsWildcard( false ),
191  m_isDeferredDbl( false )
192  {};
193 
194  VALUE( const wxString& aStr, bool aIsWildcard = false ) :
195  m_type( VT_STRING ),
196  m_valueDbl( 0 ),
197  m_valueStr( aStr ),
198  m_stringIsWildcard( aIsWildcard ),
199  m_isDeferredDbl( false )
200  {};
201 
202  VALUE( const double aVal ) :
203  m_type( VT_NUMERIC ),
204  m_valueDbl( aVal ),
205  m_stringIsWildcard( false ),
206  m_isDeferredDbl( false )
207  {};
208 
209  virtual ~VALUE()
210  {};
211 
212  virtual double AsDouble() const
213  {
214  if( m_isDeferredDbl )
215  {
217  m_isDeferredDbl = false;
218  }
219 
220  return m_valueDbl;
221  }
222 
223  virtual const wxString& AsString() const
224  {
225  return m_valueStr;
226  }
227 
228  virtual bool EqualTo( CONTEXT* aCtx, const VALUE* b ) const;
229 
230  // NB: this is not an inverse of EqualTo as they both return false for undefined values.
231  virtual bool NotEqualTo( CONTEXT* aCtx, const VALUE* b ) const;
232 
233  VAR_TYPE_T GetType() const { return m_type; };
234 
235  void Set( double aValue )
236  {
237  m_type = VT_NUMERIC;
238  m_valueDbl = aValue;
239  }
240 
241  void SetDeferredEval( std::function<double()> aLambda )
242  {
243  m_type = VT_NUMERIC;
244  m_lambdaDbl = aLambda;
245  m_isDeferredDbl = true;
246  }
247 
248  void Set( const wxString& aValue )
249  {
250  m_type = VT_STRING;
251  m_valueStr = aValue;
252  }
253 
254  void Set( const VALUE &val )
255  {
256  m_type = val.m_type;
257  m_valueDbl = val.m_valueDbl;
258 
259  if( m_type == VT_STRING )
260  m_valueStr = val.m_valueStr;
261  }
262 
263 private:
265  mutable double m_valueDbl;
266  wxString m_valueStr;
268 
269  mutable bool m_isDeferredDbl;
270  std::function<double()> m_lambdaDbl;
271 };
272 
273 class VAR_REF
274 {
275 public:
276  VAR_REF() {};
277  virtual ~VAR_REF() {};
278 
279  virtual VAR_TYPE_T GetType() const = 0;
280  virtual VALUE GetValue( CONTEXT* aCtx ) = 0;
281 };
282 
283 
284 class CONTEXT
285 {
286 public:
288  m_stack(),
289  m_stackPtr( 0 )
290  {
291  m_ownedValues.reserve( 20 );
292  }
293 
294  virtual ~CONTEXT()
295  {
296  }
297 
299  {
300  m_ownedValues.emplace_back();
301  return &m_ownedValues.back();
302  }
303 
304  void Push( VALUE* v )
305  {
306  m_stack[ m_stackPtr++ ] = v;
307  }
308 
310  {
311  if( m_stackPtr == 0 )
312  {
313  ReportError( _( "Malformed expression" ) );
314  return AllocValue();
315  }
316 
317  return m_stack[ --m_stackPtr ];
318  }
319 
320  int SP() const
321  {
322  return m_stackPtr;
323  };
324 
325  void SetErrorCallback( std::function<void( const wxString& aMessage, int aOffset )> aCallback )
326  {
327  m_errorCallback = std::move( aCallback );
328  }
329 
330  bool HasErrorCallback() { return m_errorCallback != nullptr; }
331 
332  void ReportError( const wxString& aErrorMsg );
333 
334 private:
335  std::vector<VALUE> m_ownedValues;
336  VALUE* m_stack[100]; // std::stack not performant enough
338 
339  std::function<void( const wxString& aMessage, int aOffset )> m_errorCallback;
340 };
341 
342 
343 class UCODE
344 {
345 public:
346  virtual ~UCODE();
347 
348  void AddOp( UOP* uop )
349  {
350  m_ucode.push_back(uop);
351  }
352 
353  VALUE* Run( CONTEXT* ctx );
354  wxString Dump() const;
355 
356  virtual std::unique_ptr<VAR_REF> CreateVarRef( const wxString& var, const wxString& field )
357  {
358  return nullptr;
359  };
360 
361  virtual FUNC_CALL_REF CreateFuncCall( const wxString& name )
362  {
363  return nullptr;
364  };
365 
366 protected:
367 
368  std::vector<UOP*> m_ucode;
369 };
370 
371 
372 class UOP
373 {
374 public:
375  UOP( int op, std::unique_ptr<VALUE> value ) :
376  m_op( op ),
377  m_ref(nullptr),
378  m_value( std::move( value ) )
379  {};
380 
381  UOP( int op, std::unique_ptr<VAR_REF> vref ) :
382  m_op( op ),
383  m_ref( std::move( vref ) ),
384  m_value(nullptr)
385  {};
386 
387  UOP( int op, FUNC_CALL_REF func, std::unique_ptr<VAR_REF> vref = nullptr ) :
388  m_op( op ),
389  m_func( std::move( func ) ),
390  m_ref( std::move( vref ) ),
391  m_value(nullptr)
392  {};
393 
395  {
396  }
397 
398  void Exec( CONTEXT* ctx );
399 
400  wxString Format() const;
401 
402 private:
403  int m_op;
404 
406  std::unique_ptr<VAR_REF> m_ref;
407  std::unique_ptr<VALUE> m_value;
408 };
409 
411 {
412 public:
413  void Restart( const wxString& aStr )
414  {
415  m_str = aStr;
416  m_pos = 0;
417  }
418 
419  void Clear()
420  {
421  m_str = "";
422  m_pos = 0;
423  }
424 
425  int GetChar() const
426  {
427  if( m_pos >= m_str.length() )
428  return 0;
429 
430  return m_str[m_pos];
431  }
432 
433  bool Done() const
434  {
435  return m_pos >= m_str.length();
436  }
437 
438  void NextChar( int aAdvance = 1 )
439  {
440  m_pos += aAdvance;
441  }
442 
443  size_t GetPos() const
444  {
445  return m_pos;
446  }
447 
448  wxString GetChars( const std::function<bool( wxUniChar )>& cond ) const;
449 
450  bool MatchAhead( const wxString& match,
451  const std::function<bool( wxUniChar )>& stopCond ) const;
452 
453 private:
454  wxString m_str;
455  size_t m_pos = 0;
456 };
457 
458 
459 class COMPILER
460 {
461 public:
462  COMPILER();
463  virtual ~COMPILER();
464 
465  /*
466  * clear() should be invoked by the client if a new input string is to be processed. It
467  * will reset the parser. User defined variables are retained.
468  */
469  void Clear();
470 
471  /* Used by the lemon parser */
472  void parseError( const char* s );
473  void parseOk();
474 
475  int GetSourcePos() const { return m_sourcePos; }
476 
477  void setRoot( LIBEVAL::TREE_NODE *root );
478  void freeTree( LIBEVAL::TREE_NODE *tree );
479 
480  bool Compile( const wxString& aString, UCODE* aCode, CONTEXT* aPreflightContext );
481 
482  void SetErrorCallback( std::function<void( const wxString& aMessage, int aOffset )> aCallback )
483  {
484  m_errorCallback = std::move( aCallback );
485  }
486 
487  bool IsErrorPending() const { return m_errorStatus.pendingError; }
488  const ERROR_STATUS& GetError() const { return m_errorStatus; }
489 
490  void GcItem( TREE_NODE* aItem ) { m_gcItems.push_back( aItem ); }
491  void GcItem( wxString* aItem ) { m_gcStrings.push_back( aItem ); }
492 
493 protected:
495  {
498  };
499 
501 
502  bool generateUCode( UCODE* aCode, CONTEXT* aPreflightContext );
503 
504  void reportError( COMPILATION_STAGE stage, const wxString& aErrorMsg, int aPos = -1 );
505 
506  /* Begin processing of a new input string */
507  void newString( const wxString& aString );
508 
509  /* Tokenizer: Next token/value taken from input string. */
510  T_TOKEN getToken();
511  bool lexDefault( T_TOKEN& aToken );
512  bool lexString( T_TOKEN& aToken );
513 
514  int resolveUnits();
515 
516 protected:
517  /* Token state for input string. */
518  void* m_parser; // the current lemon parser state machine
521 
522  std::unique_ptr<UNIT_RESOLVER> m_unitResolver;
523 
527 
528  std::function<void( const wxString& aMessage, int aOffset )> m_errorCallback;
529 
531 
532  std::vector<TREE_NODE*> m_gcItems;
533  std::vector<wxString*> m_gcStrings;
534 };
535 
536 
537 } // namespace LIBEVAL
538 
539 #endif /* LIBEVAL_COMPILER_H_ */
void Restart(const wxString &aStr)
void GcItem(wxString *aItem)
wxString GetChars(const std::function< bool(wxUniChar)> &cond) const
virtual FUNC_CALL_REF CreateFuncCall(const wxString &name)
bool generateUCode(UCODE *aCode, CONTEXT *aPreflightContext)
void AddOp(UOP *uop)
virtual VAR_TYPE_T GetType() const =0
VALUE * m_stack[100]
std::unique_ptr< UNIT_RESOLVER > m_unitResolver
std::vector< TREE_NODE * > m_gcItems
void freeTree(LIBEVAL::TREE_NODE *tree)
std::function< void(const wxString &aMessage, int aOffset)> m_errorCallback
void SetDeferredEval(std::function< double()> aLambda)
UOP(int op, std::unique_ptr< VALUE > value)
std::unique_ptr< VALUE > m_value
void NextChar(int aAdvance=1)
Implementation of conversion functions that require both schematic and board internal units.
UOP(int op, std::unique_ptr< VAR_REF > vref)
virtual bool EqualTo(CONTEXT *aCtx, const VALUE *b) const
void setRoot(LIBEVAL::TREE_NODE *root)
COMPILATION_STAGE stage
UOP(int op, FUNC_CALL_REF func, std::unique_ptr< VAR_REF > vref=nullptr)
Definition: bitmap.cpp:64
constexpr T_TOKEN defaultToken
bool MatchAhead(const wxString &match, const std::function< bool(wxUniChar)> &stopCond) const
void Exec(CONTEXT *ctx)
bool IsErrorPending() const
virtual VALUE GetValue(CONTEXT *aCtx)=0
bool lexString(T_TOKEN &aToken)
void Set(const wxString &aValue)
bool Compile(const wxString &aString, UCODE *aCode, CONTEXT *aPreflightContext)
void GcItem(TREE_NODE *aItem)
virtual wxString GetSupportedUnitsMessage() const
virtual double Convert(const wxString &aString, int unitType) const
std::vector< wxString * > m_gcStrings
void SetErrorCallback(std::function< void(const wxString &aMessage, int aOffset)> aCallback)
void SetUop(int aOp, double aValue)
virtual std::unique_ptr< VAR_REF > CreateVarRef(const wxString &var, const wxString &field)
std::function< double()> m_lambdaDbl
VAR_TYPE_T GetType() const
std::function< void(CONTEXT *, void *)> FUNC_CALL_REF
#define _(s)
wxString Format() const
std::function< void(const wxString &aMessage, int aOffset)> m_errorCallback
LEXER_STATE m_lexerState
void newString(const wxString &aString)
std::vector< VALUE > m_ownedValues
void Set(const VALUE &val)
virtual const std::vector< wxString > & GetSupportedUnits() const
const ERROR_STATUS & GetError() const
void ReportError(const wxString &aErrorMsg)
void reportError(COMPILATION_STAGE stage, const wxString &aErrorMsg, int aPos=-1)
const char * name
Definition: DXF_plotter.cpp:56
virtual double AsDouble() const
T_TOKEN_VALUE value
size_t GetPos() const
TREE_NODE * newNode(LIBEVAL::COMPILER *compiler, int op, const T_TOKEN_VALUE &value)
ERROR_STATUS m_errorStatus
virtual const wxString & AsString() const
std::vector< UOP * > m_ucode
int GetSourcePos() const
constexpr T_TOKEN_VALUE defaultTokenValue
FUNC_CALL_REF m_func
void parseError(const char *s)
bool lexDefault(T_TOKEN &aToken)
std::unique_ptr< VAR_REF > m_ref
VALUE(const double aVal)
VALUE * Run(CONTEXT *ctx)
wxString Dump() const
VALUE(const wxString &aStr, bool aIsWildcard=false)
void Push(VALUE *v)
void SetErrorCallback(std::function< void(const wxString &aMessage, int aOffset)> aCallback)
void Set(double aValue)
TREE_NODE * leaf[2]
virtual bool NotEqualTo(CONTEXT *aCtx, const VALUE *b) const