Allow the digit group separator, "_", in expressions.

pull/106/head
whitequark 2017-01-02 23:34:36 +00:00
parent daf3c7b070
commit 02ab358bd9
3 changed files with 32 additions and 12 deletions

View File

@ -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.

View File

@ -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 == '+') {

View File

@ -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",