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'
| ε
Term Factor Term'
Term' '&&' Term'
Term Unary Term'
Term' '&&' Unary Term'
| ε
Unary '!' Unary
| Factor
Factor INT
| BOOL
| 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) {
if (!parseFactor(str, iter)) {
if (!parseUnary(str, iter)) {
return false;
}
if (!parseTermPrime(str, iter)) {
@ -260,11 +262,11 @@ bool AnimExpression::parseTerm(const QString& str, QString::const_iterator& iter
return true;
}
// Term' → '&&' Term' | ε
// Term' → '&&' Unary Term' | ε
bool AnimExpression::parseTermPrime(const QString& str, QString::const_iterator& iter) {
auto token = consumeToken(str, iter);
if (token.type == Token::And) {
if (!parseTerm(str, iter)) {
if (!parseUnary(str, iter)) {
unconsumeToken(token);
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 ')'
bool AnimExpression::parseFactor(const QString& str, QString::const_iterator& iter) {
auto token = consumeToken(str, iter);

View file

@ -119,6 +119,7 @@ protected:
bool parseExprPrime(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 parseUnary(const QString& str, QString::const_iterator& iter);
bool parseFactor(const QString& str, QString::const_iterator& iter);
OpCode evaluate(const AnimVariantMap& map) const;

View file

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