diff --git a/CMakeLists.txt b/CMakeLists.txt index c0e8873..e5ca12b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. cmake_minimum_required(VERSION 3.21) -project(expr VERSION 1.4.0) +project(expr VERSION 1.5.0) include(cmake/CPM.cmake) configure_file(src/config.h.in config.h) set(CMAKE_CXX_STANDARD 20) diff --git a/include/drivers/interpreter.h b/include/drivers/interpreter.h index f71e16b..dc181b3 100644 --- a/include/drivers/interpreter.h +++ b/include/drivers/interpreter.h @@ -47,6 +47,7 @@ namespace expr { auto _and(const symbol_value_t &a, const symbol_value_t &b) -> symbol_value_t override { return and_(a,b); } auto _or(const symbol_value_t &a, const symbol_value_t &b) -> symbol_value_t override { return or_(a,b); } auto _xor(const symbol_value_t &a, const symbol_value_t &b) -> symbol_value_t override { return xor_(a,b); } + auto _implies(const symbol_value_t &a, const symbol_value_t &b) -> symbol_value_t override { return implies_(a,b); } auto gt(const symbol_value_t &a, const symbol_value_t &b) -> symbol_value_t override { return gt_(a,b); } auto ge(const symbol_value_t &a, const symbol_value_t &b) -> symbol_value_t override { return ge_(a,b); } diff --git a/include/symbol_table.h b/include/symbol_table.h index 308c17a..0310408 100644 --- a/include/symbol_table.h +++ b/include/symbol_table.h @@ -80,7 +80,7 @@ namespace expr { enum class operator_type_t { minus, plus, star, slash, percent, hat, - _and, _or, _xor, _not, + _and, _or, _xor, _not, _implies, gt, ge, ne, ee, le, lt, parentheses }; diff --git a/src/drivers/interpreter.cpp b/src/drivers/interpreter.cpp index f69074c..0621a69 100644 --- a/src/drivers/interpreter.cpp +++ b/src/drivers/interpreter.cpp @@ -84,6 +84,7 @@ namespace expr { case operator_type_t::_or: v = boolean._or(eval_wrapper(tree.children[0]), eval_wrapper(tree.children[1])); break; case operator_type_t::_xor: v = boolean._xor(eval_wrapper(tree.children[0]), eval_wrapper(tree.children[1])); break; case operator_type_t::_not: v = boolean._not(eval_wrapper(tree.children[0])); break; + case operator_type_t::_implies: v = boolean._implies(eval_wrapper(tree.children[0]), eval_wrapper(tree.children[1])); break; case operator_type_t::gt: v = comparator.gt(eval_wrapper(tree.children[0]), eval_wrapper(tree.children[1])); break; case operator_type_t::ge: v = comparator.ge(eval_wrapper(tree.children[0]), eval_wrapper(tree.children[1])); break; case operator_type_t::ne: v = comparator.ne(eval_wrapper(tree.children[0]), eval_wrapper(tree.children[1])); break; diff --git a/src/drivers/z3_driver.cpp b/src/drivers/z3_driver.cpp index 534d866..5b76c28 100644 --- a/src/drivers/z3_driver.cpp +++ b/src/drivers/z3_driver.cpp @@ -157,6 +157,7 @@ namespace expr { case operator_type_t::_or: v = as_z3_expression(tree.children[0]) || as_z3_expression(tree.children[1]); break; case operator_type_t::_xor: v = as_z3_expression(tree.children[0]) xor as_z3_expression(tree.children[1]); break; case operator_type_t::_not: v =!as_z3_expression(tree.children[0]); break; + case operator_type_t::_implies: v = implies(as_z3_expression(tree.children[0]),as_z3_expression(tree.children[1])); break; case operator_type_t::gt: v = (as_z3_expression(tree.children[0]) > as_z3_expression(tree.children[1])); break; case operator_type_t::ge: v = (as_z3_expression(tree.children[0]) >= as_z3_expression(tree.children[1])); break; case operator_type_t::ne: v = (as_z3_expression(tree.children[0]) != as_z3_expression(tree.children[1])); break; diff --git a/src/operations.h b/src/operations.h index 19b6362..55bb1ee 100644 --- a/src/operations.h +++ b/src/operations.h @@ -44,6 +44,7 @@ namespace expr { virtual auto _and(const symbol_value_t &a, const symbol_value_t &b) -> symbol_value_t = 0; virtual auto _or(const symbol_value_t &a, const symbol_value_t &b) -> symbol_value_t = 0; virtual auto _xor(const symbol_value_t &a, const symbol_value_t &b) -> symbol_value_t = 0; + virtual auto _implies(const symbol_value_t& a, const symbol_value_t& b) -> symbol_value_t = 0; }; struct compare_operator { virtual auto gt(const symbol_value_t &a, const symbol_value_t &b) -> symbol_value_t = 0; diff --git a/src/operations/boolean.cpp b/src/operations/boolean.cpp index cda34bd..068821a 100644 --- a/src/operations/boolean.cpp +++ b/src/operations/boolean.cpp @@ -95,6 +95,13 @@ auto t_lt(const T1&, const T2&) { throw std::domain_error(ss.str()); return nullptr; // Must return something } +template +auto t_implies(const T1&, const T2&) { + std::ostringstream ss{}; + ss << "Unable to imply (=>) types " << typeid(T1).name() << " and " << typeid(T2).name(); + throw std::domain_error(ss.str()); + return nullptr; // Must return something +} template<> auto t_and(const bool& a, const bool& b) { @@ -112,6 +119,11 @@ template<> auto t_not(const bool& a) { return !a; } +template<> +auto t_implies(const bool& a, const bool& b) { + if(a) return b; + return true; +} auto t_gt(const int& a, const int& b) {return a > b;} auto t_gt(const int& a, const float& b) {return a > b;} @@ -206,3 +218,8 @@ symbol_value_t lt_(const symbol_value_t& a, const symbol_value_t& b) { FUNC_IMPL(a, t_lt, b, res); return res; } +symbol_value_t implies_(const symbol_value_t& a, const symbol_value_t& b) { + symbol_value_t res{}; + FUNC_IMPL(a, t_implies, b, res); + return res; +} diff --git a/src/operations/boolean.h b/src/operations/boolean.h index 6118ec6..135f24a 100644 --- a/src/operations/boolean.h +++ b/src/operations/boolean.h @@ -33,6 +33,7 @@ expr::symbol_value_t ee_(const expr::symbol_value_t& a, const expr::symbol_value expr::symbol_value_t ne_(const expr::symbol_value_t& a, const expr::symbol_value_t& b); expr::symbol_value_t le_(const expr::symbol_value_t& a, const expr::symbol_value_t& b); expr::symbol_value_t lt_(const expr::symbol_value_t& a, const expr::symbol_value_t& b); +expr::symbol_value_t implies_(const expr::symbol_value_t& a, const expr::symbol_value_t& b); // TODO: These operators are ambiguous with symbol_value_t && std::false_type / std::true_type for some reason. //symbol_value_t operator&&(const symbol_value_t& a, const symbol_value_t& b); //symbol_value_t operator||(const symbol_value_t& a, const symbol_value_t& b); diff --git a/src/parser/parser.y b/src/parser/parser.y index 78d790e..e459c49 100644 --- a/src/parser/parser.y +++ b/src/parser/parser.y @@ -66,6 +66,7 @@ AND "&&" OR "||" XOR "^^" + IMPLIES "=>" GT ">" GE ">=" EE "==" @@ -96,6 +97,7 @@ %left AND %left GT GE EE NE LE LT %left PLUS MINUS STAR SLASH PERCENT HAT +%left IMPLIES %precedence LPAREN NOT %% %start unit; @@ -138,6 +140,7 @@ bin_op: | exp LT exp { $$ = expr::syntax_tree_t{expr::operator_t{expr::operator_type_t::lt}}.concat($1).concat($3); } | exp OR exp { $$ = expr::syntax_tree_t{expr::operator_t{expr::operator_type_t::_or}}.concat($1).concat($3); } | exp XOR exp { $$ = expr::syntax_tree_t{expr::operator_t{expr::operator_type_t::_xor}}.concat($1).concat($3); } +| exp IMPLIES exp { $$ = expr::syntax_tree_t{expr::operator_t{expr::operator_type_t::_implies}}.concat($1).concat($3); } | exp AND exp { $$ = expr::syntax_tree_t{expr::operator_t{expr::operator_type_t::_and}}.concat($1).concat($3); } ; diff --git a/src/parser/scanner.l b/src/parser/scanner.l index 481bcc2..3e3416d 100644 --- a/src/parser/scanner.l +++ b/src/parser/scanner.l @@ -147,6 +147,7 @@ type int|long|float|double|string|bool|var|auto "&&" return yy::parser::make_AND (loc); "||" return yy::parser::make_OR (loc); "^^" return yy::parser::make_XOR (loc); +"=>" return yy::parser::make_IMPLIES(loc); ">" return yy::parser::make_GT (loc); ">=" return yy::parser::make_GE (loc); "==" return yy::parser::make_EE (loc); diff --git a/src/symbol_table.cpp b/src/symbol_table.cpp index aab10b6..6c2240c 100644 --- a/src/symbol_table.cpp +++ b/src/symbol_table.cpp @@ -85,6 +85,8 @@ namespace expr { return o << "||"; case operator_type_t::_xor: return o << "xor"; + case operator_type_t::_implies: + return o << "=>"; case operator_type_t::_not: return o << "!"; case operator_type_t::gt: