diff options
author | Martin Braun <martin.braun@ettus.com> | 2019-08-20 10:00:47 -0700 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2019-11-26 12:16:25 -0800 |
commit | 7d69dcdcc318ccdf87038b732acbf2bf7c087b60 (patch) | |
tree | 8179f2f4a14be591d7c856f77f13687b45f9a454 /host/lib/rfnoc/nocscript | |
parent | 1ac6e6f56100a7e8186481ab0715937759f52737 (diff) | |
download | uhd-7d69dcdcc318ccdf87038b732acbf2bf7c087b60.tar.gz uhd-7d69dcdcc318ccdf87038b732acbf2bf7c087b60.tar.bz2 uhd-7d69dcdcc318ccdf87038b732acbf2bf7c087b60.zip |
Remove proto-RFNoC files
This commit removes all files and parts of files that are used by
proto-RFNoC only.
uhd: Fix include CMakeLists.txt, add missing files
Diffstat (limited to 'host/lib/rfnoc/nocscript')
-rw-r--r-- | host/lib/rfnoc/nocscript/CMakeLists.txt | 27 | ||||
-rw-r--r-- | host/lib/rfnoc/nocscript/block_iface.cpp | 236 | ||||
-rw-r--r-- | host/lib/rfnoc/nocscript/block_iface.hpp | 87 | ||||
-rw-r--r-- | host/lib/rfnoc/nocscript/expression.cpp | 380 | ||||
-rw-r--r-- | host/lib/rfnoc/nocscript/expression.hpp | 360 | ||||
-rw-r--r-- | host/lib/rfnoc/nocscript/function_table.cpp | 100 | ||||
-rw-r--r-- | host/lib/rfnoc/nocscript/function_table.hpp | 75 | ||||
-rwxr-xr-x | host/lib/rfnoc/nocscript/gen_basic_funcs.py | 465 | ||||
-rw-r--r-- | host/lib/rfnoc/nocscript/parser.cpp | 357 | ||||
-rw-r--r-- | host/lib/rfnoc/nocscript/parser.hpp | 37 |
10 files changed, 0 insertions, 2124 deletions
diff --git a/host/lib/rfnoc/nocscript/CMakeLists.txt b/host/lib/rfnoc/nocscript/CMakeLists.txt deleted file mode 100644 index 2eeb984bf..000000000 --- a/host/lib/rfnoc/nocscript/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -# -# Copyright 2015 Ettus Research LLC -# Copyright 2018 Ettus Research, a National Instruments Company -# -# SPDX-License-Identifier: GPL-3.0-or-later -# - -include_directories(${CMAKE_CURRENT_SOURCE_DIR}) -include_directories(${CMAKE_CURRENT_BINARY_DIR}) -LIBUHD_PYTHON_GEN_SOURCE( - ${CMAKE_CURRENT_SOURCE_DIR}/gen_basic_funcs.py - ${CMAKE_CURRENT_BINARY_DIR}/basic_functions.hpp -) - -if(ENABLE_MANUAL) - LIBUHD_PYTHON_GEN_SOURCE( - ${CMAKE_CURRENT_SOURCE_DIR}/gen_basic_funcs.py - ${CMAKE_BINARY_DIR}/docs/nocscript_functions.dox - ) -endif(ENABLE_MANUAL) - -LIBUHD_APPEND_SOURCES( - ${CMAKE_CURRENT_SOURCE_DIR}/expression.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/function_table.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/parser.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/block_iface.cpp -) diff --git a/host/lib/rfnoc/nocscript/block_iface.cpp b/host/lib/rfnoc/nocscript/block_iface.cpp deleted file mode 100644 index f029c3324..000000000 --- a/host/lib/rfnoc/nocscript/block_iface.cpp +++ /dev/null @@ -1,236 +0,0 @@ -// -// Copyright 2015 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#include "block_iface.hpp" -#include "function_table.hpp" -#include <uhd/exception.hpp> -#include <uhd/utils/log.hpp> -#include <boost/assign.hpp> -#include <boost/bind.hpp> -#include <boost/format.hpp> - -#define UHD_NOCSCRIPT_LOG() UHD_LOGGER_TRACE("RFNOC") - -using namespace uhd::rfnoc; -using namespace uhd::rfnoc::nocscript; - -block_iface::block_iface(block_ctrl_base* block_ptr) : _block_ptr(block_ptr) -{ - function_table::sptr ft = function_table::make(); - - // Add the SR_WRITE() function - expression_function::argtype_list_type sr_write_args_wo_port = - boost::assign::list_of(expression::TYPE_STRING)(expression::TYPE_INT); - expression_function::argtype_list_type sr_write_args_w_port = boost::assign::list_of( - expression::TYPE_STRING)(expression::TYPE_INT)(expression::TYPE_INT); - ft->register_function("SR_WRITE", - boost::bind(&block_iface::_nocscript__sr_write, this, _1), - expression::TYPE_BOOL, - sr_write_args_wo_port); - ft->register_function("SR_WRITE", - boost::bind(&block_iface::_nocscript__sr_write, this, _1), - expression::TYPE_BOOL, - sr_write_args_w_port); - - // Add read access to arguments ($foo) - expression_function::argtype_list_type arg_set_args_wo_port = - boost::assign::list_of(expression::TYPE_STRING)(expression::TYPE_INT); - expression_function::argtype_list_type arg_set_args_w_port = boost::assign::list_of( - expression::TYPE_STRING)(expression::TYPE_INT)(expression::TYPE_INT); -#define REGISTER_ARG_SETTER(noctype, setter_func) \ - arg_set_args_wo_port[1] = expression::noctype; \ - arg_set_args_w_port[1] = expression::noctype; \ - ft->register_function("SET_ARG", \ - boost::bind(&block_iface::setter_func, this, _1), \ - expression::TYPE_BOOL, \ - arg_set_args_wo_port); \ - ft->register_function("SET_ARG", \ - boost::bind(&block_iface::setter_func, this, _1), \ - expression::TYPE_BOOL, \ - arg_set_args_w_port); - REGISTER_ARG_SETTER(TYPE_INT, _nocscript__arg_set_int); - REGISTER_ARG_SETTER(TYPE_STRING, _nocscript__arg_set_string); - REGISTER_ARG_SETTER(TYPE_DOUBLE, _nocscript__arg_set_double); - REGISTER_ARG_SETTER(TYPE_INT_VECTOR, _nocscript__arg_set_intvec); - - - // Add read/write access to local variables - expression_function::argtype_list_type set_var_args = - boost::assign::list_of(expression::TYPE_STRING)(expression::TYPE_INT); - const expression_function::argtype_list_type get_var_args = - boost::assign::list_of(expression::TYPE_STRING); -#define REGISTER_VAR_ACCESS(noctype, typestr) \ - set_var_args[1] = expression::noctype; \ - ft->register_function("SET_VAR", \ - boost::bind(&block_iface::_nocscript__var_set, this, _1), \ - expression::TYPE_BOOL, \ - set_var_args); \ - ft->register_function("GET_" #typestr, \ - boost::bind(&block_iface::_nocscript__var_get, this, _1), \ - expression::noctype, \ - get_var_args); - REGISTER_VAR_ACCESS(TYPE_INT, INT); - REGISTER_VAR_ACCESS(TYPE_STRING, STRING); - REGISTER_VAR_ACCESS(TYPE_DOUBLE, DOUBLE); - REGISTER_VAR_ACCESS(TYPE_INT_VECTOR, INT_VECTOR); - - // Create the parser - _parser = parser::make(ft, - boost::bind(&block_iface::_nocscript__arg_get_type, this, _1), - boost::bind(&block_iface::_nocscript__arg_get_val, this, _1)); -} - - -void block_iface::run_and_check(const std::string& code, const std::string& error_message) -{ - boost::mutex::scoped_lock local_interpreter_lock(_lil_mutex); - - UHD_NOCSCRIPT_LOG() << "[NocScript] Executing and asserting code: " << code; - expression::sptr e = _parser->create_expr_tree(code); - expression_literal result = e->eval(); - if (not result.to_bool()) { - if (error_message.empty()) { - throw uhd::runtime_error( - str(boost::format("[NocScript] Code returned false: %s") % code)); - } else { - throw uhd::runtime_error( - str(boost::format("[NocScript] Error: %s") % error_message)); - } - } - - _vars.clear(); // We go out of scope, and so do NocScript variables -} - - -expression_literal block_iface::_nocscript__sr_write( - expression_container::expr_list_type args) -{ - const std::string reg_name = args[0]->eval().get_string(); - const uint32_t reg_val = uint32_t(args[1]->eval().get_int()); - size_t port = 0; - if (args.size() == 3) { - port = size_t(args[2]->eval().get_int()); - } - - bool result = true; - try { - UHD_NOCSCRIPT_LOG() << "[NocScript] Executing SR_WRITE() "; - _block_ptr->sr_write(reg_name, reg_val, port); - } catch (const uhd::exception& e) { - UHD_LOGGER_ERROR("RFNOC") - << boost::format("[NocScript] Error while executing SR_WRITE(%s, 0x%X):\n%s") - % reg_name % reg_val % e.what(); - result = false; - } - - return expression_literal(result); -} - -expression::type_t block_iface::_nocscript__arg_get_type(const std::string& varname) -{ - const std::string var_type = _block_ptr->get_arg_type(varname); - if (var_type == "int") { - return expression::TYPE_INT; - } else if (var_type == "string") { - return expression::TYPE_STRING; - } else if (var_type == "double") { - return expression::TYPE_DOUBLE; - } else if (var_type == "int_vector") { - UHD_THROW_INVALID_CODE_PATH(); // TODO - } else { - UHD_THROW_INVALID_CODE_PATH(); - } -} - -expression_literal block_iface::_nocscript__arg_get_val(const std::string& varname) -{ - const std::string var_type = _block_ptr->get_arg_type(varname); - if (var_type == "int") { - return expression_literal(_block_ptr->get_arg<int>(varname)); - } else if (var_type == "string") { - return expression_literal(_block_ptr->get_arg<std::string>(varname)); - } else if (var_type == "double") { - return expression_literal(_block_ptr->get_arg<double>(varname)); - } else if (var_type == "int_vector") { - UHD_THROW_INVALID_CODE_PATH(); // TODO - } else { - UHD_THROW_INVALID_CODE_PATH(); - } -} - -expression_literal block_iface::_nocscript__arg_set_int( - const expression_container::expr_list_type& args) -{ - const std::string var_name = args[0]->eval().get_string(); - const int val = args[1]->eval().get_int(); - size_t port = 0; - if (args.size() == 3) { - port = size_t(args[2]->eval().get_int()); - } - UHD_NOCSCRIPT_LOG() << "[NocScript] Setting $" << var_name; - _block_ptr->set_arg<int>(var_name, val, port); - return expression_literal(true); -} - -expression_literal block_iface::_nocscript__arg_set_string( - const expression_container::expr_list_type& args) -{ - const std::string var_name = args[0]->eval().get_string(); - const std::string val = args[1]->eval().get_string(); - size_t port = 0; - if (args.size() == 3) { - port = size_t(args[2]->eval().get_int()); - } - UHD_NOCSCRIPT_LOG() << "[NocScript] Setting $" << var_name; - _block_ptr->set_arg<std::string>(var_name, val, port); - return expression_literal(true); -} - -expression_literal block_iface::_nocscript__arg_set_double( - const expression_container::expr_list_type& args) -{ - const std::string var_name = args[0]->eval().get_string(); - const double val = args[1]->eval().get_double(); - size_t port = 0; - if (args.size() == 3) { - port = size_t(args[2]->eval().get_int()); - } - UHD_NOCSCRIPT_LOG() << "[NocScript] Setting $" << var_name; - _block_ptr->set_arg<double>(var_name, val, port); - return expression_literal(true); -} - -expression_literal block_iface::_nocscript__arg_set_intvec( - const expression_container::expr_list_type&) -{ - UHD_THROW_INVALID_CODE_PATH(); -} - -block_iface::sptr block_iface::make(uhd::rfnoc::block_ctrl_base* block_ptr) -{ - return sptr(new block_iface(block_ptr)); -} - -expression_literal block_iface::_nocscript__var_get( - const expression_container::expr_list_type& args) -{ - expression_literal expr = _vars[args[0]->eval().get_string()]; - // std::cout << "[NocScript] Getting var " << args[0]->eval().get_string() << " == " - // << expr ; std::cout << "[NocScript] Type " << expr.infer_type() ; return - // _vars[args[0]->eval().get_string()]; - return expr; -} - -expression_literal block_iface::_nocscript__var_set( - const expression_container::expr_list_type& args) -{ - _vars[args[0]->eval().get_string()] = args[1]->eval(); - // std::cout << "[NocScript] Set var " << args[0]->eval().get_string() << " to " << - // _vars[args[0]->eval().get_string()] ; std::cout << "[NocScript] Type " << - // _vars[args[0]->eval().get_string()].infer_type() ; - return expression_literal(true); -} diff --git a/host/lib/rfnoc/nocscript/block_iface.hpp b/host/lib/rfnoc/nocscript/block_iface.hpp deleted file mode 100644 index 9d13fd4ab..000000000 --- a/host/lib/rfnoc/nocscript/block_iface.hpp +++ /dev/null @@ -1,87 +0,0 @@ -// -// Copyright 2015 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#include "expression.hpp" -#include "parser.hpp" -#include <uhd/rfnoc/block_ctrl_base.hpp> -#include <boost/thread/mutex.hpp> - -#ifndef INCLUDED_LIBUHD_NOCSCRIPT_BLOCK_IFACE_HPP -# define INCLUDED_LIBUHD_NOCSCRIPT_BLOCK_IFACE_HPP - -namespace uhd { namespace rfnoc { namespace nocscript { - -/*! NocScript / Block interface class. - * - * This class only exists as a member of an rfnoc::block_ctrl_base class. - * It should never be instantiated anywhere else. It is used to execute - * NocScript function calls that require access to the original block - * controller class. - */ -class block_iface -{ -public: - typedef boost::shared_ptr<block_iface> sptr; - - static sptr make(uhd::rfnoc::block_ctrl_base* block_ptr); - - block_iface(uhd::rfnoc::block_ctrl_base* block_ptr); - - /*! Execute \p code and make sure it returns 'true'. - * - * \param code Must be a valid NocScript expression that returns a boolean value. - * If it returns false, this is interpreted as failure. - * \param error_message If the expression fails, this error message is printed. - * \throws uhd::runtime_error if the expression returns false. - * \throws uhd::syntax_error if the expression is invalid. - */ - void run_and_check(const std::string& code, const std::string& error_message = ""); - -private: - //! For the local interpreter lock (lil) - boost::mutex _lil_mutex; - - //! Wrapper for block_ctrl_base::sr_write, so we can call it from within NocScript - expression_literal _nocscript__sr_write(expression_container::expr_list_type); - - //! Argument type getter that can be used within NocScript - expression::type_t _nocscript__arg_get_type(const std::string& argname); - - //! Argument value getter that can be used within NocScript - expression_literal _nocscript__arg_get_val(const std::string& argname); - - //! Argument value setters: - expression_literal _nocscript__arg_set_int( - const expression_container::expr_list_type&); - expression_literal _nocscript__arg_set_string( - const expression_container::expr_list_type&); - expression_literal _nocscript__arg_set_double( - const expression_container::expr_list_type&); - expression_literal _nocscript__arg_set_intvec( - const expression_container::expr_list_type&); - - //! Variable value getter - expression_literal _nocscript__var_get(const expression_container::expr_list_type&); - - //! Variable value setter - expression_literal _nocscript__var_set(const expression_container::expr_list_type&); - - //! Raw pointer to the block class. Note that since block_iface may - // only live as a member of a block_ctrl_base, we don't really need - // the reference counting. - uhd::rfnoc::block_ctrl_base* _block_ptr; - - //! Pointer to the parser object - parser::sptr _parser; - - //! Container for scoped variables - std::map<std::string, expression_literal> _vars; -}; - -}}} /* namespace uhd::rfnoc::nocscript */ - -#endif /* INCLUDED_LIBUHD_NOCSCRIPT_BLOCK_IFACE_HPP */ diff --git a/host/lib/rfnoc/nocscript/expression.cpp b/host/lib/rfnoc/nocscript/expression.cpp deleted file mode 100644 index 5e03485be..000000000 --- a/host/lib/rfnoc/nocscript/expression.cpp +++ /dev/null @@ -1,380 +0,0 @@ -// -// Copyright 2015 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#include "expression.hpp" -#include "function_table.hpp" -#include <uhd/utils/cast.hpp> -#include <boost/algorithm/string.hpp> -#include <boost/format.hpp> - -using namespace uhd::rfnoc::nocscript; - -std::map<expression::type_t, std::string> expression::type_repr{{TYPE_INT, "INT"}, - {TYPE_DOUBLE, "DOUBLE"}, - {TYPE_STRING, "STRING"}, - {TYPE_BOOL, "BOOL"}, - {TYPE_INT_VECTOR, "INT_VECTOR"}}; - -/******************************************************************** - * Literal expressions (constants) - *******************************************************************/ -expression_literal::expression_literal( - const std::string token_val, expression::type_t type) - : _bool_val(false), _int_val(0), _double_val(0.0), _val(token_val), _type(type) -{ - switch (_type) { - case expression::TYPE_STRING: - // Remove the leading and trailing quotes: - _val = _val.substr(1, _val.size() - 2); - break; - - case expression::TYPE_INT: - if (_val.substr(0, 2) == "0x") { - _int_val = uhd::cast::hexstr_cast<int>(_val); - } else { - _int_val = std::stoi(_val); - } - break; - - case expression::TYPE_DOUBLE: - _double_val = std::stod(_val); - break; - - case expression::TYPE_BOOL: - if (boost::to_upper_copy(_val) == "TRUE") { - _bool_val = true; - } else { - // lexical cast to bool is too picky - _bool_val = (std::stoi(_val) != 0); - } - break; - - case expression::TYPE_INT_VECTOR: { - std::string str_vec = _val.substr(1, _val.size() - 2); - std::vector<std::string> subtoken_list; - boost::split( - subtoken_list, str_vec, boost::is_any_of(", "), boost::token_compress_on); - for (const std::string& t : subtoken_list) { - _int_vector_val.push_back(std::stoi(t)); - } - break; - } - - default: - UHD_THROW_INVALID_CODE_PATH(); - } -} - -expression_literal::expression_literal(bool b) - : _bool_val(b), _int_val(0), _double_val(0.0), _val(""), _type(expression::TYPE_BOOL) -{ - // nop -} - -expression_literal::expression_literal(int i) - : _bool_val(false) - , _int_val(i) - , _double_val(0.0) - , _val("") - , _type(expression::TYPE_INT) -{ - // nop -} - -expression_literal::expression_literal(double d) - : _bool_val(false) - , _int_val(0) - , _double_val(d) - , _val("") - , _type(expression::TYPE_DOUBLE) -{ - // nop -} - -expression_literal::expression_literal(const std::string& s) - : _bool_val(false) - , _int_val(0) - , _double_val(0.0) - , _val(s) - , _type(expression::TYPE_STRING) -{ - // nop -} - -expression_literal::expression_literal(const std::vector<int> v) - : _bool_val(false) - , _int_val(0) - , _double_val(0.0) - , _int_vector_val(v) - , _val("") - , _type(expression::TYPE_INT_VECTOR) -{ - // nop -} - -bool expression_literal::to_bool() const -{ - switch (_type) { - case TYPE_INT: - return bool(std::stoi(_val)); - case TYPE_STRING: - return not _val.empty(); - case TYPE_DOUBLE: - return bool(std::stod(_val)); - case TYPE_BOOL: - return _bool_val; - case TYPE_INT_VECTOR: - return not _int_vector_val.empty(); - default: - UHD_THROW_INVALID_CODE_PATH(); - } -} - -int expression_literal::get_int() const -{ - if (_type != TYPE_INT) { - throw uhd::type_error("Cannot call get_int() on non-int value."); - } - - return _int_val; -} - -double expression_literal::get_double() const -{ - if (_type != TYPE_DOUBLE) { - throw uhd::type_error("Cannot call get_double() on non-double value."); - } - - return _double_val; -} - -std::string expression_literal::get_string() const -{ - if (_type != TYPE_STRING) { - throw uhd::type_error("Cannot call get_string() on non-string value."); - } - - return _val; -} - -bool expression_literal::get_bool() const -{ - if (_type != TYPE_BOOL) { - throw uhd::type_error("Cannot call get_bool() on non-boolean value."); - } - - return _bool_val; -} - -std::vector<int> expression_literal::get_int_vector() const -{ - if (_type != TYPE_INT_VECTOR) { - throw uhd::type_error("Cannot call get_bool() on non-boolean value."); - } - - return _int_vector_val; -} - -std::string expression_literal::repr() const -{ - switch (_type) { - case TYPE_INT: - return std::to_string(_int_val); - case TYPE_STRING: - return _val; - case TYPE_DOUBLE: - return std::to_string(_double_val); - case TYPE_BOOL: - return _bool_val ? "TRUE" : "FALSE"; - case TYPE_INT_VECTOR: { - std::stringstream sstr; - sstr << "["; - for (size_t i = 0; i < _int_vector_val.size(); i++) { - if (i > 0) { - sstr << ", "; - } - sstr << _int_vector_val[i]; - } - sstr << "]"; - return sstr.str(); - } - default: - UHD_THROW_INVALID_CODE_PATH(); - } -} - -bool expression_literal::operator==(const expression_literal& rhs) const -{ - if (rhs.infer_type() != _type) { - return false; - } - - switch (_type) { - case TYPE_INT: - return get_int() == rhs.get_int(); - case TYPE_STRING: - return get_string() == rhs.get_string(); - case TYPE_DOUBLE: - return get_double() == rhs.get_double(); - case TYPE_BOOL: - return get_bool() == rhs.get_bool(); - default: - UHD_THROW_INVALID_CODE_PATH(); - } -} - -/******************************************************************** - * Containers - *******************************************************************/ -expression_container::sptr expression_container::make() -{ - return sptr(new expression_container); -} - -expression::type_t expression_container::infer_type() const -{ - if (_combiner == COMBINE_OR or _combiner == COMBINE_AND) { - return TYPE_BOOL; - } - - if (_sub_exprs.empty()) { - return TYPE_BOOL; - } - - return _sub_exprs.back()->infer_type(); -} - -void expression_container::add(expression::sptr new_expr) -{ - _sub_exprs.push_back(new_expr); -} - -bool expression_container::empty() const -{ - return _sub_exprs.empty(); -} - -void expression_container::set_combiner_safe(const combiner_type c) -{ - if (_combiner == COMBINE_NOTSET) { - _combiner = c; - return; - } - - throw uhd::syntax_error("Attempting to override combiner type"); -} - -expression_literal expression_container::eval() -{ - if (_sub_exprs.empty()) { - return expression_literal(true); - } - - expression_literal ret_val; - for (const expression::sptr& sub_expr : _sub_exprs) { - ret_val = sub_expr->eval(); - if (_combiner == COMBINE_AND and ret_val.to_bool() == false) { - return ret_val; - } - if (_combiner == COMBINE_OR and ret_val.to_bool() == true) { - return ret_val; - } - // For ALL, we return the last one, so just overwrite it - } - return ret_val; -} - -/******************************************************************** - * Functions - *******************************************************************/ -std::string expression_function::to_string( - const std::string& name, const argtype_list_type& types) -{ - std::string s = name; - int arg_count = 0; - for (const expression::type_t type : types) { - if (arg_count == 0) { - s += "("; - } else { - s += ", "; - } - s += type_repr[type]; - arg_count++; - } - s += ")"; - - return s; -} - -expression_function::expression_function( - const std::string& name, const function_table::sptr func_table) - : _name(name), _func_table(func_table) -{ - _combiner = COMBINE_ALL; - if (not _func_table->function_exists(_name)) { - throw uhd::syntax_error(str(boost::format("Unknown function: %s") % _name)); - } -} - -void expression_function::add(expression::sptr new_expr) -{ - expression_container::add(new_expr); - _arg_types.push_back(new_expr->infer_type()); -} - -expression::type_t expression_function::infer_type() const -{ - return _func_table->get_type(_name, _arg_types); -} - -expression_literal expression_function::eval() -{ - return _func_table->eval(_name, _arg_types, _sub_exprs); -} - - -std::string expression_function::repr() const -{ - return to_string(_name, _arg_types); -} - -expression_function::sptr expression_function::make( - const std::string& name, const function_table::sptr func_table) -{ - return sptr(new expression_function(name, func_table)); -} - -/******************************************************************** - * Variables - *******************************************************************/ -expression_variable::expression_variable(const std::string& token_val, - type_getter_type type_getter, - value_getter_type value_getter) - : _type_getter(type_getter), _value_getter(value_getter) -{ - // We can assume this is true because otherwise, it's not a valid token: - UHD_ASSERT_THROW(not token_val.empty() and token_val[0] == '$'); - - _varname = token_val.substr(1); -} - -expression::type_t expression_variable::infer_type() const -{ - return _type_getter(_varname); -} - -expression_literal expression_variable::eval() -{ - return _value_getter(_varname); -} - -expression_variable::sptr expression_variable::make(const std::string& token_val, - type_getter_type type_getter, - value_getter_type value_getter) -{ - return sptr(new expression_variable(token_val, type_getter, value_getter)); -} diff --git a/host/lib/rfnoc/nocscript/expression.hpp b/host/lib/rfnoc/nocscript/expression.hpp deleted file mode 100644 index 309741295..000000000 --- a/host/lib/rfnoc/nocscript/expression.hpp +++ /dev/null @@ -1,360 +0,0 @@ -// -// Copyright 2015 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#include <uhd/exception.hpp> -#include <boost/function.hpp> -#include <boost/make_shared.hpp> -#include <boost/shared_ptr.hpp> -#include <map> -#include <vector> - -#ifndef INCLUDED_LIBUHD_RFNOC_NOCSCRIPT_EXPR_HPP -# define INCLUDED_LIBUHD_RFNOC_NOCSCRIPT_EXPR_HPP - -namespace uhd { namespace rfnoc { namespace nocscript { - -// Forward declaration for expression::eval() -class expression_literal; - -/*! Virtual base class for Noc-Script expressions. - */ -class expression -{ -public: - typedef boost::shared_ptr<expression> sptr; - - //! All the possible return types for expressions within Noc-Script - enum type_t { TYPE_INT, TYPE_DOUBLE, TYPE_STRING, TYPE_BOOL, TYPE_INT_VECTOR }; - - // TODO make this a const and fix the [] usage - static std::map<type_t, std::string> type_repr; - - //! Returns the type of this expression without evaluating it - virtual type_t infer_type() const = 0; - - //! Evaluate current expression and return its return value - virtual expression_literal eval() = 0; -}; - -/*! Literal (constant) expression class - * - * A literal is any value that is literally given in the NoC-Script - * source code, such as '5', '"FOO"', or '2.3'. - */ -class expression_literal : public expression -{ -public: - typedef boost::shared_ptr<expression_literal> sptr; - - template <typename expr_type> static sptr make(expr_type x) - { - return boost::make_shared<expression_literal>(x); - }; - - /*! Generate the literal expression from its token string representation. - * This includes markup, e.g. a string would still have the quotes, and - * a hex value would still have leading 0x. - */ - expression_literal(const std::string token_val, expression::type_t type); - - //! Create a boolean literal expression from a C++ bool. - expression_literal(bool b = false); - //! Create an integer literal expression from a C++ int. - expression_literal(int i); - //! Create a double literal expression from a C++ double. - expression_literal(double d); - //! Create a string literal expression from a C++ string. - expression_literal(const std::string& s); - //! Create an int vector literal expression from a C++ vector<int>. - expression_literal(std::vector<int> v); - - virtual ~expression_literal() {} - - expression::type_t infer_type() const - { - return _type; - } - - //! Literals aren't evaluated as such, so the evaluation - // simply returns a copy of itself. - expression_literal eval() - { - return *this; // TODO make sure this is copy - } - - /*! A 'type cast' to bool. Cast rules are similar to most - * scripting languages: - * - Integers and doubles are false if zero, true otherwise - * - Strings are false if empty, true otherwise - * - Vectors are false if empty, true otherwise - */ - bool to_bool() const; - - /*! Convenience function to typecast to C++ int - * - * Note that the current type must be TYPE_INT. - * - * \return C++ int representation of current literal - * \throws uhd::type_error if type didn't match - */ - int get_int() const; - - /*! Convenience function to typecast to C++ double - * - * Note that the current type must be TYPE_DOUBLE. - * - * \return C++ double representation of current literal - * \throws uhd::type_error if type didn't match - */ - double get_double() const; - - /*! Convenience function to typecast to C++ std::string. - * - * Note that the current type must be TYPE_STRING. - * - * \return String representation of current literal. - * \throws uhd::type_error if type didn't match. - */ - std::string get_string() const; - - /*! Convenience function to typecast to C++ int vector. - * - * Note that the current type must be TYPE_INT_VECTOR. - * - * \return String representation of current literal. - * \throws uhd::type_error if type didn't match. - */ - std::vector<int> get_int_vector() const; - - /*! Convenience function to typecast to C++ bool. - * - * Note that the current type must be TYPE_BOOL. - * See also expression_literal::to_bool() for a type-cast - * style function. - * - * \return bool representation of current literal. - * \throws uhd::type_error if type didn't match. - */ - bool get_bool() const; - - //! String representation - std::string repr() const; - - bool operator==(const expression_literal& rhs) const; - -private: - //! For TYPE_BOOL - bool _bool_val; - - //! For TYPE_INT - int _int_val; - - //! For TYPE_DOUBLE - double _double_val; - - //! For TYPE_INT_VECTOR - std::vector<int> _int_vector_val; - - //! Store the token value - std::string _val; - - //! Current expression type - expression::type_t _type; -}; - -UHD_INLINE std::ostream& operator<<(std::ostream& out, const expression_literal& l) -{ - out << l.repr(); - return out; -} - -UHD_INLINE std::ostream& operator<<(std::ostream& out, const expression_literal::sptr& l) -{ - out << l->repr(); - return out; -} - -/*! Contains multiple (sub-)expressions. - */ -class expression_container : public expression -{ -public: - typedef boost::shared_ptr<expression_container> sptr; - typedef std::vector<expression::sptr> expr_list_type; - - //! Return an sptr to an empty container - static sptr make(); - - //! List of valid combination types (see expression_container::eval()). - enum combiner_type { COMBINE_ALL, COMBINE_AND, COMBINE_OR, COMBINE_NOTSET }; - - //! Create an empty container - expression_container() : _combiner(COMBINE_NOTSET){}; - virtual ~expression_container() {} - - /*! Type-deduction rules for containers are: - * - If the combination type is COMBINE_ALL or COMBINE_AND, - * return value must be TYPE_BOOL - * - In all other cases, we return the last expression return - * value, and hence its type is relevant - */ - expression::type_t infer_type() const; - - /*! Add another expression container to this container. - */ - virtual void add(expression::sptr new_expr); - - virtual bool empty() const; - - void set_combiner_safe(const combiner_type c); - - void set_combiner(const combiner_type c) - { - _combiner = c; - }; - - combiner_type get_combiner() const - { - return _combiner; - }; - - /*! Evaluate a container by evaluating its sub-expressions. - * - * If a container contains multiple sub-expressions, the rules - * for evaluating them depend on the combiner_type: - * - COMBINE_ALL: Run all the sub-expressions and return the last - * expression's return value - * - COMBINE_AND: Run sub-expressions, in order, until one of them - * returns false. Following expressions are not evaluated (like - * most C++ compilers). - * - COMBINE_OR: Run sub-expressions, in order, until one of them - * returns true. Following expressions are not evaluated. - * - * In the special case where no sub-expressions are contained, always - * returns true. - */ - virtual expression_literal eval(); - -protected: - //! Store all the sub-expressions, in order - expr_list_type _sub_exprs; - combiner_type _combiner; -}; - -// Forward declaration: -class function_table; -/*! A function call is a special type of container. - * - * All arguments are sub-expressions. The combiner type is - * always COMBINE_ALL in this case (changing the combiner type - * does not affect anything). - * - * The actual function maps to a C++ function available through - * a uhd::rfnoc::nocscript::function_table object. - * - * The recommended to use this is: - * 1. Create a function object giving its name (e.g. ADD) - * 2. Use the add() method to add all the function arguments - * in the right order (left to right). - * 3. Once step 2 is complete, the function object can be used. - * Call infer_type() to get the return value, if required. - * 4. Calling eval() will call into the function table. The - * argument expressions are evaluated, if so required, inside - * the function (lazy evalulation). Functions do not need - * to evaluate arguments. - */ -class expression_function : public expression_container -{ -public: - typedef boost::shared_ptr<expression_function> sptr; - typedef std::vector<expression::type_t> argtype_list_type; - - //! Return an sptr to a function object without args - static sptr make( - const std::string& name, const boost::shared_ptr<function_table> func_table); - - static std::string to_string(const std::string& name, const argtype_list_type& types); - - expression_function( - const std::string& name, const boost::shared_ptr<function_table> func_table); - ~expression_function() {} - - //! Add an argument expression - virtual void add(expression::sptr new_expr); - - /*! Looks up the function type in the function table. - * - * Note that this will only work after all arguments have been - * added, as they are also used to look up a function's type in the - * function table. - */ - expression::type_t infer_type() const; - - /*! Evaluate all arguments, then the function itself. - */ - expression_literal eval(); - - //! String representation - std::string repr() const; - -private: - std::string _name; - const boost::shared_ptr<function_table> _func_table; - std::vector<expression::type_t> _arg_types; -}; - - -/*! Variable expression - * - * Variables are like literals, only their type and value aren't known - * at parse-time. Instead, we provide a function object to look up - * variable's types and value. - */ -class expression_variable : public expression -{ -public: - typedef boost::shared_ptr<expression_variable> sptr; - typedef boost::function<expression::type_t(const std::string&)> type_getter_type; - typedef boost::function<expression_literal(const std::string&)> value_getter_type; - - static sptr make(const std::string& token_val, - type_getter_type type_getter, - value_getter_type value_getter); - - /*! Create a variable object from its token value - * (e.g. '$spp', i.e. including the '$' symbol). The variable - * does not have to exist at this point. - */ - expression_variable(const std::string& token_val, - type_getter_type type_getter, - value_getter_type value_getter); - - virtual ~expression_variable() {} - - /*! Looks up the variable type in the variable table. - * - * \throws Depending on \p type_getter, this may throw when the variable does not - * exist. Recommended behaviour is to throw uhd::syntax_error. - */ - expression::type_t infer_type() const; - - /*! Look up a variable's value in the variable table. - * - * \throws Depending on \p value_getter, this may throw when the variable does not - * exist. Recommended behaviour is to throw uhd::syntax_error. - */ - expression_literal eval(); - -private: - std::string _varname; - type_getter_type _type_getter; - value_getter_type _value_getter; -}; - -}}} /* namespace uhd::rfnoc::nocscript */ - -#endif /* INCLUDED_LIBUHD_RFNOC_NOCSCRIPT_EXPR_HPP */ diff --git a/host/lib/rfnoc/nocscript/function_table.cpp b/host/lib/rfnoc/nocscript/function_table.cpp deleted file mode 100644 index 57e32363d..000000000 --- a/host/lib/rfnoc/nocscript/function_table.cpp +++ /dev/null @@ -1,100 +0,0 @@ -// -// Copyright 2015 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#include "function_table.hpp" -#include "basic_functions.hpp" -#include <boost/bind.hpp> -#include <boost/format.hpp> -#include <map> - -using namespace uhd::rfnoc::nocscript; - -class function_table_impl : public function_table -{ -public: - struct function_info - { - expression::type_t return_type; - function_ptr function; - - function_info() : return_type(expression::TYPE_INT){}; - function_info( - const expression::type_t return_type_, const function_ptr& function_) - : return_type(return_type_), function(function_){}; - }; - // Should be an unordered_map... sigh, we'll get to C++11 someday. - typedef std::map<std::string, - std::map<expression_function::argtype_list_type, function_info>> - table_type; - - /************************************************************************ - * Structors - ***********************************************************************/ - function_table_impl() - { - _REGISTER_ALL_FUNCS(); - } - - ~function_table_impl(){}; - - - /************************************************************************ - * Interface implementation - ***********************************************************************/ - bool function_exists(const std::string& name) const - { - return bool(_table.count(name)); - } - - bool function_exists(const std::string& name, - const expression_function::argtype_list_type& arg_types) const - { - table_type::const_iterator it = _table.find(name); - return (it != _table.end()) and bool(it->second.count(arg_types)); - } - - expression::type_t get_type(const std::string& name, - const expression_function::argtype_list_type& arg_types) const - { - table_type::const_iterator it = _table.find(name); - if (it == _table.end() or (it->second.find(arg_types) == it->second.end())) { - throw uhd::syntax_error( - str(boost::format("Unable to retrieve return value for function %s") - % expression_function::to_string(name, arg_types))); - } - return it->second.find(arg_types)->second.return_type; - } - - expression_literal eval(const std::string& name, - const expression_function::argtype_list_type& arg_types, - expression_container::expr_list_type& arguments) - { - if (not function_exists(name, arg_types)) { - throw uhd::syntax_error( - str(boost::format("Cannot eval() function %s, not a known signature") - % expression_function::to_string(name, arg_types))); - } - - return _table[name][arg_types].function(arguments); - } - - void register_function(const std::string& name, - const function_table::function_ptr& ptr, - const expression::type_t return_type, - const expression_function::argtype_list_type& sig) - { - _table[name][sig] = function_info(return_type, ptr); - } - -private: - table_type _table; -}; - -function_table::sptr function_table::make() -{ - return sptr(new function_table_impl()); -} diff --git a/host/lib/rfnoc/nocscript/function_table.hpp b/host/lib/rfnoc/nocscript/function_table.hpp deleted file mode 100644 index 63125ab1b..000000000 --- a/host/lib/rfnoc/nocscript/function_table.hpp +++ /dev/null @@ -1,75 +0,0 @@ -// -// Copyright 2015 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#include "expression.hpp" -#include <boost/function.hpp> -#include <boost/shared_ptr.hpp> -#include <vector> - -#ifndef INCLUDED_LIBUHD_RFNOC_NOCSCRIPT_FUNCTABLE_HPP -# define INCLUDED_LIBUHD_RFNOC_NOCSCRIPT_FUNCTABLE_HPP - -namespace uhd { namespace rfnoc { namespace nocscript { - -class function_table -{ -public: - typedef boost::shared_ptr<function_table> sptr; - typedef boost::function<expression_literal(expression_container::expr_list_type&)> - function_ptr; - - static sptr make(); - virtual ~function_table(){}; - - /*! Check if any function with a given name exists - * - * \returns True, if any function with name \p name is registered. - */ - virtual bool function_exists(const std::string& name) const = 0; - - /*! Check if a function with a given name and list of argument types exists - * - * \returns True, if such a function is registered. - */ - virtual bool function_exists(const std::string& name, - const expression_function::argtype_list_type& arg_types) const = 0; - - /*! Get the return type of a function with given name and argument type list - * - * \returns The function's return type - * \throws uhd::syntax_error if no such function is registered - */ - virtual expression::type_t get_type(const std::string& name, - const expression_function::argtype_list_type& arg_types) const = 0; - - /*! Calls the function \p name with the argument list \p arguments - * - * \param arg_types A list of types for each argument - * \param arguments An expression list of the arguments - * \returns The return value of the called function - * \throws uhd::syntax_error if no such function is found - */ - virtual expression_literal eval(const std::string& name, - const expression_function::argtype_list_type& arg_types, - expression_container::expr_list_type& arguments) = 0; - - /*! Register a new function - * - * \param name Name of the function (e.g. 'ADD') - * \param ptr Function object - * \param return_type The function's return value - * \param sig The function signature (list of argument types) - */ - virtual void register_function(const std::string& name, - const function_ptr& ptr, - const expression::type_t return_type, - const expression_function::argtype_list_type& sig) = 0; -}; - -}}} /* namespace uhd::rfnoc::nocscript */ - -#endif /* INCLUDED_LIBUHD_RFNOC_NOCSCRIPT_FUNCTABLE_HPP */ diff --git a/host/lib/rfnoc/nocscript/gen_basic_funcs.py b/host/lib/rfnoc/nocscript/gen_basic_funcs.py deleted file mode 100755 index fec6b04ad..000000000 --- a/host/lib/rfnoc/nocscript/gen_basic_funcs.py +++ /dev/null @@ -1,465 +0,0 @@ -#!/usr/bin/env python -""" -Generate the function list for the basic NocScript functions -""" - -import re -import os -import sys -from mako.template import Template - -############################################################################# -# This is the interesting part: Add new functions in here -# -# Notes: -# - Lines starting with # are considered comments, and will be removed from -# the output -# - C++ comments will be copied onto the generated file if inside functions -# - Docstrings start with //! and are required -# - Function signature is RETURN_TYPE NAME(ARG_TYPE1, ARG_TYPE2, ...) -# - Function body is valid C++ -# - If your function requires special includes, put them in INCLUDE_LIST -# - End of functions is delimited by s/^}/, so take care with the indents! -# - Use these substitutions: -# - ${RETURN}(...): Create a valid return value -# - ${args[n]}: Access the n-th argument -# -INCLUDE_LIST = """ -#include <boost/math/special_functions/round.hpp> -#include <chrono> -#include <thread> -""" -FUNCTION_LIST = """ -CATEGORY: Math Functions -//! Returns x + y -INT ADD(INT, INT) -{ - ${RETURN}(${args[0]} + ${args[1]}); -} - -//! Returns x + y -DOUBLE ADD(DOUBLE, DOUBLE) -{ - ${RETURN}(${args[0]} + ${args[1]}); -} - -//! Returns x * y -DOUBLE MULT(DOUBLE, DOUBLE) -{ - ${RETURN}(${args[0]} * ${args[1]}); -} - -//! Returns x * y -INT MULT(INT, INT) -{ - ${RETURN}(${args[0]} * ${args[1]}); -} - -//! Returns x / y -DOUBLE DIV(DOUBLE, DOUBLE) -{ - ${RETURN}(${args[0]} / ${args[1]}); -} - -//! Returns true if x <= y (Less or Equal) -BOOL LE(INT, INT) -{ - ${RETURN}(bool(${args[0]} <= ${args[1]})); -} - -//! Returns true if x <= y (Less or Equal) -BOOL LE(DOUBLE, DOUBLE) -{ - ${RETURN}(bool(${args[0]} <= ${args[1]})); -} - -//! Returns true if x >= y (Greater or Equal) -BOOL GE(INT, INT) -{ - ${RETURN}(bool(${args[0]} >= ${args[1]})); -} - -//! Returns true if x >= y (Greater or Equal) -BOOL GE(DOUBLE, DOUBLE) -{ - ${RETURN}(bool(${args[0]} >= ${args[1]})); -} - -//! Returns true if x < y (Less Than) -BOOL LT(INT, INT) -{ - ${RETURN}(bool(${args[0]} < ${args[1]})); -} - -//! Returns true if x > y (Greater Than) -BOOL GT(INT, INT) -{ - ${RETURN}(bool(${args[0]} > ${args[1]})); -} - -//! Returns true if x < y (Less Than) -BOOL LT(DOUBLE, DOUBLE) -{ - ${RETURN}(bool(${args[0]} < ${args[1]})); -} - -//! Returns true if x > y (Greater Than) -BOOL GT(DOUBLE, DOUBLE) -{ - ${RETURN}(bool(${args[0]} > ${args[1]})); -} - -//! Round x and return it as an integer -INT IROUND(DOUBLE) -{ - ${RETURN}(int(boost::math::iround(${args[0]}))); -} - -//! Returns true if x is a power of 2 -BOOL IS_PWR_OF_2(INT) -{ - if (${args[0]} < 0) return ${FALSE}; - int i = ${args[0]}; - while ( (i & 1) == 0 and (i > 1) ) { - i >>= 1; - } - ${RETURN}(bool(i == 1)); -} - -//! Returns floor(log2(x)). -INT LOG2(INT) -{ - if (${args[0]} < 0) { - throw uhd::runtime_error(str( - boost::format("In NocScript function ${func_name}: Cannot calculate log2() of negative number.") - )); - } - - int power_value = ${args[0]}; - int log2_value = 0; - while ( (power_value & 1) == 0 and (power_value > 1) ) { - power_value >>= 1; - log2_value++; - } - ${RETURN}(log2_value); -} - -//! Returns x % y -INT MODULO(INT, INT) -{ - ${RETURN}(${args[0]} % ${args[1]}); -} - -//! Returns true if x == y -BOOL EQUAL(INT, INT) -{ - ${RETURN}(bool(${args[0]} == ${args[1]})); -} - -//! Returns true if x == y -BOOL EQUAL(DOUBLE, DOUBLE) -{ - ${RETURN}(bool(${args[0]} == ${args[1]})); -} - -//! Returns true if x == y -BOOL EQUAL(STRING, STRING) -{ - ${RETURN}(bool(${args[0]} == ${args[1]})); -} - -CATEGORY: Bitwise Operations -//! Returns x >> y -INT SHIFT_RIGHT(INT, INT) -{ - ${RETURN}(${args[0]} >> ${args[1]}); -} - -//! Returns x << y -INT SHIFT_LEFT(INT, INT) -{ - ${RETURN}(${args[0]} << ${args[1]}); -} - -//! Returns x & y -INT BITWISE_AND(INT, INT) -{ - ${RETURN}(${args[0]} & ${args[1]}); -} - -//! Returns x | y -INT BITWISE_OR(INT, INT) -{ - ${RETURN}(${args[0]} | ${args[1]}); -} - -//! Returns x ^ y -INT BITWISE_XOR(INT, INT) -{ - ${RETURN}(${args[0]} ^ ${args[1]}); -} - -CATEGORY: Boolean Logic -//! Returns x xor y. -BOOL XOR(BOOL, BOOL) -{ - ${RETURN}(${args[0]} xor ${args[1]}); -} - -//! Returns !x -BOOL NOT(BOOL) -{ - ${RETURN}(not ${args[0]}); -} - -//! Always returns true -BOOL TRUE() -{ - return ${TRUE}; -} - -//! Always returns false -BOOL FALSE() -{ - return ${FALSE}; -} - -CATEGORY: Conditional Execution -//! Executes x, if true, execute y. Returns true if x is true. -BOOL IF(BOOL, BOOL) -{ - if (${args[0]}) { - ${args[1]}; - ${RETURN}(true); - } - ${RETURN}(false); -} - -//! Executes x, if true, execute y, otherwise, execute z. Returns true if x is true. -BOOL IF_ELSE(BOOL, BOOL, BOOL) -{ - if (${args[0]}) { - ${args[1]}; - ${RETURN}(true); - } else { - ${args[2]}; - } - ${RETURN}(false); -} - -CATEGORY: Execution Control -//! Sleep for x seconds. Fractions are allowed. Millisecond accuracy. -BOOL SLEEP(DOUBLE) -{ - int ms = ${args[0]} / 1000; - std::this_thread::sleep_for(std::chrono::milliseconds(ms)); - ${RETURN}(true); -} -""" -# End of interesting part. The rest will take this and turn into a C++ -# header file. -############################################################################# - -HEADER = """<% import time %>// -/////////////////////////////////////////////////////////////////////// -// This file was generated by ${file} on ${time.strftime("%c")} -/////////////////////////////////////////////////////////////////////// -// Copyright 2015 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -/**************************************************************************** - * This file is autogenerated! Any manual changes in here will be - * overwritten by calling nocscript_gen_basic_funcs.py! - ***************************************************************************/ - -#include "expression.hpp" -#include "function_table.hpp" -#include <uhd/exception.hpp> -#include <boost/format.hpp> -#include <boost/assign/list_of.hpp> -${INCLUDE_LIST} - -#ifndef INCLUDED_LIBUHD_RFNOC_NOCSCRIPT_BASICFUNCS_HPP -#define INCLUDED_LIBUHD_RFNOC_NOCSCRIPT_BASICFUNCS_HPP - -namespace uhd { namespace rfnoc { namespace nocscript { -""" - -# Not a Mako template: -FOOTER=""" -}}} /* namespace uhd::rfnoc::nocscript */ - -#endif /* INCLUDED_LIBUHD_RFNOC_NOCSCRIPT_BASICFUNCS_HPP */ -""" - -# Not a Mako template: -FUNC_TEMPLATE = """ -expression_literal {NAME}(expression_container::expr_list_type &{ARGS}) -{BODY} -""" - -REGISTER_MACRO_TEMPLATE = """#define _REGISTER_ALL_FUNCS()${registry} -""" - -REGISTER_COMMANDS_TEMPLATE = """ - % if len(arglist): - expression_function::argtype_list_type ${func_name}_args = boost::assign::list_of - % for this_type in arglist: - (expression::TYPE_${this_type}) - % endfor - ; - % else: - expression_function::argtype_list_type ${func_name}_args; - % endif - register_function( - "${name}", - boost::bind(&${func_name}, _1), - expression::TYPE_${retval}, - ${func_name}_args - );""" - -DOXY_TEMPLATE = """/*! \page page_nocscript_funcs NocScript Function Reference -% for cat, func_by_name in func_list_tree.items(): -- ${cat} -% for func_name, func_info_list in func_by_name.items(): - - ${func_name}: ${func_info_list[0]['docstring']} -% for func_info in func_info_list: - - ${func_info['arglist']} -> ${func_info['retval']} -% endfor -% endfor -% endfor - -*/ -""" - -def parse_tmpl(_tmpl_text, **kwargs): - return Template(_tmpl_text).render(**kwargs) - -def make_cxx_func_name(func_dict): - """ - Creates a unique C++ function name from a function description - """ - return "{name}__{retval}__{arglist}".format( - name=func_dict['name'], - retval=func_dict['retval'], - arglist="_".join(func_dict['arglist']) - ) - -def make_cxx_func_body(func_dict): - """ - Formats the function body properly - """ - type_lookup_methods = { - 'INT': 'get_int', - 'DOUBLE': 'get_double', - 'BOOL': 'get_bool', - 'STRING': 'get_string', - } - args_lookup = [] - for idx, arg_type in enumerate(func_dict['arglist']): - args_lookup.append("args[{idx}]->eval().{getter}()".format(idx=idx, getter=type_lookup_methods[arg_type])) - return parse_tmpl( - func_dict['body'], - args=args_lookup, - FALSE='expression_literal(false)', - TRUE='expression_literal(true)', - RETURN='return expression_literal', - **func_dict - ) - -def prep_function_list(): - """ - - Remove all comments - - Split the function list into individual functions - - Split the functions into return value, name, argument list and body - """ - comment_remove_re = re.compile(r'^\s*#.*$', flags=re.MULTILINE) - func_list_wo_comments = comment_remove_re.sub('', FUNCTION_LIST) - func_splitter_re = re.compile(r'(?<=^})\s*$', flags=re.MULTILINE) - func_list_split = func_splitter_re.split(func_list_wo_comments) - func_list_split = [x.strip() for x in func_list_split if len(x.strip())] - func_list = [] - last_category = '' - for func in func_list_split: - split_regex = r'(^CATEGORY: (?P<cat>[^\n]*)\s*)?' \ - r'//!(?P<docstring>[^\n]*)\s*' + \ - r'(?P<retval>[A-Z][A-Z0-9_]*)\s+' + \ - r'(?P<funcname>[A-Z][A-Z0-9_]*)\s*\((?P<arglist>[^\)]*)\)\s*' + \ - r'(?P<funcbody>^{.*)' - split_re = re.compile(split_regex, flags=re.MULTILINE|re.DOTALL) - mo = split_re.match(func) - if mo.group('cat'): - last_category = mo.group('cat').strip() - func_dict = { - 'docstring': mo.group('docstring').strip(), - 'name': mo.group('funcname'), - 'retval': mo.group('retval'), - 'arglist': [x.strip() for x in mo.group('arglist').split(',') if len(x.strip())], - 'body': mo.group('funcbody'), - 'category': last_category, - } - func_dict['func_name'] = make_cxx_func_name(func_dict) - func_list.append(func_dict) - return func_list - -def write_function_header(output_filename): - """ - Create the .hpp file that defines all the NocScript functions in C++. - """ - func_list = prep_function_list() - # Step 1: Write the prototypes - func_prototypes = '' - registry_commands = '' - for func in func_list: - func_prototypes += FUNC_TEMPLATE.format( - NAME=func['func_name'], - BODY=make_cxx_func_body(func), - ARGS="args" if len(func['arglist']) else "" - ) - registry_commands += parse_tmpl( - REGISTER_COMMANDS_TEMPLATE, - **func - ) - # Step 2: Write the registry process - register_func = parse_tmpl(REGISTER_MACRO_TEMPLATE, registry=registry_commands) - register_func = register_func.replace('\n', ' \\\n') - - # Final step: Join parts and write to file - full_file = "\n".join(( - parse_tmpl(HEADER, file = os.path.basename(__file__), INCLUDE_LIST=INCLUDE_LIST), - func_prototypes, - register_func, - FOOTER, - )) - open(output_filename, 'w').write(full_file) - -def write_manual_file(output_filename): - """ - Write the Doxygen file for the NocScript functions. - """ - func_list = prep_function_list() - func_list_tree = {} - for func in func_list: - if func['category'] not in func_list_tree: - func_list_tree[func['category']] = {} - if func['name'] not in func_list_tree[func['category']]: - func_list_tree[func['category']][func['name']] = [] - func_list_tree[func['category']][func['name']].append(func) - open(output_filename, 'w').write(parse_tmpl(DOXY_TEMPLATE, func_list_tree=func_list_tree)) - - -def main(): - if len(sys.argv) < 2: - print("No output file specified!") - exit(1) - outfile = sys.argv[1] - if os.path.splitext(outfile)[1] == '.dox': - write_manual_file(outfile) - else: - write_function_header(outfile) - -if __name__ == "__main__": - main() diff --git a/host/lib/rfnoc/nocscript/parser.cpp b/host/lib/rfnoc/nocscript/parser.cpp deleted file mode 100644 index 8ef1b7f44..000000000 --- a/host/lib/rfnoc/nocscript/parser.cpp +++ /dev/null @@ -1,357 +0,0 @@ -// -// Copyright 2015 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#include "parser.hpp" -#include <uhd/utils/cast.hpp> -#include <boost/assign.hpp> -#include <boost/bind.hpp> -#include <boost/format.hpp> -#include <boost/make_shared.hpp> -#include <boost/spirit/include/lex_lexertl.hpp> -#include <sstream> -#include <stack> - -using namespace uhd::rfnoc::nocscript; -namespace lex = boost::spirit::lex; - -class parser_impl : public parser -{ -public: - /****************************************************************** - * Structors TODO make them protected - *****************************************************************/ - parser_impl(function_table::sptr ftable, - expression_variable::type_getter_type var_type_getter, - expression_variable::value_getter_type var_value_getter) - : _ftable(ftable) - , _var_type_getter(var_type_getter) - , _var_value_getter(var_value_getter) - { - // nop - } - - virtual ~parser_impl() {} - - - /****************************************************************** - * Parsing - *****************************************************************/ - //! List of parser tokens - enum token_ids { - ID_WHITESPACE = lex::min_token_id + 42, - ID_KEYWORD, - ID_ARG_SEP, - ID_PARENS_OPEN, - ID_PARENS_CLOSE, - ID_VARIABLE, - ID_LITERAL_DOUBLE, - ID_LITERAL_INT, - ID_LITERAL_HEX, - ID_LITERAL_STR, - ID_LITERAL_VECTOR_INT - }; - - //! The Lexer object used for NocScript - template <typename Lexer> struct ns_lexer : lex::lexer<Lexer> - { - ns_lexer() - { - this->self.add("\\s+", ID_WHITESPACE)(",", ID_ARG_SEP)( - "[A-Z][A-Z0-9_]*", ID_KEYWORD)("\\(", ID_PARENS_OPEN)( - "\\)", ID_PARENS_CLOSE)("\\$[a-z][a-z0-9_]*", ID_VARIABLE)( - "-?\\d+\\.\\d+", ID_LITERAL_DOUBLE)("-?\\d+", ID_LITERAL_INT)( - "0x[0-9A-F]+", ID_LITERAL_HEX)("\\\"[^\\\"]*\\\"", ID_LITERAL_STR)( - "'[^']*'", ID_LITERAL_STR) // both work - ("\\[[0-9]\\]", ID_LITERAL_VECTOR_INT); - } - }; - -private: - struct grammar_props - { - function_table::sptr ftable; - expression_variable::type_getter_type var_type_getter; - expression_variable::value_getter_type var_value_getter; - - //! Store the last keyword - std::string function_name; - std::string error; - std::stack<expression_container::sptr> expr_stack; - - grammar_props(function_table::sptr ftable_, - expression_variable::type_getter_type var_type_getter_, - expression_variable::value_getter_type var_value_getter_) - : ftable(ftable_) - , var_type_getter(var_type_getter_) - , var_value_getter(var_value_getter_) - , function_name("") - { - UHD_ASSERT_THROW(expr_stack.empty()); - // Push an empty container to the stack to hold the result - expr_stack.push(expression_container::make()); - } - - expression::sptr get_result() - { - UHD_ASSERT_THROW(expr_stack.size() == 1); - return expr_stack.top(); - } - }; - - //! This isn't strictly a grammar, as it also includes semantic - // actions etc. I'm not going to spend ages thinking of a better - // name at this point. - struct grammar - { - // Implementation detail specific to boost::bind (see Boost::Spirit - // examples) - typedef bool result_type; - - static const int VALID_COMMA = 0x1; - static const int VALID_PARENS_OPEN = 0x2; - static const int VALID_PARENS_CLOSE = 0x4; - static const int VALID_EXPRESSION = 0x8 + 0x02; - static const int VALID_OPERATOR = 0x10; - - // !This function operator gets called for each of the matched tokens. - template <typename Token> - bool operator()(Token const& t, grammar_props& P, int& next_valid_state) const - { - //! This is totally not how Boost::Spirit is meant to be used, - // as there's token types etc. But for now let's just convert - // every token to a string, and then handle it as such. - std::stringstream sstr; - sstr << t.value(); - std::string val = sstr.str(); - // std::cout << "VAL: " << val << std::endl; - // std::cout << "Next valid states:\n" - //<< boost::format("VALID_COMMA [%s]\n") % ((next_valid_state & 0x1) ? - //"x" : " ") - //<< boost::format("VALID_PARENS_OPEN [%s]\n") % ((next_valid_state & 0x2) ? - //"x" : " ") - //<< boost::format("VALID_PARENS_CLOSE [%s]\n") % ((next_valid_state & 0x4) ? - //"x" : " ") - //<< boost::format("VALID_EXPRESSION [%s]\n") % ((next_valid_state & (0x8 + - //0x02)) ? "x" : " ") - //<< boost::format("VALID_OPERATOR [%s]\n") % ((next_valid_state & 0x10) - //? "x" : " ") - //<< std::endl; - - switch (t.id()) { - case ID_WHITESPACE: - // Ignore - break; - - case ID_KEYWORD: - // Ambiguous, could be an operator (AND, OR) or a function name (ADD, - // MULT...). So first, check which it is: - if (val == "AND" or val == "OR") { - if (not(next_valid_state & VALID_OPERATOR)) { - P.error = str(boost::format("Unexpected operator: %s") % val); - return false; - } - next_valid_state = VALID_EXPRESSION; - try { - if (val == "AND") { - P.expr_stack.top()->set_combiner_safe( - expression_container::COMBINE_AND); - } else if (val == "OR") { - P.expr_stack.top()->set_combiner_safe( - expression_container::COMBINE_OR); - } - } catch (const uhd::syntax_error&) { - P.error = str(boost::format("Operator %s is mixing operator " - "types within this container.") - % val); - } - // Right now, we can't have multiple operator types within a - // container. We might be able to change that, if there's enough - // demand. Either we keep track of multiple operators, or we open - // a new container. In the latter case, we'd need a way of keeping - // track of those containers, so it's a bit tricky. - break; - } - // If it's not a keyword, it has to be a function, so check the - // function table: - if (not(next_valid_state & VALID_EXPRESSION)) { - P.error = str(boost::format("Unexpected expression: %s") % val); - return false; - } - if (not P.ftable->function_exists(val)) { - P.error = str(boost::format("Unknown function: %s") % val); - return false; - } - P.function_name = val; - next_valid_state = VALID_PARENS_OPEN; - break; - - // Every () creates a new container, either a raw container or - // a function. - case ID_PARENS_OPEN: - if (not(next_valid_state & VALID_PARENS_OPEN)) { - P.error = str(boost::format("Unexpected parentheses.")); - return false; - } - if (not P.function_name.empty()) { - // We've already checked the function name exists - P.expr_stack.push( - expression_function::make(P.function_name, P.ftable)); - P.function_name.clear(); - } else { - P.expr_stack.push(expression_container::make()); - } - // Push another empty container to hold the first element/argument - // in this container: - P.expr_stack.push(expression_container::make()); - next_valid_state = VALID_EXPRESSION | VALID_PARENS_CLOSE; - break; - - case ID_PARENS_CLOSE: { - if (not(next_valid_state & VALID_PARENS_CLOSE)) { - P.error = str(boost::format("Unexpected parentheses.")); - return false; - } - if (P.expr_stack.size() < 2) { - P.error = str(boost::format("Unbalanced closing parentheses.")); - return false; - } - // First pop the last expression inside the parentheses, - // if it's not empty, add it to the top container (this also avoids - // adding arguments to functions if none were provided): - expression_container::sptr c = P.expr_stack.top(); - P.expr_stack.pop(); - if (not c->empty()) { - P.expr_stack.top()->add(c); - } - // At the end of (), either a function or container is complete, - // so pop that and add it to its top container: - expression_container::sptr c2 = P.expr_stack.top(); - P.expr_stack.pop(); - P.expr_stack.top()->add(c2); - next_valid_state = VALID_OPERATOR | VALID_COMMA | VALID_PARENS_CLOSE; - } break; - - case ID_ARG_SEP: { - if (not(next_valid_state & VALID_COMMA)) { - P.error = str(boost::format("Unexpected comma.")); - return false; - } - next_valid_state = VALID_EXPRESSION; - // If stack size is 1, we're on the base container, which means we - // simply string stuff. - if (P.expr_stack.size() == 1) { - break; - } - // Otherwise, a ',' always means we add the previous expression to - // the current container: - expression_container::sptr c = P.expr_stack.top(); - P.expr_stack.pop(); - P.expr_stack.top()->add(c); - // It also means another expression is following, so create another - // empty container for that: - P.expr_stack.push(expression_container::make()); - } break; - - // All the atomic expressions just get added to the current container: - - case ID_VARIABLE: { - if (not(next_valid_state & VALID_EXPRESSION)) { - P.error = str(boost::format("Unexpected expression.")); - return false; - } - expression_variable::sptr v = expression_variable::make( - val, P.var_type_getter, P.var_value_getter); - P.expr_stack.top()->add(v); - next_valid_state = VALID_OPERATOR | VALID_COMMA | VALID_PARENS_CLOSE; - } break; - - default: - // If we get here, we assume it's a literal expression - { - if (not(next_valid_state & VALID_EXPRESSION)) { - P.error = str(boost::format("Unexpected expression.")); - return false; - } - expression::type_t token_type; - switch (t.id()) { // A map lookup would be more elegant, but we'd - // need a nicer C++ for that - case ID_LITERAL_DOUBLE: - token_type = expression::TYPE_DOUBLE; - break; - case ID_LITERAL_INT: - token_type = expression::TYPE_INT; - break; - case ID_LITERAL_HEX: - token_type = expression::TYPE_INT; - break; - case ID_LITERAL_STR: - token_type = expression::TYPE_STRING; - break; - case ID_LITERAL_VECTOR_INT: - token_type = expression::TYPE_INT_VECTOR; - break; - default: - UHD_THROW_INVALID_CODE_PATH(); - } - P.expr_stack.top()->add( - boost::make_shared<expression_literal>(val, token_type)); - next_valid_state = VALID_OPERATOR | VALID_COMMA - | VALID_PARENS_CLOSE; - break; - } - - } // end switch - return true; - } - }; - -public: - expression::sptr create_expr_tree(const std::string& code) - { - // Create empty stack and keyword states - grammar_props P(_ftable, _var_type_getter, _var_value_getter); - int next_valid_state = grammar::VALID_EXPRESSION; - - // Create a lexer instance - ns_lexer<lex::lexertl::lexer<>> lexer_functor; - - // Tokenize the string - char const* first = code.c_str(); - char const* last = &first[code.size()]; - bool r = lex::tokenize(first, - last, // Iterators - lexer_functor, // Lexer - boost::bind(grammar(), - _1, - boost::ref(P), - boost::ref(next_valid_state)) // Function object - ); - - // Check the parsing worked: - if (not r or P.expr_stack.size() != 1) { - std::string rest(first, last); - throw uhd::syntax_error( - str(boost::format("Parsing stopped at: %s\nError message: %s") % rest - % P.error)); - } - - // Clear stack and return result - return P.get_result(); - } - -private: - function_table::sptr _ftable; - expression_variable::type_getter_type _var_type_getter; - expression_variable::value_getter_type _var_value_getter; -}; - -parser::sptr parser::make(function_table::sptr ftable, - expression_variable::type_getter_type var_type_getter, - expression_variable::value_getter_type var_value_getter) -{ - return sptr(new parser_impl(ftable, var_type_getter, var_value_getter)); -} diff --git a/host/lib/rfnoc/nocscript/parser.hpp b/host/lib/rfnoc/nocscript/parser.hpp deleted file mode 100644 index e9d9f0820..000000000 --- a/host/lib/rfnoc/nocscript/parser.hpp +++ /dev/null @@ -1,37 +0,0 @@ -// -// Copyright 2015 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#include "expression.hpp" -#include "function_table.hpp" -#include <boost/shared_ptr.hpp> - -#ifndef INCLUDED_LIBUHD_RFNOC_NOCSCRIPT_PARSER_HPP -# define INCLUDED_LIBUHD_RFNOC_NOCSCRIPT_PARSER_HPP - -namespace uhd { namespace rfnoc { namespace nocscript { - -class parser -{ -public: - typedef boost::shared_ptr<parser> sptr; - - static sptr make(function_table::sptr ftable, - expression_variable::type_getter_type var_type_getter, - expression_variable::value_getter_type var_value_getter); - - /*! The main parsing call: Turn a string of code into an expression tree. - * - * Evaluating the returned object will execute the code. - * - * \throws uhd::syntax_error if \p code contains syntax errors - */ - virtual expression::sptr create_expr_tree(const std::string& code) = 0; -}; - -}}} /* namespace uhd::rfnoc::nocscript */ - -#endif /* INCLUDED_LIBUHD_RFNOC_NOCSCRIPT_PARSER_HPP */ |