Allow the digit group separator, "_", in expressions.
parent
daf3c7b070
commit
02ab358bd9
|
@ -43,6 +43,7 @@ Other new features:
|
|||
* When zooming to fit, constraints are also considered.
|
||||
* When selecting a point and a line, projected distance to to current
|
||||
workplane is displayed.
|
||||
* In expressions, numbers can contain the digit group separator, "_".
|
||||
* The "=" key is bound to "Zoom In", like "+" key.
|
||||
* The numpad decimal separator key is bound to "." regardless of locale.
|
||||
|
||||
|
|
39
src/expr.cpp
39
src/expr.cpp
|
@ -612,7 +612,6 @@ public:
|
|||
char ReadChar();
|
||||
char PeekChar();
|
||||
|
||||
double ReadNumber();
|
||||
std::string ReadWord();
|
||||
void SkipSpace();
|
||||
|
||||
|
@ -620,6 +619,7 @@ public:
|
|||
Token PopOperand(std::string *error);
|
||||
|
||||
int Precedence(Token token);
|
||||
Token LexNumber(std::string *error);
|
||||
Token Lex(std::string *error);
|
||||
bool Reduce(std::string *error);
|
||||
bool Parse(std::string *error, size_t reduceUntil = 0);
|
||||
|
@ -650,14 +650,6 @@ char ExprParser::PeekChar() {
|
|||
return input[inputPos];
|
||||
}
|
||||
|
||||
double ExprParser::ReadNumber() {
|
||||
char *endptr;
|
||||
double d = strtod(input + inputPos, &endptr);
|
||||
unsigned len = endptr - (input + inputPos);
|
||||
inputPos += len;
|
||||
return d;
|
||||
}
|
||||
|
||||
std::string ExprParser::ReadWord() {
|
||||
std::string s;
|
||||
|
||||
|
@ -676,6 +668,31 @@ void ExprParser::SkipSpace() {
|
|||
}
|
||||
}
|
||||
|
||||
ExprParser::Token ExprParser::LexNumber(std::string *error) {
|
||||
std::string s;
|
||||
|
||||
while(char c = PeekChar()) {
|
||||
if(!((c >= '0' && c <= '9') || c == 'e' || c == 'E' || c == '.' || c == '_')) break;
|
||||
if(c == '_') {
|
||||
ReadChar();
|
||||
continue;
|
||||
}
|
||||
s.push_back(ReadChar());
|
||||
}
|
||||
|
||||
char *endptr;
|
||||
double d = strtod(s.c_str(), &endptr);
|
||||
|
||||
Token t = Token::From();
|
||||
if(endptr == &*s.end()) {
|
||||
t = Token::From(TokenType::OPERAND, Expr::Op::CONSTANT);
|
||||
t.expr->v = d;
|
||||
} else {
|
||||
*error = "'" + s + "' is not a valid number";
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
ExprParser::Token ExprParser::Lex(std::string *error) {
|
||||
SkipSpace();
|
||||
|
||||
|
@ -705,9 +722,7 @@ ExprParser::Token ExprParser::Lex(std::string *error) {
|
|||
*error = "'" + s + "' is not a valid variable, function or constant";
|
||||
}
|
||||
} else if(isdigit(c) || c == '.') {
|
||||
double d = ReadNumber();
|
||||
t = Token::From(TokenType::OPERAND, Expr::Op::CONSTANT);
|
||||
t.expr->v = d;
|
||||
return LexNumber(error);
|
||||
} else if(ispunct(c)) {
|
||||
ReadChar();
|
||||
if(c == '+') {
|
||||
|
|
|
@ -26,6 +26,8 @@ TEST_CASE(literal) {
|
|||
CHECK_TRUE(e->Eval() == 42);
|
||||
CHECK_PARSE(e, "42.5");
|
||||
CHECK_TRUE(e->Eval() == 42.5);
|
||||
CHECK_PARSE(e, "1_000_000");
|
||||
CHECK_TRUE(e->Eval() == 1000000);
|
||||
}
|
||||
|
||||
TEST_CASE(unary_ops) {
|
||||
|
@ -95,6 +97,8 @@ TEST_CASE(errors) {
|
|||
"Unexpected character");
|
||||
CHECK_PARSE_ERR("notavar",
|
||||
"'notavar' is not a valid variable, function or constant");
|
||||
CHECK_PARSE_ERR("1e2e3",
|
||||
"'1e2e3' is not a valid number");
|
||||
CHECK_PARSE_ERR("_",
|
||||
"'_' is not a valid operator");
|
||||
CHECK_PARSE_ERR("2 2",
|
||||
|
|
Loading…
Reference in New Issue