KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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, [email protected]
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 <kicommon.h>
31#include <base_units.h>
32#include <wx/intl.h>
33
34#if defined(WIN32)
35// This gets leaked by python headers on MSVC only and will cause chaos
36#undef COMPILER
37#endif
38
39#define TR_OP_BINARY_MASK 0x200
40#define TR_OP_UNARY_MASK 0x100
41
42#define TR_OP_MUL 0x201
43#define TR_OP_DIV 0x202
44#define TR_OP_ADD 0x203
45#define TR_OP_SUB 0x204
46#define TR_OP_LESS 0x205
47#define TR_OP_GREATER 0x206
48#define TR_OP_LESS_EQUAL 0x207
49#define TR_OP_GREATER_EQUAL 0x208
50#define TR_OP_EQUAL 0x209
51#define TR_OP_NOT_EQUAL 0x20a
52#define TR_OP_BOOL_AND 0x20b
53#define TR_OP_BOOL_OR 0x20c
54#define TR_OP_BOOL_NOT 0x100
55#define TR_OP_FUNC_CALL 24
56#define TR_OP_METHOD_CALL 25
57#define TR_UOP_PUSH_VAR 1
58#define TR_UOP_PUSH_VALUE 2
59
60// This namespace is used for the lemon parser
61namespace LIBEVAL
62{
63
64class COMPILER;
65
67{
71};
72
74{
75 bool pendingError = false;
76
78 wxString message;
79 int srcPos;
80};
81
82
84{
89};
90
92{
101 TR_NULL = 8
103
104class UOP;
105class UCODE;
106class CONTEXT;
107class VAR_REF;
108
109typedef std::function<void( CONTEXT*, void* )> FUNC_CALL_REF;
110
112{
113 wxString* str;
114 double num;
115 int idx;
116};
117
118// Lemon can't handle c'tors and d'tors, so we provide a poor-man's version.
119constexpr T_TOKEN_VALUE defaultTokenValue = { nullptr, 0.0, 0 };
120
121
123{
124 int token;
126};
127
128// Lemon can't handle c'tors and d'tors, so we provide a poor-man's version.
130
131
133{
134public:
136
137 int op;
138 TREE_NODE* leaf[2];
140 bool valid;
144
145 void SetUop( int aOp, double aValue );
146 void SetUop( int aOp, const wxString& aValue, bool aStringIsWildcard );
147 void SetUop( int aOp, std::unique_ptr<VAR_REF> aRef = nullptr );
148 void SetUop( int aOp, FUNC_CALL_REF aFunc, std::unique_ptr<VAR_REF> aRef = nullptr );
149};
150
151
152TREE_NODE* newNode( LIBEVAL::COMPILER* compiler, int op,
153 const T_TOKEN_VALUE& value = defaultTokenValue );
154
156{
157public:
159 {
160 }
161
163 {
164 }
165
166 virtual const std::vector<wxString>& GetSupportedUnits() const
167 {
168 static const std::vector<wxString> nullUnits;
169
170 return nullUnits;
171 }
172
173 virtual wxString GetSupportedUnitsMessage() const
174 {
175 return wxEmptyString;
176 }
177
178 virtual double Convert( const wxString& aString, int unitType ) const
179 {
180 return 0.0;
181 };
182};
183
184
186{
187public:
189 m_type( VT_UNDEFINED ),
190 m_valueDbl( 0 ),
191 m_stringIsWildcard( false ),
192 m_isDeferredDbl( false ),
193 m_isDeferredStr( false )
194 {};
195
196 VALUE( const wxString& aStr, bool aIsWildcard = false ) :
197 m_type( VT_STRING ),
198 m_valueDbl( 0 ),
199 m_valueStr( aStr ),
200 m_stringIsWildcard( aIsWildcard ),
201 m_isDeferredDbl( false ),
202 m_isDeferredStr( false )
203 {};
204
205 VALUE( const double aVal ) :
206 m_type( VT_NUMERIC ),
207 m_valueDbl( aVal ),
208 m_stringIsWildcard( false ),
209 m_isDeferredDbl( false ),
210 m_isDeferredStr( false )
211 {};
212
213 virtual ~VALUE()
214 {};
215
216 virtual double AsDouble() const
217 {
218 if( m_isDeferredDbl )
219 {
220 m_valueDbl = m_lambdaDbl();
221 m_isDeferredDbl = false;
222 }
223
224 return m_valueDbl;
225 }
226
227 virtual const wxString& AsString() const
228 {
229 if( m_isDeferredStr )
230 {
231 m_valueStr = m_lambdaStr();
232 m_isDeferredStr = false;
233 }
234
235 return m_valueStr;
236 }
237
238 virtual bool EqualTo( CONTEXT* aCtx, const VALUE* b ) const;
239
240 // NB: this is not an inverse of EqualTo as they both return false for undefined values.
241 virtual bool NotEqualTo( CONTEXT* aCtx, const VALUE* b ) const;
242
243 VAR_TYPE_T GetType() const { return m_type; };
244
245 void Set( double aValue )
246 {
247 m_type = VT_NUMERIC;
248 m_valueDbl = aValue;
249 }
250
251 void SetDeferredEval( std::function<double()> aLambda )
252 {
253 m_type = VT_NUMERIC;
254 m_lambdaDbl = aLambda;
255 m_isDeferredDbl = true;
256 }
257
258 void SetDeferredEval( std::function<wxString()> aLambda )
259 {
260 m_type = VT_STRING;
261 m_lambdaStr = aLambda;
262 m_isDeferredStr = true;
263 }
264
265 void Set( const wxString& aValue )
266 {
267 m_type = VT_STRING;
268 m_valueStr = aValue;
269 }
270
271 void Set( const VALUE &val )
272 {
273 m_type = val.m_type;
274 m_valueDbl = val.m_valueDbl;
275
276 if( m_type == VT_STRING )
277 m_valueStr = val.m_valueStr;
278 }
279
280private:
282 mutable double m_valueDbl; // mutable to support deferred evaluation
283 mutable wxString m_valueStr; // mutable to support deferred evaluation
285
286 mutable bool m_isDeferredDbl;
287 std::function<double()> m_lambdaDbl;
288
289 mutable bool m_isDeferredStr;
290 std::function<wxString()> m_lambdaStr;
291};
292
294{
295public:
297 virtual ~VAR_REF() {};
298
299 virtual VAR_TYPE_T GetType() const = 0;
300 virtual VALUE* GetValue( CONTEXT* aCtx ) = 0;
301};
302
303
305{
306public:
308 m_stack(),
309 m_stackPtr( 0 )
310 {
311 m_ownedValues.reserve( 20 );
312 }
313
314 virtual ~CONTEXT()
315 {
316 for( VALUE* v : m_ownedValues )
317 {
318 delete v;
319 }
320 }
321
323 {
324 m_ownedValues.emplace_back( new VALUE );
325 return m_ownedValues.back();
326 }
327
329 {
330 m_ownedValues.emplace_back( aValue );
331 return m_ownedValues.back();
332 }
333
334 void Push( VALUE* v )
335 {
336 m_stack[ m_stackPtr++ ] = v;
337 }
338
340 {
341 if( m_stackPtr == 0 )
342 {
343 ReportError( _( "Malformed expression" ) );
344 return AllocValue();
345 }
346
347 return m_stack[ --m_stackPtr ];
348 }
349
350 int SP() const
351 {
352 return m_stackPtr;
353 };
354
355 void SetErrorCallback( std::function<void( const wxString& aMessage, int aOffset )> aCallback )
356 {
357 m_errorCallback = std::move( aCallback );
358 }
359
360 bool HasErrorCallback() { return m_errorCallback != nullptr; }
361
362 void ReportError( const wxString& aErrorMsg );
363
364private:
365 std::vector<VALUE*> m_ownedValues;
366 VALUE* m_stack[100]; // std::stack not performant enough
368
369 std::function<void( const wxString& aMessage, int aOffset )> m_errorCallback;
370};
371
372
374{
375public:
376 virtual ~UCODE();
377
378 void AddOp( UOP* uop )
379 {
380 m_ucode.push_back(uop);
381 }
382
383 VALUE* Run( CONTEXT* ctx );
384 wxString Dump() const;
385
386 virtual std::unique_ptr<VAR_REF> CreateVarRef( const wxString& var, const wxString& field )
387 {
388 return nullptr;
389 };
390
391 virtual FUNC_CALL_REF CreateFuncCall( const wxString& name )
392 {
393 return nullptr;
394 };
395
396protected:
397
398 std::vector<UOP*> m_ucode;
399};
400
401
403{
404public:
405 UOP( int op, std::unique_ptr<VALUE> value ) :
406 m_op( op ),
407 m_ref(nullptr),
408 m_value( std::move( value ) )
409 {};
410
411 UOP( int op, std::unique_ptr<VAR_REF> vref ) :
412 m_op( op ),
413 m_ref( std::move( vref ) ),
414 m_value(nullptr)
415 {};
416
417 UOP( int op, FUNC_CALL_REF func, std::unique_ptr<VAR_REF> vref = nullptr ) :
418 m_op( op ),
419 m_func( std::move( func ) ),
420 m_ref( std::move( vref ) ),
421 m_value(nullptr)
422 {};
423
425 {
426 }
427
428 void Exec( CONTEXT* ctx );
429
430 wxString Format() const;
431
432private:
433 int m_op;
434
436 std::unique_ptr<VAR_REF> m_ref;
437 std::unique_ptr<VALUE> m_value;
438};
439
441{
442public:
443 void Restart( const wxString& aStr )
444 {
445 m_str = aStr;
446 m_pos = 0;
447 }
448
449 void Clear()
450 {
451 m_str = "";
452 m_pos = 0;
453 }
454
455 int GetChar() const
456 {
457 if( m_pos >= m_str.length() )
458 return 0;
459
460 return m_str[m_pos];
461 }
462
463 bool Done() const
464 {
465 return m_pos >= m_str.length();
466 }
467
468 void NextChar( int aAdvance = 1 )
469 {
470 m_pos += aAdvance;
471 }
472
473 size_t GetPos() const
474 {
475 return m_pos;
476 }
477
478 wxString GetString();
479
480 wxString GetChars( const std::function<bool( wxUniChar )>& cond ) const;
481
482 bool MatchAhead( const wxString& match,
483 const std::function<bool( wxUniChar )>& stopCond ) const;
484
485private:
486 wxString m_str;
487 size_t m_pos = 0;
488};
489
490
492{
493public:
494 COMPILER();
495 virtual ~COMPILER();
496
497 /*
498 * clear() should be invoked by the client if a new input string is to be processed. It
499 * will reset the parser. User defined variables are retained.
500 */
501 void Clear();
502
503 /* Used by the lemon parser */
504 void parseError( const char* s );
505 void parseOk();
506
507 int GetSourcePos() const { return m_sourcePos; }
508
509 void setRoot( LIBEVAL::TREE_NODE *root );
510 void freeTree( LIBEVAL::TREE_NODE *tree );
511
512 bool Compile( const wxString& aString, UCODE* aCode, CONTEXT* aPreflightContext );
513
514 void SetErrorCallback( std::function<void( const wxString& aMessage, int aOffset )> aCallback )
515 {
516 m_errorCallback = std::move( aCallback );
517 }
518
519 bool IsErrorPending() const { return m_errorStatus.pendingError; }
520 const ERROR_STATUS& GetError() const { return m_errorStatus; }
521
522 void GcItem( TREE_NODE* aItem ) { m_gcItems.push_back( aItem ); }
523 void GcItem( wxString* aItem ) { m_gcStrings.push_back( aItem ); }
524
525protected:
527 {
528 LS_DEFAULT = 0,
529 LS_STRING = 1,
530 };
531
533
534 bool generateUCode( UCODE* aCode, CONTEXT* aPreflightContext );
535
536 void reportError( COMPILATION_STAGE stage, const wxString& aErrorMsg, int aPos = -1 );
537
538 /* Begin processing of a new input string */
539 void newString( const wxString& aString );
540
541 /* Tokenizer: Next token/value taken from input string. */
542 T_TOKEN getToken();
543 bool lexDefault( T_TOKEN& aToken );
544 bool lexString( T_TOKEN& aToken );
545
546 int resolveUnits();
547
548protected:
549 /* Token state for input string. */
550 void* m_parser; // the current lemon parser state machine
553
554 std::unique_ptr<UNIT_RESOLVER> m_unitResolver;
555
559
560 std::function<void( const wxString& aMessage, int aOffset )> m_errorCallback;
561
563
564 std::vector<TREE_NODE*> m_gcItems;
565 std::vector<wxString*> m_gcStrings;
566};
567
568
569} // namespace LIBEVAL
570
571#endif /* LIBEVAL_COMPILER_H_ */
const char * name
Definition: DXF_plotter.cpp:57
void SetErrorCallback(std::function< void(const wxString &aMessage, int aOffset)> aCallback)
bool IsErrorPending() const
std::unique_ptr< UNIT_RESOLVER > m_unitResolver
void GcItem(wxString *aItem)
void GcItem(TREE_NODE *aItem)
LEXER_STATE m_lexerState
std::function< void(const wxString &aMessage, int aOffset)> m_errorCallback
int GetSourcePos() const
std::vector< TREE_NODE * > m_gcItems
const ERROR_STATUS & GetError() const
std::vector< wxString * > m_gcStrings
ERROR_STATUS m_errorStatus
std::vector< VALUE * > m_ownedValues
VALUE * StoreValue(VALUE *aValue)
std::function< void(const wxString &aMessage, int aOffset)> m_errorCallback
void SetErrorCallback(std::function< void(const wxString &aMessage, int aOffset)> aCallback)
void Push(VALUE *v)
void NextChar(int aAdvance=1)
void Restart(const wxString &aStr)
size_t GetPos() const
virtual std::unique_ptr< VAR_REF > CreateVarRef(const wxString &var, const wxString &field)
void AddOp(UOP *uop)
std::vector< UOP * > m_ucode
virtual FUNC_CALL_REF CreateFuncCall(const wxString &name)
virtual wxString GetSupportedUnitsMessage() const
virtual double Convert(const wxString &aString, int unitType) const
virtual const std::vector< wxString > & GetSupportedUnits() const
UOP(int op, FUNC_CALL_REF func, std::unique_ptr< VAR_REF > vref=nullptr)
std::unique_ptr< VAR_REF > m_ref
FUNC_CALL_REF m_func
UOP(int op, std::unique_ptr< VALUE > value)
std::unique_ptr< VALUE > m_value
UOP(int op, std::unique_ptr< VAR_REF > vref)
void Set(double aValue)
virtual const wxString & AsString() const
void SetDeferredEval(std::function< wxString()> aLambda)
void Set(const wxString &aValue)
std::function< double()> m_lambdaDbl
virtual double AsDouble() const
VAR_TYPE_T GetType() const
void Set(const VALUE &val)
VALUE(const double aVal)
void SetDeferredEval(std::function< double()> aLambda)
std::function< wxString()> m_lambdaStr
VALUE(const wxString &aStr, bool aIsWildcard=false)
virtual VALUE * GetValue(CONTEXT *aCtx)=0
virtual VAR_TYPE_T GetType() const =0
#define _(s)
#define KICOMMON_API
Definition: kicommon.h:28
TREE_NODE * newNode(LIBEVAL::COMPILER *compiler, int op, const T_TOKEN_VALUE &value)
constexpr T_TOKEN defaultToken
constexpr T_TOKEN_VALUE defaultTokenValue
std::function< void(CONTEXT *, void *)> FUNC_CALL_REF
STL namespace.
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
COMPILATION_STAGE stage
T_TOKEN_VALUE value