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 <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 0x205
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
60namespace LIBEVAL
61{
62
63class COMPILER;
64
66{
70};
71
73{
74 bool pendingError = false;
75
77 wxString message;
78 int srcPos;
79};
80
81
83{
88};
89
91{
100 TR_NULL = 8
102
103class UOP;
104class UCODE;
105class CONTEXT;
106class VAR_REF;
107
108typedef 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.
118constexpr T_TOKEN_VALUE defaultTokenValue = { nullptr, 0.0, 0 };
119
120
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{
133public:
135
136 int op;
139 bool valid;
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
151TREE_NODE* newNode( LIBEVAL::COMPILER* compiler, int op,
152 const T_TOKEN_VALUE& value = defaultTokenValue );
153
155{
156public:
158 {
159 }
160
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
184class VALUE
185{
186public:
189 m_valueDbl( 0 ),
190 m_stringIsWildcard( false ),
191 m_isDeferredDbl( false ),
192 m_isDeferredStr( false )
193 {};
194
195 VALUE( const wxString& aStr, bool aIsWildcard = false ) :
196 m_type( VT_STRING ),
197 m_valueDbl( 0 ),
198 m_valueStr( aStr ),
199 m_stringIsWildcard( aIsWildcard ),
200 m_isDeferredDbl( false ),
201 m_isDeferredStr( false )
202 {};
203
204 VALUE( const double aVal ) :
206 m_valueDbl( aVal ),
207 m_stringIsWildcard( false ),
208 m_isDeferredDbl( false ),
209 m_isDeferredStr( false )
210 {};
211
212 virtual ~VALUE()
213 {};
214
215 virtual double AsDouble() const
216 {
217 if( m_isDeferredDbl )
218 {
220 m_isDeferredDbl = false;
221 }
222
223 return m_valueDbl;
224 }
225
226 virtual const wxString& AsString() const
227 {
228 if( m_isDeferredStr )
229 {
231 m_isDeferredStr = false;
232 }
233
234 return m_valueStr;
235 }
236
237 virtual bool EqualTo( CONTEXT* aCtx, const VALUE* b ) const;
238
239 // NB: this is not an inverse of EqualTo as they both return false for undefined values.
240 virtual bool NotEqualTo( CONTEXT* aCtx, const VALUE* b ) const;
241
242 VAR_TYPE_T GetType() const { return m_type; };
243
244 void Set( double aValue )
245 {
247 m_valueDbl = aValue;
248 }
249
250 void SetDeferredEval( std::function<double()> aLambda )
251 {
253 m_lambdaDbl = aLambda;
254 m_isDeferredDbl = true;
255 }
256
257 void SetDeferredEval( std::function<wxString()> aLambda )
258 {
260 m_lambdaStr = aLambda;
261 m_isDeferredStr = true;
262 }
263
264 void Set( const wxString& aValue )
265 {
267 m_valueStr = aValue;
268 }
269
270 void Set( const VALUE &val )
271 {
272 m_type = val.m_type;
274
275 if( m_type == VT_STRING )
277 }
278
279private:
281 mutable double m_valueDbl; // mutable to support deferred evaluation
282 mutable wxString m_valueStr; // mutable to support deferred evaluation
284
285 mutable bool m_isDeferredDbl;
286 std::function<double()> m_lambdaDbl;
287
288 mutable bool m_isDeferredStr;
289 std::function<wxString()> m_lambdaStr;
290};
291
293{
294public:
296 virtual ~VAR_REF() {};
297
298 virtual VAR_TYPE_T GetType() const = 0;
299 virtual VALUE* GetValue( CONTEXT* aCtx ) = 0;
300};
301
302
304{
305public:
307 m_stack(),
308 m_stackPtr( 0 )
309 {
310 m_ownedValues.reserve( 20 );
311 }
312
313 virtual ~CONTEXT()
314 {
315 for( VALUE* v : m_ownedValues )
316 {
317 delete v;
318 }
319 }
320
322 {
323 m_ownedValues.emplace_back( new VALUE );
324 return m_ownedValues.back();
325 }
326
328 {
329 m_ownedValues.emplace_back( aValue );
330 return m_ownedValues.back();
331 }
332
333 void Push( VALUE* v )
334 {
335 m_stack[ m_stackPtr++ ] = v;
336 }
337
339 {
340 if( m_stackPtr == 0 )
341 {
342 ReportError( _( "Malformed expression" ) );
343 return AllocValue();
344 }
345
346 return m_stack[ --m_stackPtr ];
347 }
348
349 int SP() const
350 {
351 return m_stackPtr;
352 };
353
354 void SetErrorCallback( std::function<void( const wxString& aMessage, int aOffset )> aCallback )
355 {
356 m_errorCallback = std::move( aCallback );
357 }
358
359 bool HasErrorCallback() { return m_errorCallback != nullptr; }
360
361 void ReportError( const wxString& aErrorMsg );
362
363private:
364 std::vector<VALUE*> m_ownedValues;
365 VALUE* m_stack[100]; // std::stack not performant enough
367
368 std::function<void( const wxString& aMessage, int aOffset )> m_errorCallback;
369};
370
371
372class UCODE
373{
374public:
375 virtual ~UCODE();
376
377 void AddOp( UOP* uop )
378 {
379 m_ucode.push_back(uop);
380 }
381
382 VALUE* Run( CONTEXT* ctx );
383 wxString Dump() const;
384
385 virtual std::unique_ptr<VAR_REF> CreateVarRef( const wxString& var, const wxString& field )
386 {
387 return nullptr;
388 };
389
390 virtual FUNC_CALL_REF CreateFuncCall( const wxString& name )
391 {
392 return nullptr;
393 };
394
395protected:
396
397 std::vector<UOP*> m_ucode;
398};
399
400
401class UOP
402{
403public:
404 UOP( int op, std::unique_ptr<VALUE> value ) :
405 m_op( op ),
406 m_ref(nullptr),
407 m_value( std::move( value ) )
408 {};
409
410 UOP( int op, std::unique_ptr<VAR_REF> vref ) :
411 m_op( op ),
412 m_ref( std::move( vref ) ),
413 m_value(nullptr)
414 {};
415
416 UOP( int op, FUNC_CALL_REF func, std::unique_ptr<VAR_REF> vref = nullptr ) :
417 m_op( op ),
418 m_func( std::move( func ) ),
419 m_ref( std::move( vref ) ),
420 m_value(nullptr)
421 {};
422
424 {
425 }
426
427 void Exec( CONTEXT* ctx );
428
429 wxString Format() const;
430
431private:
432 int m_op;
433
435 std::unique_ptr<VAR_REF> m_ref;
436 std::unique_ptr<VALUE> m_value;
437};
438
440{
441public:
442 void Restart( const wxString& aStr )
443 {
444 m_str = aStr;
445 m_pos = 0;
446 }
447
448 void Clear()
449 {
450 m_str = "";
451 m_pos = 0;
452 }
453
454 int GetChar() const
455 {
456 if( m_pos >= m_str.length() )
457 return 0;
458
459 return m_str[m_pos];
460 }
461
462 bool Done() const
463 {
464 return m_pos >= m_str.length();
465 }
466
467 void NextChar( int aAdvance = 1 )
468 {
469 m_pos += aAdvance;
470 }
471
472 size_t GetPos() const
473 {
474 return m_pos;
475 }
476
477 wxString GetString();
478
479 wxString GetChars( const std::function<bool( wxUniChar )>& cond ) const;
480
481 bool MatchAhead( const wxString& match,
482 const std::function<bool( wxUniChar )>& stopCond ) const;
483
484private:
485 wxString m_str;
486 size_t m_pos = 0;
487};
488
489
491{
492public:
493 COMPILER();
494 virtual ~COMPILER();
495
496 /*
497 * clear() should be invoked by the client if a new input string is to be processed. It
498 * will reset the parser. User defined variables are retained.
499 */
500 void Clear();
501
502 /* Used by the lemon parser */
503 void parseError( const char* s );
504 void parseOk();
505
506 int GetSourcePos() const { return m_sourcePos; }
507
508 void setRoot( LIBEVAL::TREE_NODE *root );
509 void freeTree( LIBEVAL::TREE_NODE *tree );
510
511 bool Compile( const wxString& aString, UCODE* aCode, CONTEXT* aPreflightContext );
512
513 void SetErrorCallback( std::function<void( const wxString& aMessage, int aOffset )> aCallback )
514 {
515 m_errorCallback = std::move( aCallback );
516 }
517
519 const ERROR_STATUS& GetError() const { return m_errorStatus; }
520
521 void GcItem( TREE_NODE* aItem ) { m_gcItems.push_back( aItem ); }
522 void GcItem( wxString* aItem ) { m_gcStrings.push_back( aItem ); }
523
524protected:
526 {
529 };
530
532
533 bool generateUCode( UCODE* aCode, CONTEXT* aPreflightContext );
534
535 void reportError( COMPILATION_STAGE stage, const wxString& aErrorMsg, int aPos = -1 );
536
537 /* Begin processing of a new input string */
538 void newString( const wxString& aString );
539
540 /* Tokenizer: Next token/value taken from input string. */
542 bool lexDefault( T_TOKEN& aToken );
543 bool lexString( T_TOKEN& aToken );
544
545 int resolveUnits();
546
547protected:
548 /* Token state for input string. */
549 void* m_parser; // the current lemon parser state machine
552
553 std::unique_ptr<UNIT_RESOLVER> m_unitResolver;
554
558
559 std::function<void( const wxString& aMessage, int aOffset )> m_errorCallback;
560
562
563 std::vector<TREE_NODE*> m_gcItems;
564 std::vector<wxString*> m_gcStrings;
565};
566
567
568} // namespace LIBEVAL
569
570#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 newString(const wxString &aString)
void GcItem(wxString *aItem)
void freeTree(LIBEVAL::TREE_NODE *tree)
bool lexString(T_TOKEN &aToken)
void GcItem(TREE_NODE *aItem)
LEXER_STATE m_lexerState
bool generateUCode(UCODE *aCode, CONTEXT *aPreflightContext)
std::function< void(const wxString &aMessage, int aOffset)> m_errorCallback
bool lexDefault(T_TOKEN &aToken)
int GetSourcePos() const
std::vector< TREE_NODE * > m_gcItems
void reportError(COMPILATION_STAGE stage, const wxString &aErrorMsg, int aPos=-1)
const ERROR_STATUS & GetError() const
void setRoot(LIBEVAL::TREE_NODE *root)
std::vector< wxString * > m_gcStrings
bool Compile(const wxString &aString, UCODE *aCode, CONTEXT *aPreflightContext)
ERROR_STATUS m_errorStatus
void parseError(const char *s)
std::vector< VALUE * > m_ownedValues
VALUE * StoreValue(VALUE *aValue)
void ReportError(const wxString &aErrorMsg)
VALUE * m_stack[100]
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)
wxString GetChars(const std::function< bool(wxUniChar)> &cond) const
size_t GetPos() const
bool MatchAhead(const wxString &match, const std::function< bool(wxUniChar)> &stopCond) const
TREE_NODE * leaf[2]
void SetUop(int aOp, double aValue)
virtual std::unique_ptr< VAR_REF > CreateVarRef(const wxString &var, const wxString &field)
void AddOp(UOP *uop)
std::vector< UOP * > m_ucode
wxString Dump() const
VALUE * Run(CONTEXT *ctx)
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
wxString Format() const
UOP(int op, std::unique_ptr< VALUE > value)
void Exec(CONTEXT *ctx)
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)
virtual bool NotEqualTo(CONTEXT *aCtx, const VALUE *b) const
std::function< double()> m_lambdaDbl
virtual double AsDouble() const
VAR_TYPE_T GetType() const
void Set(const VALUE &val)
VALUE(const double aVal)
virtual bool EqualTo(CONTEXT *aCtx, const VALUE *b) const
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)
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.
COMPILATION_STAGE stage
T_TOKEN_VALUE value