charset=UTF-8 Last-Modified: Mon, 05 May 2025 05:44:21 GMT Expires: Thu, 03 May 2035 05:44:21 GMT Merge branch 'stupid_git' - mame - MAME - Multiple Arcade Machine Emulator
summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/formats/img_dsk.cpp
diff options
context:
space:
mode:
author AJR <ajrhacker@users.noreply.github.com>2021-11-21 11:00:29 -0500
committer AJR <ajrhacker@users.noreply.github.com>2021-11-21 11:00:29 -0500
commit3137478c090584cd9c014e9638278ca83fa8b51d (patch)
tree80e6bf8b9454ce1467fc9ddfc9ba268fe923157f /src/lib/formats/img_dsk.cpp
parent246ba1f482200c87a63c5e8777fceab4727b9b21 (diff)
parent4dc7a7780723294b8cf050004b7177d9bc5cb251 (diff)
Merge branch 'stupid_git'
Diffstat (limited to 'src/lib/formats/img_dsk.cpp')
0 files changed, 0 insertions, 0 deletions
>103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
// license:GPL-2.0+
// copyright-holders:Couriersud
/*
 * palloc.c
 *
 */

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

#include <cmath>
#include <stack>

namespace plib {

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

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

	template <typename NT>
	void pfunction<NT>::compile_postfix(const std::vector<pstring> &inputs,
			const std::vector<pstring> &cmds, const pstring &expr)
	{
		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 == "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)
				{
					rc.m_cmd = PUSH_CONST;
					bool err(false);
					rc.m_param = plib::pstonum_ne<decltype(rc.m_param)>(cmd, err);
					if (err)
						throw plib::pexception(plib::pfmt("pfunction: unknown/misformatted token <{1}> in <{2}>")(cmd)(expr));
					stk += 1;
				}
			}
			if (stk < 1)
				throw plib::pexception(plib::pfmt("pfunction: stack underflow on token <{1}> in <{2}>")(cmd)(expr));
			m_precompiled.push_back(rc);
		}
		if (stk != 1)
			throw plib::pexception(plib::pfmt("pfunction: stack count different to one on <{2}>")(expr));
	}

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

	static pstring pop_check(std::stack<pstring> &stk, const pstring &expr)
	{
		if (stk.size() == 0)
			throw plib::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 std::vector<pstring> &inputs, const pstring &expr)
	{
		// Shunting-yard infix parsing
		std::vector<pstring> sep = {"(", ")", ",", "*", "/", "+", "-", "^"};
		std::vector<pstring> sexpr(plib::psplit(plib::replace_all(expr, " ", ""), sep));
		std::stack<pstring> opstk;
		std::vector<pstring> postfix;

		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.size() > 0 && 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.size() == 0)
						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 (sexpr[i+1] == "(")
						opstk.push(s);
					else
						postfix.push_back(s);
				}
				else
					postfix.push_back(s);
			}
		}
		while (opstk.size() > 0)
		{
			postfix.push_back(opstk.top());
			opstk.pop();
		}
		compile_postfix(inputs, postfix, expr);
	}


	#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 std::vector<NT> &values) noexcept
	{
		std::array<NT, 20> stack = { 0 };
		unsigned ptr = 0;
		stack[0] = 0.0;
		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, std::pow(ST2, ST1))
				OP(SIN,  0, std::sin(ST2))
				OP(COS,  0, std::cos(ST2))
				OP(TRUNC,  0, std::trunc(ST2))
				case RAND:
					stack[ptr++] = lfsr_random();
					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>;

} // namespace plib