|
|
@ -17,24 +17,9 @@ |
|
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
*/ |
|
|
|
|
|
|
|
#define TESTMODE 0
|
|
|
|
|
|
|
|
#include <libeval/numeric_evaluator.h>
|
|
|
|
|
|
|
|
#if !TESTMODE
|
|
|
|
#include <common.h>
|
|
|
|
#else
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
|
|
|
|
/* The (generated) lemon parser is written in C.
|
|
|
|
* In order to keep its symbol from the global namespace include the parser code with |
|
|
|
* a C++ namespace. |
|
|
@ -49,335 +34,330 @@ namespace numEval |
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "grammar.c"
|
|
|
|
|
|
|
|
#ifdef __GNUC__
|
|
|
|
#pragma GCC diagnostic pop
|
|
|
|
#endif
|
|
|
|
|
|
|
|
} /* namespace numEval */ |
|
|
|
|
|
|
|
// JEY TODO: remove this version;
|
|
|
|
NumericEvaluator :: NumericEvaluator() : |
|
|
|
pClParser( 0 ) |
|
|
|
NUMERIC_EVALUATOR::NUMERIC_EVALUATOR( EDA_UNITS_T aUnits, bool aUseMils ) |
|
|
|
{ |
|
|
|
struct lconv* lc = localeconv(); |
|
|
|
cClDecSep = *lc->decimal_point; |
|
|
|
|
|
|
|
bClTextInputStorage = true; |
|
|
|
|
|
|
|
bClError = false; |
|
|
|
bClParseFinished = false; |
|
|
|
|
|
|
|
if( pClParser == nullptr ) |
|
|
|
pClParser = numEval::ParseAlloc(malloc); |
|
|
|
|
|
|
|
switch( g_UserUnit ) |
|
|
|
{ |
|
|
|
case INCHES: |
|
|
|
eClUnitDefault = Unit::Inch; |
|
|
|
break; |
|
|
|
case MILLIMETRES: |
|
|
|
eClUnitDefault = Unit::Metric; |
|
|
|
break; |
|
|
|
default: |
|
|
|
eClUnitDefault = Unit::Metric; |
|
|
|
break; |
|
|
|
} |
|
|
|
struct lconv* lc = localeconv(); |
|
|
|
m_localeDecimalSeparator = *lc->decimal_point; |
|
|
|
|
|
|
|
m_parseError = false; |
|
|
|
m_parseFinished = false; |
|
|
|
|
|
|
|
m_parser = numEval::ParseAlloc( malloc ); |
|
|
|
|
|
|
|
switch( aUnits ) |
|
|
|
{ |
|
|
|
case INCHES: |
|
|
|
if( aUseMils ) |
|
|
|
m_defaultUnits = Unit::Mil; |
|
|
|
else |
|
|
|
m_defaultUnits = Unit::Inch; |
|
|
|
break; |
|
|
|
case MILLIMETRES:m_defaultUnits = Unit::Metric; |
|
|
|
break; |
|
|
|
default:m_defaultUnits = Unit::Metric; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
NumericEvaluator::NumericEvaluator( EDA_UNITS_T aUnits, bool aUseMils ) : |
|
|
|
pClParser( 0 ) |
|
|
|
{ |
|
|
|
struct lconv* lc = localeconv(); |
|
|
|
cClDecSep = *lc->decimal_point; |
|
|
|
|
|
|
|
bClTextInputStorage = true; |
|
|
|
pClParser = numEval::ParseAlloc(malloc); |
|
|
|
|
|
|
|
switch( aUnits ) |
|
|
|
{ |
|
|
|
case INCHES: |
|
|
|
if( aUseMils ) |
|
|
|
eClUnitDefault = Unit::Mil; |
|
|
|
else |
|
|
|
eClUnitDefault = Unit::Inch; |
|
|
|
break; |
|
|
|
case MILLIMETRES: |
|
|
|
eClUnitDefault = Unit::Metric; |
|
|
|
break; |
|
|
|
default: |
|
|
|
eClUnitDefault = Unit::Metric; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
NumericEvaluator :: ~NumericEvaluator() |
|
|
|
NUMERIC_EVALUATOR::~NUMERIC_EVALUATOR() |
|
|
|
{ |
|
|
|
numEval::ParseFree(pClParser, free); |
|
|
|
numEval::ParseFree( m_parser, free ); |
|
|
|
|
|
|
|
// Allow explicit call to destructor
|
|
|
|
pClParser = nullptr; |
|
|
|
// Allow explicit call to destructor
|
|
|
|
m_parser = nullptr; |
|
|
|
|
|
|
|
clear(); |
|
|
|
Clear(); |
|
|
|
} |
|
|
|
|
|
|
|
void |
|
|
|
NumericEvaluator :: clear(const void* pObj) |
|
|
|
{ |
|
|
|
free(clToken.token); |
|
|
|
clToken.token = nullptr; |
|
|
|
clToken.input = nullptr; |
|
|
|
bClError = true; |
|
|
|
|
|
|
|
if (bClTextInputStorage) |
|
|
|
clObjMap.clear(); |
|
|
|
void NUMERIC_EVALUATOR::Clear() |
|
|
|
{ |
|
|
|
free( m_token.token ); |
|
|
|
m_token.token = nullptr; |
|
|
|
m_token.input = nullptr; |
|
|
|
m_parseError = true; |
|
|
|
m_originalText = wxEmptyString; |
|
|
|
} |
|
|
|
|
|
|
|
void |
|
|
|
NumericEvaluator :: parse(int token, numEval::TokenType value) |
|
|
|
|
|
|
|
void NUMERIC_EVALUATOR::parseError( const char* s ) |
|
|
|
{ |
|
|
|
numEval::Parse(pClParser, token, value, this); |
|
|
|
m_parseError = true; |
|
|
|
} |
|
|
|
|
|
|
|
void |
|
|
|
NumericEvaluator :: parseError(const char* s) |
|
|
|
|
|
|
|
void NUMERIC_EVALUATOR::parseOk() |
|
|
|
{ |
|
|
|
bClError = true; |
|
|
|
m_parseFinished = true; |
|
|
|
} |
|
|
|
|
|
|
|
void |
|
|
|
NumericEvaluator :: parseOk() |
|
|
|
|
|
|
|
void NUMERIC_EVALUATOR::parseSetResult( double val ) |
|
|
|
{ |
|
|
|
bClParseFinished = true; |
|
|
|
snprintf( m_token.token, m_token.OutLen, "%.10g", val ); |
|
|
|
} |
|
|
|
|
|
|
|
void |
|
|
|
NumericEvaluator :: parseSetResult(double val) |
|
|
|
|
|
|
|
wxString NUMERIC_EVALUATOR::OriginalText() const |
|
|
|
{ |
|
|
|
snprintf(clToken.token, clToken.OutLen, "%.10g", val); |
|
|
|
return m_originalText; |
|
|
|
} |
|
|
|
|
|
|
|
const char* |
|
|
|
NumericEvaluator :: textInput(const void* pObj) const |
|
|
|
|
|
|
|
bool NUMERIC_EVALUATOR::Process( const wxString& aString ) |
|
|
|
{ |
|
|
|
auto it = clObjMap.find(pObj); |
|
|
|
if (it != clObjMap.end()) return it->second.c_str(); |
|
|
|
m_originalText = aString; |
|
|
|
|
|
|
|
return nullptr; |
|
|
|
} |
|
|
|
// Feed parser token after token until end of input.
|
|
|
|
|
|
|
|
bool |
|
|
|
NumericEvaluator :: process(const char* s) |
|
|
|
{ |
|
|
|
/* Process new string.
|
|
|
|
* Feed parser token after token until end of input. |
|
|
|
*/ |
|
|
|
|
|
|
|
newString(s); |
|
|
|
|
|
|
|
if (pClParser == nullptr) |
|
|
|
pClParser = numEval::ParseAlloc(malloc); |
|
|
|
|
|
|
|
bClError = false; |
|
|
|
bClParseFinished = false; |
|
|
|
|
|
|
|
Token tok; |
|
|
|
do { |
|
|
|
tok = getToken(); |
|
|
|
parse(tok.token, tok.value); |
|
|
|
if (bClParseFinished || tok.token == ENDS) { |
|
|
|
// Reset parser by passing zero as token ID, value is ignored.
|
|
|
|
numEval::Parse(pClParser, 0, tok.value, this); |
|
|
|
break; |
|
|
|
} |
|
|
|
//usleep(200000);
|
|
|
|
} while (tok.token); |
|
|
|
|
|
|
|
return !bClError; |
|
|
|
} |
|
|
|
newString( aString ); |
|
|
|
m_parseError = false; |
|
|
|
m_parseFinished = false; |
|
|
|
Token tok; |
|
|
|
|
|
|
|
bool |
|
|
|
NumericEvaluator :: process(const char* s, const void* pObj) |
|
|
|
{ |
|
|
|
if (bClTextInputStorage) // Store input string for (text entry) pObj.
|
|
|
|
clObjMap[pObj] = s; |
|
|
|
return process(s); |
|
|
|
do |
|
|
|
{ |
|
|
|
tok = getToken(); |
|
|
|
numEval::Parse( m_parser, tok.token, tok.value, this ); |
|
|
|
|
|
|
|
if( m_parseFinished || tok.token == ENDS ) |
|
|
|
{ |
|
|
|
// Reset parser by passing zero as token ID, value is ignored.
|
|
|
|
numEval::Parse( m_parser, 0, tok.value, this ); |
|
|
|
break; |
|
|
|
} |
|
|
|
} while( tok.token ); |
|
|
|
|
|
|
|
return !m_parseError; |
|
|
|
} |
|
|
|
|
|
|
|
void |
|
|
|
NumericEvaluator :: newString(const char* s) |
|
|
|
|
|
|
|
void NUMERIC_EVALUATOR::newString( const wxString& aString ) |
|
|
|
{ |
|
|
|
clear(); |
|
|
|
auto len = strlen(s); |
|
|
|
clToken.token = reinterpret_cast<decltype(clToken.token)>(malloc(TokenStat::OutLen+1)); |
|
|
|
strcpy(clToken.token, "0"); |
|
|
|
clToken.inputLen = len; |
|
|
|
clToken.pos = 0; |
|
|
|
clToken.input = s; |
|
|
|
bClParseFinished = false; |
|
|
|
Clear(); |
|
|
|
auto len = aString.length(); |
|
|
|
m_token.token = reinterpret_cast<decltype( m_token.token )>( malloc( TokenStat::OutLen + 1 )); |
|
|
|
strcpy( m_token.token, "0" ); |
|
|
|
m_token.inputLen = len; |
|
|
|
m_token.pos = 0; |
|
|
|
m_token.input = aString.mb_str(); |
|
|
|
m_parseFinished = false; |
|
|
|
} |
|
|
|
|
|
|
|
NumericEvaluator::Token NumericEvaluator::getToken() |
|
|
|
|
|
|
|
NUMERIC_EVALUATOR::Token NUMERIC_EVALUATOR::getToken() |
|
|
|
{ |
|
|
|
Token retval; |
|
|
|
size_t idx; |
|
|
|
|
|
|
|
retval.token = ENDS; |
|
|
|
retval.value.dValue = 0; |
|
|
|
|
|
|
|
if (clToken.token == nullptr) return retval; |
|
|
|
if (clToken.input == nullptr) return retval; |
|
|
|
if (clToken.pos >= clToken.inputLen) return retval; |
|
|
|
|
|
|
|
auto isDecSep = [&](char ch) -> bool { |
|
|
|
if (ch == cClDecSep) return true; |
|
|
|
if (cClDecSep == ',' && ch == '.') return true; |
|
|
|
return false; |
|
|
|
}; |
|
|
|
|
|
|
|
// Lambda: get value as string, store into clToken.token and update current index.
|
|
|
|
auto extractNumber = [&]() { |
|
|
|
short sepCount = 0; |
|
|
|
idx = 0; |
|
|
|
auto ch = clToken.input[clToken.pos]; |
|
|
|
do { |
|
|
|
if (ch == isDecSep(ch) && sepCount) break; |
|
|
|
clToken.token[idx++] = ch; |
|
|
|
if (isDecSep(ch)) sepCount++; |
|
|
|
ch = clToken.input[++clToken.pos]; |
|
|
|
} while (isdigit(ch) || isDecSep(ch)); |
|
|
|
clToken.token[idx] = 0; |
|
|
|
|
|
|
|
// Ensure that the systems decimal separator is used
|
|
|
|
for (int i = strlen(clToken.token); i; i--) if (isDecSep(clToken.token[i-1])) clToken.token[i-1] = cClDecSep; |
|
|
|
}; |
|
|
|
|
|
|
|
// Lamda: Get unit for current token.
|
|
|
|
// Valid units are ", in, mm, mil and thou. Returns Unit::Invalid otherwise.
|
|
|
|
auto checkUnit = [this]() -> Unit { |
|
|
|
char ch = clToken.input[clToken.pos]; |
|
|
|
if (ch == '"') { |
|
|
|
clToken.pos++; |
|
|
|
return Unit::Inch; |
|
|
|
} |
|
|
|
// Do not use strcasecmp() as it is not available on all platforms
|
|
|
|
const char* cptr = &clToken.input[clToken.pos]; |
|
|
|
const auto sizeLeft = clToken.inputLen - clToken.pos; |
|
|
|
if (sizeLeft >= 2 && ch == 'm' && tolower(cptr[1]) == 'm' && !isalnum(cptr[2])) { |
|
|
|
clToken.pos += 2; |
|
|
|
return Unit::Metric; |
|
|
|
} |
|
|
|
if (sizeLeft >= 2 && ch == 'i' && tolower(cptr[1]) == 'n' && !isalnum(cptr[2])) { |
|
|
|
clToken.pos += 2; |
|
|
|
return Unit::Inch; |
|
|
|
} |
|
|
|
if (sizeLeft >= 3 && ch == 'm' && tolower(cptr[1]) == 'i' && tolower(cptr[2]) == 'l' && !isalnum(cptr[3])) { |
|
|
|
clToken.pos += 3; |
|
|
|
return Unit::Mil; |
|
|
|
} |
|
|
|
if (sizeLeft >= 4 && ch == 't' && tolower(cptr[1]) == 'h' && tolower(cptr[2]) == 'o' && tolower(cptr[2]) == 'u' && !isalnum(cptr[3])) { |
|
|
|
clToken.pos += 4; |
|
|
|
return Unit::Mil; |
|
|
|
} |
|
|
|
|
|
|
|
return Unit::Invalid; |
|
|
|
}; |
|
|
|
|
|
|
|
// Start processing of first/next token: Remove whitespace
|
|
|
|
char ch; |
|
|
|
for (;;) { |
|
|
|
ch = clToken.input[clToken.pos]; |
|
|
|
if (ch == ' ') { |
|
|
|
clToken.pos++; |
|
|
|
} |
|
|
|
else break; |
|
|
|
} |
|
|
|
|
|
|
|
Unit convertFrom; |
|
|
|
|
|
|
|
if (ch == 0) { |
|
|
|
/* End of input */ |
|
|
|
} |
|
|
|
else if (isdigit(ch) || isDecSep(ch)) { // VALUE
|
|
|
|
extractNumber(); |
|
|
|
retval.token = VALUE; |
|
|
|
retval.value.dValue = atof(clToken.token); |
|
|
|
} |
|
|
|
else if ((convertFrom = checkUnit()) != Unit::Invalid) { // UNIT
|
|
|
|
/* Units are appended to a VALUE.
|
|
|
|
* Determine factor to default unit if unit for value is given. |
|
|
|
* Example: Default is mm, unit is inch: factor is 25.4 |
|
|
|
* The factor is assigned to the terminal UNIT. The actual |
|
|
|
* conversion is done within a parser action. |
|
|
|
*/ |
|
|
|
retval.token = UNIT; |
|
|
|
if (eClUnitDefault == Unit::Metric) |
|
|
|
{ |
|
|
|
switch (convertFrom) { |
|
|
|
case Unit::Inch : retval.value.dValue = 25.4; break; |
|
|
|
case Unit::Mil : retval.value.dValue = 25.4/1000.0; break; |
|
|
|
case Unit::Metric : retval.value.dValue = 1.0; break; |
|
|
|
case Unit::Invalid : break; |
|
|
|
} |
|
|
|
} |
|
|
|
else if (eClUnitDefault == Unit::Inch) |
|
|
|
{ |
|
|
|
switch (convertFrom) { |
|
|
|
case Unit::Inch : retval.value.dValue = 1.0; break; |
|
|
|
case Unit::Mil : retval.value.dValue = 1.0/1000.0; break; |
|
|
|
case Unit::Metric : retval.value.dValue = 1.0/25.4; break; |
|
|
|
case Unit::Invalid : break; |
|
|
|
} |
|
|
|
} |
|
|
|
else if (eClUnitDefault == Unit::Mil) |
|
|
|
{ |
|
|
|
switch (convertFrom) |
|
|
|
{ |
|
|
|
case Unit::Inch : retval.value.dValue = 1.0*1000.0; break; |
|
|
|
case Unit::Mil : retval.value.dValue = 1.0; break; |
|
|
|
case Unit::Metric : retval.value.dValue = 1000.0/25.4; break; |
|
|
|
case Unit::Invalid : break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
else if (isalpha(ch)) { // VAR
|
|
|
|
const char* cptr = &clToken.input[clToken.pos]; |
|
|
|
cptr++; |
|
|
|
while (isalnum(*cptr)) cptr++; |
|
|
|
retval.token = VAR; |
|
|
|
size_t bytesToCopy = cptr - &clToken.input[clToken.pos]; |
|
|
|
if (bytesToCopy >= sizeof(retval.value.text)) bytesToCopy = sizeof(retval.value.text)-1; |
|
|
|
strncpy(retval.value.text, &clToken.input[clToken.pos], bytesToCopy); |
|
|
|
retval.value.text[bytesToCopy] = 0; |
|
|
|
clToken.pos += cptr - &clToken.input[clToken.pos]; |
|
|
|
} |
|
|
|
else { // Single char tokens
|
|
|
|
switch (ch) { |
|
|
|
case '+' : retval.token = PLUS; break; |
|
|
|
case '-' : retval.token = MINUS; break; |
|
|
|
case '*' : retval.token = MULT; break; |
|
|
|
case '/' : retval.token = DIVIDE; break; |
|
|
|
case '(' : retval.token = PARENL; break; |
|
|
|
case ')' : retval.token = PARENR; break; |
|
|
|
case '=' : retval.token = ASSIGN; break; |
|
|
|
case ';' : retval.token = SEMCOL; break; |
|
|
|
default: bClError = true; break; /* invalid character */ |
|
|
|
} |
|
|
|
clToken.pos++; |
|
|
|
} |
|
|
|
|
|
|
|
return retval; |
|
|
|
Token retval; |
|
|
|
size_t idx; |
|
|
|
|
|
|
|
retval.token = ENDS; |
|
|
|
retval.value.dValue = 0; |
|
|
|
|
|
|
|
if( m_token.token == nullptr ) |
|
|
|
return retval; |
|
|
|
|
|
|
|
if( m_token.input == nullptr ) |
|
|
|
return retval; |
|
|
|
|
|
|
|
if( m_token.pos >= m_token.inputLen ) |
|
|
|
return retval; |
|
|
|
|
|
|
|
auto isDecimalSeparator = [ & ]( char ch ) -> bool { |
|
|
|
return ( ch == m_localeDecimalSeparator || ch == '.' || ch == ',' ); |
|
|
|
}; |
|
|
|
|
|
|
|
// Lambda: get value as string, store into clToken.token and update current index.
|
|
|
|
auto extractNumber = [ & ]() { |
|
|
|
bool haveSeparator = false; |
|
|
|
idx = 0; |
|
|
|
auto ch = m_token.input[ m_token.pos ]; |
|
|
|
|
|
|
|
do |
|
|
|
{ |
|
|
|
if( isDecimalSeparator( ch ) && haveSeparator ) |
|
|
|
break; |
|
|
|
|
|
|
|
m_token.token[ idx++ ] = ch; |
|
|
|
|
|
|
|
if( isDecimalSeparator( ch )) |
|
|
|
haveSeparator = true; |
|
|
|
|
|
|
|
ch = m_token.input[ ++m_token.pos ]; |
|
|
|
} while( isdigit( ch ) || isDecimalSeparator( ch )); |
|
|
|
|
|
|
|
m_token.token[ idx ] = 0; |
|
|
|
|
|
|
|
// Ensure that the systems decimal separator is used
|
|
|
|
for( int i = strlen( m_token.token ); i; i-- ) |
|
|
|
if( isDecimalSeparator( m_token.token[ i - 1 ] )) |
|
|
|
m_token.token[ i - 1 ] = m_localeDecimalSeparator; |
|
|
|
}; |
|
|
|
|
|
|
|
// Lamda: Get unit for current token.
|
|
|
|
// Valid units are ", in, mm, mil and thou. Returns Unit::Invalid otherwise.
|
|
|
|
auto checkUnit = [ this ]() -> Unit { |
|
|
|
char ch = m_token.input[ m_token.pos ]; |
|
|
|
|
|
|
|
if( ch == '"' ) |
|
|
|
{ |
|
|
|
m_token.pos++; |
|
|
|
return Unit::Inch; |
|
|
|
} |
|
|
|
|
|
|
|
// Do not use strcasecmp() as it is not available on all platforms
|
|
|
|
const char* cptr = &m_token.input[ m_token.pos ]; |
|
|
|
const auto sizeLeft = m_token.inputLen - m_token.pos; |
|
|
|
|
|
|
|
if( sizeLeft >= 2 && ch == 'm' && cptr[ 1 ] == 'm' && !isalnum( cptr[ 2 ] )) |
|
|
|
{ |
|
|
|
m_token.pos += 2; |
|
|
|
return Unit::Metric; |
|
|
|
} |
|
|
|
|
|
|
|
if( sizeLeft >= 2 && ch == 'i' && cptr[ 1 ] == 'n' && !isalnum( cptr[ 2 ] )) |
|
|
|
{ |
|
|
|
m_token.pos += 2; |
|
|
|
return Unit::Inch; |
|
|
|
} |
|
|
|
|
|
|
|
if( sizeLeft >= 3 && ch == 'm' && cptr[ 1 ] == 'i' && cptr[ 2 ] == 'l' && !isalnum( cptr[ 3 ] )) |
|
|
|
{ |
|
|
|
m_token.pos += 3; |
|
|
|
return Unit::Mil; |
|
|
|
} |
|
|
|
|
|
|
|
if( sizeLeft >= 4 && ch == 't' && cptr[ 1 ] == 'h' && cptr[ 2 ] == 'o' && cptr[ 2 ] == 'u' && !isalnum( cptr[ 3 ] )) |
|
|
|
{ |
|
|
|
m_token.pos += 4; |
|
|
|
return Unit::Mil; |
|
|
|
} |
|
|
|
|
|
|
|
return Unit::Invalid; |
|
|
|
}; |
|
|
|
|
|
|
|
char ch; |
|
|
|
|
|
|
|
// Start processing of first/next token: Remove whitespace
|
|
|
|
for( ;; ) |
|
|
|
{ |
|
|
|
ch = m_token.input[ m_token.pos ]; |
|
|
|
|
|
|
|
if( ch == ' ' ) |
|
|
|
m_token.pos++; |
|
|
|
else |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
Unit convertFrom; |
|
|
|
|
|
|
|
if( ch == 0 ) |
|
|
|
{ |
|
|
|
/* End of input */ |
|
|
|
} |
|
|
|
else if( isdigit( ch ) || isDecimalSeparator( ch )) |
|
|
|
{ |
|
|
|
// VALUE
|
|
|
|
extractNumber(); |
|
|
|
retval.token = VALUE; |
|
|
|
retval.value.dValue = atof( m_token.token ); |
|
|
|
} |
|
|
|
else if(( convertFrom = checkUnit()) != Unit::Invalid ) |
|
|
|
{ |
|
|
|
// UNIT
|
|
|
|
// Units are appended to a VALUE.
|
|
|
|
// Determine factor to default unit if unit for value is given.
|
|
|
|
// Example: Default is mm, unit is inch: factor is 25.4
|
|
|
|
// The factor is assigned to the terminal UNIT. The actual
|
|
|
|
// conversion is done within a parser action.
|
|
|
|
retval.token = UNIT; |
|
|
|
if( m_defaultUnits == Unit::Metric ) |
|
|
|
{ |
|
|
|
switch( convertFrom ) |
|
|
|
{ |
|
|
|
case Unit::Inch :retval.value.dValue = 25.4; break; |
|
|
|
case Unit::Mil :retval.value.dValue = 25.4 / 1000.0; break; |
|
|
|
case Unit::Metric :retval.value.dValue = 1.0; break; |
|
|
|
case Unit::Invalid :break; |
|
|
|
} |
|
|
|
} |
|
|
|
else if( m_defaultUnits == Unit::Inch ) |
|
|
|
{ |
|
|
|
switch( convertFrom ) |
|
|
|
{ |
|
|
|
case Unit::Inch :retval.value.dValue = 1.0; break; |
|
|
|
case Unit::Mil :retval.value.dValue = 1.0 / 1000.0; break; |
|
|
|
case Unit::Metric :retval.value.dValue = 1.0 / 25.4; break; |
|
|
|
case Unit::Invalid :break; |
|
|
|
} |
|
|
|
} |
|
|
|
else if( m_defaultUnits == Unit::Mil ) |
|
|
|
{ |
|
|
|
switch( convertFrom ) |
|
|
|
{ |
|
|
|
case Unit::Inch :retval.value.dValue = 1.0 * 1000.0; break; |
|
|
|
case Unit::Mil :retval.value.dValue = 1.0; break; |
|
|
|
case Unit::Metric :retval.value.dValue = 1000.0 / 25.4; break; |
|
|
|
case Unit::Invalid :break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
else if( isalpha( ch )) |
|
|
|
{ |
|
|
|
// VAR
|
|
|
|
const char* cptr = &m_token.input[ m_token.pos ]; |
|
|
|
cptr++; |
|
|
|
|
|
|
|
while( isalnum( *cptr )) |
|
|
|
cptr++; |
|
|
|
|
|
|
|
retval.token = VAR; |
|
|
|
size_t bytesToCopy = cptr - &m_token.input[ m_token.pos ]; |
|
|
|
|
|
|
|
if( bytesToCopy >= sizeof( retval.value.text )) |
|
|
|
bytesToCopy = sizeof( retval.value.text ) - 1; |
|
|
|
|
|
|
|
strncpy( retval.value.text, &m_token.input[ m_token.pos ], bytesToCopy ); |
|
|
|
retval.value.text[ bytesToCopy ] = 0; |
|
|
|
m_token.pos += cptr - &m_token.input[ m_token.pos ]; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
// Single char tokens
|
|
|
|
switch( ch ) |
|
|
|
{ |
|
|
|
case '+' :retval.token = PLUS; break; |
|
|
|
case '-' :retval.token = MINUS; break; |
|
|
|
case '*' :retval.token = MULT; break; |
|
|
|
case '/' :retval.token = DIVIDE; break; |
|
|
|
case '(' :retval.token = PARENL; break; |
|
|
|
case ')' :retval.token = PARENR; break; |
|
|
|
case '=' :retval.token = ASSIGN; break; |
|
|
|
case ';' :retval.token = SEMCOL; break; |
|
|
|
default :m_parseError = true; break; /* invalid character */ |
|
|
|
} |
|
|
|
m_token.pos++; |
|
|
|
} |
|
|
|
|
|
|
|
return retval; |
|
|
|
} |
|
|
|
|
|
|
|
void |
|
|
|
NumericEvaluator :: setVar(const std::string& s, double value) |
|
|
|
void NUMERIC_EVALUATOR::SetVar( const wxString& aString, double aValue ) |
|
|
|
{ |
|
|
|
clVarMap[s] = value; |
|
|
|
m_varMap[ aString ] = aValue; |
|
|
|
} |
|
|
|
|
|
|
|
double |
|
|
|
NumericEvaluator :: getVar(const std::string& s) |
|
|
|
double NUMERIC_EVALUATOR::GetVar( const wxString& aString ) |
|
|
|
{ |
|
|
|
auto result = clVarMap.find(s); |
|
|
|
if (result != clVarMap.end()) return result->second; |
|
|
|
return 0.0; |
|
|
|
if( m_varMap[ aString ] ) |
|
|
|
return m_varMap[ aString ]; |
|
|
|
else |
|
|
|
return 0.0; |
|
|
|
} |