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::string OperatorExpression::toString() const
{ {
std::stringstream s; std::stringstream s;
bool needsParens;
Operator leftOperator(NONE), rightOperator(NONE);
switch (op) { switch (op) {
case NEG: case NEG:
s << "-"; s << "-" << left->toString();
break; return s.str();
case POS: case POS:
s << "+"; s << "+" << left->toString();
break; return s.str();
default: default:
break; 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() << ")"; s << "(" << left->toString() << ")";
else else
s << left->toString(); s << left->toString();
@ -505,14 +519,23 @@ std::string OperatorExpression::toString() const
break; break;
case UNIT: case UNIT:
break; break;
case POS:
case NEG:
return s.str();
default: default:
assert(0); 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() << ")"; s << "(" << right->toString() << ")";
else else
s << right->toString(); s << right->toString();
@ -585,6 +608,35 @@ void OperatorExpression::visit(ExpressionVisitor &v)
v.visit(this); 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. // FunctionExpression class. This class handles functions with one or two parameters.
// //

View File

@ -253,6 +253,13 @@ public:
Expression * getRight() const { return right; } Expression * getRight() const { return right; }
protected: protected:
virtual bool isCommutative() const;
virtual bool isLeftAssociative() const;
virtual bool isRightAssociative() const;
Operator op; /**< Operator working on left and right */ Operator op; /**< Operator working on left and right */
Expression * left; /**< Left operand */ Expression * left; /**< Left operand */
Expression * right; /**< Right 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 <fvalue> NUM
%type <constant> CONSTANT %type <constant> CONSTANT
%type <expr> num %type <expr> num
%type <expr> basic_num
%type <expr> range %type <expr> range
%type <path> identifier %type <path> identifier
%type <components> path subpath %type <components> path subpath
@ -46,18 +45,16 @@ std::stack<FunctionExpression::Function> functions; /**< Function
%type <string_or_identifier> document %type <string_or_identifier> document
%type <string_or_identifier> object %type <string_or_identifier> object
%type <ivalue> integer %type <ivalue> integer
%left ONE %left ONE NUM INTEGER CONSTANT
%left NUM
%left INTEGER
%left CONSTANT
%left EQ NEQ LT GT GTE LTE %left EQ NEQ LT GT GTE LTE
%left '?' ':' %left '?' ':'
%left MINUSSIGN '+' %left MINUSSIGN '+'
%left '*' '/' %left '*' '/'
%precedence NUM_AND_UNIT
%left '^' /* exponentiation */
%left EXPONENT
%left NEG /* negation--unary minus */ %left NEG /* negation--unary minus */
%left POS /* unary plus */ %left POS /* unary plus */
%right '^' /* exponentiation */
%right EXPONENT
%destructor { delete $$; } exp cond unit_exp %destructor { delete $$; } exp cond unit_exp
%destructor { std::vector<Expression*>::const_iterator i = $$.begin(); while (i != $$.end()) { delete *i; ++i; } } args %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; } exp: num { $$ = $1; }
| num unit_exp %prec NUM_AND_UNIT { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::UNIT, $2); }
| STRING { $$ = new StringExpression(DocumentObject, $1); } | STRING { $$ = new StringExpression(DocumentObject, $1); }
| identifier { $$ = new VariableExpression(DocumentObject, $1); } | identifier { $$ = new VariableExpression(DocumentObject, $1); }
| MINUSSIGN exp %prec NEG { $$ = new OperatorExpression(DocumentObject, $2, OperatorExpression::NEG, new NumberExpression(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::MUL, $3); }
| exp '/' exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::DIV, $3); } | exp '/' exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::DIV, $3); }
| exp '/' unit_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; } | '(' exp ')' { $$ = $2; }
| FUNC args ')' { $$ = new FunctionExpression(DocumentObject, $1, $2); } | FUNC args ')' { $$ = new FunctionExpression(DocumentObject, $1, $2); }
| cond '?' exp ':' exp { $$ = new ConditionalExpression(DocumentObject, $1, $3, $5); } | cond '?' exp ':' exp { $$ = new ConditionalExpression(DocumentObject, $1, $3, $5); }
; ;
basic_num: ONE { $$ = new NumberExpression(DocumentObject, $1); } num: ONE { $$ = new NumberExpression(DocumentObject, $1); }
| NUM { $$ = new NumberExpression(DocumentObject, $1); } | NUM { $$ = new NumberExpression(DocumentObject, $1); }
| INTEGER { $$ = new NumberExpression(DocumentObject, (double)$1); } | INTEGER { $$ = new NumberExpression(DocumentObject, (double)$1); }
; | CONSTANT { $$ = new ConstantExpression(DocumentObject, $1.name, $1.fvalue); }
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); }
;
args: exp { $$.push_back($1); } args: exp { $$.push_back($1); }
| range { $$.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); } | exp LTE exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::LTE, $3); }
; ;
unit_exp: UNIT { $$ = new UnitExpression(DocumentObject, $1.scaler, $1.unitStr ); } 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::DIV, $3); } | unit_exp '*' unit_exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::MUL, $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 '^' basic_num %prec EXPONENT { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::POW, $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 '^' 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 ')' { $$ = $2; }
; ;
identifier: path { /* Path to property within document object */ identifier: path { /* Path to property within document object */