Skip to content

Commit ead430a

Browse files
authored
Merge pull request #11 from sillydan1/fix/multiple-use-compatibility
Fix/multiple use compatibility
2 parents 3cb3e53 + 585bd0a commit ead430a

File tree

13 files changed

+227
-134
lines changed

13 files changed

+227
-134
lines changed

CHANGELOG.MD

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Changelog
2+
All notable changes to this project will be documented in this file.
3+
4+
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
5+
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
6+
7+
## [v1.7.0](https://github.com/sillydan1/expr/releases/tag/v1.7.0) - 2022-09-11
8+
9+
<small>[Compare with v1.6.0](https://github.com/sillydan1/expr/compare/v1.6.0...v1.7.0)</small>
10+
11+
### Bug Fixes
12+
- Cleanup interpreter::evaluate function ([137fdad](https://github.com/sillydan1/expr/commit/137fdad5284563f22ff52841b8ce5b9e90a5848e) by Asger Gitz-Johansen).
13+
- Interpreter now does an environment lookup for all identifier references ([e3250f5](https://github.com/sillydan1/expr/commit/e3250f53716d0d3ebc24e858dadd3ba72a36dfed) by Asger Gitz-Johansen).
14+
- Add space between the macro and parentheses ([0a7b2a2](https://github.com/sillydan1/expr/commit/0a7b2a213d8bf2ceca25531d90707f274f87b9cf) by Asger Gitz-Johansen).
15+
- Add m4_define_default parser_ns for namespace overwritability ([8b896b1](https://github.com/sillydan1/expr/commit/8b896b1334840adb3c8152720c072dee4a6d4167) by Asger Gitz-Johansen).
16+
17+
### Features
18+
- Add interpret_declarations and interpret_expression functions to interpreter ([2ccc3e6](https://github.com/sillydan1/expr/commit/2ccc3e69f6271009d0d28b54ea5beb1251d96e4a) by Asger Gitz-Johansen).
19+
20+
21+
## [v1.6.0](https://github.com/sillydan1/expr/releases/tag/v1.6.0) - 2022-08-23
22+
23+
<small>[Compare with v1.5.0](https://github.com/sillydan1/expr/compare/v1.5.0...v1.6.0)</small>
24+
25+
26+
## [v1.5.0](https://github.com/sillydan1/expr/releases/tag/v1.5.0) - 2022-07-19
27+
28+
<small>[Compare with v1.4.1](https://github.com/sillydan1/expr/compare/v1.4.1...v1.5.0)</small>
29+
30+
31+
## [v1.4.1](https://github.com/sillydan1/expr/releases/tag/v1.4.1) - 2022-07-19
32+
33+
<small>[Compare with v1.3.2](https://github.com/sillydan1/expr/compare/v1.3.2...v1.4.1)</small>
34+
35+
36+
## [v1.3.2](https://github.com/sillydan1/expr/releases/tag/v1.3.2) - 2022-05-02
37+
38+
<small>[Compare with v1.3.0](https://github.com/sillydan1/expr/compare/v1.3.0...v1.3.2)</small>
39+
40+
41+
## [v1.3.0](https://github.com/sillydan1/expr/releases/tag/v1.3.0) - 2022-04-07
42+
43+
<small>[Compare with v1.2.0](https://github.com/sillydan1/expr/compare/v1.2.0...v1.3.0)</small>
44+
45+
46+
## [v1.2.0](https://github.com/sillydan1/expr/releases/tag/v1.2.0) - 2022-03-20
47+
48+
<small>[Compare with v1.1.3](https://github.com/sillydan1/expr/compare/v1.1.3...v1.2.0)</small>
49+
50+
51+
## [v1.1.3](https://github.com/sillydan1/expr/releases/tag/v1.1.3) - 2022-03-06
52+
53+
<small>[Compare with v1.1.2](https://github.com/sillydan1/expr/compare/v1.1.2...v1.1.3)</small>
54+
55+
56+
## [v1.1.2](https://github.com/sillydan1/expr/releases/tag/v1.1.2) - 2022-03-05
57+
58+
<small>[Compare with v1.0.0](https://github.com/sillydan1/expr/compare/v1.0.0...v1.1.2)</small>
59+
60+
61+
## [v1.0.0](https://github.com/sillydan1/expr/releases/tag/v1.0.0) - 2022-03-05
62+
63+
<small>[Compare with first commit](https://github.com/sillydan1/expr/compare/8337824c2e8488a3226b773b345b0d5b537c3a7a...v1.0.0)</small>
64+
65+

CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2121
# SOFTWARE.
2222
cmake_minimum_required(VERSION 3.21)
23-
project(expr VERSION 1.6.0)
23+
project(expr VERSION 1.7.0)
2424
include(cmake/CPM.cmake)
2525
configure_file(src/config.h.in config.h)
2626
set(CMAKE_CXX_STANDARD 20)
@@ -36,7 +36,7 @@ CPMAddPackage("gh:yalibs/[email protected]")
3636
CPMAddPackage("gh:yalibs/[email protected]")
3737
CPMAddPackage("gh:sillydan1/[email protected]")
3838
if(ENABLE_Z3)
39-
CPMAddPackage("gh:Z3Prover/z3#z3-4.8.17")
39+
CPMAddPackage("gh:Z3Prover/z3#z3-4.11.0")
4040
endif()
4141

4242
set(${PROJECT_NAME}_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR} CACHE STRING "expr_BUILD_DIR" FORCE)

include/drivers/interpreter.h

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -32,35 +32,39 @@ namespace expr {
3232
~interpreter() override = default;
3333

3434
auto parse(const std::string &f) -> int override;
35+
auto interpret_declarations(const std::string& f) -> symbol_table_t;
36+
auto interpret_expression(const std::string& f) -> symbol_value_t;
3537
auto get_symbol(const std::string& identifier) -> syntax_tree_t override;
3638
void add_tree(const syntax_tree_t& tree) override;
3739
void add_tree(const std::string& identifier, const syntax_tree_t& tree) override;
3840

39-
auto add(const symbol_value_t &a, const symbol_value_t &b) -> symbol_value_t override { return ::operator+(a,b); };
40-
auto sub(const symbol_value_t &a, const symbol_value_t &b) -> symbol_value_t override { return a - b; };
41-
auto mul(const symbol_value_t &a, const symbol_value_t &b) -> symbol_value_t override { return a * b; };
42-
auto div(const symbol_value_t &a, const symbol_value_t &b) -> symbol_value_t override { return a / b; };
43-
auto mod(const symbol_value_t &a, const symbol_value_t &b) -> symbol_value_t override { return a % b; };
44-
auto pow(const symbol_value_t &a, const symbol_value_t &b) -> symbol_value_t override { return a ^ b; };
41+
auto add(const symbol_value_t &a, const symbol_value_t &b) const -> symbol_value_t override { return ::operator+(a,b); };
42+
auto sub(const symbol_value_t &a, const symbol_value_t &b) const -> symbol_value_t override { return a - b; };
43+
auto mul(const symbol_value_t &a, const symbol_value_t &b) const -> symbol_value_t override { return a * b; };
44+
auto div(const symbol_value_t &a, const symbol_value_t &b) const -> symbol_value_t override { return a / b; };
45+
auto mod(const symbol_value_t &a, const symbol_value_t &b) const -> symbol_value_t override { return a % b; };
46+
auto pow(const symbol_value_t &a, const symbol_value_t &b) const -> symbol_value_t override { return a ^ b; };
4547

46-
auto _not(const symbol_value_t &a) -> symbol_value_t override { return not_(a); }
47-
auto _and(const symbol_value_t &a, const symbol_value_t &b) -> symbol_value_t override { return and_(a,b); }
48-
auto _or(const symbol_value_t &a, const symbol_value_t &b) -> symbol_value_t override { return or_(a,b); }
49-
auto _xor(const symbol_value_t &a, const symbol_value_t &b) -> symbol_value_t override { return xor_(a,b); }
50-
auto _implies(const symbol_value_t &a, const symbol_value_t &b) -> symbol_value_t override { return implies_(a,b); }
48+
auto _not(const symbol_value_t &a) const -> symbol_value_t override { return not_(a); }
49+
auto _and(const symbol_value_t &a, const symbol_value_t &b) const -> symbol_value_t override { return and_(a,b); }
50+
auto _or(const symbol_value_t &a, const symbol_value_t &b) const -> symbol_value_t override { return or_(a,b); }
51+
auto _xor(const symbol_value_t &a, const symbol_value_t &b) const -> symbol_value_t override { return xor_(a,b); }
52+
auto _implies(const symbol_value_t &a, const symbol_value_t &b) const -> symbol_value_t override { return implies_(a,b); }
5153

52-
auto gt(const symbol_value_t &a, const symbol_value_t &b) -> symbol_value_t override { return gt_(a,b); }
53-
auto ge(const symbol_value_t &a, const symbol_value_t &b) -> symbol_value_t override { return ge_(a,b); }
54-
auto ee(const symbol_value_t &a, const symbol_value_t &b) -> symbol_value_t override { return ee_(a,b); }
55-
auto ne(const symbol_value_t &a, const symbol_value_t &b) -> symbol_value_t override { return ne_(a,b); }
56-
auto le(const symbol_value_t &a, const symbol_value_t &b) -> symbol_value_t override { return le_(a,b); }
57-
auto lt(const symbol_value_t &a, const symbol_value_t &b) -> symbol_value_t override { return lt_(a,b); }
54+
auto gt(const symbol_value_t &a, const symbol_value_t &b) const -> symbol_value_t override { return gt_(a,b); }
55+
auto ge(const symbol_value_t &a, const symbol_value_t &b) const -> symbol_value_t override { return ge_(a,b); }
56+
auto ee(const symbol_value_t &a, const symbol_value_t &b) const -> symbol_value_t override { return ee_(a,b); }
57+
auto ne(const symbol_value_t &a, const symbol_value_t &b) const -> symbol_value_t override { return ne_(a,b); }
58+
auto le(const symbol_value_t &a, const symbol_value_t &b) const -> symbol_value_t override { return le_(a,b); }
59+
auto lt(const symbol_value_t &a, const symbol_value_t &b) const -> symbol_value_t override { return lt_(a,b); }
5860

5961
symbol_table_t result{};
6062
symbol_value_t expression_result{};
6163

62-
static auto evaluate(const syntax_tree_t& tree, expr::arithmetic_operator& arith, expr::boolean_operator& boolean, expr::compare_operator& comparator) -> symbol_value_t;
63-
static auto evaluate(const compiler::compiled_expr_collection_t& symbol_tree_map, expr::arithmetic_operator& arith, expr::boolean_operator& boolean, expr::compare_operator& comparator) -> symbol_table_t;
64+
auto evaluate(const syntax_tree_t& tree) -> symbol_value_t;
65+
auto evaluate(const compiler::compiled_expr_collection_t& tree) -> symbol_table_t;
66+
static auto evaluate(const syntax_tree_t& tree, const interpreter& op, const symbol_table_t& symbols) -> symbol_value_t;
67+
static auto evaluate(const compiler::compiled_expr_collection_t& symbol_tree_map, const interpreter& op, const symbol_table_t& symbols) -> symbol_table_t;
6468

6569
protected:
6670
const symbol_table_t &environment{};

src/drivers/interpreter.cpp

Lines changed: 50 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,22 @@ namespace expr {
5050
}
5151
}
5252

53+
auto interpreter::interpret_declarations(const std::string &f) -> symbol_table_t {
54+
result = {};
55+
auto res = parse(f);
56+
if(res != 0)
57+
throw std::logic_error(error);
58+
return result;
59+
}
60+
61+
auto interpreter::interpret_expression(const std::string &f) -> symbol_value_t {
62+
expression_result = {};
63+
auto res = parse(f);
64+
if(res != 0)
65+
throw std::logic_error(error);
66+
return expression_result;
67+
}
68+
5369
auto interpreter::get_symbol(const std::string &identifier) -> syntax_tree_t {
5470
#ifndef NDEBUG
5571
if (!environment.contains(identifier))
@@ -59,55 +75,62 @@ namespace expr {
5975
}
6076

6177
void interpreter::add_tree(const syntax_tree_t& tree) {
62-
expression_result = evaluate(tree, *this, *this, *this);
78+
expression_result = evaluate(tree);
6379
}
6480

6581
void interpreter::add_tree(const std::string& identifier, const syntax_tree_t& tree) {
66-
result[identifier] = evaluate(tree, *this, *this, *this);
82+
result[identifier] = evaluate(tree);
83+
}
84+
85+
auto interpreter::evaluate(const syntax_tree_t& tree) -> symbol_value_t {
86+
return evaluate(tree, *this, environment);
87+
}
88+
89+
auto interpreter::evaluate(const compiler::compiled_expr_collection_t& trees) -> symbol_table_t {
90+
return evaluate(trees, *this, environment);
6791
}
6892

69-
auto interpreter::evaluate(const syntax_tree_t& tree, arithmetic_operator& arith, boolean_operator& boolean, compare_operator& comparator) -> symbol_value_t {
93+
auto interpreter::evaluate(const syntax_tree_t& tree, const interpreter& op, const symbol_table_t& symbols) -> symbol_value_t {
7094
symbol_value_t v{};
71-
auto eval_wrapper = [&](const syntax_tree_t& t) { return evaluate(t, arith, boolean, comparator); };
7295
std::visit(ya::overload(
73-
[&v](const symbol_reference_t& r){ v = r->second; },
74-
[&v](const c_symbol_reference_t& r){ v = r->second; },
96+
[&](const symbol_reference_t& r){ v = symbols.at(r->first); }, // TODO: Should we look up every time? If so, what is the point of storing an iterator in the ast?
97+
[&](const c_symbol_reference_t& r){ v = symbols.at(r->first); }, // TODO: Should we look up every time? If so, what is the point of storing an iterator in the ast?
7598
[&](const operator_t& o) {
7699
switch (o.operator_type) {
77-
case operator_type_t::minus: v = arith.sub(eval_wrapper(tree.children[0]), eval_wrapper(tree.children[1])); break;
78-
case operator_type_t::plus: v = arith.add(eval_wrapper(tree.children[0]), eval_wrapper(tree.children[1])); break;
79-
case operator_type_t::star: v = arith.mul(eval_wrapper(tree.children[0]), eval_wrapper(tree.children[1])); break;
80-
case operator_type_t::slash: v = arith.div(eval_wrapper(tree.children[0]), eval_wrapper(tree.children[1])); break;
81-
case operator_type_t::percent: v = arith.mod(eval_wrapper(tree.children[0]), eval_wrapper(tree.children[1])); break;
82-
case operator_type_t::hat: v = arith.pow(eval_wrapper(tree.children[0]), eval_wrapper(tree.children[1])); break;
83-
case operator_type_t::_and: v = boolean._and(eval_wrapper(tree.children[0]), eval_wrapper(tree.children[1])); break;
84-
case operator_type_t::_or: v = boolean._or(eval_wrapper(tree.children[0]), eval_wrapper(tree.children[1])); break;
85-
case operator_type_t::_xor: v = boolean._xor(eval_wrapper(tree.children[0]), eval_wrapper(tree.children[1])); break;
86-
case operator_type_t::_not: v = boolean._not(eval_wrapper(tree.children[0])); break;
87-
case operator_type_t::_implies: v = boolean._implies(eval_wrapper(tree.children[0]), eval_wrapper(tree.children[1])); break;
88-
case operator_type_t::gt: v = comparator.gt(eval_wrapper(tree.children[0]), eval_wrapper(tree.children[1])); break;
89-
case operator_type_t::ge: v = comparator.ge(eval_wrapper(tree.children[0]), eval_wrapper(tree.children[1])); break;
90-
case operator_type_t::ne: v = comparator.ne(eval_wrapper(tree.children[0]), eval_wrapper(tree.children[1])); break;
91-
case operator_type_t::ee: v = comparator.ee(eval_wrapper(tree.children[0]), eval_wrapper(tree.children[1])); break;
92-
case operator_type_t::le: v = comparator.le(eval_wrapper(tree.children[0]), eval_wrapper(tree.children[1])); break;
93-
case operator_type_t::lt: v = comparator.lt(eval_wrapper(tree.children[0]), eval_wrapper(tree.children[1])); break;
94-
case operator_type_t::parentheses: v = eval_wrapper(tree.children[0]); break;
100+
case operator_type_t::minus: v = op.sub(evaluate(tree.children[0], op, symbols), evaluate(tree.children[1], op, symbols)); break;
101+
case operator_type_t::plus: v = op.add(evaluate(tree.children[0], op, symbols), evaluate(tree.children[1], op, symbols)); break;
102+
case operator_type_t::star: v = op.mul(evaluate(tree.children[0], op, symbols), evaluate(tree.children[1], op, symbols)); break;
103+
case operator_type_t::slash: v = op.div(evaluate(tree.children[0], op, symbols), evaluate(tree.children[1], op, symbols)); break;
104+
case operator_type_t::percent: v = op.mod(evaluate(tree.children[0], op, symbols), evaluate(tree.children[1], op, symbols)); break;
105+
case operator_type_t::hat: v = op.pow(evaluate(tree.children[0], op, symbols), evaluate(tree.children[1], op, symbols)); break;
106+
case operator_type_t::_and: v = op._and(evaluate(tree.children[0], op, symbols), evaluate(tree.children[1], op, symbols)); break;
107+
case operator_type_t::_or: v = op._or(evaluate(tree.children[0], op, symbols), evaluate(tree.children[1], op, symbols)); break;
108+
case operator_type_t::_xor: v = op._xor(evaluate(tree.children[0], op, symbols), evaluate(tree.children[1], op, symbols)); break;
109+
case operator_type_t::_not: v = op._not(evaluate(tree.children[0], op, symbols)); break;
110+
case operator_type_t::_implies: v = op._implies(evaluate(tree.children[0], op, symbols), evaluate(tree.children[1], op, symbols)); break;
111+
case operator_type_t::gt: v = op.gt(evaluate(tree.children[0], op, symbols), evaluate(tree.children[1], op, symbols)); break;
112+
case operator_type_t::ge: v = op.ge(evaluate(tree.children[0], op, symbols), evaluate(tree.children[1], op, symbols)); break;
113+
case operator_type_t::ne: v = op.ne(evaluate(tree.children[0], op, symbols), evaluate(tree.children[1], op, symbols)); break;
114+
case operator_type_t::ee: v = op.ee(evaluate(tree.children[0], op, symbols), evaluate(tree.children[1], op, symbols)); break;
115+
case operator_type_t::le: v = op.le(evaluate(tree.children[0], op, symbols), evaluate(tree.children[1], op, symbols)); break;
116+
case operator_type_t::lt: v = op.lt(evaluate(tree.children[0], op, symbols), evaluate(tree.children[1], op, symbols)); break;
117+
case operator_type_t::parentheses: v = evaluate(tree.children[0], op, symbols); break;
95118
}
96119
},
97120
[&v](const symbol_value_t& o){ v = o; },
98121
[&](const root_t& r){
99122
if(!tree.children.empty())
100-
v = eval_wrapper(tree.children[0]);
123+
v = evaluate(tree.children[0], op, symbols);
101124
},
102125
[](auto&&){ throw std::logic_error("operator type not recognized"); }
103126
), static_cast<const underlying_syntax_node_t&>(tree.node));
104127
return v;
105128
}
106129

107-
auto interpreter::evaluate(const compiler::compiled_expr_collection_t& symbol_tree_map, expr::arithmetic_operator &arith, expr::boolean_operator &boolean, expr::compare_operator &comparator) -> symbol_table_t {
130+
auto interpreter::evaluate(const compiler::compiled_expr_collection_t& symbol_tree_map, const interpreter& op, const symbol_table_t& symbols) -> symbol_table_t {
108131
symbol_table_t result{};
109132
for(auto& tree : symbol_tree_map)
110-
result[tree.first] = evaluate(tree.second, arith, boolean, comparator);
133+
result[tree.first] = evaluate(tree.second, op, symbols);
111134
return result;
112135
}
113136
}

src/main.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,7 @@ int main (int argc, char *argv[]) {
117117
std::cout << tree.first << ": " << tree.second << "\n";
118118
std::cout << "\n";
119119
interpreter i{drv_c->get_environment()};
120-
auto eval = [&i](const compiler::compiled_expr_collection_t& t){return interpreter::evaluate(t,i,i,i);};
121-
std::cout << eval(drv_c->trees) << "\n";
120+
std::cout << i.evaluate(drv_c->trees) << "\n";
122121
}
123122
if(cli_arguments["driver"].as_string() == "interpreter") {
124123
auto drv_i = std::dynamic_pointer_cast<interpreter>(drv);

0 commit comments

Comments
 (0)