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 The 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{
91};
92
94{
103 TR_NULL = 8
105
106class UOP;
107class UCODE;
108class CONTEXT;
109class VAR_REF;
110
111typedef std::function<void( CONTEXT*, void* )> FUNC_CALL_REF;
112
114{
115 wxString* str;
116 double num;
117 int idx;
118};
119
120// Lemon can't handle c'tors and d'tors, so we provide a poor-man's version.
121constexpr T_TOKEN_VALUE defaultTokenValue = { nullptr, 0.0, 0 };
122
123
125{
126 int token;
128};
129
130// Lemon can't handle c'tors and d'tors, so we provide a poor-man's version.
132
133
135{
136public:
138
139 int op;
140 TREE_NODE* leaf[2];
142 bool valid;
146
147 void SetUop( int aOp, double aValue, EDA_UNITS aUnits );
148 void SetUop( int aOp, const wxString& aValue, bool aStringIsWildcard );
149 void SetUop( int aOp, std::unique_ptr<VAR_REF> aRef = nullptr );
150 void SetUop( int aOp, FUNC_CALL_REF aFunc, std::unique_ptr<VAR_REF> aRef = nullptr );
151};
152
153
154TREE_NODE* newNode( LIBEVAL::COMPILER* compiler, int op,
155 const T_TOKEN_VALUE& value = defaultTokenValue );
156
158{
159public:
161 {
162 }
163
165 {
166 }
167
168 virtual const std::vector<wxString>& GetSupportedUnits() const
169 {
170 static const std::vector<wxString> nullUnits;
171
172 return nullUnits;
173 }
174
175
176 virtual const std::vector<EDA_UNITS>& GetSupportedUnitsTypes() const
177 {
178 static const std::vector<EDA_UNITS> nullUnits;
179
180 return nullUnits;
181 }
182
183 virtual wxString GetSupportedUnitsMessage() const
184 {
185 return wxEmptyString;
186 }
187
188 virtual double Convert( const wxString& aString, int unitType ) const
189 {
190 return 0.0;
191 };
192};
193
194
196{
197public:
199 m_type( VT_UNDEFINED ),
200 m_valueDbl( 0 ),
201 m_stringIsWildcard( false ),
202 m_isDeferredDbl( false ),
203 m_isDeferredStr( false ),
204 m_units( EDA_UNITS::UNSCALED )
205 {};
206
207 VALUE( const wxString& aStr, bool aIsWildcard = false ) :
208 m_type( VT_STRING ),
209 m_valueDbl( 0 ),
210 m_valueStr( aStr ),
211 m_stringIsWildcard( aIsWildcard ),
212 m_isDeferredDbl( false ),
213 m_isDeferredStr( false ),
214 m_units( EDA_UNITS::UNSCALED )
215 {};
216
217 VALUE( const double aVal ) :
218 m_type( VT_NUMERIC ),
219 m_valueDbl( aVal ),
220 m_stringIsWildcard( false ),
221 m_isDeferredDbl( false ),
222 m_isDeferredStr( false ),
223 m_units( EDA_UNITS::UNSCALED )
224 {};
225
227 {
228 VALUE* v = new VALUE();
229 v->m_type = VT_NULL;
230 return v;
231 }
232
233 virtual ~VALUE()
234 {};
235
236 virtual double AsDouble() const
237 {
238 if( m_isDeferredDbl )
239 {
240 m_valueDbl = m_lambdaDbl();
241 m_isDeferredDbl = false;
242 }
243
244 return m_valueDbl;
245 }
246
247 virtual const wxString& AsString() const
248 {
249 if( m_isDeferredStr )
250 {
251 m_valueStr = m_lambdaStr();
252 m_isDeferredStr = false;
253 }
254
255 return m_valueStr;
256 }
257
258 virtual bool EqualTo( CONTEXT* aCtx, const VALUE* b ) const;
259
260 // NB: this is not an inverse of EqualTo as they both return false for undefined values.
261 virtual bool NotEqualTo( CONTEXT* aCtx, const VALUE* b ) const;
262
263 VAR_TYPE_T GetType() const { return m_type; };
264
265 void Set( double aValue )
266 {
267 m_type = VT_NUMERIC;
268 m_valueDbl = aValue;
269 }
270
271 void SetDeferredEval( std::function<double()> aLambda )
272 {
273 m_type = VT_NUMERIC;
274 m_lambdaDbl = std::move( aLambda );
275 m_isDeferredDbl = true;
276 }
277
278 void SetDeferredEval( std::function<wxString()> aLambda )
279 {
280 m_type = VT_STRING;
281 m_lambdaStr = std::move( aLambda );
282 m_isDeferredStr = true;
283 }
284
285 void Set( const wxString& aValue )
286 {
287 m_type = VT_STRING;
288 m_valueStr = aValue;
289 }
290
291 void Set( const VALUE &val )
292 {
293 m_type = val.m_type;
294 m_valueDbl = val.m_valueDbl;
295
296 if( m_type == VT_STRING )
297 m_valueStr = val.m_valueStr;
298 }
299
300 void SetUnits( const EDA_UNITS aUnits ) { m_units = aUnits; }
301
302 EDA_UNITS GetUnits() const { return m_units; }
303
304 bool StringIsWildcard() const { return m_stringIsWildcard; }
305
306private:
308 mutable double m_valueDbl; // mutable to support deferred evaluation
309 mutable wxString m_valueStr; // mutable to support deferred evaluation
311
312 mutable bool m_isDeferredDbl;
313 std::function<double()> m_lambdaDbl;
314
315 mutable bool m_isDeferredStr;
316 std::function<wxString()> m_lambdaStr;
317
319};
320
322{
323public:
325 virtual ~VAR_REF() {};
326
327 virtual VAR_TYPE_T GetType() const = 0;
328 virtual VALUE* GetValue( CONTEXT* aCtx ) = 0;
329};
330
331
333{
334public:
336 m_stack(),
337 m_stackPtr( 0 )
338 {
339 m_ownedValues.reserve( 20 );
340 }
341
342 virtual ~CONTEXT()
343 {
344 for( VALUE* v : m_ownedValues )
345 {
346 delete v;
347 }
348 }
349
351 {
352 m_ownedValues.emplace_back( new VALUE );
353 return m_ownedValues.back();
354 }
355
357 {
358 m_ownedValues.emplace_back( aValue );
359 return m_ownedValues.back();
360 }
361
362 void Push( VALUE* v )
363 {
364 m_stack[ m_stackPtr++ ] = v;
365 }
366
368 {
369 if( m_stackPtr == 0 )
370 {
371 ReportError( _( "Malformed expression" ) );
372 return AllocValue();
373 }
374
375 return m_stack[ --m_stackPtr ];
376 }
377
378 int SP() const
379 {
380 return m_stackPtr;
381 };
382
383 void SetErrorCallback( std::function<void( const wxString& aMessage, int aOffset )> aCallback )
384 {
385 m_errorCallback = std::move( aCallback );
386 }
387
388 bool HasErrorCallback() { return m_errorCallback != nullptr; }
389
390 void ReportError( const wxString& aErrorMsg );
391
392private:
393 std::vector<VALUE*> m_ownedValues;
394 VALUE* m_stack[100]; // std::stack not performant enough
396
397 std::function<void( const wxString& aMessage, int aOffset )> m_errorCallback;
398};
399
400
402{
403public:
404 virtual ~UCODE();
405
406 void AddOp( UOP* uop )
407 {
408 m_ucode.push_back(uop);
409 }
410
411 VALUE* Run( CONTEXT* ctx );
412 wxString Dump() const;
413
414 virtual std::unique_ptr<VAR_REF> CreateVarRef( const wxString& var, const wxString& field )
415 {
416 return nullptr;
417 };
418
419 virtual FUNC_CALL_REF CreateFuncCall( const wxString& name )
420 {
421 return nullptr;
422 };
423
424protected:
425
426 std::vector<UOP*> m_ucode;
427};
428
429
431{
432public:
433 UOP( int op, std::unique_ptr<VALUE> value ) :
434 m_op( op ),
435 m_ref(nullptr),
436 m_value( std::move( value ) )
437 {};
438
439 UOP( int op, std::unique_ptr<VAR_REF> vref ) :
440 m_op( op ),
441 m_ref( std::move( vref ) ),
442 m_value(nullptr)
443 {};
444
445 UOP( int op, FUNC_CALL_REF func, std::unique_ptr<VAR_REF> vref = nullptr ) :
446 m_op( op ),
447 m_func( std::move( func ) ),
448 m_ref( std::move( vref ) ),
449 m_value(nullptr)
450 {};
451
453 {
454 }
455
456 void Exec( CONTEXT* ctx );
457
458 wxString Format() const;
459
460private:
461 int m_op;
462
464 std::unique_ptr<VAR_REF> m_ref;
465 std::unique_ptr<VALUE> m_value;
466};
467
469{
470public:
471 void Restart( const wxString& aStr )
472 {
473 m_str = aStr;
474 m_pos = 0;
475 }
476
477 void Clear()
478 {
479 m_str = "";
480 m_pos = 0;
481 }
482
483 int GetChar() const
484 {
485 if( m_pos >= m_str.length() )
486 return 0;
487
488 return m_str[m_pos];
489 }
490
491 bool Done() const
492 {
493 return m_pos >= m_str.length();
494 }
495
496 void NextChar( int aAdvance = 1 )
497 {
498 m_pos += aAdvance;
499 }
500
501 size_t GetPos() const
502 {
503 return m_pos;
504 }
505
506 wxString GetString();
507
508 wxString GetChars( const std::function<bool( wxUniChar )>& cond ) const;
509
510 bool MatchAhead( const wxString& match,
511 const std::function<bool( wxUniChar )>& stopCond ) const;
512
513private:
514 wxString m_str;
515 size_t m_pos = 0;
516};
517
518
520{
521public:
522 COMPILER();
523 virtual ~COMPILER();
524
525 /*
526 * clear() should be invoked by the client if a new input string is to be processed. It
527 * will reset the parser. User defined variables are retained.
528 */
529 void Clear();
530
531 /* Used by the lemon parser */
532 void parseError( const char* s );
533 void parseOk();
534
535 int GetSourcePos() const { return m_sourcePos; }
536
537 void setRoot( LIBEVAL::TREE_NODE *root );
538 void freeTree( LIBEVAL::TREE_NODE *tree );
539
540 bool Compile( const wxString& aString, UCODE* aCode, CONTEXT* aPreflightContext );
541
542 void SetErrorCallback( std::function<void( const wxString& aMessage, int aOffset )> aCallback )
543 {
544 m_errorCallback = std::move( aCallback );
545 }
546
547 bool IsErrorPending() const { return m_errorStatus.pendingError; }
548 const ERROR_STATUS& GetError() const { return m_errorStatus; }
549
550 void GcItem( TREE_NODE* aItem ) { m_gcItems.push_back( aItem ); }
551 void GcItem( wxString* aItem ) { m_gcStrings.push_back( aItem ); }
552
553protected:
555 {
556 LS_DEFAULT = 0,
557 LS_STRING = 1,
558 };
559
561
562 bool generateUCode( UCODE* aCode, CONTEXT* aPreflightContext );
563
564 void reportError( COMPILATION_STAGE stage, const wxString& aErrorMsg, int aPos = -1 );
565
566 /* Begin processing of a new input string */
567 void newString( const wxString& aString );
568
569 /* Tokenizer: Next token/value taken from input string. */
570 T_TOKEN getToken();
571 bool lexDefault( T_TOKEN& aToken );
572 bool lexString( T_TOKEN& aToken );
573
574 int resolveUnits();
575
576protected:
577 /* Token state for input string. */
578 void* m_parser; // the current lemon parser state machine
581
582 std::unique_ptr<UNIT_RESOLVER> m_unitResolver;
583
587
588 std::function<void( const wxString& aMessage, int aOffset )> m_errorCallback;
589
591
592 std::vector<TREE_NODE*> m_gcItems;
593 std::vector<wxString*> m_gcStrings;
594};
595
596
597} // namespace LIBEVAL
598
599#endif /* LIBEVAL_COMPILER_H_ */
const char * name
Definition: DXF_plotter.cpp:62
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 const std::vector< EDA_UNITS > & GetSupportedUnitsTypes() 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 SetUnits(const EDA_UNITS aUnits)
void SetDeferredEval(std::function< wxString()> aLambda)
bool StringIsWildcard() const
void Set(const wxString &aValue)
static VALUE * MakeNullValue()
std::function< double()> m_lambdaDbl
virtual double AsDouble() const
EDA_UNITS GetUnits() 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)
EDA_UNITS
Definition: eda_units.h:48
#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:198
COMPILATION_STAGE stage
T_TOKEN_VALUE value
@ VALUE
Field Value of part, i.e. "3.3K".