AnimExpression: support for unary not.

This commit is contained in:
Anthony J. Thibault 2015-12-15 13:18:30 -08:00
parent 22756d168b
commit ab85e2967a
3 changed files with 53 additions and 57 deletions

View file

@ -208,9 +208,11 @@ AnimExpression::Token AnimExpression::consumeNot(const QString& str, QString::co
Expr Term Expr' Expr Term Expr'
Expr' '||' Term Expr' Expr' '||' Term Expr'
| ε | ε
Term Factor Term' Term Unary Term'
Term' '&&' Term' Term' '&&' Unary Term'
| ε | ε
Unary '!' Unary
| Factor
Factor INT Factor INT
| BOOL | BOOL
| FLOAT | FLOAT
@ -249,9 +251,9 @@ bool AnimExpression::parseExprPrime(const QString& str, QString::const_iterator&
} }
} }
// Term → Factor Term' // Term → Unary Term'
bool AnimExpression::parseTerm(const QString& str, QString::const_iterator& iter) { bool AnimExpression::parseTerm(const QString& str, QString::const_iterator& iter) {
if (!parseFactor(str, iter)) { if (!parseUnary(str, iter)) {
return false; return false;
} }
if (!parseTermPrime(str, iter)) { if (!parseTermPrime(str, iter)) {
@ -260,11 +262,11 @@ bool AnimExpression::parseTerm(const QString& str, QString::const_iterator& iter
return true; return true;
} }
// Term' → '&&' Term' | ε // Term' → '&&' Unary Term' | ε
bool AnimExpression::parseTermPrime(const QString& str, QString::const_iterator& iter) { bool AnimExpression::parseTermPrime(const QString& str, QString::const_iterator& iter) {
auto token = consumeToken(str, iter); auto token = consumeToken(str, iter);
if (token.type == Token::And) { if (token.type == Token::And) {
if (!parseTerm(str, iter)) { if (!parseUnary(str, iter)) {
unconsumeToken(token); unconsumeToken(token);
return false; return false;
} }
@ -280,6 +282,24 @@ bool AnimExpression::parseTermPrime(const QString& str, QString::const_iterator&
} }
} }
// Unary → '!' Unary | Factor
bool AnimExpression::parseUnary(const QString& str, QString::const_iterator& iter) {
auto token = consumeToken(str, iter);
if (token.type == Token::Not) {
if (!parseUnary(str, iter)) {
unconsumeToken(token);
return false;
}
_opCodes.push_back(OpCode {OpCode::Not});
return true;
}
unconsumeToken(token);
return parseFactor(str, iter);
}
// Factor → INT | BOOL | FLOAT | IDENTIFIER | '(' Expr ')' // Factor → INT | BOOL | FLOAT | IDENTIFIER | '(' Expr ')'
bool AnimExpression::parseFactor(const QString& str, QString::const_iterator& iter) { bool AnimExpression::parseFactor(const QString& str, QString::const_iterator& iter) {
auto token = consumeToken(str, iter); auto token = consumeToken(str, iter);

View file

@ -119,6 +119,7 @@ protected:
bool parseExprPrime(const QString& str, QString::const_iterator& iter); bool parseExprPrime(const QString& str, QString::const_iterator& iter);
bool parseTerm(const QString& str, QString::const_iterator& iter); bool parseTerm(const QString& str, QString::const_iterator& iter);
bool parseTermPrime(const QString& str, QString::const_iterator& iter); bool parseTermPrime(const QString& str, QString::const_iterator& iter);
bool parseUnary(const QString& str, QString::const_iterator& iter);
bool parseFactor(const QString& str, QString::const_iterator& iter); bool parseFactor(const QString& str, QString::const_iterator& iter);
OpCode evaluate(const AnimVariantMap& map) const; OpCode evaluate(const AnimVariantMap& map) const;

View file

@ -522,43 +522,19 @@ void AnimTests::testExpressionParser() {
QVERIFY(e._opCodes[4].type == AnimExpression::OpCode::And); QVERIFY(e._opCodes[4].type == AnimExpression::OpCode::And);
} }
/* e = AnimExpression("!(true || false) && true");
e = AnimExpression("2 + 3"); QVERIFY(e._opCodes.size() == 6);
QVERIFY(e._opCodes.size() == 3); if (e._opCodes.size() == 6) {
if (e._opCodes.size() == 3) { QVERIFY(e._opCodes[0].type == AnimExpression::OpCode::Bool);
QVERIFY(e._opCodes[0].type == AnimExpression::OpCode::Int); QVERIFY(e._opCodes[0].intVal == (int)true);
QVERIFY(e._opCodes[0].intVal == 2); QVERIFY(e._opCodes[1].type == AnimExpression::OpCode::Bool);
QVERIFY(e._opCodes[1].type == AnimExpression::OpCode::Int); QVERIFY(e._opCodes[1].intVal == (int)false);
QVERIFY(e._opCodes[1].intVal == 3); QVERIFY(e._opCodes[2].type == AnimExpression::OpCode::Or);
QVERIFY(e._opCodes[2].type == AnimExpression::OpCode::Add); QVERIFY(e._opCodes[3].type == AnimExpression::OpCode::Not);
QVERIFY(e._opCodes[4].type == AnimExpression::OpCode::Bool);
QVERIFY(e._opCodes[4].intVal == (int)true);
QVERIFY(e._opCodes[5].type == AnimExpression::OpCode::And);
} }
e = AnimExpression("2 + 3 * 10");
QVERIFY(e._opCodes.size() == 5);
if (e._opCodes.size() == 5) {
QVERIFY(e._opCodes[0].type == AnimExpression::OpCode::Int);
QVERIFY(e._opCodes[0].intVal == 2);
QVERIFY(e._opCodes[1].type == AnimExpression::OpCode::Int);
QVERIFY(e._opCodes[1].intVal == 3);
QVERIFY(e._opCodes[2].type == AnimExpression::OpCode::Int);
QVERIFY(e._opCodes[2].intVal == 10);
QVERIFY(e._opCodes[3].type == AnimExpression::OpCode::Multiply);
QVERIFY(e._opCodes[4].type == AnimExpression::OpCode::Add);
}
e = AnimExpression("(2 + 3) * 10");
QVERIFY(e._opCodes.size() == 5);
if (e._opCodes.size() == 5) {
QVERIFY(e._opCodes[0].type == AnimExpression::OpCode::Int);
QVERIFY(e._opCodes[0].intVal == 2);
QVERIFY(e._opCodes[1].type == AnimExpression::OpCode::Int);
QVERIFY(e._opCodes[1].intVal == 3);
QVERIFY(e._opCodes[2].type == AnimExpression::OpCode::Add);
QVERIFY(e._opCodes[3].type == AnimExpression::OpCode::Int);
QVERIFY(e._opCodes[3].intVal == 10);
QVERIFY(e._opCodes[4].type == AnimExpression::OpCode::Multiply);
}
*/
} }
#define TEST_BOOL_EXPR(EXPR) \ #define TEST_BOOL_EXPR(EXPR) \
@ -630,23 +606,22 @@ void AnimTests::testExpressionEvaluator() {
TEST_BOOL_EXPR(f || false); TEST_BOOL_EXPR(f || false);
TEST_BOOL_EXPR(f || true); TEST_BOOL_EXPR(f || true);
/* TEST_BOOL_EXPR(!true);
result = AnimExpression("(2 + 3) * (5 + 3)").evaluate(vars); TEST_BOOL_EXPR(!false);
QVERIFY(result.type == AnimExpression::OpCode::Int); TEST_BOOL_EXPR(!true || true);
QVERIFY(result.intVal == (2 + 3) * (5 + 3));
result = AnimExpression("(ten + twenty) * 5").evaluate(vars); TEST_BOOL_EXPR(!true && !false || !true);
QVERIFY(result.type == AnimExpression::OpCode::Int); TEST_BOOL_EXPR(!true && !false || true);
QVERIFY(result.intVal == (10 + 20) * 5); TEST_BOOL_EXPR(!true && false || !true);
TEST_BOOL_EXPR(!true && false || true);
TEST_BOOL_EXPR(true && !false || !true);
TEST_BOOL_EXPR(true && !false || true);
TEST_BOOL_EXPR(true && false || !true);
TEST_BOOL_EXPR(true && false || true);
result = AnimExpression("(ten + twenty) * 5.0").evaluate(vars); TEST_BOOL_EXPR(!(true && f) || !t);
QVERIFY(result.type == AnimExpression::OpCode::Float); TEST_BOOL_EXPR(!!!(t) && (!!f || true));
QVERIFY(result.floatVal == (10 + 20) * 5.0f); TEST_BOOL_EXPR(!(true && f) && true);
result = AnimExpression("five * forty").evaluate(vars);
QVERIFY(result.type == AnimExpression::OpCode::Float);
QVERIFY(result.floatVal == 5.0f * 40.0f);
*/
} }