You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
333 lines
7.9 KiB
333 lines
7.9 KiB
/***************************************************************************
|
|
expression.cpp - Expression parser
|
|
-------------------
|
|
copyright : (C) 2004 Michal Rudolf <mrudolf@kdewebdwev.org>
|
|
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#include "expression.h"
|
|
|
|
#include <tdelocale.h>
|
|
|
|
Expression::Expression() : m_start(0), m_error(false)
|
|
{
|
|
}
|
|
|
|
Expression::Expression(const TQString& expr)
|
|
{
|
|
*this = expr;
|
|
}
|
|
|
|
Expression& Expression::operator=(const TQString& s)
|
|
{
|
|
m_start = 0;
|
|
m_error = false;
|
|
m_parts.clear();
|
|
const TQString single = "()<>!+-/*%";
|
|
int start = 0;
|
|
int len = s.length();
|
|
int i = 0;
|
|
while (i < len)
|
|
{
|
|
if (((s[i] == '>' || s[i] == '<' || s[i] == '=' || s[i] == '!') &&
|
|
s[i + 1] == '=') || (s[i] == '<' && s[i + 1] == '>'))
|
|
{
|
|
m_parts.append(TQVariant(s.mid(i, 2)));
|
|
i += 2;
|
|
} else if (s[i].isDigit())
|
|
{
|
|
i++;
|
|
bool decimal = false;
|
|
while (i < len && (s[i].isDigit() || (!decimal && s[i] == TQChar('.'))))
|
|
{
|
|
if (s[i] == '.')
|
|
decimal = true;
|
|
i++;
|
|
}
|
|
if (decimal)
|
|
m_parts.append(TQVariant(s.mid(start, i - start).toDouble()));
|
|
else
|
|
m_parts.append(TQVariant(s.mid(start, i - start).toInt()));
|
|
} else if (single.contains(s[i]))
|
|
m_parts.append(TQVariant(TQString(s[i++])));
|
|
else if (s[i] == '\"')
|
|
{
|
|
i++;
|
|
while (i < len && s[i] != '\"')
|
|
i++;
|
|
m_parts.append(TQVariant(s.mid(start + 1, i - start - 1)));
|
|
i++;
|
|
} else if (s[i].isSpace())
|
|
while (i < len && s[i].isSpace())
|
|
i++;
|
|
else
|
|
{
|
|
while (i < len && !s[i].isSpace())
|
|
i++;
|
|
TQString keyword = s.mid(start, i - start);
|
|
if (keyword == "true")
|
|
m_parts.append(TQVariant(true));
|
|
else if (keyword == "false")
|
|
m_parts.append(TQVariant(false));
|
|
else /* will be deprecated soon */
|
|
m_parts.append(TQVariant(keyword));
|
|
}
|
|
start = i;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
TQString Expression::next() const
|
|
{
|
|
if (m_start < m_parts.count())
|
|
return m_parts[m_start].toString();
|
|
else
|
|
return TQString();
|
|
}
|
|
|
|
bool Expression::validate()
|
|
{
|
|
if (m_start >= m_parts.count())
|
|
setError();
|
|
return !m_error;
|
|
}
|
|
Expression::Type Expression::commonType(const TQVariant v1, const TQVariant v2) const
|
|
{
|
|
if (v1.type() == TQVariant::String || v2.type() == TQVariant::String)
|
|
return TypeString;
|
|
else if (v1.type() == TQVariant::Double || v2.type() == TQVariant::Double)
|
|
return TypeDouble;
|
|
return TypeInt;
|
|
}
|
|
|
|
static int expression_compareDouble(const double A, const double B)
|
|
{
|
|
return A<B ? -1 : (A==B ? 0 : 1);
|
|
}
|
|
|
|
|
|
int Expression::compare(const TQVariant v1, const TQVariant v2) const
|
|
{
|
|
switch (commonType(v1, v2)) {
|
|
case TypeString: return v1.toString().compare(v2.toString());
|
|
case TypeDouble: return expression_compareDouble(v1.toDouble(), v2.toDouble());
|
|
case TypeInt: return v1.toInt() - v2.toInt();
|
|
default: return 0;
|
|
}
|
|
}
|
|
|
|
|
|
void Expression::setError(int pos)
|
|
{
|
|
m_errorPosition = pos == -1 ? m_start : pos;
|
|
m_error = true;
|
|
}
|
|
|
|
TQVariant Expression::parseNumber()
|
|
{
|
|
if (!validate())
|
|
return -1;
|
|
return m_parts[m_start++];
|
|
}
|
|
|
|
TQVariant Expression::parseMinus()
|
|
{
|
|
if (!validate()) return -1;
|
|
bool sign = next() == "-";
|
|
if (sign)
|
|
{
|
|
m_start++;
|
|
TQVariant value = parseNumber();
|
|
if (value.type() == TQVariant::Double)
|
|
return -value.toDouble();
|
|
else
|
|
return -value.toInt();
|
|
}
|
|
else
|
|
return parseNumber();
|
|
}
|
|
|
|
|
|
|
|
TQVariant Expression::parseBracket()
|
|
{
|
|
if (!validate()) return -1;
|
|
if (next() == "(")
|
|
{
|
|
m_start++;
|
|
TQVariant value = parse();
|
|
if (next() == ")")
|
|
m_start++;
|
|
else
|
|
setError();
|
|
return value;
|
|
}
|
|
else
|
|
return parseMinus();
|
|
}
|
|
|
|
|
|
TQVariant Expression::parseMultiply()
|
|
{
|
|
if (!validate()) return -1;
|
|
TQVariant value = parseBracket();
|
|
TQString op = next();
|
|
while (op == "*" || op == "/" || op == "%")
|
|
{
|
|
m_start++;
|
|
TQVariant value2 = parseBracket();
|
|
Type mode = commonType(value, value2);
|
|
if (op == "*")
|
|
{
|
|
if (mode == TypeDouble)
|
|
value = value.toDouble() * value2.toDouble();
|
|
else
|
|
value = value.toInt() * value2.toInt();
|
|
}
|
|
else if (op == "/")
|
|
{
|
|
if (value2.toInt() == 0)
|
|
return i18n("error");
|
|
if (mode == TypeDouble || value.toInt() != value.toInt() / value2.toInt() * value2.toInt())
|
|
value = value.toDouble() / value2.toDouble();
|
|
else
|
|
value = value.toInt() / value2.toInt();
|
|
}
|
|
else
|
|
{
|
|
if (value2.toInt() == 0)
|
|
return i18n("error");
|
|
if (mode == TypeDouble)
|
|
value = value.toDouble() / value2.toInt();
|
|
else
|
|
value = value.toInt() / value2.toInt();
|
|
}
|
|
op = next();
|
|
}
|
|
return value;
|
|
}
|
|
|
|
TQVariant Expression::parseAdd()
|
|
{
|
|
if (!validate()) return -1;
|
|
TQVariant value = parseMultiply();
|
|
TQString op = next();
|
|
while (op == "+" || op == "-")
|
|
{
|
|
m_start++;
|
|
TQVariant value2 = parseMultiply();
|
|
Type mode = commonType(value, value2);
|
|
if (op == "+")
|
|
if (mode == TypeDouble)
|
|
value = value.toDouble() + value2.toDouble();
|
|
else
|
|
value = value.toInt() + value2.toInt();
|
|
else
|
|
if (mode == TypeDouble)
|
|
value = value.toDouble() - value2.toDouble();
|
|
else
|
|
value = value.toInt() - value2.toInt();
|
|
op = next();
|
|
}
|
|
return value;
|
|
}
|
|
|
|
TQVariant Expression::parseComparison()
|
|
{
|
|
if (!validate()) return -1;
|
|
TQVariant value = parseAdd();
|
|
TQString cmp = next();
|
|
if (cmp == "<" || cmp == "<=" || cmp == "==" || cmp == ">=" || cmp == ">" || cmp == "<>" || cmp == "!=")
|
|
{
|
|
m_start++;
|
|
TQVariant value2 = parseAdd();
|
|
if (cmp == "<")
|
|
return compare(value, value2) < 0;
|
|
else if (cmp == "<=")
|
|
return compare(value, value2) <= 0;
|
|
else if (cmp == "==")
|
|
return compare(value, value2) == 0;
|
|
else if (cmp == ">=")
|
|
return compare(value, value2) >= 0;
|
|
else if (cmp == "<>" || cmp == "!=")
|
|
return compare(value, value2) != 0;
|
|
else
|
|
return compare(value, value2) > 0;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
TQVariant Expression::parseNot()
|
|
{
|
|
if (next() == "!" || next() == "not")
|
|
{
|
|
m_start++;
|
|
return !parseComparison().asBool();
|
|
}
|
|
else
|
|
return parseComparison();
|
|
}
|
|
|
|
TQVariant Expression::parseAnd()
|
|
{
|
|
if (!validate()) return -1;
|
|
TQVariant value = parseNot();
|
|
while (next() == "&&" || next() == "and")
|
|
{
|
|
m_start++;
|
|
value = parseNot().toBool() && value.toBool();
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
TQVariant Expression::parseOr()
|
|
{
|
|
if (!validate()) return -1;
|
|
TQVariant value = parseAnd();
|
|
while (next() == "||" || next() == "or")
|
|
{
|
|
m_start++;
|
|
value = parseAnd().toBool() || value.toBool();
|
|
}
|
|
return value;
|
|
}
|
|
|
|
TQVariant Expression::parse()
|
|
{
|
|
return parseOr();
|
|
}
|
|
|
|
TQVariant Expression::value(bool* valid)
|
|
{
|
|
m_start = 0;
|
|
m_error = false;
|
|
TQVariant val = parse();
|
|
if (valid)
|
|
*valid = !m_error && m_start == m_parts.count();
|
|
return val;
|
|
}
|
|
|
|
TQVariant Expression::value(const TQString& s, bool* valid)
|
|
{
|
|
*this = s;
|
|
return value(valid);
|
|
}
|
|
|
|
bool Expression::isTrue(const TQString& s, bool* valid)
|
|
{
|
|
TQVariant v = value(s, valid);
|
|
return (v.type() == TQVariant::String && !v.toString().isNull()) ||
|
|
(v.type() != TQVariant::String && v.toInt() != 0);
|
|
}
|
|
|