added: checking whether an user gives a correct value of a variable or function
(user-defined variables/functions in the mathematical parser) added: into the parser: logical operators: > < >= <= == != && || added: into the parser: logical functions: and() or() not() if() changed: a method for looking for a mathematical operator (there's the operators table now) added: ErrorCode::err_unknown_operator when the parser couldn't read an operator git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@23 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
parent
1a12d3692a
commit
06e0294841
10
CHANGELOG
10
CHANGELOG
|
@ -1,3 +1,13 @@
|
||||||
|
Version 0.7.2 (2007.03.09):
|
||||||
|
* added: Big::Mod - the remainder from a division
|
||||||
|
* added: Big::Sgn - the 'sign' from the value (-1,0,1)
|
||||||
|
* added: global functions Mod and Sgn too
|
||||||
|
* added: checking whether an user gives a correct value of a variable or function
|
||||||
|
(user-defined variables/functions in the mathematical parser)
|
||||||
|
* added: into the parser: logical operators: > < >= <= == != && ||
|
||||||
|
* added: into the parser: logical functions: and() or() not() if()
|
||||||
|
* added: ErrorCode::err_unknown_operator when the parser couldn't read an operator
|
||||||
|
|
||||||
Version 0.7.1 (2007.02.27):
|
Version 0.7.1 (2007.02.27):
|
||||||
* fixed the error 'overflow during printing' which was caused
|
* fixed the error 'overflow during printing' which was caused
|
||||||
by Big::FromInt(Int<int_size> value) (the sign has to be set at the end)
|
by Big::FromInt(Int<int_size> value) (the sign has to be set at the end)
|
||||||
|
|
|
@ -69,16 +69,18 @@ public:
|
||||||
|
|
||||||
ErrorCode Add(const std::string & name, const std::string & value, int param = 0)
|
ErrorCode Add(const std::string & name, const std::string & value, int param = 0)
|
||||||
{
|
{
|
||||||
Table::iterator i = table.find(name);
|
if( !CorrectCharacters(name) )
|
||||||
|
return err_incorrect_name;
|
||||||
|
|
||||||
if( i != table.end() )
|
if( AreBigLetters(name) )
|
||||||
// we have this object in our table
|
{
|
||||||
return err_object_exists;
|
std::string name_copy(name);
|
||||||
|
ToSmallLetters(name_copy);
|
||||||
|
|
||||||
|
return AddAfterChecking(name_copy, value, param);
|
||||||
table.insert( std::make_pair(name, ObjectValue(value, param)) );
|
}
|
||||||
|
else
|
||||||
return err_ok;
|
return AddAfterChecking(name, value, param);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -174,6 +176,80 @@ private:
|
||||||
|
|
||||||
Table table;
|
Table table;
|
||||||
|
|
||||||
|
|
||||||
|
bool CorrectCharacter(int c, bool digit)
|
||||||
|
{
|
||||||
|
if( (c>='a' && c<='z') || (c>='A' && c<='Z') )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if( digit && (c>='0' && c<='9') )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool CorrectCharacters(const std::string & name)
|
||||||
|
{
|
||||||
|
if( name.empty() )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if( !CorrectCharacter(name[0], false) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::string::const_iterator i=name.begin();
|
||||||
|
|
||||||
|
for(++i ; i!=name.end() ; ++i)
|
||||||
|
if( !CorrectCharacter(*i, true) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int SmallLetter(int c)
|
||||||
|
{
|
||||||
|
if( c>='A' && c<='Z' )
|
||||||
|
return c-'A'+'a';
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool AreBigLetters(const std::string & name)
|
||||||
|
{
|
||||||
|
std::string::const_iterator i;
|
||||||
|
|
||||||
|
for(i=name.begin() ; i!=name.end() ; ++i)
|
||||||
|
if( *i>='A' && *i<='Z' )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ToSmallLetters(std::string & name)
|
||||||
|
{
|
||||||
|
std::string::iterator i;
|
||||||
|
|
||||||
|
for(i=name.begin() ; i!=name.end() ; ++i)
|
||||||
|
*i = SmallLetter(*i);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ErrorCode AddAfterChecking(const std::string & name, const std::string & value, int param)
|
||||||
|
{
|
||||||
|
Table::iterator i = table.find(name);
|
||||||
|
|
||||||
|
if( i != table.end() )
|
||||||
|
// we have this object in our table
|
||||||
|
return err_object_exists;
|
||||||
|
|
||||||
|
table.insert( std::make_pair(name, ObjectValue(value, param)) );
|
||||||
|
|
||||||
|
return err_ok;
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -65,12 +65,27 @@ namespace ttmath
|
||||||
|
|
||||||
x = [+|-]Value[operator[+|-]Value][operator[+|-]Value]...
|
x = [+|-]Value[operator[+|-]Value][operator[+|-]Value]...
|
||||||
where:
|
where:
|
||||||
operator can be:
|
an operator can be:
|
||||||
+ (add)
|
^ (pow) (the highest priority)
|
||||||
- (sub)
|
|
||||||
* (mul)
|
* (mul)
|
||||||
/ (div)
|
/ (div) (* and / have the same priority)
|
||||||
^ (pow)
|
|
||||||
|
+ (add)
|
||||||
|
- (sub) (+ and - have the same priority)
|
||||||
|
|
||||||
|
< (lower than)
|
||||||
|
> (greater than)
|
||||||
|
<= (lower or equal than)
|
||||||
|
>= (greater or equal than)
|
||||||
|
== (equal)
|
||||||
|
!= (not equal) (all above logical operators have the same priority)
|
||||||
|
|
||||||
|
and (logical and)
|
||||||
|
|
||||||
|
or (logical or) (the lowest priority)
|
||||||
|
|
||||||
|
|
||||||
and Value can be:
|
and Value can be:
|
||||||
constant e.g. 100
|
constant e.g. 100
|
||||||
variable e.g. pi
|
variable e.g. pi
|
||||||
|
@ -89,6 +104,8 @@ namespace ttmath
|
||||||
"(1+2)*(2+3)"
|
"(1+2)*(2+3)"
|
||||||
"log(2;1234)" there's a semicolon here (not a comma), we use it in functions
|
"log(2;1234)" there's a semicolon here (not a comma), we use it in functions
|
||||||
for separating parameters
|
for separating parameters
|
||||||
|
"1 < 2" (the result will be: 1)
|
||||||
|
"4 < 3" (the result will be: 0)
|
||||||
etc.
|
etc.
|
||||||
|
|
||||||
we can also use a semicolon for separating any 'x' input strings
|
we can also use a semicolon for separating any 'x' input strings
|
||||||
|
@ -96,7 +113,6 @@ namespace ttmath
|
||||||
"1+2;4+5"
|
"1+2;4+5"
|
||||||
the result will be on the stack as follows:
|
the result will be on the stack as follows:
|
||||||
"3"
|
"3"
|
||||||
"semicolon operator"
|
|
||||||
"9"
|
"9"
|
||||||
*/
|
*/
|
||||||
template<class ValueType>
|
template<class ValueType>
|
||||||
|
@ -120,7 +136,7 @@ private:
|
||||||
|
|
||||||
enum Type
|
enum Type
|
||||||
{
|
{
|
||||||
none,add,sub,mul,div,pow
|
none,add,sub,mul,div,pow,lt,gt,let,get,eq,neq,lor,land
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -134,6 +150,23 @@ private:
|
||||||
|
|
||||||
switch( type )
|
switch( type )
|
||||||
{
|
{
|
||||||
|
case lor:
|
||||||
|
priority = 4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case land:
|
||||||
|
priority = 5;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case eq:
|
||||||
|
case neq:
|
||||||
|
case lt:
|
||||||
|
case gt:
|
||||||
|
case let:
|
||||||
|
case get:
|
||||||
|
priority = 7;
|
||||||
|
break;
|
||||||
|
|
||||||
case add:
|
case add:
|
||||||
case sub:
|
case sub:
|
||||||
priority = 10;
|
priority = 10;
|
||||||
|
@ -338,6 +371,17 @@ typedef std::map<std::string, pfunction> FunctionsTable;
|
||||||
FunctionsTable functions_table;
|
FunctionsTable functions_table;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
table of mathematic operators
|
||||||
|
|
||||||
|
this map consists of:
|
||||||
|
std::string - operators's name
|
||||||
|
MatOperator::Type - type of the operator
|
||||||
|
*/
|
||||||
|
typedef std::map<std::string, typename MatOperator::Type> OperatorsTable;
|
||||||
|
OperatorsTable operators_table;
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
table of mathematic variables
|
table of mathematic variables
|
||||||
|
|
||||||
|
@ -773,6 +817,66 @@ void Mod(int sindex, int amount_of_args, ValueType & result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void If(int sindex, int amount_of_args, ValueType & result)
|
||||||
|
{
|
||||||
|
if( amount_of_args != 3 )
|
||||||
|
Error( err_improper_amount_of_arguments );
|
||||||
|
|
||||||
|
|
||||||
|
if( !stack[sindex].value.IsZero() )
|
||||||
|
result = stack[sindex+2].value;
|
||||||
|
else
|
||||||
|
result = stack[sindex+4].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Or(int sindex, int amount_of_args, ValueType & result)
|
||||||
|
{
|
||||||
|
if( amount_of_args < 2 )
|
||||||
|
Error( err_improper_amount_of_arguments );
|
||||||
|
|
||||||
|
for(int i=0 ; i<amount_of_args ; ++i)
|
||||||
|
{
|
||||||
|
if( !stack[sindex+i*2].value.IsZero() )
|
||||||
|
{
|
||||||
|
result.SetOne();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.SetZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void And(int sindex, int amount_of_args, ValueType & result)
|
||||||
|
{
|
||||||
|
if( amount_of_args < 2 )
|
||||||
|
Error( err_improper_amount_of_arguments );
|
||||||
|
|
||||||
|
for(int i=0 ; i<amount_of_args ; ++i)
|
||||||
|
{
|
||||||
|
if( stack[sindex+i*2].value.IsZero() )
|
||||||
|
{
|
||||||
|
result.SetZero();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.SetOne();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Not(int sindex, int amount_of_args, ValueType & result)
|
||||||
|
{
|
||||||
|
if( amount_of_args != 1 )
|
||||||
|
Error( err_improper_amount_of_arguments );
|
||||||
|
|
||||||
|
|
||||||
|
if( stack[sindex].value.IsZero() )
|
||||||
|
result.SetOne();
|
||||||
|
else
|
||||||
|
result.SetZero();
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
this method returns the value from a user-defined function
|
this method returns the value from a user-defined function
|
||||||
|
@ -876,7 +980,7 @@ void InsertVariableToTable(const std::string & variable_name, pfunction_var pf)
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
this method create the table of functions
|
this method creates the table of functions
|
||||||
*/
|
*/
|
||||||
void CreateFunctionsTable()
|
void CreateFunctionsTable()
|
||||||
{
|
{
|
||||||
|
@ -902,6 +1006,10 @@ void CreateFunctionsTable()
|
||||||
InsertFunctionToTable(std::string("actan"), &Parser<ValueType>::ACTan);
|
InsertFunctionToTable(std::string("actan"), &Parser<ValueType>::ACTan);
|
||||||
InsertFunctionToTable(std::string("sgn"), &Parser<ValueType>::Sgn);
|
InsertFunctionToTable(std::string("sgn"), &Parser<ValueType>::Sgn);
|
||||||
InsertFunctionToTable(std::string("mod"), &Parser<ValueType>::Mod);
|
InsertFunctionToTable(std::string("mod"), &Parser<ValueType>::Mod);
|
||||||
|
InsertFunctionToTable(std::string("if"), &Parser<ValueType>::If);
|
||||||
|
InsertFunctionToTable(std::string("or"), &Parser<ValueType>::Or);
|
||||||
|
InsertFunctionToTable(std::string("and"), &Parser<ValueType>::And);
|
||||||
|
InsertFunctionToTable(std::string("not"), &Parser<ValueType>::Not);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1176,10 +1284,64 @@ return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void InsertOperatorToTable(const std::string & name, typename MatOperator::Type type)
|
||||||
|
{
|
||||||
|
operators_table.insert( std::make_pair(name, type) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
this method creates the table of operators
|
||||||
|
*/
|
||||||
|
void CreateMathematicalOperatorsTable()
|
||||||
|
{
|
||||||
|
InsertOperatorToTable(std::string("||"), MatOperator::lor);
|
||||||
|
InsertOperatorToTable(std::string("&&"), MatOperator::land);
|
||||||
|
InsertOperatorToTable(std::string("!="), MatOperator::neq);
|
||||||
|
InsertOperatorToTable(std::string("=="), MatOperator::eq);
|
||||||
|
InsertOperatorToTable(std::string(">="), MatOperator::get);
|
||||||
|
InsertOperatorToTable(std::string("<="), MatOperator::let);
|
||||||
|
InsertOperatorToTable(std::string(">"), MatOperator::gt);
|
||||||
|
InsertOperatorToTable(std::string("<"), MatOperator::lt);
|
||||||
|
InsertOperatorToTable(std::string("-"), MatOperator::sub);
|
||||||
|
InsertOperatorToTable(std::string("+"), MatOperator::add);
|
||||||
|
InsertOperatorToTable(std::string("/"), MatOperator::div);
|
||||||
|
InsertOperatorToTable(std::string("*"), MatOperator::mul);
|
||||||
|
InsertOperatorToTable(std::string("^"), MatOperator::pow);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool CanBeMathematicalOperator(unsigned char c)
|
||||||
|
{
|
||||||
|
if( c=='|' || c=='&' || c=='!' || c=='=' || c=='<' || c=='>' ||
|
||||||
|
c=='*' || c=='/' || c=='+' || c=='-' || c=='^' )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
this method's reading one of the mathematic operators
|
this method reads a mathematical (or logical) operator
|
||||||
|
*/
|
||||||
|
void ReadMathematicalOperator(Item & result)
|
||||||
|
{
|
||||||
|
std::string oper;
|
||||||
|
|
||||||
|
for( ; CanBeMathematicalOperator(*pstring) ; ++pstring )
|
||||||
|
oper += *pstring;
|
||||||
|
|
||||||
|
typename OperatorsTable::iterator iter = operators_table.find(oper);
|
||||||
|
|
||||||
|
if( iter == operators_table.end() )
|
||||||
|
Error( err_unknown_operator );
|
||||||
|
|
||||||
|
result.type = Item::mat_operator;
|
||||||
|
result.moperator.SetType( iter->second );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
this method reads a mathematic operators
|
||||||
or the final bracket or the semicolon operator
|
or the final bracket or the semicolon operator
|
||||||
|
|
||||||
return values:
|
return values:
|
||||||
|
@ -1189,46 +1351,26 @@ return 0;
|
||||||
int ReadOperator(Item & result)
|
int ReadOperator(Item & result)
|
||||||
{
|
{
|
||||||
SkipWhiteCharacters();
|
SkipWhiteCharacters();
|
||||||
result.type = Item::mat_operator;
|
|
||||||
|
|
||||||
switch( *pstring )
|
if( *pstring == 0 )
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
return 1;
|
return 1;
|
||||||
|
else
|
||||||
case '-':
|
if( *pstring == ')' )
|
||||||
result.moperator.SetType( MatOperator::sub );
|
{
|
||||||
break;
|
|
||||||
|
|
||||||
case '+':
|
|
||||||
result.moperator.SetType( MatOperator::add );
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '*':
|
|
||||||
result.moperator.SetType( MatOperator::mul );
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '/':
|
|
||||||
result.moperator.SetType( MatOperator::div );
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '^':
|
|
||||||
result.moperator.SetType( MatOperator::pow );
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ')':
|
|
||||||
result.type = Item::last_bracket;
|
result.type = Item::last_bracket;
|
||||||
break;
|
|
||||||
|
|
||||||
case ';':
|
|
||||||
result.type = Item::semicolon;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
Error( err_unknown_character );
|
|
||||||
}
|
|
||||||
|
|
||||||
++pstring;
|
++pstring;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if( *pstring == ';' )
|
||||||
|
{
|
||||||
|
result.type = Item::semicolon;
|
||||||
|
++pstring;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if( CanBeMathematicalOperator(*pstring) )
|
||||||
|
ReadMathematicalOperator(result);
|
||||||
|
else
|
||||||
|
Error( err_unknown_character );
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1246,9 +1388,40 @@ void MakeStandardMathematicOperation(ValueType & value1, typename MatOperator::T
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
|
|
||||||
switch( mat_operator )
|
switch( mat_operator )
|
||||||
{
|
{
|
||||||
|
case MatOperator::land:
|
||||||
|
(!value1.IsZero() && !value2.IsZero()) ? value1.SetOne() : value1.SetZero();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MatOperator::lor:
|
||||||
|
(!value1.IsZero() || !value2.IsZero()) ? value1.SetOne() : value1.SetZero();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MatOperator::eq:
|
||||||
|
(value1 == value2) ? value1.SetOne() : value1.SetZero();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MatOperator::neq:
|
||||||
|
(value1 != value2) ? value1.SetOne() : value1.SetZero();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MatOperator::lt:
|
||||||
|
(value1 < value2) ? value1.SetOne() : value1.SetZero();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MatOperator::gt:
|
||||||
|
(value1 > value2) ? value1.SetOne() : value1.SetZero();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MatOperator::let:
|
||||||
|
(value1 <= value2) ? value1.SetOne() : value1.SetZero();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MatOperator::get:
|
||||||
|
(value1 >= value2) ? value1.SetOne() : value1.SetZero();
|
||||||
|
break;
|
||||||
|
|
||||||
case MatOperator::sub:
|
case MatOperator::sub:
|
||||||
if( value1.Sub(value2) ) Error( err_overflow );
|
if( value1.Sub(value2) ) Error( err_overflow );
|
||||||
break;
|
break;
|
||||||
|
@ -1663,11 +1836,12 @@ Parser(): default_stack_size(100)
|
||||||
|
|
||||||
CreateFunctionsTable();
|
CreateFunctionsTable();
|
||||||
CreateVariablesTable();
|
CreateVariablesTable();
|
||||||
|
CreateMathematicalOperatorsTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
the copying operator
|
the assignment operator
|
||||||
*/
|
*/
|
||||||
Parser<ValueType> & operator=(const Parser<ValueType> & p)
|
Parser<ValueType> & operator=(const Parser<ValueType> & p)
|
||||||
{
|
{
|
||||||
|
@ -1679,11 +1853,12 @@ Parser<ValueType> & operator=(const Parser<ValueType> & p)
|
||||||
error = err_ok;
|
error = err_ok;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
we don't have to call 'CreateFunctionsTable()' and 'CreateVariablesTable()'
|
we don't have to call 'CreateFunctionsTable()' etc.
|
||||||
we can only copy these tables
|
we can only copy these tables
|
||||||
*/
|
*/
|
||||||
functions_table = p.functions_table;
|
functions_table = p.functions_table;
|
||||||
variables_table = p.variables_table;
|
variables_table = p.variables_table;
|
||||||
|
operators_table = p.operators_table;
|
||||||
|
|
||||||
visited_variables = p.visited_variables;
|
visited_variables = p.visited_variables;
|
||||||
visited_functions = p.visited_functions;
|
visited_functions = p.visited_functions;
|
||||||
|
|
|
@ -61,7 +61,7 @@
|
||||||
*/
|
*/
|
||||||
#define TTMATH_MAJOR_VER 0
|
#define TTMATH_MAJOR_VER 0
|
||||||
#define TTMATH_MINOR_VER 7
|
#define TTMATH_MINOR_VER 7
|
||||||
#define TTMATH_REVISION_VER 1
|
#define TTMATH_REVISION_VER 2
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -205,6 +205,7 @@ namespace ttmath
|
||||||
err_interrupt,
|
err_interrupt,
|
||||||
err_overflow,
|
err_overflow,
|
||||||
err_unknown_function,
|
err_unknown_function,
|
||||||
|
err_unknown_operator,
|
||||||
err_unexpected_semicolon_operator,
|
err_unexpected_semicolon_operator,
|
||||||
err_improper_amount_of_arguments,
|
err_improper_amount_of_arguments,
|
||||||
err_improper_argument,
|
err_improper_argument,
|
||||||
|
|
Loading…
Reference in New Issue