summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/netlist/plib/pfunction.cpp
blob: b5c1a46dda2e671e6a131ee61d2ee6c3dbc9ddbb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
// license:BSD-3-Clause
// copyright-holders:Curt Coder
/**********************************************************************

    RCA VIP ASCII Keyboard Interface VP-620 emulation

**********************************************************************/

#include "emu.h"
#include "vp620.h"



//**************************************************************************
//  DEVICE DEFINITIONS
//**************************************************************************

DEFINE_DEVICE_TYPE(VP620, vp620_device, "vp620", "VP-620 ASCII Keyboard")


//-------------------------------------------------
//  ASCII_KEYBOARD_INTERFACE( kb_intf )
//-------------------------------------------------

void vp620_device::kb_w(uint8_t data)
{
	m_keydata = data;

	m_slot->inst_w(0);
	m_slot->inst_w(1);

	m_keystb = ASSERT_LINE;
}

//-------------------------------------------------
//  MACHINE_CONFIG_START( vp620 )
//-------------------------------------------------

void vp620_device::device_add_mconfig(machine_config &config)
{
	generic_keyboard_device &keyboard(GENERIC_KEYBOARD(config, "keyboard", 0));
	pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
// license:GPL-2.0+
// copyright-holders:Couriersud

#include "pfunction.h"
#include "pexception.h"
#include "pfmtlog.h"
#include "pmath.h"
#include "pstonum.h"
#include "pstrutil.h"
#include "putil.h"

#include <stack>
#include <type_traits>
#include <map>
#include <utility>

namespace plib {

	static constexpr const std::size_t MAX_STACK = 32;

	// FIXME: Exa parsing conflicts with e,E parsing
	template<typename F>
	static const std::map<pstring, F> &units_si()
	{
		static std::map<pstring, F> units_si_stat =
		{
			//{ "Y", static_cast<F>(1e24) }, // NOLINT: Yotta
			//{ "Z", static_cast<F>(1e21) }, // NOLINT: Zetta
			//{ "E", static_cast<F>(1e18) }, // NOLINT: Exa
			{ "P", static_cast<F>(1e15) }, // NOLINT: Peta
			{ "T", static_cast<F>(1e12) }, // NOLINT: Tera
			{ "G", static_cast<F>( 1e9) }, // NOLINT: Giga
			{ "M", static_cast<F>( 1e6) }, // NOLINT: Mega
			{ "k", static_cast<F>( 1e3) }, // NOLINT: Kilo
			{ "h", static_cast<F>( 1e2) }, // NOLINT: Hekto
			//{ "da", static_cast<F>(1e1) }, // NOLINT: Deka
			{ "d", static_cast<F>(1e-1) }, // NOLINT: Dezi
			{ "c", static_cast<F>(1e-2) }, // NOLINT: Zenti
			{ "m", static_cast<F>(1e-3) }, // NOLINT: Milli
			{ "μ", static_cast<F>(1e-6) }, // NOLINT: Mikro
			{ "n", static_cast<F>(1e-9) }, // NOLINT: Nano
			{ "p", static_cast<F>(1e-12) }, // NOLINT: Piko
			{ "f", static_cast<F>(1e-15) }, // NOLINT: Femto
			{ "a", static_cast<F>(1e-18) }, // NOLINT: Atto
			{ "z", static_cast<F>(1e-21) }, // NOLINT: Zepto
			{ "y", static_cast<F>(1e-24) }, // NOLINT: Yokto
		};
		return units_si_stat;
	}


	template <typename NT>
	void pfunction<NT>::compile(const pstring &expr, const inputs_container &inputs) noexcept(false)
	{
		if (plib::startsWith(expr, "rpn:"))
			compile_postfix(expr.substr(4), inputs);
		else
			compile_infix(expr, inputs);
	}

	template <typename NT>
	void pfunction<NT>::compile_postfix(const pstring &expr, const inputs_container &inputs) noexcept(false)
	{
		std::vector<pstring> cmds(plib::psplit(expr, " "));
		compile_postfix(inputs, cmds, expr);
	}

	template <typename NT>
	void pfunction<NT>::compile_postfix(const inputs_container &inputs,
			const std::vector<pstring> &cmds, const pstring &expr) noexcept(false)
	{
		m_precompiled.clear();
		int stk = 0;

		for (const pstring &cmd : cmds)
		{
			rpn_inst rc;
			if (cmd == "+")
				{ rc.m_cmd = ADD; stk -= 1; }
			else if (cmd == "-")
				{ rc.m_cmd = SUB; stk -= 1; }
			else if (cmd == "*")
				{ rc.m_cmd = MULT; stk -= 1; }
			else if (cmd == "/")
				{ rc.m_cmd = DIV; stk -= 1; }
			else if (cmd == "pow")
				{ rc.m_cmd = POW; stk -= 1; }
			else if (cmd == "sin")
				{ rc.m_cmd = SIN; stk -= 0; }
			else if (cmd == "cos")
				{ rc.m_cmd = COS; stk -= 0; }
			else if (cmd == "max")
				{ rc.m_cmd = MAX; stk -= 1; }
			else if (cmd == "min")
				{ rc.m_cmd = MIN; stk -= 1; }
			else if (cmd == "trunc")
				{ rc.m_cmd = TRUNC; stk -= 0; }
			else if (cmd == "rand")
				{ rc.m_cmd = RAND; stk += 1; }
			else
			{
				for (std::size_t i = 0; i < inputs.size(); i++)
				{
					if (inputs[i] == cmd)
					{
						rc.m_cmd = PUSH_INPUT;
						rc.m_param = static_cast<NT>(i);
						stk += 1;
						break;
					}
				}
				if (rc.m_cmd != PUSH_INPUT)
				{
					using fl_t = decltype(rc.m_param);
					rc.m_cmd = PUSH_CONST;
					bool err(false);
					auto rs(plib::right(cmd,1));
					auto r=units_si<fl_t>().find(rs);
					if (r == units_si<fl_t>().end())
						rc.m_param = plib::pstonum_ne<fl_t>(cmd, err);
					else
						rc.m_param = plib::pstonum_ne<fl_t>(plib::left(cmd, cmd.size()-1), err) * r->second;
					if (err)
						throw pexception(plib::pfmt("pfunction: unknown/misformatted token <{1}> in <{2}>")(cmd)(expr));
					stk += 1;
				}
			}
			if (stk < 1)
				throw pexception(plib::pfmt("pfunction: stack underflow on token <{1}> in <{2}>")(cmd)(expr));
			if (stk >= static_cast<int>(MAX_STACK))
				throw pexception(plib::pfmt("pfunction: stack overflow on token <{1}> in <{2}>")(cmd)(expr));
			m_precompiled.push_back(rc);
		}
		if (stk != 1)
			throw pexception(plib::pfmt("pfunction: stack count different to one on <{2}>")(expr));
	}

	static int get_prio(const pstring &v)
	{
		if (v == "(" || v == ")")
			return 1;
		if (plib::left(v, 1) >= "a" && plib::left(v, 1) <= "z")
			return 0;
		if (v == "*" || v == "/")
			return 20;
		if (v == "+" || v == "-")
			return 10;
		if (v == "^")
			return 30;

		return -1;
	}

	static pstring pop_check(std::stack<pstring> &stk, const pstring &expr) noexcept(false)
	{
		if (stk.empty())
			throw pexception(plib::pfmt("pfunction: stack underflow during infix parsing of: <{1}>")(expr));
		pstring res = stk.top();
		stk.pop();
		return res;
	}

	template <typename NT>
	void pfunction<NT>::compile_infix(const pstring &expr, const inputs_container &inputs)
	{
		// Shunting-yard infix parsing
		std::vector<pstring> sep = {"(", ")", ",", "*", "/", "+", "-", "^"};
		std::vector<pstring> sexpr1(plib::psplit(plib::replace_all(expr, " ", ""), sep));
		std::stack<pstring> opstk;
		std::vector<pstring> postfix;
		std::vector<pstring> sexpr;

		// FIXME: We really need to switch to ptokenizer and fix negative number
		//        handling in ptokenizer.

		// Fix numbers
		for (std::size_t i = 0; i < sexpr1.size(); )
		{
			if ((i == 0) && (sexpr1.size() > 1) && (sexpr1[0] == "-")
				&& (plib::left(sexpr1[1],1) >= "0") && (plib::left(sexpr1[1],1) <= "9"))
			{
				if (sexpr1.size() < 4)
				{
					sexpr.push_back(sexpr1[0] + sexpr1[1]);
					i+=2;
				}
				else
				{
					auto r(plib::right(sexpr1[1], 1));
					auto ne(sexpr1[2]);
					if ((r == "e" || r == "E") && (ne == "-" || ne == "+"))
					{
						sexpr.push_back(sexpr1[0] + sexpr1[1] + ne + sexpr1[3]);
						i+=4;
					}
					else
					{
						sexpr.push_back(sexpr1[0] + sexpr1[1]);
						i+=2;
					}
				}
			}
			else if (i + 2 < sexpr1.size() && sexpr1[i].length() > 1)
			{
				auto l(plib::left(sexpr1[i], 1));
				auto r(plib::right(sexpr1[i], 1));
				auto ne(sexpr1[i+1]);
				if ((l >= "0") && (l <= "9")
					&& (r == "e" || r == "E")
					&& (ne == "-" || ne == "+"))
				{
					sexpr.push_back(sexpr1[i] + ne + sexpr1[i+2]);
					i+=3;
				}
				else
					sexpr.push_back(sexpr1[i++]);
			}
			else
				sexpr.push_back(sexpr1[i++]);
		}

		for (std::size_t i = 0; i < sexpr.size(); i++)
		{
			pstring &s = sexpr[i];
			if (s=="(")
				opstk.push(s);
			else if (s==")")
			{
				pstring x = pop_check(opstk, expr);
				while (x != "(")
				{
					postfix.push_back(x);
					x = pop_check(opstk, expr);
				}
				if (!opstk.empty() && get_prio(opstk.top()) == 0)
					postfix.push_back(pop_check(opstk, expr));
			}
			else if (s==",")
			{
				pstring x = pop_check(opstk, expr);
				while (x != "(")
				{
					postfix.push_back(x);
					x = pop_check(opstk, expr);
				}
				opstk.push(x);
			}
			else {
				int p = get_prio(s);
				if (p>0)
				{
					if (opstk.empty())
						opstk.push(s);
					else
					{
						if (get_prio(opstk.top()) >= get_prio(s))
							postfix.push_back(pop_check(opstk, expr));
						opstk.push(s);
					}
				}
				else if (p == 0) // Function or variable
				{
					if ((i+1<sexpr.size()) && sexpr[i+1] == "(")
						opstk.push(s);
					else
						postfix.push_back(s);
				}
				else
					postfix.push_back(s);
			}
		}
		while (!opstk.empty())
		{
			postfix.push_back(opstk.top());
			opstk.pop();
		}
		//printf("e : %s\n", expr.c_str());
		//for (auto &s : postfix)
		//  printf("x : %s\n", s.c_str());
		compile_postfix(inputs, postfix, expr);
	}

	template <typename NT>
	static inline typename std::enable_if<plib::is_floating_point<NT>::value, NT>::type
	lfsr_random(std::uint16_t &lfsr) noexcept
	{
		std::uint16_t lsb = lfsr & 1;
		lfsr >>= 1;
		if (lsb)
			lfsr ^= 0xB400U; // NOLINT: taps 15, 13, 12, 10
		return static_cast<NT>(lfsr) / static_cast<NT>(0xffffU); // NOLINT
	}

	template <typename NT>
	static inline typename std::enable_if<plib::is_integral<NT>::value, NT>::type
	lfsr_random(std::uint16_t &lfsr) noexcept
	{
		std::uint16_t lsb = lfsr & 1;
		lfsr >>= 1;
		if (lsb)
			lfsr ^= 0xB400U; // NOLINT: taps 15, 13, 12, 10
		return static_cast<NT>(lfsr);
	}

	#define ST1 stack[ptr]
	#define ST2 stack[ptr-1]

	#define OP(OP, ADJ, EXPR) \
	case OP: \
		ptr-= (ADJ); \
		stack[ptr-1] = (EXPR); \
		break;

	template <typename NT>
	NT pfunction<NT>::evaluate(const values_container &values) noexcept
	{
		std::array<value_type, MAX_STACK> stack = { plib::constants<value_type>::zero() };
		unsigned ptr = 0;
		stack[0] = plib::constants<value_type>::zero();
		for (auto &rc : m_precompiled)
		{
			switch (rc.m_cmd)
			{
				OP(ADD,  1, ST2 + ST1)
				OP(MULT, 1, ST2 * ST1)
				OP(SUB,  1, ST2 - ST1)
				OP(DIV,  1, ST2 / ST1)
				OP(POW,  1, plib::pow(ST2, ST1))
				OP(SIN,  0, plib::sin(ST2))
				OP(COS,  0, plib::cos(ST2))
				OP(MAX,  1, std::max(ST2, ST1))
				OP(MIN,  1, std::min(ST2, ST1))
				OP(TRUNC,  0, plib::trunc(ST2))
				case RAND:
					stack[ptr++] = lfsr_random<value_type>(m_lfsr);
					break;
				case PUSH_INPUT:
					stack[ptr++] = values[static_cast<unsigned>(rc.m_param)];
					break;
				case PUSH_CONST:
					stack[ptr++] = rc.m_param;
					break;
			}
		}
		return stack[ptr-1];
	}

	template class pfunction<float>;
	template class pfunction<double>;
	template class pfunction<long double>;
#if (PUSE_FLOAT128)
	template class pfunction<FLOAT128>;
#endif

} // namespace plib