From 562dde76399fae073a7dcf2da916dc5bf1c8d515 Mon Sep 17 00:00:00 2001 From: Asger Gitz-Johansen Date: Sun, 24 Apr 2022 10:45:38 +0200 Subject: [PATCH 1/7] Make the driver virtual, so users can override the behavior --- include/parser/driver.h | 12 ++++++------ src/parser/driver.cpp | 2 +- src/parser/parser.y | 12 ++++++------ src/parser/scanner.l | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/include/parser/driver.h b/include/parser/driver.h index 9d1d816..5ed53b9 100644 --- a/include/parser/driver.h +++ b/include/parser/driver.h @@ -3,25 +3,25 @@ #include #include "symbol_table.h" #include "parser.hpp" -#define YY_DECL yy::parser::symbol_type yylex (driver& drv) +#define YY_DECL yy::parser::symbol_type yylex (driver* drv) YY_DECL; struct driver { explicit driver(const symbol_table_t& env); + virtual ~driver() = default; const symbol_table_t& environment{}; symbol_table_t result{}; symbol_value_t error{}; symbol_value_t expression_result{}; - - int parse(const std::string& f); - auto get_symbol(const std::string& identifier) -> symbol_value_t; std::string file; bool trace_parsing; + bool trace_scanning; + yy::location location; + virtual int parse(const std::string& f); + virtual auto get_symbol(const std::string& identifier) -> symbol_value_t; void scan_begin(); void scan_end(); - bool trace_scanning; - yy::location location; }; #endif diff --git a/src/parser/driver.cpp b/src/parser/driver.cpp index 48c3fde..0b2e840 100644 --- a/src/parser/driver.cpp +++ b/src/parser/driver.cpp @@ -15,7 +15,7 @@ int driver::parse(const std::string &f) { file = f; location.initialize (&file); scan_begin(); - yy::parser parse(*this); + yy::parser parse(this); parse.set_debug_level(trace_parsing); try { int res = parse(); diff --git a/src/parser/parser.y b/src/parser/parser.y index b7deb82..8292705 100644 --- a/src/parser/parser.y +++ b/src/parser/parser.y @@ -15,7 +15,7 @@ class driver; } -%param { driver& drv } +%param { driver* drv } // Enable parser location tracking %locations @@ -74,7 +74,7 @@ %start unit; unit: statements { } -| exp { drv.expression_result = $1; } +| exp { drv->expression_result = $1; } ; statements: @@ -83,9 +83,9 @@ statements: ; statement: - "identifier" ASSIGN exp { drv.result[$1] = $3; } -| "type" "identifier" ASSIGN exp { drv.result[$2] = $4; } -| "access_modifier" "type" "identifier" ASSIGN exp { drv.result[$3] = $5; } + "identifier" ASSIGN exp { drv->result[$1] = $3; } +| "type" "identifier" ASSIGN exp { drv->result[$2] = $4; } +| "access_modifier" "type" "identifier" ASSIGN exp { drv->result[$3] = $5; } | statement TERM { } ; @@ -114,7 +114,7 @@ lit: | MINUS "float" { $$ = -$2; } | "string" { $$ = $1; } | "bool" { $$ = $1; } -| "identifier" { $$ = drv.get_symbol($1); } +| "identifier" { $$ = drv->get_symbol($1); } ; %% diff --git a/src/parser/scanner.l b/src/parser/scanner.l index 10956b8..18e1fac 100644 --- a/src/parser/scanner.l +++ b/src/parser/scanner.l @@ -109,7 +109,7 @@ type int|long|float|double|string|bool|var|auto %% %{ // A handy shortcut to the location held by the driver. - yy::location& loc = drv.location; + yy::location& loc = drv->location; // Code run each time yylex is called. loc.step(); %} From dfce21ff27a8e9a21d5e4b617f1b7b6288bbf289 Mon Sep 17 00:00:00 2001 From: Asger Gitz-Johansen Date: Sun, 24 Apr 2022 10:45:44 +0200 Subject: [PATCH 2/7] minor cleanup --- src/parser/scanner.l | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/parser/scanner.l b/src/parser/scanner.l index 18e1fac..b5c21b8 100644 --- a/src/parser/scanner.l +++ b/src/parser/scanner.l @@ -178,15 +178,9 @@ void driver::scan_begin() { yy_flex_debug = trace_scanning; if(file.empty() || file == "-") yyin = stdin; - else { + else yy_scan_string(file.c_str()); - } -// else if(!(yyin = fopen(file.c_str(), "r"))) { -// std::cerr << "cannot open " << file << ": " << strerror (errno) << '\n'; -// exit(EXIT_FAILURE); // TODO: This is pretty aggressive, maybe just throw exception instead -// } } void driver::scan_end() { -// fclose(yyin); } From 953916c13990dc9a084ded3b7240350836ffd5e0 Mon Sep 17 00:00:00 2001 From: Asger Gitz-Johansen Date: Sun, 24 Apr 2022 16:17:39 +0200 Subject: [PATCH 3/7] Add modulo operator support --- CMakeLists.txt | 1 + include/operations.h | 1 + include/operations/modulo.h | 6 ++++++ src/operations/modulo.cpp | 23 +++++++++++++++++++++++ src/parser/parser.y | 4 +++- src/parser/scanner.l | 1 + 6 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 include/operations/modulo.h create mode 100644 src/operations/modulo.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 86397fa..e51d175 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,7 @@ add_library(${PROJECT_NAME} SHARED src/operations/subtract.cpp src/operations/multiply.cpp src/operations/divide.cpp + src/operations/modulo.cpp src/operations/boolean.cpp ) add_executable(${PROJECT_NAME}_demo diff --git a/include/operations.h b/include/operations.h index 715fbc4..15721a4 100644 --- a/include/operations.h +++ b/include/operations.h @@ -4,5 +4,6 @@ #include "operations/subtract.h" #include "operations/multiply.h" #include "operations/divide.h" +#include "operations/modulo.h" #include "operations/boolean.h" #endif //EXPR_OPERATIONS_H diff --git a/include/operations/modulo.h b/include/operations/modulo.h new file mode 100644 index 0000000..aa90380 --- /dev/null +++ b/include/operations/modulo.h @@ -0,0 +1,6 @@ +#ifndef EXPR_MODULO_H +#define EXPR_MODULO_H +#include "symbol_table.h" +symbol_value_t modulo(const symbol_value_t& a, const symbol_value_t& b); +symbol_value_t operator%(const symbol_value_t& a, const symbol_value_t& b); +#endif //EXPR_MODULO_H diff --git a/src/operations/modulo.cpp b/src/operations/modulo.cpp new file mode 100644 index 0000000..33221c7 --- /dev/null +++ b/src/operations/modulo.cpp @@ -0,0 +1,23 @@ +#include "operations/multiply.h" +#include "operations/util.h" +#include + +template +auto t_modulo(const T1&, const T2&) { + std::ostringstream ss{}; + ss << "Unable to multiply type " << typeid(T1).name() << " and " << typeid(T2).name(); + throw std::domain_error(ss.str()); + return nullptr; // Must return something +} +template<> auto t_modulo(const int& x, const int& y) { + return x % y; +} + +symbol_value_t modulo(const symbol_value_t& a, const symbol_value_t& b) { + symbol_value_t res{}; + FUNC_IMPL(a, t_modulo, b, res); + return res; +} +symbol_value_t operator%(const symbol_value_t& a, const symbol_value_t& b) { + return modulo(a,b); +} diff --git a/src/parser/parser.y b/src/parser/parser.y index 8292705..c242b23 100644 --- a/src/parser/parser.y +++ b/src/parser/parser.y @@ -40,6 +40,7 @@ PLUS "+" STAR "*" SLASH "/" + PERCENT "%" AND "&&" OR "||" GT ">" @@ -68,7 +69,7 @@ %left OR %left AND %left GT GE EE NE LE LT -%left PLUS MINUS STAR SLASH +%left PLUS MINUS STAR SLASH PERCENT %precedence LPAREN NOT %% %start unit; @@ -95,6 +96,7 @@ exp: | exp MINUS exp { $$ = $1 - $3; } | exp STAR exp { $$ = $1 * $3; } | exp SLASH exp { $$ = $1 / $3; } +| exp PERCENT exp { $$ = $1 % $3; } | exp GT exp { $$ = gt_($1,$3); } | exp GE exp { $$ = ge_($1,$3); } | exp EE exp { $$ = ee_($1,$3); } diff --git a/src/parser/scanner.l b/src/parser/scanner.l index b5c21b8..a12080b 100644 --- a/src/parser/scanner.l +++ b/src/parser/scanner.l @@ -120,6 +120,7 @@ type int|long|float|double|string|bool|var|auto "+" return yy::parser::make_PLUS (loc); "*" return yy::parser::make_STAR (loc); "/" return yy::parser::make_SLASH (loc); +"%" return yy::parser::make_PERCENT(loc); "&&" return yy::parser::make_AND (loc); "||" return yy::parser::make_OR (loc); ">" return yy::parser::make_GT (loc); From 5650d89b14ed11de332c2d494e17251c63e8de52 Mon Sep 17 00:00:00 2001 From: Asger Gitz-Johansen Date: Sun, 24 Apr 2022 21:47:59 +0200 Subject: [PATCH 4/7] Enhance the symbol_value_t to be natively castable from a string --- include/symbol_table.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/include/symbol_table.h b/include/symbol_table.h index e83aec5..ce60b1d 100644 --- a/include/symbol_table.h +++ b/include/symbol_table.h @@ -4,6 +4,7 @@ #include #include #include +#include using underlying_symbol_value_t = std::variant; struct symbol_value_t : public underlying_symbol_value_t { @@ -15,6 +16,20 @@ struct symbol_value_t : public underlying_symbol_value_t { this->underlying_symbol_value_t::operator=(t); return *this; } + template<> + symbol_value_t& operator=(const std::string& t) { + std::stringstream ss{t}; + int i; float f; bool b; + if(ss >> i) + this->underlying_symbol_value_t::operator=(i); + else if(ss >> f) + this->underlying_symbol_value_t::operator=(f); + else if(ss >> b) + this->underlying_symbol_value_t::operator=(b); + else + this->underlying_symbol_value_t::operator=(t); + return *this; + } }; using underlying_symbol_table_t = std::map; From 5aad805ea0602a81437f7647f7e91a85f22079f9 Mon Sep 17 00:00:00 2001 From: Asger Gitz-Johansen Date: Mon, 25 Apr 2022 07:17:34 +0200 Subject: [PATCH 5/7] Symbol assignment is now a virtual function --- include/parser/driver.h | 1 + src/parser/driver.cpp | 4 ++++ src/parser/parser.y | 6 +++--- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/include/parser/driver.h b/include/parser/driver.h index 5ed53b9..9fb7777 100644 --- a/include/parser/driver.h +++ b/include/parser/driver.h @@ -20,6 +20,7 @@ struct driver { virtual int parse(const std::string& f); virtual auto get_symbol(const std::string& identifier) -> symbol_value_t; + virtual void set_symbol(const std::string& identifier, const symbol_value_t& value); void scan_begin(); void scan_end(); }; diff --git a/src/parser/driver.cpp b/src/parser/driver.cpp index 0b2e840..c257cd3 100644 --- a/src/parser/driver.cpp +++ b/src/parser/driver.cpp @@ -34,3 +34,7 @@ auto driver::get_symbol(const std::string &identifier) -> symbol_value_t { #endif return environment.at(identifier); } + +void driver::set_symbol(const std::string &identifier, const symbol_value_t &value) { + result[identifier] = value; +} diff --git a/src/parser/parser.y b/src/parser/parser.y index c242b23..42c77ef 100644 --- a/src/parser/parser.y +++ b/src/parser/parser.y @@ -84,9 +84,9 @@ statements: ; statement: - "identifier" ASSIGN exp { drv->result[$1] = $3; } -| "type" "identifier" ASSIGN exp { drv->result[$2] = $4; } -| "access_modifier" "type" "identifier" ASSIGN exp { drv->result[$3] = $5; } + "identifier" ASSIGN exp { drv->set_symbol($1, $3); } +| "type" "identifier" ASSIGN exp { drv->set_symbol($2, $4); } +| "access_modifier" "type" "identifier" ASSIGN exp { drv->set_symbol($3, $5); } | statement TERM { } ; From 209d75e4a643313f7f83daa66cd71ebcd0526e0e Mon Sep 17 00:00:00 2001 From: Asger Gitz-Johansen Date: Mon, 25 Apr 2022 18:05:57 +0200 Subject: [PATCH 6/7] Add interpret / <<= operator to replace the =operator interpretation It caused some problems when declaring a string with only an int in it e.g. "0" --- include/symbol_table.h | 10 ++++++---- src/parser/scanner.l | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/include/symbol_table.h b/include/symbol_table.h index ce60b1d..bea888a 100644 --- a/include/symbol_table.h +++ b/include/symbol_table.h @@ -16,9 +16,8 @@ struct symbol_value_t : public underlying_symbol_value_t { this->underlying_symbol_value_t::operator=(t); return *this; } - template<> - symbol_value_t& operator=(const std::string& t) { - std::stringstream ss{t}; + symbol_value_t& interpret(const std::string& s) { + std::stringstream ss{s}; int i; float f; bool b; if(ss >> i) this->underlying_symbol_value_t::operator=(i); @@ -27,9 +26,12 @@ struct symbol_value_t : public underlying_symbol_value_t { else if(ss >> b) this->underlying_symbol_value_t::operator=(b); else - this->underlying_symbol_value_t::operator=(t); + this->underlying_symbol_value_t::operator=(s); return *this; } + symbol_value_t& operator<<=(const std::string& s) { + return interpret(s); + } }; using underlying_symbol_table_t = std::map; diff --git a/src/parser/scanner.l b/src/parser/scanner.l index a12080b..f2b2f84 100644 --- a/src/parser/scanner.l +++ b/src/parser/scanner.l @@ -97,7 +97,7 @@ id [a-z_A-Z]([.ðđ€\(\)a-zA-Z_0-9]*[a-zA-Z_0-9]+)? int [0-9]+[Ll]? flt [0-9]+[.][0-9]+[fd]? bool [Ff]alse|[Tt]rue -str \"(\\.|[^"\\])*\" +str \"(\\.|[^\\"])*\" blank [ \t\r] accmod [Pp](ublic|rivate|rotected) type int|long|float|double|string|bool|var|auto From f166e474ddaecd25be707629d1d7b6f791484a1e Mon Sep 17 00:00:00 2001 From: Asger Gitz-Johansen Date: Mon, 2 May 2022 07:02:53 +0200 Subject: [PATCH 7/7] bump version --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e51d175..8eb3550 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.0) -project(expr VERSION 1.3.1) +project(expr VERSION 1.3.2) include(cmake/CPM.cmake) configure_file(src/config.h.in config.h) set(CMAKE_CXX_STANDARD 20)