I'm learning C++ by implementing a previous project I did in Python. This is a simple stack machine which evaluates mathematical expressions, e.g. pow(9, 12). The code to run this on the stack machine would be an ordered list of constants and instructions: 12 9 POW.
In Python, preparing such a list is quite straightforward due to the heterogeneous nature of Python containers. I just make a list of numeric types for the constants and string types for the instructions, e.g. [12, 9, "op_pow"]. Constants get pushed to a data stack, and strings are looked up in a dispatch map for their corresponding functions.
I'm a bit stuck on how to do the same thing in C++, due to containers only having a single type. The very inefficient way I'm currently doing it is by passing a program as a vector of strings, and then converting the string constants to doubles with the fast_float library.
Is there a more efficient way to do this?
Below is what I have so far:
#include <vector>
#include <cmath>
#include <string_view>
#include <string>
#include <iostream>
#include "fast_float/fast_float.h"
class Machine {
public:
std::vector<double> stack ;
void add () {
if (stack.size() > 1) {
double a {stack[stack.size() - 1]} ;
double b {stack[stack.size() - 2]} ;
stack.pop_back() ;
stack.pop_back() ;
stack.emplace_back(a+b) ; }
}
void sub () {
if (stack.size() > 1) {
double a {stack[stack.size() - 1]} ;
double b {stack[stack.size() - 2]} ;
stack.pop_back() ;
stack.pop_back() ;
stack.emplace_back(a-b) ; }
}
void mul () {
if (stack.size() > 1) {
double a {stack[stack.size() - 1]} ;
double b {stack[stack.size() - 2]} ;
stack.pop_back() ;
stack.pop_back() ;
stack.emplace_back(a*b) ; }
}
void div () {
if (stack.size() > 1
&& !(stack[stack.size() - 1] == 0)
&& !(stack[stack.size() - 2] == 0)) {
double a {stack[stack.size() - 1]} ;
double b {stack[stack.size() - 2]} ;
stack.pop_back() ;
stack.pop_back() ;
stack.emplace_back(a/b) ; }
}
void mod () {
if (stack.size() > 1
&& !(stack[stack.size() - 1] == 0)
&& !(stack[stack.size() - 2] == 0)) {
double a {stack[stack.size() - 1]} ;
double b {stack[stack.size() - 2]} ;
stack.pop_back() ;
stack.pop_back() ;
stack.emplace_back(std::fmod(a,b)) ; }
}
void flr () {
if (stack.size() > 0) {
double a {stack[stack.size() - 1]} ;
stack.pop_back() ;
stack.emplace_back(std::floor(a)) ; }
}
void cei () {
if (stack.size() > 0) {
double a {stack[stack.size() - 1]} ;
stack.pop_back() ;
stack.emplace_back(std::ceil(a)) ; }
}
void abs () {
if (stack.size() > 0) {
double a {stack[stack.size() - 1]} ;
stack.pop_back() ;
stack.emplace_back(std::fabs(a)) ; }
}
void sqrt () {
if (stack.size() > 0
&& stack[stack.size() - 1] > 0) {
double a {stack[stack.size() - 1]} ;
stack.pop_back() ;
stack.emplace_back(std::sqrt(a)) ; }
}
void pow () {
if (stack.size() > 1
&& stack[stack.size() - 1] > 0) {
double a {stack[stack.size() - 1]} ;
double b {stack[stack.size() - 2]} ;
stack.pop_back() ;
stack.pop_back() ;
stack.emplace_back(std::pow(a, b)) ; }
}
void log () {
if (stack.size() > 0
&& stack[stack.size() - 1] > 0) {
double a {stack[stack.size() - 1]} ;
stack.pop_back() ;
stack.emplace_back(std::log(a)) ; }
}
void exp () {
if (stack.size() > 0) {
double a {stack[stack.size() - 1]} ;
stack.pop_back() ;
stack.emplace_back(std::exp(a)) ; }
}
void sin () {
if (stack.size() > 0) {
double a {stack[stack.size() - 1]} ;
stack.pop_back() ;
stack.emplace_back(std::sin(a)) ; }
}
void cos () {
if (stack.size() > 0) {
double a {stack[stack.size() - 1]} ;
stack.pop_back() ;
stack.emplace_back(std::cos(a)) ; }
}
void tan () {
if (stack.size() > 0) {
double a {stack[stack.size() - 1]} ;
stack.pop_back() ;
stack.emplace_back(std::tan(a)) ; }
}
double run (const std::vector<std::string> &program) {
double num ;
for (std::string_view instruction : program) {
if (instruction == "op_add") { add() ; }
else if (instruction == "op_sub") { sub() ; }
else if (instruction == "op_mul") { mul() ; }
else if (instruction == "op_div") { div() ; }
else if (instruction == "op_mod") { mod() ; }
else if (instruction == "op_flr") { flr() ; }
else if (instruction == "op_cei") { cei() ; }
else if (instruction == "op_abs") { abs() ; }
else if (instruction == "op_sqrt") { sqrt() ; }
else if (instruction == "op_pow") { pow() ; }
else if (instruction == "op_log") { log() ; }
else if (instruction == "op_exp") { exp() ; }
else if (instruction == "op_sin") { sin() ; }
else if (instruction == "op_cos") { cos() ; }
else if (instruction == "op_tan") { tan() ; }
else {
fast_float::from_chars(
instruction.data(),
instruction.data() +
instruction.size(),
num);
stack.emplace_back(num) ; }
}
if (stack.size()) {
return stack[stack.size() -1] ;
}
else {
return 0 ;
}
}
};
int main(int argc, char *argv[]) {
std::vector<std::string> program (argv + 1, argv + argc);
double solution ;
Machine machine ;
machine.stack.reserve(50) ;
solution = machine.run(program) ;
machine.stack.clear() ;
std::cout << solution << '\n' ;
return 0 ;
}
main()supposed to be double-spaced like that, or is it a problem of how you copied the code into your question? \$\endgroup\$