KiCad PCB EDA Suite
PCB_EXPR_COMPILER Class Reference

#include <pcb_expr_evaluator.h>

Inheritance diagram for PCB_EXPR_COMPILER:
LIBEVAL::COMPILER

Public Member Functions

 PCB_EXPR_COMPILER (LIBEVAL::UNIT_RESOLVER *aUnitResolver)
 
void Clear ()
 
void parseError (const char *s)
 
void parseOk ()
 
int GetSourcePos () const
 
void setRoot (LIBEVAL::TREE_NODE *root)
 
void freeTree (LIBEVAL::TREE_NODE *tree)
 
bool Compile (const wxString &aString, UCODE *aCode, CONTEXT *aPreflightContext)
 
void SetErrorCallback (std::function< void(const wxString &aMessage, int aOffset)> aCallback)
 
bool IsErrorPending () const
 
const ERROR_STATUS & GetError () const
 
void GcItem (TREE_NODE *aItem)
 
void GcItem (wxString *aItem)
 

Protected Types

enum  LEXER_STATE { LS_DEFAULT = 0 , LS_STRING = 1 }
 

Protected Member Functions

bool generateUCode (UCODE *aCode, CONTEXT *aPreflightContext)
 
void reportError (COMPILATION_STAGE stage, const wxString &aErrorMsg, int aPos=-1)
 
void newString (const wxString &aString)
 
T_TOKEN getToken ()
 
bool lexDefault (T_TOKEN &aToken)
 
bool lexString (T_TOKEN &aToken)
 
int resolveUnits ()
 

Protected Attributes

LEXER_STATE m_lexerState
 
void * m_parser
 
TOKENIZER m_tokenizer
 
char m_localeDecimalSeparator
 
std::unique_ptr< UNIT_RESOLVER > m_unitResolver
 
int m_sourcePos
 
bool m_parseFinished
 
ERROR_STATUS m_errorStatus
 
std::function< void(const wxString &aMessage, int aOffset)> m_errorCallback
 
TREE_NODE * m_tree
 
std::vector< TREE_NODE * > m_gcItems
 
std::vector< wxString * > m_gcStrings
 

Detailed Description

Definition at line 219 of file pcb_expr_evaluator.h.

Member Enumeration Documentation

◆ LEXER_STATE

enum LIBEVAL::COMPILER::LEXER_STATE
protectedinherited
Enumerator
LS_DEFAULT 
LS_STRING 

Definition at line 523 of file libeval_compiler.h.

524 {
525 LS_DEFAULT = 0,
526 LS_STRING = 1,
527 };

Constructor & Destructor Documentation

◆ PCB_EXPR_COMPILER()

PCB_EXPR_COMPILER::PCB_EXPR_COMPILER ( LIBEVAL::UNIT_RESOLVER aUnitResolver)

Definition at line 334 of file pcb_expr_evaluator.cpp.

335{
336 m_unitResolver.reset( aUnitResolver );
337}
std::unique_ptr< UNIT_RESOLVER > m_unitResolver

References LIBEVAL::COMPILER::m_unitResolver.

Member Function Documentation

◆ Clear()

void LIBEVAL::COMPILER::Clear ( )
inherited

Definition at line 263 of file libeval_compiler.cpp.

264{
265 //free( current.token );
267
268 if( m_tree )
269 {
270 freeTree( m_tree );
271 m_tree = nullptr;
272 }
273
274 m_tree = nullptr;
275
276 for( auto tok : m_gcItems )
277 delete tok;
278
279 for( auto tok: m_gcStrings )
280 delete tok;
281
282 m_gcItems.clear();
283 m_gcStrings.clear();
284}
void freeTree(LIBEVAL::TREE_NODE *tree)
std::vector< TREE_NODE * > m_gcItems
std::vector< wxString * > m_gcStrings

References LIBEVAL::TOKENIZER::Clear(), LIBEVAL::COMPILER::freeTree(), LIBEVAL::COMPILER::m_gcItems, LIBEVAL::COMPILER::m_gcStrings, LIBEVAL::COMPILER::m_tokenizer, and LIBEVAL::COMPILER::m_tree.

Referenced by LIBEVAL::COMPILER::newString(), and LIBEVAL::COMPILER::~COMPILER().

◆ Compile()

bool LIBEVAL::COMPILER::Compile ( const wxString &  aString,
UCODE aCode,
CONTEXT aPreflightContext 
)
inherited

Definition at line 299 of file libeval_compiler.cpp.

300{
301 // Feed parser token after token until end of input.
302
303 newString( aString );
304
305 if( m_tree )
306 {
307 freeTree( m_tree );
308 m_tree = nullptr;
309 }
310
311 m_tree = nullptr;
312 m_parseFinished = false;
313 T_TOKEN tok( defaultToken );
314
315 libeval_dbg(0, "str: '%s' empty: %d\n", aString.c_str(), !!aString.empty() );
316
317 if( aString.empty() )
318 {
319 m_parseFinished = true;
320 return generateUCode( aCode, aPreflightContext );
321 }
322
323 do
324 {
326
327 tok = getToken();
328
329 if( tok.value.str )
330 GcItem( tok.value.str );
331
332 libeval_dbg(10, "parse: tok %d valstr %p\n", tok.token, tok.value.str );
333 Parse( m_parser, tok.token, tok, this );
334
336 return false;
337
338 if( m_parseFinished || tok.token == G_ENDS )
339 {
340 // Reset parser by passing zero as token ID, value is ignored.
341 Parse( m_parser, 0, tok, this );
342 break;
343 }
344 } while( tok.token );
345
346 return generateUCode( aCode, aPreflightContext );
347}
void newString(const wxString &aString)
void GcItem(TREE_NODE *aItem)
bool generateUCode(UCODE *aCode, CONTEXT *aPreflightContext)
ERROR_STATUS m_errorStatus
size_t GetPos() const
#define libeval_dbg(level, fmt,...)
constexpr T_TOKEN defaultToken
PARSE_RESULT Parse(const std::string &aString, NOTATION aNotation=NOTATION::SI, SIM_VALUE::TYPE aValueType=SIM_VALUE::TYPE_FLOAT)
Definition: sim_value.cpp:189

References LIBEVAL::defaultToken, LIBEVAL::COMPILER::freeTree(), LIBEVAL::COMPILER::GcItem(), LIBEVAL::COMPILER::generateUCode(), LIBEVAL::TOKENIZER::GetPos(), LIBEVAL::COMPILER::getToken(), libeval_dbg, LIBEVAL::COMPILER::m_errorStatus, LIBEVAL::COMPILER::m_parseFinished, LIBEVAL::COMPILER::m_parser, LIBEVAL::COMPILER::m_sourcePos, LIBEVAL::COMPILER::m_tokenizer, LIBEVAL::COMPILER::m_tree, LIBEVAL::COMPILER::newString(), SIM_VALUE_PARSER::Parse(), LIBEVAL::ERROR_STATUS::pendingError, LIBEVAL::T_TOKEN_VALUE::str, LIBEVAL::T_TOKEN::token, and LIBEVAL::T_TOKEN::value.

Referenced by DRC_RULE_CONDITION::Compile(), PCB_EXPR_EVALUATOR::Evaluate(), and testEvalExpr().

◆ freeTree()

void LIBEVAL::COMPILER::freeTree ( LIBEVAL::TREE_NODE tree)
inherited

Definition at line 690 of file libeval_compiler.cpp.

691{
692 if ( tree->leaf[0] )
693 freeTree( tree->leaf[0] );
694
695 if ( tree->leaf[1] )
696 freeTree( tree->leaf[1] );
697
698 delete tree->uop;
699 tree->uop = nullptr;
700}
TREE_NODE * leaf[2]

References LIBEVAL::COMPILER::freeTree(), LIBEVAL::TREE_NODE::leaf, and LIBEVAL::TREE_NODE::uop.

Referenced by LIBEVAL::COMPILER::Clear(), LIBEVAL::COMPILER::Compile(), LIBEVAL::COMPILER::freeTree(), and LIBEVAL::COMPILER::~COMPILER().

◆ GcItem() [1/2]

void LIBEVAL::COMPILER::GcItem ( TREE_NODE aItem)
inlineinherited

Definition at line 519 of file libeval_compiler.h.

519{ m_gcItems.push_back( aItem ); }

References LIBEVAL::COMPILER::m_gcItems.

Referenced by LIBEVAL::COMPILER::Compile(), and LIBEVAL::newNode().

◆ GcItem() [2/2]

void LIBEVAL::COMPILER::GcItem ( wxString *  aItem)
inlineinherited

Definition at line 520 of file libeval_compiler.h.

520{ m_gcStrings.push_back( aItem ); }

References LIBEVAL::COMPILER::m_gcStrings.

◆ generateUCode()

bool LIBEVAL::COMPILER::generateUCode ( UCODE aCode,
CONTEXT aPreflightContext 
)
protectedinherited

Definition at line 795 of file libeval_compiler.cpp.

796{
797 std::vector<TREE_NODE*> stack;
798 wxString msg;
799
800 if( !m_tree )
801 {
802 std::unique_ptr<VALUE> val = std::make_unique<VALUE>( 1.0 );
803 // Empty expression returns true
804 aCode->AddOp( new UOP( TR_UOP_PUSH_VALUE, std::move(val) ) );
805 return true;
806 }
807
809
810 stack.push_back( m_tree );
811
812 wxString dump;
813
814 dumpNode( dump, m_tree, 0 );
815 libeval_dbg( 3, "Tree dump:\n%s\n\n", (const char*) dump.c_str() );
816
817 while( !stack.empty() )
818 {
819 TREE_NODE* node = stack.back();
820
821 libeval_dbg( 4, "process node %p [op %d] [stack %lu]\n",
822 node, node->op, (unsigned long)stack.size() );
823
824 // process terminal nodes first
825 switch( node->op )
826 {
827 case TR_OP_FUNC_CALL:
828 // Function call's uop was generated inside TR_STRUCT_REF
829 if( !node->uop )
830 {
831 reportError( CST_CODEGEN, _( "Unknown parent of function parameters" ),
832 node->srcPos );
833 }
834
835 node->isTerminal = true;
836 break;
837
838 case TR_STRUCT_REF:
839 {
840 // leaf[0]: object
841 // leaf[1]: field (TR_IDENTIFIER) or TR_OP_FUNC_CALL
842
843 if( node->leaf[0]->op != TR_IDENTIFIER )
844 {
845 int pos = node->leaf[0]->srcPos;
846
847 if( node->leaf[0]->value.str )
848 pos -= static_cast<int>( node->leaf[0]->value.str->length() );
849
850 reportError( CST_CODEGEN, _( "Unknown parent of property" ), pos );
851
852 node->leaf[0]->isVisited = true;
853 node->leaf[1]->isVisited = true;
854
855 node->SetUop( TR_UOP_PUSH_VALUE, 0.0 );
856 node->isTerminal = true;
857 break;
858 }
859
860 switch( node->leaf[1]->op )
861 {
862 case TR_IDENTIFIER:
863 {
864 // leaf[0]: object
865 // leaf[1]: field
866
867 wxString itemName = *node->leaf[0]->value.str;
868 wxString propName = *node->leaf[1]->value.str;
869 std::unique_ptr<VAR_REF> vref = aCode->CreateVarRef( itemName, propName );
870
871 if( !vref )
872 {
873 msg.Printf( _( "Unrecognized item '%s'" ), itemName );
875 node->leaf[0]->srcPos - (int) itemName.length() );
876 }
877 else if( vref->GetType() == VT_PARSE_ERROR )
878 {
879 msg.Printf( _( "Unrecognized property '%s'" ), propName );
881 node->leaf[1]->srcPos - (int) propName.length() );
882 }
883
884 node->leaf[0]->isVisited = true;
885 node->leaf[1]->isVisited = true;
886
887 node->SetUop( TR_UOP_PUSH_VAR, std::move( vref ) );
888 node->isTerminal = true;
889 break;
890 }
891 case TR_OP_FUNC_CALL:
892 {
893 // leaf[0]: object
894 // leaf[1]: TR_OP_FUNC_CALL
895 // leaf[0]: function name
896 // leaf[1]: parameter
897
898 wxString itemName = *node->leaf[0]->value.str;
899 std::unique_ptr<VAR_REF> vref = aCode->CreateVarRef( itemName, "" );
900
901 if( !vref )
902 {
903 msg.Printf( _( "Unrecognized item '%s'" ), itemName );
905 node->leaf[0]->srcPos - (int) itemName.length() );
906 }
907
908 wxString functionName = *node->leaf[1]->leaf[0]->value.str;
909 auto func = aCode->CreateFuncCall( functionName );
910 std::vector<TREE_NODE*> params = squashParamList( node->leaf[1]->leaf[1] );
911
912 libeval_dbg( 10, "emit func call: %s\n", functionName );
913
914 if( !func )
915 {
916 msg.Printf( _( "Unrecognized function '%s'" ), functionName );
917 reportError( CST_CODEGEN, msg, node->leaf[0]->srcPos + 1 );
918 }
919
920 if( func )
921 {
922 // Preflight the function call
923
924 for( TREE_NODE* pnode : params )
925 {
926 VALUE* param = aPreflightContext->AllocValue();
927 param->Set( *pnode->value.str );
928 aPreflightContext->Push( param );
929 }
930
931 aPreflightContext->SetErrorCallback(
932 [&]( const wxString& aMessage, int aOffset )
933 {
934 size_t loc = node->leaf[1]->leaf[1]->srcPos;
935 reportError( CST_CODEGEN, aMessage, (int) loc - 1 );
936 } );
937
938 try
939 {
940 func( aPreflightContext, vref.get() );
941 aPreflightContext->Pop(); // return value
942 }
943 catch( ... )
944 {
945 }
946 }
947
948 node->leaf[0]->isVisited = true;
949 node->leaf[1]->isVisited = true;
950 node->leaf[1]->leaf[0]->isVisited = true;
951 node->leaf[1]->leaf[1]->isVisited = true;
952
953 // Our non-terminal-node stacking algorithm can't handle doubly-nested
954 // structures so we need to pop a level by replacing the TR_STRUCT_REF with
955 // a TR_OP_FUNC_CALL and its function parameter
956 stack.pop_back();
957 stack.push_back( node->leaf[1] );
958
959 for( TREE_NODE* pnode : params )
960 stack.push_back( pnode );
961
962 node->leaf[1]->SetUop( TR_OP_METHOD_CALL, func, std::move( vref ) );
963 node->isTerminal = false;
964 break;
965 }
966
967 default:
968 // leaf[0]: object
969 // leaf[1]: malformed syntax
970
971 wxString itemName = *node->leaf[0]->value.str;
972 wxString propName = *node->leaf[1]->value.str;
973 std::unique_ptr<VAR_REF> vref = aCode->CreateVarRef( itemName, propName );
974
975 if( !vref )
976 {
977 msg.Printf( _( "Unrecognized item '%s'" ), itemName );
979 node->leaf[0]->srcPos - (int) itemName.length() );
980 }
981
982 msg.Printf( _( "Unrecognized property '%s'" ), propName );
983 reportError( CST_CODEGEN, msg, node->leaf[0]->srcPos + 1 );
984
985 node->leaf[0]->isVisited = true;
986 node->leaf[1]->isVisited = true;
987
988 node->SetUop( TR_UOP_PUSH_VALUE, 0.0 );
989 node->isTerminal = true;
990 break;
991 }
992
993 break;
994 }
995
996 case TR_NUMBER:
997 {
998 TREE_NODE* son = node->leaf[0];
999 double value;
1000
1001 if( !node->value.str )
1002 {
1003 value = 0.0;
1004 }
1005 else if( son && son->op == TR_UNIT )
1006 {
1007 if( m_unitResolver->GetSupportedUnits().empty() )
1008 {
1009 msg.Printf( _( "Unexpected units for '%s'" ), *node->value.str );
1010 reportError( CST_CODEGEN, msg, node->srcPos );
1011 }
1012
1013 int units = son->value.idx;
1014 value = m_unitResolver->Convert( *node->value.str, units );
1015 son->isVisited = true;
1016 }
1017 else
1018 {
1019 if( !m_unitResolver->GetSupportedUnitsMessage().empty() )
1020 {
1021 msg.Printf( _( "Missing units for '%s'| (%s)" ),
1022 *node->value.str,
1023 m_unitResolver->GetSupportedUnitsMessage() );
1024 reportError( CST_CODEGEN, msg, node->srcPos );
1025 }
1026
1027 value = EDA_UNIT_UTILS::UI::DoubleValueFromString( *node->value.str );
1028 }
1029
1030 node->SetUop( TR_UOP_PUSH_VALUE, value );
1031 node->isTerminal = true;
1032 break;
1033 }
1034
1035 case TR_STRING:
1036 {
1037 wxString str = *node->value.str;
1038 bool isWildcard = str.Contains("?") || str.Contains("*");
1039 node->SetUop( TR_UOP_PUSH_VALUE, str, isWildcard );
1040 node->isTerminal = true;
1041 break;
1042 }
1043
1044 case TR_IDENTIFIER:
1045 {
1046 std::unique_ptr<VAR_REF> vref = aCode->CreateVarRef( *node->value.str, "" );
1047
1048 if( !vref )
1049 {
1050 msg.Printf( _( "Unrecognized item '%s'" ), *node->value.str );
1051 reportError( CST_CODEGEN, msg, node->srcPos - (int) node->value.str->length() );
1052 }
1053
1054 node->SetUop( TR_UOP_PUSH_VAR, std::move( vref ) );
1055 node->isTerminal = true;
1056 break;
1057 }
1058
1059 default:
1060 node->SetUop( node->op );
1061 node->isTerminal = ( !node->leaf[0] || node->leaf[0]->isVisited )
1062 && ( !node->leaf[1] || node->leaf[1]->isVisited );
1063 break;
1064 }
1065
1066 if( !node->isTerminal )
1067 {
1068 if( node->leaf[0] && !node->leaf[0]->isVisited )
1069 {
1070 stack.push_back( node->leaf[0] );
1071 node->leaf[0]->isVisited = true;
1072 continue;
1073 }
1074 else if( node->leaf[1] && !node->leaf[1]->isVisited )
1075 {
1076 stack.push_back( node->leaf[1] );
1077 node->leaf[1]->isVisited = true;
1078 }
1079
1080 continue;
1081 }
1082
1083 node->isVisited = true;
1084
1085 if( node->uop )
1086 {
1087 aCode->AddOp( node->uop );
1088 node->uop = nullptr;
1089 }
1090
1091 stack.pop_back();
1092 }
1093
1094 libeval_dbg(2,"dump: \n%s\n", aCode->Dump().c_str() );
1095
1096 return true;
1097}
void reportError(COMPILATION_STAGE stage, const wxString &aErrorMsg, int aPos=-1)
#define _(s)
#define TR_UOP_PUSH_VAR
#define TR_UOP_PUSH_VALUE
#define TR_OP_FUNC_CALL
#define TR_OP_METHOD_CALL
double DoubleValueFromString(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, const wxString &aTextValue, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Function DoubleValueFromString converts aTextValue to a double.
Definition: eda_units.cpp:445
static std::vector< TREE_NODE * > squashParamList(TREE_NODE *root)
void dumpNode(wxString &buf, TREE_NODE *tok, int depth=0)
static void prepareTree(LIBEVAL::TREE_NODE *node)
wxString dump(const wxArrayString &aArray)
Debug helper for printing wxArrayString contents.

References _, LIBEVAL::UCODE::AddOp(), LIBEVAL::CONTEXT::AllocValue(), LIBEVAL::UCODE::CreateFuncCall(), LIBEVAL::UCODE::CreateVarRef(), LIBEVAL::CST_CODEGEN, EDA_UNIT_UTILS::UI::DoubleValueFromString(), LIBEVAL::UCODE::Dump(), dump(), LIBEVAL::dumpNode(), LIBEVAL::T_TOKEN_VALUE::idx, LIBEVAL::TREE_NODE::isTerminal, LIBEVAL::TREE_NODE::isVisited, LIBEVAL::TREE_NODE::leaf, libeval_dbg, LIBEVAL::COMPILER::m_tree, LIBEVAL::COMPILER::m_unitResolver, LIBEVAL::TREE_NODE::op, LIBEVAL::CONTEXT::Pop(), LIBEVAL::prepareTree(), LIBEVAL::CONTEXT::Push(), LIBEVAL::COMPILER::reportError(), LIBEVAL::VALUE::Set(), LIBEVAL::CONTEXT::SetErrorCallback(), LIBEVAL::TREE_NODE::SetUop(), LIBEVAL::squashParamList(), LIBEVAL::TREE_NODE::srcPos, LIBEVAL::T_TOKEN_VALUE::str, LIBEVAL::TR_IDENTIFIER, LIBEVAL::TR_NUMBER, TR_OP_FUNC_CALL, TR_OP_METHOD_CALL, LIBEVAL::TR_STRING, LIBEVAL::TR_STRUCT_REF, LIBEVAL::TR_UNIT, TR_UOP_PUSH_VALUE, TR_UOP_PUSH_VAR, LIBEVAL::TREE_NODE::uop, LIBEVAL::TREE_NODE::value, and LIBEVAL::VT_PARSE_ERROR.

Referenced by LIBEVAL::COMPILER::Compile().

◆ GetError()

const ERROR_STATUS & LIBEVAL::COMPILER::GetError ( ) const
inlineinherited

Definition at line 517 of file libeval_compiler.h.

517{ return m_errorStatus; }

References LIBEVAL::COMPILER::m_errorStatus.

Referenced by testEvalExpr().

◆ GetSourcePos()

int LIBEVAL::COMPILER::GetSourcePos ( ) const
inlineinherited

Definition at line 504 of file libeval_compiler.h.

504{ return m_sourcePos; }

References LIBEVAL::COMPILER::m_sourcePos.

Referenced by LIBEVAL::newNode().

◆ getToken()

T_TOKEN LIBEVAL::COMPILER::getToken ( )
protectedinherited

Definition at line 360 of file libeval_compiler.cpp.

361{
362 T_TOKEN rv;
363 rv.value = defaultTokenValue;
364
365 bool done = false;
366
367 do
368 {
369 switch( m_lexerState )
370 {
371 case LS_DEFAULT:
372 done = lexDefault( rv );
373 break;
374 case LS_STRING:
375 done = lexString( rv );
376 break;
377 }
378 } while( !done );
379
380 return rv;
381}
bool lexString(T_TOKEN &aToken)
LEXER_STATE m_lexerState
bool lexDefault(T_TOKEN &aToken)
constexpr T_TOKEN_VALUE defaultTokenValue

References LIBEVAL::defaultTokenValue, LIBEVAL::COMPILER::lexDefault(), LIBEVAL::COMPILER::lexString(), LIBEVAL::COMPILER::LS_DEFAULT, LIBEVAL::COMPILER::LS_STRING, LIBEVAL::COMPILER::m_lexerState, and LIBEVAL::T_TOKEN::value.

Referenced by LIBEVAL::COMPILER::Compile().

◆ IsErrorPending()

bool LIBEVAL::COMPILER::IsErrorPending ( ) const
inlineinherited

◆ lexDefault()

bool LIBEVAL::COMPILER::lexDefault ( T_TOKEN aToken)
protectedinherited

Definition at line 417 of file libeval_compiler.cpp.

418{
419 T_TOKEN retval;
420 wxString current;
421 int convertFrom;
422 wxString msg;
423
424 retval.value.str = nullptr;
425 retval.value.num = 0.0;
426 retval.value.idx = -1;
427 retval.token = G_ENDS;
428
429 if( m_tokenizer.Done() )
430 {
431 aToken = retval;
432 return true;
433 }
434
435 auto isDecimalSeparator =
436 [&]( wxUniChar ch ) -> bool
437 {
438 return ( ch == m_localeDecimalSeparator || ch == '.' || ch == ',' );
439 };
440
441 // Lambda: get value as string, store into clToken.token and update current index.
442 auto extractNumber =
443 [&]()
444 {
445 bool haveSeparator = false;
446 wxUniChar ch = m_tokenizer.GetChar();
447
448 do
449 {
450 if( isDecimalSeparator( ch ) && haveSeparator )
451 break;
452
453 current.append( 1, ch );
454
455 if( isDecimalSeparator( ch ) )
456 haveSeparator = true;
457
459 ch = m_tokenizer.GetChar();
460 } while( isdigit( ch ) || isDecimalSeparator( ch ) );
461
462 // Ensure that the systems decimal separator is used
463 for( int i = current.length(); i; i-- )
464 {
465 if( isDecimalSeparator( current[i - 1] ) )
466 current[i - 1] = m_localeDecimalSeparator;
467 }
468 };
469
470
471 int ch;
472
473 // Start processing of first/next token: Remove whitespace
474 for( ;; )
475 {
476 ch = m_tokenizer.GetChar();
477
478 if( ch == ' ' )
480 else
481 break;
482 }
483
484 libeval_dbg(10, "LEX ch '%c' pos %lu\n", ch, (unsigned long)m_tokenizer.GetPos() );
485
486 if( ch == 0 )
487 {
488 /* End of input */
489 }
490 else if( isdigit( ch ) )
491 {
492 // VALUE
493 extractNumber();
494 retval.token = G_VALUE;
495 retval.value.str = new wxString( current );
496 }
497 else if( ( convertFrom = resolveUnits() ) >= 0 )
498 {
499 // UNIT
500 // Units are appended to a VALUE.
501 // Determine factor to default unit if unit for value is given.
502 // Example: Default is mm, unit is inch: factor is 25.4
503 // The factor is assigned to the terminal UNIT. The actual
504 // conversion is done within a parser action.
505 retval.token = G_UNIT;
506 retval.value.idx = convertFrom;
507 }
508 else if( ch == '\'' ) // string literal
509 {
512 return false;
513 }
514 else if( isalpha( ch ) || ch == '_' )
515 {
516 current = m_tokenizer.GetChars( []( int c ) -> bool { return isalnum( c ) || c == '_'; } );
517 retval.token = G_IDENTIFIER;
518 retval.value.str = new wxString( current );
519 m_tokenizer.NextChar( current.length() );
520 }
521 else if( m_tokenizer.MatchAhead( "==", []( int c ) -> bool { return c != '='; } ) )
522 {
523 retval.token = G_EQUAL;
525 }
526 else if( m_tokenizer.MatchAhead( "!=", []( int c ) -> bool { return c != '='; } ) )
527 {
528 retval.token = G_NOT_EQUAL;
530 }
531 else if( m_tokenizer.MatchAhead( "<=", []( int c ) -> bool { return c != '='; } ) )
532 {
533 retval.token = G_LESS_EQUAL_THAN;
535 }
536 else if( m_tokenizer.MatchAhead( ">=", []( int c ) -> bool { return c != '='; } ) )
537 {
538 retval.token = G_GREATER_EQUAL_THAN;
540 }
541 else if( m_tokenizer.MatchAhead( "&&", []( int c ) -> bool { return c != '&'; } ) )
542 {
543 retval.token = G_BOOL_AND;
545 }
546 else if( m_tokenizer.MatchAhead( "||", []( int c ) -> bool { return c != '|'; } ) )
547 {
548 retval.token = G_BOOL_OR;
550 }
551 else
552 {
553 // Single char tokens
554 switch( ch )
555 {
556 case '+': retval.token = G_PLUS; break;
557 case '!': retval.token = G_BOOL_NOT; break;
558 case '-': retval.token = G_MINUS; break;
559 case '*': retval.token = G_MULT; break;
560 case '/': retval.token = G_DIVIDE; break;
561 case '<': retval.token = G_LESS_THAN; break;
562 case '>': retval.token = G_GREATER_THAN; break;
563 case '(': retval.token = G_PARENL; break;
564 case ')': retval.token = G_PARENR; break;
565 case ';': retval.token = G_SEMCOL; break;
566 case '.': retval.token = G_STRUCT_REF; break;
567 case ',': retval.token = G_COMMA; break;
568
569 default:
570 reportError( CST_PARSE, wxString::Format( _( "Unrecognized character '%c'" ),
571 (char) ch ) );
572 break;
573 }
574
576 }
577
578 aToken = retval;
579 return true;
580}
void NextChar(int aAdvance=1)
wxString GetChars(const std::function< bool(wxUniChar)> &cond) const
bool MatchAhead(const wxString &match, const std::function< bool(wxUniChar)> &stopCond) const
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

References _, LIBEVAL::CST_PARSE, LIBEVAL::TOKENIZER::Done(), Format(), LIBEVAL::TOKENIZER::GetChar(), LIBEVAL::TOKENIZER::GetChars(), LIBEVAL::TOKENIZER::GetPos(), LIBEVAL::T_TOKEN_VALUE::idx, libeval_dbg, LIBEVAL::COMPILER::LS_STRING, LIBEVAL::COMPILER::m_lexerState, LIBEVAL::COMPILER::m_localeDecimalSeparator, LIBEVAL::COMPILER::m_tokenizer, LIBEVAL::TOKENIZER::MatchAhead(), LIBEVAL::TOKENIZER::NextChar(), LIBEVAL::T_TOKEN_VALUE::num, LIBEVAL::COMPILER::reportError(), LIBEVAL::COMPILER::resolveUnits(), LIBEVAL::T_TOKEN_VALUE::str, LIBEVAL::T_TOKEN::token, and LIBEVAL::T_TOKEN::value.

Referenced by LIBEVAL::COMPILER::getToken().

◆ lexString()

bool LIBEVAL::COMPILER::lexString ( T_TOKEN aToken)
protectedinherited

Definition at line 384 of file libeval_compiler.cpp.

385{
386 wxString str = m_tokenizer.GetChars( []( int c ) -> bool { return c != '\''; } );
387
388 aToken.token = G_STRING;
389 aToken.value.str = new wxString( str );
390
391 m_tokenizer.NextChar( str.length() + 1 );
393 return true;
394}

References LIBEVAL::TOKENIZER::GetChars(), LIBEVAL::COMPILER::LS_DEFAULT, LIBEVAL::COMPILER::m_lexerState, LIBEVAL::COMPILER::m_tokenizer, LIBEVAL::TOKENIZER::NextChar(), LIBEVAL::T_TOKEN_VALUE::str, LIBEVAL::T_TOKEN::token, and LIBEVAL::T_TOKEN::value.

Referenced by LIBEVAL::COMPILER::getToken().

◆ newString()

void LIBEVAL::COMPILER::newString ( const wxString &  aString)
protectedinherited

◆ parseError()

void LIBEVAL::COMPILER::parseError ( const char *  s)
inherited

Definition at line 287 of file libeval_compiler.cpp.

288{
290}

References LIBEVAL::CST_PARSE, and LIBEVAL::COMPILER::reportError().

◆ parseOk()

void LIBEVAL::COMPILER::parseOk ( )
inherited

Definition at line 293 of file libeval_compiler.cpp.

294{
295 m_parseFinished = true;
296}

References LIBEVAL::COMPILER::m_parseFinished.

◆ reportError()

void LIBEVAL::COMPILER::reportError ( COMPILATION_STAGE  stage,
const wxString &  aErrorMsg,
int  aPos = -1 
)
protectedinherited

◆ resolveUnits()

int LIBEVAL::COMPILER::resolveUnits ( )
protectedinherited

Definition at line 397 of file libeval_compiler.cpp.

398{
399 int unitId = 0;
400
401 for( const wxString& unitName : m_unitResolver->GetSupportedUnits() )
402 {
403 if( m_tokenizer.MatchAhead( unitName, []( int c ) -> bool { return !isalnum( c ); } ) )
404 {
405 libeval_dbg(10, "Match unit '%s'\n", unitName.c_str() );
406 m_tokenizer.NextChar( unitName.length() );
407 return unitId;
408 }
409
410 unitId++;
411 }
412
413 return -1;
414}

References libeval_dbg, LIBEVAL::COMPILER::m_tokenizer, LIBEVAL::COMPILER::m_unitResolver, LIBEVAL::TOKENIZER::MatchAhead(), and LIBEVAL::TOKENIZER::NextChar().

Referenced by LIBEVAL::COMPILER::lexDefault().

◆ SetErrorCallback()

void LIBEVAL::COMPILER::SetErrorCallback ( std::function< void(const wxString &aMessage, int aOffset)>  aCallback)
inlineinherited

Definition at line 511 of file libeval_compiler.h.

512 {
513 m_errorCallback = std::move( aCallback );
514 }

References LIBEVAL::COMPILER::m_errorCallback.

Referenced by DRC_RULE_CONDITION::Compile(), and PCB_EXPR_EVALUATOR::SetErrorCallback().

◆ setRoot()

void LIBEVAL::COMPILER::setRoot ( LIBEVAL::TREE_NODE root)
inherited

Definition at line 684 of file libeval_compiler.cpp.

685{
686 m_tree = root;
687}

References LIBEVAL::COMPILER::m_tree.

Member Data Documentation

◆ m_errorCallback

std::function<void( const wxString& aMessage, int aOffset )> LIBEVAL::COMPILER::m_errorCallback
protectedinherited

◆ m_errorStatus

ERROR_STATUS LIBEVAL::COMPILER::m_errorStatus
protectedinherited

◆ m_gcItems

std::vector<TREE_NODE*> LIBEVAL::COMPILER::m_gcItems
protectedinherited

Definition at line 561 of file libeval_compiler.h.

Referenced by LIBEVAL::COMPILER::Clear(), and LIBEVAL::COMPILER::GcItem().

◆ m_gcStrings

std::vector<wxString*> LIBEVAL::COMPILER::m_gcStrings
protectedinherited

Definition at line 562 of file libeval_compiler.h.

Referenced by LIBEVAL::COMPILER::Clear(), and LIBEVAL::COMPILER::GcItem().

◆ m_lexerState

LEXER_STATE LIBEVAL::COMPILER::m_lexerState
protectedinherited

◆ m_localeDecimalSeparator

char LIBEVAL::COMPILER::m_localeDecimalSeparator
protectedinherited

◆ m_parseFinished

bool LIBEVAL::COMPILER::m_parseFinished
protectedinherited

◆ m_parser

void* LIBEVAL::COMPILER::m_parser
protectedinherited

◆ m_sourcePos

int LIBEVAL::COMPILER::m_sourcePos
protectedinherited

◆ m_tokenizer

◆ m_tree

◆ m_unitResolver

std::unique_ptr<UNIT_RESOLVER> LIBEVAL::COMPILER::m_unitResolver
protectedinherited

The documentation for this class was generated from the following files: