Expressions: Simpified parser, fixed precedence (parentheses)

This commit is contained in:
Eivind Kvedalen 2016-03-26 22:55:10 +01:00 committed by wmayer
parent 909727ade8
commit c506881614
4 changed files with 442 additions and 412 deletions

View File

@ -452,19 +452,33 @@ Expression *OperatorExpression::simplify() const
std::string OperatorExpression::toString() const
{
std::stringstream s;
bool needsParens;
Operator leftOperator(NONE), rightOperator(NONE);
switch (op) {
case NEG:
s << "-";
break;
s << "-" << left->toString();
return s.str();
case POS:
s << "+";
break;
s << "+" << left->toString();
return s.str();
default:
break;
}
if (left->priority() < priority())
needsParens = false;
if (freecad_dynamic_cast<OperatorExpression>(left))
leftOperator = static_cast<OperatorExpression*>(left)->op;
if (left->priority() < priority()) // Check on operator priority first
needsParens = true;
else if (leftOperator == op) { // Equal priority?
if (!isLeftAssociative())
needsParens = true;
//else if (!isCommutative())
// needsParens = true;
}
if (needsParens)
s << "(" << left->toString() << ")";
else
s << left->toString();
@ -505,14 +519,23 @@ std::string OperatorExpression::toString() const
break;
case UNIT:
break;
case POS:
case NEG:
return s.str();
default:
assert(0);
}
if (right->priority() < priority())
needsParens = false;
if (freecad_dynamic_cast<OperatorExpression>(right))
rightOperator = static_cast<OperatorExpression*>(right)->op;
if (right->priority() < priority()) // Check on operator priority first
needsParens = true;
else if (rightOperator == op) { // Equal priority?
if (!isRightAssociative())
needsParens = true;
else if (!isCommutative())
needsParens = true;
}
if (needsParens)
s << "(" << right->toString() << ")";
else
s << right->toString();
@ -585,6 +608,35 @@ void OperatorExpression::visit(ExpressionVisitor &v)
v.visit(this);
}
bool OperatorExpression::isCommutative() const
{
switch (op) {
case EQ:
case NEQ:
case ADD:
case MUL:
return true;
default:
return false;
}
}
bool OperatorExpression::isLeftAssociative() const
{
return true;
}
bool OperatorExpression::isRightAssociative() const
{
switch (op) {
case ADD:
case MUL:
return true;
default:
return false;
}
}
//
// FunctionExpression class. This class handles functions with one or two parameters.
//

View File

@ -253,6 +253,13 @@ public:
Expression * getRight() const { return right; }
protected:
virtual bool isCommutative() const;
virtual bool isLeftAssociative() const;
virtual bool isRightAssociative() const;
Operator op; /**< Operator working on left and right */
Expression * left; /**< Left operand */
Expression * right; /**< Right operand */

File diff suppressed because it is too large Load Diff

View File

@ -38,7 +38,6 @@ std::stack<FunctionExpression::Function> functions; /**< Function
%type <fvalue> NUM
%type <constant> CONSTANT
%type <expr> num
%type <expr> basic_num
%type <expr> range
%type <path> identifier
%type <components> path subpath
@ -46,18 +45,16 @@ std::stack<FunctionExpression::Function> functions; /**< Function
%type <string_or_identifier> document
%type <string_or_identifier> object
%type <ivalue> integer
%left ONE
%left NUM
%left INTEGER
%left CONSTANT
%left ONE NUM INTEGER CONSTANT
%left EQ NEQ LT GT GTE LTE
%left '?' ':'
%left MINUSSIGN '+'
%left '*' '/'
%precedence NUM_AND_UNIT
%left '^' /* exponentiation */
%left EXPONENT
%left NEG /* negation--unary minus */
%left POS /* unary plus */
%right '^' /* exponentiation */
%right EXPONENT
%destructor { delete $$; } exp cond unit_exp
%destructor { std::vector<Expression*>::const_iterator i = $$.begin(); while (i != $$.end()) { delete *i; ++i; } } args
@ -71,6 +68,7 @@ input: exp { ScanResult = $1; valueExpression = true;
;
exp: num { $$ = $1; }
| num unit_exp %prec NUM_AND_UNIT { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::UNIT, $2); }
| STRING { $$ = new StringExpression(DocumentObject, $1); }
| identifier { $$ = new VariableExpression(DocumentObject, $1); }
| MINUSSIGN exp %prec NEG { $$ = new OperatorExpression(DocumentObject, $2, OperatorExpression::NEG, new NumberExpression(DocumentObject, -1)); }
@ -80,22 +78,16 @@ exp: num { $$ = $1;
| exp '*' exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::MUL, $3); }
| exp '/' exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::DIV, $3); }
| exp '/' unit_exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::DIV, $3); }
| exp '^' exp %prec EXPONENT { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::POW, $3); }
| exp '^' exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::POW, $3); }
| '(' exp ')' { $$ = $2; }
| FUNC args ')' { $$ = new FunctionExpression(DocumentObject, $1, $2); }
| cond '?' exp ':' exp { $$ = new ConditionalExpression(DocumentObject, $1, $3, $5); }
;
basic_num: ONE { $$ = new NumberExpression(DocumentObject, $1); }
| NUM { $$ = new NumberExpression(DocumentObject, $1); }
| INTEGER { $$ = new NumberExpression(DocumentObject, (double)$1); }
;
num: basic_num { $$ = $1; }
| CONSTANT { $$ = new ConstantExpression(DocumentObject, $1.name, $1.fvalue); }
| basic_num unit_exp %prec EXPONENT { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::UNIT, $2); }
| CONSTANT unit_exp { $$ = new OperatorExpression(DocumentObject, new ConstantExpression(DocumentObject, $1.name, $1.fvalue), OperatorExpression::UNIT, $2); }
;
num: ONE { $$ = new NumberExpression(DocumentObject, $1); }
| NUM { $$ = new NumberExpression(DocumentObject, $1); }
| INTEGER { $$ = new NumberExpression(DocumentObject, (double)$1); }
| CONSTANT { $$ = new ConstantExpression(DocumentObject, $1.name, $1.fvalue); }
args: exp { $$.push_back($1); }
| range { $$.push_back($1); }
@ -119,13 +111,12 @@ cond: exp EQ exp { $$ = new OperatorExpression(Do
| exp LTE exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::LTE, $3); }
;
unit_exp: UNIT { $$ = new UnitExpression(DocumentObject, $1.scaler, $1.unitStr ); }
| ONE '/' unit_exp { $$ = new OperatorExpression(DocumentObject, new NumberExpression(DocumentObject, $1), OperatorExpression::DIV, $3); }
| unit_exp '/' unit_exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::DIV, $3); }
| unit_exp '*' unit_exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::MUL, $3); }
| unit_exp '^' basic_num %prec EXPONENT { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::POW, $3); }
| unit_exp '^' MINUSSIGN basic_num %prec EXPONENT { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::POW, new OperatorExpression(DocumentObject, $4, OperatorExpression::NEG, new NumberExpression(DocumentObject, -1))); }
| '(' unit_exp ')' { $$ = $2; }
unit_exp: UNIT { $$ = new UnitExpression(DocumentObject, $1.scaler, $1.unitStr ); }
| unit_exp '/' unit_exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::DIV, $3); }
| unit_exp '*' unit_exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::MUL, $3); }
| unit_exp '^' integer { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::POW, new NumberExpression(DocumentObject, (double)$3)); }
| unit_exp '^' MINUSSIGN integer { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::POW, new OperatorExpression(DocumentObject, new NumberExpression(DocumentObject, (double)$4), OperatorExpression::NEG, new NumberExpression(DocumentObject, -1))); }
| '(' unit_exp ')' { $$ = $2; }
;
identifier: path { /* Path to property within document object */