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