From 06e029484199cc9cc4053884d334148417e40488 Mon Sep 17 00:00:00 2001 From: Tomasz Sowa Date: Fri, 9 Mar 2007 19:05:38 +0000 Subject: [PATCH] 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 --- CHANGELOG | 10 ++ ttmath/ttmathobjects.h | 94 ++++++++++++-- ttmath/ttmathparser.h | 271 +++++++++++++++++++++++++++++++++-------- ttmath/ttmathtypes.h | 3 +- 4 files changed, 320 insertions(+), 58 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 37b70e5..b00da9f 100644 --- a/CHANGELOG +++ b/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): * fixed the error 'overflow during printing' which was caused by Big::FromInt(Int value) (the sign has to be set at the end) diff --git a/ttmath/ttmathobjects.h b/ttmath/ttmathobjects.h index a2cb7aa..4dc0b7b 100644 --- a/ttmath/ttmathobjects.h +++ b/ttmath/ttmathobjects.h @@ -69,16 +69,18 @@ public: 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() ) - // we have this object in our table - return err_object_exists; - + if( AreBigLetters(name) ) + { + std::string name_copy(name); + ToSmallLetters(name_copy); - table.insert( std::make_pair(name, ObjectValue(value, param)) ); - - return err_ok; + return AddAfterChecking(name_copy, value, param); + } + else + return AddAfterChecking(name, value, param); } @@ -110,7 +112,7 @@ public: // we don't have this variable in our table return err_unknown_object; - i->second.value = value; + i->second.value = value; i->second.param = param; return err_ok; @@ -174,6 +176,80 @@ private: 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 diff --git a/ttmath/ttmathparser.h b/ttmath/ttmathparser.h index 362b66d..2a60f09 100644 --- a/ttmath/ttmathparser.h +++ b/ttmath/ttmathparser.h @@ -65,12 +65,27 @@ namespace ttmath x = [+|-]Value[operator[+|-]Value][operator[+|-]Value]... where: - operator can be: + an operator can be: + ^ (pow) (the highest priority) + + * (mul) + / (div) (* and / have the same priority) + + (add) - - (sub) - * (mul) - / (div) - ^ (pow) + - (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: constant e.g. 100 variable e.g. pi @@ -89,6 +104,8 @@ namespace ttmath "(1+2)*(2+3)" "log(2;1234)" there's a semicolon here (not a comma), we use it in functions for separating parameters + "1 < 2" (the result will be: 1) + "4 < 3" (the result will be: 0) etc. we can also use a semicolon for separating any 'x' input strings @@ -96,7 +113,6 @@ namespace ttmath "1+2;4+5" the result will be on the stack as follows: "3" - "semicolon operator" "9" */ template @@ -120,7 +136,7 @@ private: 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 ) { + 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 sub: priority = 10; @@ -338,6 +371,17 @@ typedef std::map FunctionsTable; 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 OperatorsTable; +OperatorsTable operators_table; + + /*! 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::ACTan); InsertFunctionToTable(std::string("sgn"), &Parser::Sgn); InsertFunctionToTable(std::string("mod"), &Parser::Mod); + InsertFunctionToTable(std::string("if"), &Parser::If); + InsertFunctionToTable(std::string("or"), &Parser::Or); + InsertFunctionToTable(std::string("and"), &Parser::And); + InsertFunctionToTable(std::string("not"), &Parser::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 return values: @@ -1189,46 +1351,26 @@ return 0; int ReadOperator(Item & result) { SkipWhiteCharacters(); - result.type = Item::mat_operator; - - switch( *pstring ) - { - case 0: - return 1; - - case '-': - 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 ')': + if( *pstring == 0 ) + return 1; + else + if( *pstring == ')' ) + { result.type = Item::last_bracket; - break; - - case ';': + ++pstring; + } + else + if( *pstring == ';' ) + { result.type = Item::semicolon; - break; - - default: + ++pstring; + } + else + if( CanBeMathematicalOperator(*pstring) ) + ReadMathematicalOperator(result); + else Error( err_unknown_character ); - } - - ++pstring; return 0; } @@ -1246,9 +1388,40 @@ void MakeStandardMathematicOperation(ValueType & value1, typename MatOperator::T { int res; - 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: if( value1.Sub(value2) ) Error( err_overflow ); break; @@ -1663,11 +1836,12 @@ Parser(): default_stack_size(100) CreateFunctionsTable(); CreateVariablesTable(); + CreateMathematicalOperatorsTable(); } /*! - the copying operator + the assignment operator */ Parser & operator=(const Parser & p) { @@ -1679,11 +1853,12 @@ Parser & operator=(const Parser & p) 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 */ functions_table = p.functions_table; variables_table = p.variables_table; + operators_table = p.operators_table; visited_variables = p.visited_variables; visited_functions = p.visited_functions; diff --git a/ttmath/ttmathtypes.h b/ttmath/ttmathtypes.h index aea5774..bdfceb4 100644 --- a/ttmath/ttmathtypes.h +++ b/ttmath/ttmathtypes.h @@ -61,7 +61,7 @@ */ #define TTMATH_MAJOR_VER 0 #define TTMATH_MINOR_VER 7 -#define TTMATH_REVISION_VER 1 +#define TTMATH_REVISION_VER 2 /*! @@ -205,6 +205,7 @@ namespace ttmath err_interrupt, err_overflow, err_unknown_function, + err_unknown_operator, err_unexpected_semicolon_operator, err_improper_amount_of_arguments, err_improper_argument,