From f1c7f27ef91a917b89a07a323a1ae8d1df5fec47 Mon Sep 17 00:00:00 2001 From: Asger Gitz-Johansen Date: Mon, 7 Mar 2022 17:22:30 +0100 Subject: [PATCH 1/5] added support for >,>=,==,!=,<=,< comparison operators --- include/operations/boolean.h | 6 ++ src/operations/boolean.cpp | 106 +++++++++++++++++++++++++++++++++++ src/parser/parser.y | 12 ++++ src/parser/scanner.l | 6 ++ 4 files changed, 130 insertions(+) diff --git a/include/operations/boolean.h b/include/operations/boolean.h index 00c5925..d3c4cf2 100644 --- a/include/operations/boolean.h +++ b/include/operations/boolean.h @@ -4,6 +4,12 @@ symbol_value_t and_(const symbol_value_t& a, const symbol_value_t& b); symbol_value_t or_(const symbol_value_t& a, const symbol_value_t& b); symbol_value_t not_(const symbol_value_t& a); +symbol_value_t gt_(const symbol_value_t& a, const symbol_value_t& b); +symbol_value_t ge_(const symbol_value_t& a, const symbol_value_t& b); +symbol_value_t ee_(const symbol_value_t& a, const symbol_value_t& b); +symbol_value_t ne_(const symbol_value_t& a, const symbol_value_t& b); +symbol_value_t le_(const symbol_value_t& a, const symbol_value_t& b); +symbol_value_t lt_(const symbol_value_t& a, const 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/operations/boolean.cpp b/src/operations/boolean.cpp index ca951d3..cc59a27 100644 --- a/src/operations/boolean.cpp +++ b/src/operations/boolean.cpp @@ -23,6 +23,48 @@ auto t_not(const T1&) { throw std::domain_error(ss.str()); return nullptr; // Must return something } +template +auto t_gt(const T1&, const T2&) { + std::ostringstream ss{}; + ss << "Unable to compare (>) types " << typeid(T1).name() << " and " << typeid(T2).name(); + throw std::domain_error(ss.str()); + return nullptr; // Must return something +} +template +auto t_ge(const T1&, const T2&) { + std::ostringstream ss{}; + ss << "Unable to compare (>=) types " << typeid(T1).name() << " and " << typeid(T2).name(); + throw std::domain_error(ss.str()); + return nullptr; // Must return something +} +template +auto t_ee(const T1&, const T2&) { + std::ostringstream ss{}; + ss << "Unable to compare (==) types " << typeid(T1).name() << " and " << typeid(T2).name(); + throw std::domain_error(ss.str()); + return nullptr; // Must return something +} +template +auto t_ne(const T1&, const T2&) { + std::ostringstream ss{}; + ss << "Unable to compare (!=) types " << typeid(T1).name() << " and " << typeid(T2).name(); + throw std::domain_error(ss.str()); + return nullptr; // Must return something +} +template +auto t_le(const T1&, const T2&) { + std::ostringstream ss{}; + ss << "Unable to compare (<=) types " << typeid(T1).name() << " and " << typeid(T2).name(); + throw std::domain_error(ss.str()); + return nullptr; // Must return something +} +template +auto t_lt(const T1&, const T2&) { + std::ostringstream ss{}; + ss << "Unable to compare (<) 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) { @@ -37,6 +79,40 @@ auto t_not(const bool& a) { return !a; } +auto t_gt(const int& a, const int& b) {return a > b;} +auto t_gt(const int& a, const float& b) {return a > b;} +auto t_gt(const float& a, const int& b) {return a > b;} +auto t_gt(const float& a, const float& b) {return a > b;} + +auto t_ge(const int& a, const int& b) {return a >= b;} +auto t_ge(const int& a, const float& b) {return a >= b;} +auto t_ge(const float& a, const int& b) {return a >= b;} +auto t_ge(const float& a, const float& b) {return a >= b;} + +auto t_ee(const bool& a, const bool& b) {return a == b;} +auto t_ee(const int& a, const int& b) {return a == b;} +auto t_ee(const int& a, const float& b) {return a == b;} +auto t_ee(const float& a, const int& b) {return a == b;} +auto t_ee(const float& a, const float& b) {return a == b;} +auto t_ee(const std::string& a, const std::string& b) {return a == b;} + +auto t_ne(const bool& a, const bool& b) {return a != b;} +auto t_ne(const int& a, const int& b) {return a != b;} +auto t_ne(const int& a, const float& b) {return a != b;} +auto t_ne(const float& a, const int& b) {return a != b;} +auto t_ne(const float& a, const float& b) {return a != b;} +auto t_ne(const std::string& a, const std::string& b) {return a != b;} + +auto t_lt(const int& a, const int& b) {return a < b;} +auto t_lt(const int& a, const float& b) {return a < b;} +auto t_lt(const float& a, const int& b) {return a < b;} +auto t_lt(const float& a, const float& b) {return a < b;} + +auto t_le(const int& a, const int& b) {return a <= b;} +auto t_le(const int& a, const float& b) {return a <= b;} +auto t_le(const float& a, const int& b) {return a <= b;} +auto t_le(const float& a, const float& b) {return a <= b;} + symbol_value_t and_(const symbol_value_t& a, const symbol_value_t& b) { symbol_value_t res{}; FUNC_IMPL(a, t_and, b, res); @@ -61,3 +137,33 @@ symbol_value_t not_(const symbol_value_t& a) { symbol_value_t operator!(const symbol_value_t& a) { return not_(a); } +symbol_value_t gt_(const symbol_value_t& a, const symbol_value_t& b) { + symbol_value_t res{}; + FUNC_IMPL(a, t_gt, b, res); + return res; +} +symbol_value_t ge_(const symbol_value_t& a, const symbol_value_t& b) { + symbol_value_t res{}; + FUNC_IMPL(a, t_ge, b, res); + return res; +} +symbol_value_t ee_(const symbol_value_t& a, const symbol_value_t& b) { + symbol_value_t res{}; + FUNC_IMPL(a, t_ee, b, res); + return res; +} +symbol_value_t ne_(const symbol_value_t& a, const symbol_value_t& b) { + symbol_value_t res{}; + FUNC_IMPL(a, t_ne, b, res); + return res; +} +symbol_value_t le_(const symbol_value_t& a, const symbol_value_t& b) { + symbol_value_t res{}; + FUNC_IMPL(a, t_le, b, res); + return res; +} +symbol_value_t lt_(const symbol_value_t& a, const symbol_value_t& b) { + symbol_value_t res{}; + FUNC_IMPL(a, t_lt, b, res); + return res; +} diff --git a/src/parser/parser.y b/src/parser/parser.y index 4bfe6d9..b5ee8c9 100644 --- a/src/parser/parser.y +++ b/src/parser/parser.y @@ -42,6 +42,12 @@ SLASH "/" AND "&&" OR "||" + GT ">" + GE ">=" + EE "==" + NE "!=" + LE "<=" + LT "<" NOT "!" LPAREN "(" RPAREN ")" @@ -87,6 +93,12 @@ exp: | exp "/" exp { $$ = $1 / $3; } | exp "||" exp { $$ = or_($1,$3); } | exp "&&" exp { $$ = and_($1,$3); } +| exp ">" exp { $$ = gt_($1,$3); } +| exp ">=" exp { $$ = ge_($1,$3); } +| exp "==" exp { $$ = ee_($1,$3); } +| exp "!=" exp { $$ = ne_($1,$3); } +| exp "<=" exp { $$ = le_($1,$3); } +| exp "<" exp { $$ = lt_($1,$3); } | "!" exp { $$ = not_($2); } | "(" exp ")" { $$ = $2; } %% diff --git a/src/parser/scanner.l b/src/parser/scanner.l index 108ceba..e03c533 100644 --- a/src/parser/scanner.l +++ b/src/parser/scanner.l @@ -117,6 +117,12 @@ blank [ \t\r] "/" return yy::parser::make_SLASH (loc); "&&" return yy::parser::make_AND (loc); "||" return yy::parser::make_OR (loc); +">" return yy::parser::make_GT (loc); +">=" return yy::parser::make_GE (loc); +"==" return yy::parser::make_EE (loc); +"!=" return yy::parser::make_NE (loc); +"<=" return yy::parser::make_LE (loc); +"<" return yy::parser::make_LT (loc); "!" return yy::parser::make_NOT (loc); "(" return yy::parser::make_LPAREN (loc); ")" return yy::parser::make_RPAREN (loc); From 10f1c81543b07c192969a972676aefa03be8adeb Mon Sep 17 00:00:00 2001 From: Asger Gitz-Johansen Date: Fri, 18 Mar 2022 20:09:36 +0100 Subject: [PATCH 2/5] Comparators are more important than && and || --- src/parser/parser.y | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/parser/parser.y b/src/parser/parser.y index b5ee8c9..0bd7127 100644 --- a/src/parser/parser.y +++ b/src/parser/parser.y @@ -81,6 +81,7 @@ assignment: %left "+" "-"; %left "*" "/"; +%left ">" ">=" "==" "!=" "<=" "<" "&&" "||"; exp: "number" { $$ = $1; } | "float" { $$ = $1; } @@ -101,6 +102,7 @@ exp: | exp "<" exp { $$ = lt_($1,$3); } | "!" exp { $$ = not_($2); } | "(" exp ")" { $$ = $2; } +; %% void yy::parser::error (const location_type& l, const std::string& m) { From 98b2865e3c1e2e618c55caa46c6418f80fd9e837 Mon Sep 17 00:00:00 2001 From: Asger Gitz-Johansen Date: Fri, 18 Mar 2022 21:23:30 +0100 Subject: [PATCH 3/5] Introduced a ton of reduce/reduce conflicts and shift/reduce conflicts --- src/parser/parser.y | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/src/parser/parser.y b/src/parser/parser.y index 0bd7127..354571a 100644 --- a/src/parser/parser.y +++ b/src/parser/parser.y @@ -60,14 +60,14 @@ %token FLOAT "float" %token BOOL "bool" %token STRING "string" -%nterm exp +%nterm exp cmp op %printer { yyo << $$; } <*>; %% %start unit; unit: assignments { } -| exp { drv.result["expression_result"] = $1; } +| cmp { drv.result["expression_result"] = $1; } ; assignments: @@ -77,31 +77,41 @@ assignments: ; assignment: - "identifier" ":=" exp { drv.result[$1] = $3; }; + "identifier" ":=" cmp { drv.result[$1] = $3; }; %left "+" "-"; %left "*" "/"; -%left ">" ">=" "==" "!=" "<=" "<" "&&" "||"; -exp: - "number" { $$ = $1; } -| "float" { $$ = $1; } -| "string" { $$ = $1; } -| "bool" { $$ = $1; } -| "identifier" { $$ = drv.environment.at($1); } -| exp "+" exp { $$ = $1 + $3; } +%precedence "||" "&&"; + +cmp: + op "||" op { $$ = or_($1,$3); } +| op "&&" op { $$ = and_($1,$3); } +| "!" op { $$ = not_($2); } +| op { $$ = $1; } +| "(" op ")" { $$ = $2; } +; + +op: + exp "+" exp { $$ = $1 + $3; } | exp "-" exp { $$ = $1 - $3; } | exp "*" exp { $$ = $1 * $3; } | exp "/" exp { $$ = $1 / $3; } -| exp "||" exp { $$ = or_($1,$3); } -| exp "&&" exp { $$ = and_($1,$3); } | exp ">" exp { $$ = gt_($1,$3); } | exp ">=" exp { $$ = ge_($1,$3); } | exp "==" exp { $$ = ee_($1,$3); } | exp "!=" exp { $$ = ne_($1,$3); } | exp "<=" exp { $$ = le_($1,$3); } | exp "<" exp { $$ = lt_($1,$3); } -| "!" exp { $$ = not_($2); } -| "(" exp ")" { $$ = $2; } +| exp { $$ = $1; } +; + +exp: + cmp { $$ = $1; } +| "number" { $$ = $1; } +| "float" { $$ = $1; } +| "string" { $$ = $1; } +| "bool" { $$ = $1; } +| "identifier" { $$ = drv.environment.at($1); } ; %% From bc3d15c4aefc493c0f7163748b30d1085955a8dd Mon Sep 17 00:00:00 2001 From: Asger Gitz-Johansen Date: Sun, 20 Mar 2022 09:44:30 +0100 Subject: [PATCH 4/5] empty strings do not have en EOF --- src/parser/driver.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/parser/driver.cpp b/src/parser/driver.cpp index cbcfc6f..fe2d2b5 100644 --- a/src/parser/driver.cpp +++ b/src/parser/driver.cpp @@ -6,6 +6,8 @@ driver::driver(const symbol_table_t& map) : trace_parsing (false), trace_scannin } int driver::parse(const std::string &f) { + if(f.empty()) + return 0; file = f; location.initialize (&file); scan_begin(); From 85e34d21d261a76c3a982bddebccef25d0d0a72e Mon Sep 17 00:00:00 2001 From: Asger Gitz-Johansen Date: Sun, 20 Mar 2022 09:45:56 +0100 Subject: [PATCH 5/5] Update version number --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a717e8e..a610997 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.0) -project(expr VERSION 1.1.3) +project(expr VERSION 1.2.0) include(cmake/CPM.cmake) configure_file(src/config.h.in config.h) set(CMAKE_CXX_STANDARD 20)