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  {};
192 
193  VALUE( const wxString& aStr, bool aIsWildcard = false ) :
194  m_type( VT_STRING ),
195  m_valueDbl( 0 ),
196  m_valueStr( aStr ),
197  m_stringIsWildcard( aIsWildcard )
198  {};
199 
200  VALUE( const double aVal ) :
201  m_type( VT_NUMERIC ),
202  m_valueDbl( aVal ),
203  m_stringIsWildcard( false )
204  {};
205 
206  virtual ~VALUE()
207  {};
208 
209  virtual double AsDouble() const
210  {
211  return m_valueDbl;
212  }
213 
214  virtual const wxString& AsString() const
215  {
216  return m_valueStr;
217  }
218 
219  virtual bool EqualTo( const VALUE* b ) const;
220 
221  VAR_TYPE_T GetType() const { return m_type; };
222 
223  void Set( double aValue )
224  {
225  m_type = VT_NUMERIC;
226  m_valueDbl = aValue;
227  }
228 
229  void Set( const wxString& aValue )
230  {
231  m_type = VT_STRING;
232  m_valueStr = aValue;
233  }
234 
235  void Set( const VALUE &val )
236  {
237  m_type = val.m_type;
238  m_valueDbl = val.m_valueDbl;
239 
240  if( m_type == VT_STRING )
241  m_valueStr = val.m_valueStr;
242  }
243 
244 private:
246  double m_valueDbl;
247  wxString m_valueStr;
249 };
250 
251 class VAR_REF
252 {
253 public:
254  VAR_REF() {};
255  virtual ~VAR_REF() {};
256 
257  virtual VAR_TYPE_T GetType() const = 0;
258  virtual VALUE GetValue( CONTEXT* aCtx ) = 0;
259 };
260 
261 
262 class CONTEXT
263 {
264 public:
265  virtual ~CONTEXT()
266  {
267  for( VALUE* value : m_ownedValues )
268  delete value;
269  }
270 
272  {
273  VALUE* value = new VALUE();
274  m_ownedValues.push_back( value );
275  return value;
276  }
277 
278  void Push( VALUE* v )
279  {
280  m_stack.push( v );
281  }
282 
284  {
285  if( m_stack.size() == 0 )
286  {
287  ReportError( _( "Malformed expression" ) );
288  return AllocValue();
289  }
290 
291  VALUE* value = m_stack.top();
292  m_stack.pop();
293  return value;
294  }
295 
296  int SP() const
297  {
298  return m_stack.size();
299  };
300 
301  void SetErrorCallback( std::function<void( const wxString& aMessage, int aOffset )> aCallback )
302  {
303  m_errorCallback = std::move( aCallback );
304  }
305 
306  void ReportError( const wxString& aErrorMsg );
307  bool IsErrorPending() const { return m_errorStatus.pendingError; }
308  const ERROR_STATUS& GetError() const { return m_errorStatus; }
309 
310 private:
311  std::vector<VALUE*> m_ownedValues;
312  std::stack<VALUE*> m_stack;
314 
315  std::function<void( const wxString& aMessage, int aOffset )> m_errorCallback;
316 };
317 
318 
319 class UCODE
320 {
321 public:
322  virtual ~UCODE();
323 
324  void AddOp( UOP* uop )
325  {
326  m_ucode.push_back(uop);
327  }
328 
329  VALUE* Run( CONTEXT* ctx );
330  wxString Dump() const;
331 
332  virtual std::unique_ptr<VAR_REF> CreateVarRef( const wxString& var, const wxString& field )
333  {
334  return nullptr;
335  };
336 
337  virtual FUNC_CALL_REF CreateFuncCall( const wxString& name )
338  {
339  return nullptr;
340  };
341 
342 protected:
343 
344  std::vector<UOP*> m_ucode;
345 };
346 
347 
348 class UOP
349 {
350 public:
351  UOP( int op, std::unique_ptr<VALUE> value ) :
352  m_op( op ),
353  m_ref(nullptr),
354  m_value( std::move( value ) )
355  {};
356 
357  UOP( int op, std::unique_ptr<VAR_REF> vref ) :
358  m_op( op ),
359  m_ref( std::move( vref ) ),
360  m_value(nullptr)
361  {};
362 
363  UOP( int op, FUNC_CALL_REF func, std::unique_ptr<VAR_REF> vref = nullptr ) :
364  m_op( op ),
365  m_func( std::move( func ) ),
366  m_ref( std::move( vref ) ),
367  m_value(nullptr)
368  {};
369 
371  {
372  }
373 
374  void Exec( CONTEXT* ctx );
375 
376  wxString Format() const;
377 
378 private:
379  int m_op;
380 
382  std::unique_ptr<VAR_REF> m_ref;
383  std::unique_ptr<VALUE> m_value;
384 };
385 
387 {
388 public:
389  void Restart( const wxString& aStr )
390  {
391  m_str = aStr;
392  m_pos = 0;
393  }
394 
395  void Clear()
396  {
397  m_str = "";
398  m_pos = 0;
399  }
400 
401  int GetChar() const
402  {
403  if( m_pos >= m_str.length() )
404  return 0;
405 
406  return m_str[m_pos];
407  }
408 
409  bool Done() const
410  {
411  return m_pos >= m_str.length();
412  }
413 
414  void NextChar( int aAdvance = 1 )
415  {
416  m_pos += aAdvance;
417  }
418 
419  size_t GetPos() const
420  {
421  return m_pos;
422  }
423 
424  wxString GetChars( const std::function<bool( wxUniChar )>& cond ) const;
425 
426  bool MatchAhead( const wxString& match,
427  const std::function<bool( wxUniChar )>& stopCond ) const;
428 
429 private:
430  wxString m_str;
431  size_t m_pos = 0;
432 };
433 
434 
435 class COMPILER
436 {
437 public:
438  COMPILER();
439  virtual ~COMPILER();
440 
441  /*
442  * clear() should be invoked by the client if a new input string is to be processed. It
443  * will reset the parser. User defined variables are retained.
444  */
445  void Clear();
446 
447  /* Used by the lemon parser */
448  void parseError( const char* s );
449  void parseOk();
450 
451  int GetSourcePos() const { return m_sourcePos; }
452 
453  void setRoot( LIBEVAL::TREE_NODE *root );
454  void freeTree( LIBEVAL::TREE_NODE *tree );
455 
456  bool Compile( const wxString& aString, UCODE* aCode, CONTEXT* aPreflightContext );
457 
458  void SetErrorCallback( std::function<void( const wxString& aMessage, int aOffset )> aCallback )
459  {
460  m_errorCallback = std::move( aCallback );
461  }
462 
463  bool IsErrorPending() const { return m_errorStatus.pendingError; }
464  const ERROR_STATUS& GetError() const { return m_errorStatus; }
465 
466  void GcItem( TREE_NODE* aItem ) { m_gcItems.push_back( aItem ); }
467  void GcItem( wxString* aItem ) { m_gcStrings.push_back( aItem ); }
468 
469 protected:
471  {
474  };
475 
477 
478  bool generateUCode( UCODE* aCode, CONTEXT* aPreflightContext );
479 
480  void reportError( COMPILATION_STAGE stage, const wxString& aErrorMsg, int aPos = -1 );
481 
482  /* Begin processing of a new input string */
483  void newString( const wxString& aString );
484 
485  /* Tokenizer: Next token/value taken from input string. */
486  T_TOKEN getToken();
487  bool lexDefault( T_TOKEN& aToken );
488  bool lexString( T_TOKEN& aToken );
489 
490  int resolveUnits();
491 
492 protected:
493  /* Token state for input string. */
494  void* m_parser; // the current lemon parser state machine
497 
498  std::unique_ptr<UNIT_RESOLVER> m_unitResolver;
499 
503 
504  std::function<void( const wxString& aMessage, int aOffset )> m_errorCallback;
505 
507 
508  std::vector<TREE_NODE*> m_gcItems;
509  std::vector<wxString*> m_gcStrings;
510 };
511 
512 
513 } // namespace LIBEVAL
514 
515 #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
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
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)
const ERROR_STATUS & GetError() const
bool IsErrorPending() const
void setRoot(LIBEVAL::TREE_NODE *root)
COMPILATION_STAGE stage
UOP(int op, FUNC_CALL_REF func, std::unique_ptr< VAR_REF > vref=nullptr)
Template specialization to enable wxStrings for certain containers (e.g. unordered_map)
Definition: bitmap.cpp:58
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)
std::stack< VALUE * > m_stack
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)
VAR_TYPE_T GetType() const
std::function< void(CONTEXT *, void *)> FUNC_CALL_REF
virtual bool EqualTo(const VALUE *b) const
ERROR_STATUS m_errorStatus
wxString Format() const
std::function< void(const wxString &aMessage, int aOffset)> m_errorCallback
LEXER_STATE m_lexerState
void newString(const wxString &aString)
void Set(const VALUE &val)
virtual const std::vector< wxString > & GetSupportedUnits() const
std::vector< VALUE * > m_ownedValues
Field Value of part, i.e. "3.3K".
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:59
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)
#define _(s)
Definition: 3d_actions.cpp:33
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]