Skip to content

Commit

Permalink
Merge pull request #11 from sillydan1/fix/multiple-use-compatibility
Browse files Browse the repository at this point in the history
Fix/multiple use compatibility
  • Loading branch information
sillydan1 committed Sep 11, 2022
2 parents 3cb3e53 + 585bd0a commit ead430a
Show file tree
Hide file tree
Showing 13 changed files with 227 additions and 134 deletions.
65 changes: 65 additions & 0 deletions CHANGELOG.MD
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Changelog
All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [v1.7.0](https://github.com/sillydan1/expr/releases/tag/v1.7.0) - 2022-09-11

<small>[Compare with v1.6.0](https://github.com/sillydan1/expr/compare/v1.6.0...v1.7.0)</small>

### Bug Fixes
- Cleanup interpreter::evaluate function ([137fdad](https://github.com/sillydan1/expr/commit/137fdad5284563f22ff52841b8ce5b9e90a5848e) by Asger Gitz-Johansen).
- Interpreter now does an environment lookup for all identifier references ([e3250f5](https://github.com/sillydan1/expr/commit/e3250f53716d0d3ebc24e858dadd3ba72a36dfed) by Asger Gitz-Johansen).
- Add space between the macro and parentheses ([0a7b2a2](https://github.com/sillydan1/expr/commit/0a7b2a213d8bf2ceca25531d90707f274f87b9cf) by Asger Gitz-Johansen).
- Add m4_define_default parser_ns for namespace overwritability ([8b896b1](https://github.com/sillydan1/expr/commit/8b896b1334840adb3c8152720c072dee4a6d4167) by Asger Gitz-Johansen).

### Features
- Add interpret_declarations and interpret_expression functions to interpreter ([2ccc3e6](https://github.com/sillydan1/expr/commit/2ccc3e69f6271009d0d28b54ea5beb1251d96e4a) by Asger Gitz-Johansen).


## [v1.6.0](https://github.com/sillydan1/expr/releases/tag/v1.6.0) - 2022-08-23

<small>[Compare with v1.5.0](https://github.com/sillydan1/expr/compare/v1.5.0...v1.6.0)</small>


## [v1.5.0](https://github.com/sillydan1/expr/releases/tag/v1.5.0) - 2022-07-19

<small>[Compare with v1.4.1](https://github.com/sillydan1/expr/compare/v1.4.1...v1.5.0)</small>


## [v1.4.1](https://github.com/sillydan1/expr/releases/tag/v1.4.1) - 2022-07-19

<small>[Compare with v1.3.2](https://github.com/sillydan1/expr/compare/v1.3.2...v1.4.1)</small>


## [v1.3.2](https://github.com/sillydan1/expr/releases/tag/v1.3.2) - 2022-05-02

<small>[Compare with v1.3.0](https://github.com/sillydan1/expr/compare/v1.3.0...v1.3.2)</small>


## [v1.3.0](https://github.com/sillydan1/expr/releases/tag/v1.3.0) - 2022-04-07

<small>[Compare with v1.2.0](https://github.com/sillydan1/expr/compare/v1.2.0...v1.3.0)</small>


## [v1.2.0](https://github.com/sillydan1/expr/releases/tag/v1.2.0) - 2022-03-20

<small>[Compare with v1.1.3](https://github.com/sillydan1/expr/compare/v1.1.3...v1.2.0)</small>


## [v1.1.3](https://github.com/sillydan1/expr/releases/tag/v1.1.3) - 2022-03-06

<small>[Compare with v1.1.2](https://github.com/sillydan1/expr/compare/v1.1.2...v1.1.3)</small>


## [v1.1.2](https://github.com/sillydan1/expr/releases/tag/v1.1.2) - 2022-03-05

<small>[Compare with v1.0.0](https://github.com/sillydan1/expr/compare/v1.0.0...v1.1.2)</small>


## [v1.0.0](https://github.com/sillydan1/expr/releases/tag/v1.0.0) - 2022-03-05

<small>[Compare with first commit](https://github.com/sillydan1/expr/compare/8337824c2e8488a3226b773b345b0d5b537c3a7a...v1.0.0)</small>


4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.6.0)
project(expr VERSION 1.7.0)
include(cmake/CPM.cmake)
configure_file(src/config.h.in config.h)
set(CMAKE_CXX_STANDARD 20)
Expand All @@ -36,7 +36,7 @@ CPMAddPackage("gh:yalibs/[email protected]")
CPMAddPackage("gh:yalibs/[email protected]")
CPMAddPackage("gh:sillydan1/[email protected]")
if(ENABLE_Z3)
CPMAddPackage("gh:Z3Prover/z3#z3-4.8.17")
CPMAddPackage("gh:Z3Prover/z3#z3-4.11.0")
endif()

set(${PROJECT_NAME}_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR} CACHE STRING "expr_BUILD_DIR" FORCE)
Expand Down
42 changes: 23 additions & 19 deletions include/drivers/interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,35 +32,39 @@ namespace expr {
~interpreter() override = default;

auto parse(const std::string &f) -> int override;
auto interpret_declarations(const std::string& f) -> symbol_table_t;
auto interpret_expression(const std::string& f) -> symbol_value_t;
auto get_symbol(const std::string& identifier) -> syntax_tree_t override;
void add_tree(const syntax_tree_t& tree) override;
void add_tree(const std::string& identifier, const syntax_tree_t& tree) override;

auto add(const symbol_value_t &a, const symbol_value_t &b) -> symbol_value_t override { return ::operator+(a,b); };
auto sub(const symbol_value_t &a, const symbol_value_t &b) -> symbol_value_t override { return a - b; };
auto mul(const symbol_value_t &a, const symbol_value_t &b) -> symbol_value_t override { return a * b; };
auto div(const symbol_value_t &a, const symbol_value_t &b) -> symbol_value_t override { return a / b; };
auto mod(const symbol_value_t &a, const symbol_value_t &b) -> symbol_value_t override { return a % b; };
auto pow(const symbol_value_t &a, const symbol_value_t &b) -> symbol_value_t override { return a ^ b; };
auto add(const symbol_value_t &a, const symbol_value_t &b) const -> symbol_value_t override { return ::operator+(a,b); };
auto sub(const symbol_value_t &a, const symbol_value_t &b) const -> symbol_value_t override { return a - b; };
auto mul(const symbol_value_t &a, const symbol_value_t &b) const -> symbol_value_t override { return a * b; };
auto div(const symbol_value_t &a, const symbol_value_t &b) const -> symbol_value_t override { return a / b; };
auto mod(const symbol_value_t &a, const symbol_value_t &b) const -> symbol_value_t override { return a % b; };
auto pow(const symbol_value_t &a, const symbol_value_t &b) const -> symbol_value_t override { return a ^ b; };

auto _not(const symbol_value_t &a) -> symbol_value_t override { return not_(a); }
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 _not(const symbol_value_t &a) const -> symbol_value_t override { return not_(a); }
auto _and(const symbol_value_t &a, const symbol_value_t &b) const -> symbol_value_t override { return and_(a,b); }
auto _or(const symbol_value_t &a, const symbol_value_t &b) const -> symbol_value_t override { return or_(a,b); }
auto _xor(const symbol_value_t &a, const symbol_value_t &b) const -> symbol_value_t override { return xor_(a,b); }
auto _implies(const symbol_value_t &a, const symbol_value_t &b) const -> 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); }
auto ee(const symbol_value_t &a, const symbol_value_t &b) -> symbol_value_t override { return ee_(a,b); }
auto ne(const symbol_value_t &a, const symbol_value_t &b) -> symbol_value_t override { return ne_(a,b); }
auto le(const symbol_value_t &a, const symbol_value_t &b) -> symbol_value_t override { return le_(a,b); }
auto lt(const symbol_value_t &a, const symbol_value_t &b) -> symbol_value_t override { return lt_(a,b); }
auto gt(const symbol_value_t &a, const symbol_value_t &b) const -> symbol_value_t override { return gt_(a,b); }
auto ge(const symbol_value_t &a, const symbol_value_t &b) const -> symbol_value_t override { return ge_(a,b); }
auto ee(const symbol_value_t &a, const symbol_value_t &b) const -> symbol_value_t override { return ee_(a,b); }
auto ne(const symbol_value_t &a, const symbol_value_t &b) const -> symbol_value_t override { return ne_(a,b); }
auto le(const symbol_value_t &a, const symbol_value_t &b) const -> symbol_value_t override { return le_(a,b); }
auto lt(const symbol_value_t &a, const symbol_value_t &b) const -> symbol_value_t override { return lt_(a,b); }

symbol_table_t result{};
symbol_value_t expression_result{};

static auto evaluate(const syntax_tree_t& tree, expr::arithmetic_operator& arith, expr::boolean_operator& boolean, expr::compare_operator& comparator) -> symbol_value_t;
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;
auto evaluate(const syntax_tree_t& tree) -> symbol_value_t;
auto evaluate(const compiler::compiled_expr_collection_t& tree) -> symbol_table_t;
static auto evaluate(const syntax_tree_t& tree, const interpreter& op, const symbol_table_t& symbols) -> symbol_value_t;
static auto evaluate(const compiler::compiled_expr_collection_t& symbol_tree_map, const interpreter& op, const symbol_table_t& symbols) -> symbol_table_t;

protected:
const symbol_table_t &environment{};
Expand Down
77 changes: 50 additions & 27 deletions src/drivers/interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,22 @@ namespace expr {
}
}

auto interpreter::interpret_declarations(const std::string &f) -> symbol_table_t {
result = {};
auto res = parse(f);
if(res != 0)
throw std::logic_error(error);
return result;
}

auto interpreter::interpret_expression(const std::string &f) -> symbol_value_t {
expression_result = {};
auto res = parse(f);
if(res != 0)
throw std::logic_error(error);
return expression_result;
}

auto interpreter::get_symbol(const std::string &identifier) -> syntax_tree_t {
#ifndef NDEBUG
if (!environment.contains(identifier))
Expand All @@ -59,55 +75,62 @@ namespace expr {
}

void interpreter::add_tree(const syntax_tree_t& tree) {
expression_result = evaluate(tree, *this, *this, *this);
expression_result = evaluate(tree);
}

void interpreter::add_tree(const std::string& identifier, const syntax_tree_t& tree) {
result[identifier] = evaluate(tree, *this, *this, *this);
result[identifier] = evaluate(tree);
}

auto interpreter::evaluate(const syntax_tree_t& tree) -> symbol_value_t {
return evaluate(tree, *this, environment);
}

auto interpreter::evaluate(const compiler::compiled_expr_collection_t& trees) -> symbol_table_t {
return evaluate(trees, *this, environment);
}

auto interpreter::evaluate(const syntax_tree_t& tree, arithmetic_operator& arith, boolean_operator& boolean, compare_operator& comparator) -> symbol_value_t {
auto interpreter::evaluate(const syntax_tree_t& tree, const interpreter& op, const symbol_table_t& symbols) -> symbol_value_t {
symbol_value_t v{};
auto eval_wrapper = [&](const syntax_tree_t& t) { return evaluate(t, arith, boolean, comparator); };
std::visit(ya::overload(
[&v](const symbol_reference_t& r){ v = r->second; },
[&v](const c_symbol_reference_t& r){ v = r->second; },
[&](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?
[&](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?
[&](const operator_t& o) {
switch (o.operator_type) {
case operator_type_t::minus: v = arith.sub(eval_wrapper(tree.children[0]), eval_wrapper(tree.children[1])); break;
case operator_type_t::plus: v = arith.add(eval_wrapper(tree.children[0]), eval_wrapper(tree.children[1])); break;
case operator_type_t::star: v = arith.mul(eval_wrapper(tree.children[0]), eval_wrapper(tree.children[1])); break;
case operator_type_t::slash: v = arith.div(eval_wrapper(tree.children[0]), eval_wrapper(tree.children[1])); break;
case operator_type_t::percent: v = arith.mod(eval_wrapper(tree.children[0]), eval_wrapper(tree.children[1])); break;
case operator_type_t::hat: v = arith.pow(eval_wrapper(tree.children[0]), eval_wrapper(tree.children[1])); break;
case operator_type_t::_and: v = boolean._and(eval_wrapper(tree.children[0]), eval_wrapper(tree.children[1])); break;
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;
case operator_type_t::ee: v = comparator.ee(eval_wrapper(tree.children[0]), eval_wrapper(tree.children[1])); break;
case operator_type_t::le: v = comparator.le(eval_wrapper(tree.children[0]), eval_wrapper(tree.children[1])); break;
case operator_type_t::lt: v = comparator.lt(eval_wrapper(tree.children[0]), eval_wrapper(tree.children[1])); break;
case operator_type_t::parentheses: v = eval_wrapper(tree.children[0]); break;
case operator_type_t::minus: v = op.sub(evaluate(tree.children[0], op, symbols), evaluate(tree.children[1], op, symbols)); break;
case operator_type_t::plus: v = op.add(evaluate(tree.children[0], op, symbols), evaluate(tree.children[1], op, symbols)); break;
case operator_type_t::star: v = op.mul(evaluate(tree.children[0], op, symbols), evaluate(tree.children[1], op, symbols)); break;
case operator_type_t::slash: v = op.div(evaluate(tree.children[0], op, symbols), evaluate(tree.children[1], op, symbols)); break;
case operator_type_t::percent: v = op.mod(evaluate(tree.children[0], op, symbols), evaluate(tree.children[1], op, symbols)); break;
case operator_type_t::hat: v = op.pow(evaluate(tree.children[0], op, symbols), evaluate(tree.children[1], op, symbols)); break;
case operator_type_t::_and: v = op._and(evaluate(tree.children[0], op, symbols), evaluate(tree.children[1], op, symbols)); break;
case operator_type_t::_or: v = op._or(evaluate(tree.children[0], op, symbols), evaluate(tree.children[1], op, symbols)); break;
case operator_type_t::_xor: v = op._xor(evaluate(tree.children[0], op, symbols), evaluate(tree.children[1], op, symbols)); break;
case operator_type_t::_not: v = op._not(evaluate(tree.children[0], op, symbols)); break;
case operator_type_t::_implies: v = op._implies(evaluate(tree.children[0], op, symbols), evaluate(tree.children[1], op, symbols)); break;
case operator_type_t::gt: v = op.gt(evaluate(tree.children[0], op, symbols), evaluate(tree.children[1], op, symbols)); break;
case operator_type_t::ge: v = op.ge(evaluate(tree.children[0], op, symbols), evaluate(tree.children[1], op, symbols)); break;
case operator_type_t::ne: v = op.ne(evaluate(tree.children[0], op, symbols), evaluate(tree.children[1], op, symbols)); break;
case operator_type_t::ee: v = op.ee(evaluate(tree.children[0], op, symbols), evaluate(tree.children[1], op, symbols)); break;
case operator_type_t::le: v = op.le(evaluate(tree.children[0], op, symbols), evaluate(tree.children[1], op, symbols)); break;
case operator_type_t::lt: v = op.lt(evaluate(tree.children[0], op, symbols), evaluate(tree.children[1], op, symbols)); break;
case operator_type_t::parentheses: v = evaluate(tree.children[0], op, symbols); break;
}
},
[&v](const symbol_value_t& o){ v = o; },
[&](const root_t& r){
if(!tree.children.empty())
v = eval_wrapper(tree.children[0]);
v = evaluate(tree.children[0], op, symbols);
},
[](auto&&){ throw std::logic_error("operator type not recognized"); }
), static_cast<const underlying_syntax_node_t&>(tree.node));
return v;
}

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 {
auto interpreter::evaluate(const compiler::compiled_expr_collection_t& symbol_tree_map, const interpreter& op, const symbol_table_t& symbols) -> symbol_table_t {
symbol_table_t result{};
for(auto& tree : symbol_tree_map)
result[tree.first] = evaluate(tree.second, arith, boolean, comparator);
result[tree.first] = evaluate(tree.second, op, symbols);
return result;
}
}
3 changes: 1 addition & 2 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,7 @@ int main (int argc, char *argv[]) {
std::cout << tree.first << ": " << tree.second << "\n";
std::cout << "\n";
interpreter i{drv_c->get_environment()};
auto eval = [&i](const compiler::compiled_expr_collection_t& t){return interpreter::evaluate(t,i,i,i);};
std::cout << eval(drv_c->trees) << "\n";
std::cout << i.evaluate(drv_c->trees) << "\n";
}
if(cli_arguments["driver"].as_string() == "interpreter") {
auto drv_i = std::dynamic_pointer_cast<interpreter>(drv);
Expand Down
Loading

0 comments on commit ead430a

Please sign in to comment.