Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

Im working on a JVM it very basic and am writing it in c++ Im getting 2 errors 1

ID: 3834709 • Letter: I

Question

Im working on a JVM it very basic and am writing it in c++

Im getting 2 errors

1)undefined reference to 'Machine::Machine(std::istream&)'

2)undefined reference to 'Machine::run()'

Below is my source code, i havent been able to check my implementation if some functions are correct since i cant get the program to compile. I'm stuck on the errors. If you could look at the errors, functions in machine.cpp with //TODO: Implement me! by them, and my implementation of stack. Some other oddities inlcude String and Vector, i have to write implementations for them but am using standard library for them in the time being, i want to get it working then add them after, using Stringg = std:string; and using Vector = std::vector<T>.

main.cpp

#include "machine.hpp"

#include <iostream>
#include <fstream>
#include <sstream>


int
main(int argc, char* argv[])
{
if (argc < 2) {
std::cerr << "error: vm input-file";
return 1;
}

std::ifstream ifs(argv[1]);
Machine vm(ifs);
vm.run();

return 0;
}

machine.hpp

#include "string.hpp"
#include "vector.hpp"
#include "stack.hpp"
#include "memory.hpp"


/*
// to replace vector.hpp and string.hpp
using String = std::string;
template<typename T>
using Vector = std::vector<T>;
*/

// Operation codes. These represent operations that can be executed
// by the virtual machine.
enum
{
// Basic push/pop
push_op, // Push a constant operand
pop_op, // Pop an operand
copy_op, // Copy the top operand

// Arithmetic
add_op, // Add the top two operands
sub_op, // Subtract the top from the lower operands
mul_op, // Multiply the top two operands
div_op, // Divide the lower from the top
rem_op, // Remainder of lower divided by the top

// Misc.
print_op, // Pop the top value and print.
read_op, // Read a value, push it.
halt_op, // Stop executing
};


// Represents an instruction. Every instruction has an operation
// code (one of the values above), and an integer operand.
struct Instruction
{
Instruction(int o, int a)
: op(o), arg(a)
{ }

Instruction(int o)
: op(o)
{ }

int op;
int arg;
};


// Represents the virtual machine. Each machine instance contains
// the source code for a single program.
struct Machine
{
Machine(std::istream& );

void run();

// Program control
Instruction fetch();

// Operand stack methods
int top() const;
void push(int);
int pop();

// Operations
void copy();
void add();
void sub();
void mul();
void div();
void rem();
void print();
void read();
void halt();

Vector<Instruction> prog; // A loaded program
Stack<int> stack; // The operand stack

// Registers
int pc;
};

machine.cpp

#include "machine.hpp"

#include <map>
#include <iostream>
#include <sstream>
#include <fstream>


// Returns the op code found in the first n characters of s. Throws an
// exception if the operation name is invalid.
static int
get_op(String const& s)
{
// A lookup table that maps from strings to opcodes.
static std::map<String, int> ops {
{"push", push_op},
{"pop", pop_op},
{"copy", copy_op},
{"add", add_op},
{"sub", sub_op},
{"mul", mul_op},
{"div", div_op},
{"rem", rem_op},
{"print", print_op},
{"read", read_op},
{"halt", halt_op},
};

auto iter = ops.find(s);
if (iter == ops.end()) {
String msg = "no such opcode '" + s + "'";
throw std::runtime_error(msg);
}
return iter->second;
}

//found online
//stoi wouldnt work so i found the code for an of equivalent stoi
int stringToInterger(const String &text)
{
std::istringstream ss(text);
int result;
return ss >> result ? result : 0;
}
int
get_arg(String const& s)
{
if (s.empty())
return 0;
else
return stringToInterger(s);
}


Machine::Machine(std::istream& is)
{
// Parse instructions from input.
while (is) {
String s;
getline(is, s);
if (!is)
break;

// Search for a ';', indicating a comment and strip that from the line.
std::size_t k = s.find(';');
if (k != String::npos)
s = s.substr(0, k);

// Skip empty lines.
if (s.empty())
continue;

// Parse out the opcode and operand.
std::stringstream ss(s);
std::string opstr, argstr;
ss >> opstr >> argstr;

int op = get_op(opstr);
int arg = get_arg(argstr);
Instruction ins(op, arg);
prog.push_back(ins);
}
}


void Machine::run()
{
// Start the pc at the first instruction.
pc = 0;

while (pc != prog.size()) {

// Get the next instruction.
Instruction ins = fetch();

// "Decode" and execute the instruction.
switch (ins.op) {
case push_op:
push(ins.arg);
break;
case pop_op:
pop();
break;
case copy_op:
copy();
break;
case add_op:
add();
break;
case sub_op:
sub();
break;
case mul_op:
mul();
break;
case div_op:
div();
break;
case rem_op:
rem();
break;
case print_op:
print();
break;
case read_op:
read();
break;
case halt_op:
halt();
break;
}
}
}


Instruction
Machine::fetch()
{
return prog[pc++];
}

// prog is the vector
//pc is the register- int
//stack is well the stack
//can use op and ar

//Most likely these arent right


//pre:none
//post: finds top of stack
int
Machine::top() const
{
if(pc == -1) //not possible
{
throw std::logic_error("not implemented");
}
else
{
return pc; //think should be prog[pc] but const is a problem

}
// TODO: Implement me!
//throw std::logic_error("not implemented");
}

//pre: int n
//post: pushes n onto stack
//push: Push the constant `n` onto the operand stack
void
Machine::push(int n)
{
if(pc == top()) //if the top reaches maximum stack size
{
throw std::logic_error("not implemented");
}
else
{
pc++;
prog[pc] = n;
}

// TODO: Implement me!
//throw std::logic_error("not implemented");
}


//pre: at least one thing on stack
//post: pops last on off stack
//pop: Pop the top operand on the stack, discarding it
int
Machine::pop()
{
if (pc == -1) //something is wrong if this happens
{
throw std::logic_error("not implemented");
}
pc--;

// TODO: Implement me!
//throw std::logic_error("not implemented");
}

//pre:needs a top operand
//post: pushes copy of top operand on the stack
//copy: Push a copy of the top operand on the stack
void
Machine::copy()
{
if (pc == -1) //something is wrong if this happens
{
throw std::logic_error("not implemented");
}
else
{
push(pc);
}
// TODO: Implement me!
//throw std::logic_error("not implemented");
}

//pre:at least 2 operands on stack
//post: adds two operands after they get popped off stack
//add: Pops two operands, pushes the result of adding the first to the second
void
Machine::add()
{
if (pc == -1) //something is wrong if this happens
{
throw std::logic_error("not implemented");
}
else
{
int sum;
sum = pop() + pop();
push(sum);
}
// TODO: Implement me!
//throw std::logic_error("not implemented");
}

//pre: at least 2 operands on stack
//post: subtracts two operands after they get popped off stack
// sub: Pops two operands, pushes the result of subtracting the first from the second
void
Machine::sub()
{
if (pc == -1) //something is wrong if this happens
{
throw std::logic_error("not implemented");
}
else
{
int difference;
difference = pop() - pop();
push(difference);
}
// TODO: Implement me!
//throw std::logic_error("not implemented");
}

//pre: at least 2 operands
//post: multiplies operands after they get popped off stack
// mul: Pops two operands, pushes the result of multiplying the second by the first
void
Machine::mul()
{
if (pc == -1) //something is wrong if this happens
{
throw std::logic_error("not implemented");
}
else
{
int product;
product = pop() * pop();
push(product);

}
// TODO: Implement me!
//throw std::logic_error("not implemented");
}

//pre: at least 2 operands
//post: divides operands after they are popped off
//div: Pops two operands, pushes the quotient of dividing the second by the first
void
Machine::div()
{
if (pc == -1) //something is wrong if this happens
{
throw std::logic_error("not implemented");
}
else
{
float quotient;
try
{
float int1;
float int2;
int1 = pop();
int2 = pop();
if (int2 == 0)
{
throw 0;
}
quotient = pop() / pop();
push(quotient);
}
catch(int x)
{
std::cerr << "Cant divide by zero" << std::endl;
}
}
// TODO: Implement me!
//throw std::logic_error("not implemented");
}

//pre: at least 2 operands
//post: finds remainder after operands are popped off stack
//rem: Pops two operands, pushes the remainder of dividing the second by the first
void
Machine::rem()
{
if (pc == -1) //something is wrong if this happens
{
throw std::logic_error("not implemented");
}
else
{
int remainder;
remainder = pop() % pop();
push(remainder);
}
// TODO: Implement me!
//throw std::logic_error("not implemented");
}

//ostream operator overloaded in string, may be simpler, if its done correctly
//pre:one operand on stack
//post: prints value to standard output
// print: Pops one operand, prints the value to standard outpu
void
Machine::print()
{
if (pc == -1) //something is wrong if this happens
{
throw std::logic_error("not implemented");
}
else
{
for(int i = 0; i < pc; i++)
{
i = pop();
std::cout << i << " ";
}
std::cout<<" ";
}
// TODO: Implement me!
//throw std::logic_error("not implemented");
}

//pre: none
//post: read from standard input and push onto stack
//read: Read one value from standard input, push it on the stac
void
Machine::read()
{
std::cin >> pc;
if (std::cin.fail() ) //something is wrong if this happens
{
throw std::logic_error("not implemented");
}
else
{
push(pc);
}
// TODO: Implement me!
//throw std::logic_error("not implemented");
}

//pre: none
//post:sets pc to last instruction. stops machine
//halt: Sets the `pc` past the last instruction, causing the machine to stop
void
Machine::halt()
{
pc = prog.size();
}

stack.hpp

#include <stack>

// TODO: You *must* implement a stack.
template<typename T>
//using Stack = std::stack<T>; //shouldnt have to use
class Stack
{
public:
//default constructor
Stack() { }
//copy constructor
Stack(const Stack &s) {tops = -1; capcity = s; storage = new int[s];}
//copy assignment
Stack& operator=(const Stack&);

//destructor
~Stack() {delete[] storage;}

// member functions
bool empty();
int size();
void push_front(int);
void pop();
int top();


private:
int tops;
int capcity;
int *storage;

};

stack.cpp

#include "stack.hpp"
#include <iostream>

template <class T>
Stack<T>& Stack<T>::operator=(const Stack &rhs)
{
return *this;
}

//empty
// pre: none
// post: true is empty, false if something inside
template <class T>
bool Stack<T>::empty()
{
if (tops == 0){
return true;
}
else{
return false;
}
}

//size
// pre: none
// post: finds size of stack, not how much is can hold
template <class T>
int Stack<T>::size()
{
int count;
for(int i = 0; i < capcity; ++i)
{
if(pop() == storage[i])
{
count++;
}
}
return count;
}

//top()
template <class T>
int Stack<T>::top()
{
return storage[tops];
}

//front
template <class T>
void Stack<T>::push_front(int x)
{
if (tops == capcity)
{
std::cerr << "stackoverflow ";
}
storage[++tops] = x;

}

//pop
template <class T>
void Stack<T>::pop()
{
if(tops == -1)
{
return;
}
tops--;
}

Explanation / Answer

main.cpp

#include "machine.hpp"

#include <iostream>
#include <fstream>
#include <sstream>


int
main(int argc, char* argv[])
{
if (argc < 2) {
std::cerr << "error: vm input-file";
return 1;
}

std::ifstream ifs(argv[1]);
Machine vm(ifs);
vm.run();

return 0;
}

machine.hpp

#include "string.hpp"
#include "vector.hpp"
#include "stack.hpp"
#include "memory.hpp"


/*
// to replace vector.hpp and string.hpp
using String = std::string;
template<typename T>
using Vector = std::vector<T>;
*/

// Operation codes. These represent operations that can be executed
// by the virtual machine.
enum
{
// Basic push/pop
push_op, // Push a constant operand
pop_op, // Pop an operand
copy_op, // Copy the top operand

// Arithmetic
add_op, // Add the top two operands
sub_op, // Subtract the top from the lower operands
mul_op, // Multiply the top two operands
div_op, // Divide the lower from the top
rem_op, // Remainder of lower divided by the top

// Misc.
print_op, // Pop the top value and print.
read_op, // Read a value, push it.
halt_op, // Stop executing
};


// Represents an instruction. Every instruction has an operation
// code (one of the values above), and an integer operand.
struct Instruction
{
Instruction(int o, int a)
: op(o), arg(a)
{ }

Instruction(int o)
: op(o)
{ }

int op;
int arg;
};


// Represents the virtual machine. Each machine instance contains
// the source code for a single program.
struct Machine
{
Machine(std::istream& );

void run();

// Program control
Instruction fetch();

// Operand stack methods
int top() const;
void push(int);
int pop();

// Operations
void copy();
void add();
void sub();
void mul();
void div();
void rem();
void print();
void read();
void halt();

Vector<Instruction> prog; // A loaded program
Stack<int> stack; // The operand stack

// Registers
int pc;
};

machine.cpp

#include "machine.hpp"

#include <map>
#include <iostream>
#include <sstream>
#include <fstream>


// Returns the op code found in the first n characters of s. Throws an
// exception if the operation name is invalid.
static int
get_op(String const& s)
{
// A lookup table that maps from strings to opcodes.
static std::map<String, int> ops {
{"push", push_op},
{"pop", pop_op},
{"copy", copy_op},
{"add", add_op},
{"sub", sub_op},
{"mul", mul_op},
{"div", div_op},
{"rem", rem_op},
{"print", print_op},
{"read", read_op},
{"halt", halt_op},
};

auto iter = ops.find(s);
if (iter == ops.end()) {
String msg = "no such opcode '" + s + "'";
throw std::runtime_error(msg);
}
return iter->second;
}

//found online
//stoi wouldnt work so i found the code for an of equivalent stoi
int stringToInterger(const String &text)
{
std::istringstream ss(text);
int result;
return ss >> result ? result : 0;
}
int
get_arg(String const& s)
{
if (s.empty())
return 0;
else
return stringToInterger(s);
}


Machine::Machine(std::istream& is)
{
// Parse instructions from input.
while (is) {
String s;
getline(is, s);
if (!is)
break;

// Search for a ';', indicating a comment and strip that from the line.
std::size_t k = s.find(';');
if (k != String::npos)
s = s.substr(0, k);

// Skip empty lines.
if (s.empty())
continue;

// Parse out the opcode and operand.
std::stringstream ss(s);
std::string opstr, argstr;
ss >> opstr >> argstr;

int op = get_op(opstr);
int arg = get_arg(argstr);
Instruction ins(op, arg);
prog.push_back(ins);
}
}


void Machine::run()
{
// Start the pc at the first instruction.
pc = 0;

while (pc != prog.size()) {

// Get the next instruction.
Instruction ins = fetch();

// "Decode" and execute the instruction.
switch (ins.op) {
case push_op:
push(ins.arg);
break;
case pop_op:
pop();
break;
case copy_op:
copy();
break;
case add_op:
add();
break;
case sub_op:
sub();
break;
case mul_op:
mul();
break;
case div_op:
div();
break;
case rem_op:
rem();
break;
case print_op:
print();
break;
case read_op:
read();
break;
case halt_op:
halt();
break;
}
}
}


Instruction
Machine::fetch()
{
return prog[pc++];
}

// prog is the vector
//pc is the register- int
//stack is well the stack
//can use op and ar

//Most likely these arent right


//pre:none
//post: finds top of stack
int
Machine::top() const
{
if(pc == -1) //not possible
{
throw std::logic_error("not implemented");
}
else
{
return pc; //think should be prog[pc] but const is a problem

}
// TODO: Implement me!
//throw std::logic_error("not implemented");
}

//pre: int n
//post: pushes n onto stack
//push: Push the constant `n` onto the operand stack
void
Machine::push(int n)
{
if(pc == top()) //if the top reaches maximum stack size
{
throw std::logic_error("not implemented");
}
else
{
pc++;
prog[pc] = n;
}

// TODO: Implement me!
//throw std::logic_error("not implemented");
}


//pre: at least one thing on stack
//post: pops last on off stack
//pop: Pop the top operand on the stack, discarding it
int
Machine::pop()
{
if (pc == -1) //something is wrong if this happens
{
throw std::logic_error("not implemented");
}
pc--;

// TODO: Implement me!
//throw std::logic_error("not implemented");
}

//pre:needs a top operand
//post: pushes copy of top operand on the stack
//copy: Push a copy of the top operand on the stack
void
Machine::copy()
{
if (pc == -1) //something is wrong if this happens
{
throw std::logic_error("not implemented");
}
else
{
push(pc);
}
// TODO: Implement me!
//throw std::logic_error("not implemented");
}

//pre:at least 2 operands on stack
//post: adds two operands after they get popped off stack
//add: Pops two operands, pushes the result of adding the first to the second
void
Machine::add()
{
if (pc == -1) //something is wrong if this happens
{
throw std::logic_error("not implemented");
}
else
{
int sum;
sum = pop() + pop();
push(sum);
}
// TODO: Implement me!
//throw std::logic_error("not implemented");
}

//pre: at least 2 operands on stack
//post: subtracts two operands after they get popped off stack
// sub: Pops two operands, pushes the result of subtracting the first from the second
void
Machine::sub()
{
if (pc == -1) //something is wrong if this happens
{
throw std::logic_error("not implemented");
}
else
{
int difference;
difference = pop() - pop();
push(difference);
}
// TODO: Implement me!
//throw std::logic_error("not implemented");
}

//pre: at least 2 operands
//post: multiplies operands after they get popped off stack
// mul: Pops two operands, pushes the result of multiplying the second by the first
void
Machine::mul()
{
if (pc == -1) //something is wrong if this happens
{
throw std::logic_error("not implemented");
}
else
{
int product;
product = pop() * pop();
push(product);

}
// TODO: Implement me!
//throw std::logic_error("not implemented");
}

//pre: at least 2 operands
//post: divides operands after they are popped off
//div: Pops two operands, pushes the quotient of dividing the second by the first
void
Machine::div()
{
if (pc == -1) //something is wrong if this happens
{
throw std::logic_error("not implemented");
}
else
{
float quotient;
try
{
float int1;
float int2;
int1 = pop();
int2 = pop();
if (int2 == 0)
{
throw 0;
}
quotient = pop() / pop();
push(quotient);
}
catch(int x)
{
std::cerr << "Cant divide by zero" << std::endl;
}
}
// TODO: Implement me!
//throw std::logic_error("not implemented");
}

//pre: at least 2 operands
//post: finds remainder after operands are popped off stack
//rem: Pops two operands, pushes the remainder of dividing the second by the first
void
Machine::rem()
{
if (pc == -1) //something is wrong if this happens
{
throw std::logic_error("not implemented");
}
else
{
int remainder;
remainder = pop() % pop();
push(remainder);
}
// TODO: Implement me!
//throw std::logic_error("not implemented");
}

//ostream operator overloaded in string, may be simpler, if its done correctly
//pre:one operand on stack
//post: prints value to standard output
// print: Pops one operand, prints the value to standard outpu
void
Machine::print()
{
if (pc == -1) //something is wrong if this happens
{
throw std::logic_error("not implemented");
}
else
{
for(int i = 0; i < pc; i++)
{
i = pop();
std::cout << i << " ";
}
std::cout<<" ";
}
// TODO: Implement me!
//throw std::logic_error("not implemented");
}

//pre: none
//post: read from standard input and push onto stack
//read: Read one value from standard input, push it on the stac
void
Machine::read()
{
std::cin >> pc;
if (std::cin.fail() ) //something is wrong if this happens
{
throw std::logic_error("not implemented");
}
else
{
push(pc);
}
// TODO: Implement me!
//throw std::logic_error("not implemented");
}

//pre: none
//post:sets pc to last instruction. stops machine
//halt: Sets the `pc` past the last instruction, causing the machine to stop
void
Machine::halt()
{
pc = prog.size();
}

stack.hpp

#include <stack>

// TODO: You *must* implement a stack.
template<typename T>
//using Stack = std::stack<T>; //shouldnt have to use
class Stack
{
public:
//default constructor
Stack() { }
//copy constructor
Stack(const Stack &s) {tops = -1; capcity = s; storage = new int[s];}
//copy assignment
Stack& operator=(const Stack&);

//destructor
~Stack() {delete[] storage;}

// member functions
bool empty();
int size();
void push_front(int);
void pop();
int top();


private:
int tops;
int capcity;
int *storage;

};

stack.cpp

#include "stack.hpp"
#include <iostream>

template <class T>
Stack<T>& Stack<T>::operator=(const Stack &rhs)
{
return *this;
}

//empty
// pre: none
// post: true is empty, false if something inside
template <class T>
bool Stack<T>::empty()
{
if (tops == 0){
return true;
}
else{
return false;
}
}

//size
// pre: none
// post: finds size of stack, not how much is can hold
template <class T>
int Stack<T>::size()
{
int count;
for(int i = 0; i < capcity; ++i)
{
if(pop() == storage[i])
{
count++;
}
}
return count;
}

//top()
template <class T>
int Stack<T>::top()
{
return storage[tops];
}

//front
template <class T>
void Stack<T>::push_front(int x)
{
if (tops == capcity)
{
std::cerr << "stackoverflow ";
}
storage[++tops] = x;

}

//pop
template <class T>
void Stack<T>::pop()
{
if(tops == -1)
{
return;
}
tops--;
}