C++ Project: Abstract VM
C++ Project: Abstract VM
Abstract VM
Summary: The purpose of this project is to create a simple virtual machine that can
interpret programs written in a basic assembly language.
Contents
I A Machine 2
II The project 3
II.1 The assembly language . . . . . . . . . . . . . . . . . . . . . . . . . . 3
II.1.1 Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
II.1.2 Description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
II.1.3 Grammar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
II.1.4 Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
II.1.5 Execution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
IV Bonus part 11
1
Chapter I
A Machine
A machine, virtual or not, has a specific architecture. The only real difference between
a virtual machine and a physical one is that the physical one uses real electronic compo-
nents, while a virtual one emulates them by using to a program.
A virtual machine is nothing more than a program that simulates a physical machine,
or another virtual machine. Nevertheless, it is clear that a virtual machine that emulates
a physical machine such as a desktop computer is a very advanced program that requires
an important programming experience as well as a very in-depth architectural knowledge.
For this project, requirements will be limited to a very simple virtual machine: it will
run some basic arithmetic programs coded in a very basic assembly language. If you want
to have an idea of what your program’s capabilities should look like, type the command
man dc in your shell.
The virtual machine we are describing has a classical architecture. However you may
wonder what a classical architecture is...
There is no easy answer to this question. It depends on the precision you want to
adopt, as well as the kind of problem you are looking at. Each "organ" of a machine can
be translated into a program or set of (more or less) complex functions. Moreover, this
complexity is linked to what your machine is used for in the end. Let’s look at memory
for instance. We do agree that the emulation complexity of a machine’s memory between
a virtual machine running an operating system, such as Linux or Windows, and a virtual
machine running a CoreWar is completely different !
Whatever decision you make, you really should have a look at these articles:
1. http://en.wikipedia.org/wiki/Central_processing_unit
2. http://en.wikipedia.org/wiki/Chipset
3. http://en.wikipedia.org/wiki/Computer_data_storage
4. http://en.wikipedia.org/wiki/Input/output
2
Chapter II
The project
3
C++ Project Abstract VM
II.1.2 Description
As for any assembly language, the language of AbstractVM is composed of a series of
instructions, with one instruction per line. However, AbstractVM’s assembly language
has a limited type system, which is a major difference from other real world assembly
languages.
• Comments: Comments start with a ’;’ and finish with a newline. A comment can
be either at the start of a line, or after an instruction.
• push v: Pushes the value v at the top of the stack. The value v must have one of
the following form:
• pop: Unstacks the value from the top of the stack. If the stack is empty, the
program execution must stop with an error.
• dump: Displays each value of the stack, from the most recent one to the oldest
one WITHOUT CHANGING the stack. Each value is separated from the next one
by a newline.
• assert v: Asserts that the value at the top of the stack is equal to the one passed
as parameter for this instruction. If it is not the case, the program execution must
stop with an error. The value v has the same form that those passed as parameters
to the instruction push.
• add: Unstacks the first two values on the stack, adds them together and stacks the
result. If the number of values on the stack is strictly inferior to 2, the program
execution must stop with an error.
• sub: Unstacks the first two values on the stack, subtracts them, then stacks the
result. If the number of values on the stack is strictly inferior to 2, the program
execution must stop with an error.
• mul: Unstacks the first two values on the stack, multiplies them, then stacks the
result. If the number of values on the stack is strictly inferior to 2, the program
execution must stop with an error.
4
C++ Project Abstract VM
• div: Unstacks the first two values on the stack, divides them, then stacks the result.
If the number of values on the stack is strictly inferior to 2, the program execution
must stop with an error. Moreover, if the divisor is equal to 0, the program execution
must stop with an error too. Chatting about floating point values is relevant a this
point. If you don’t understand why, some will understand. The linked question is
an open one, there’s no definitive answer.
• mod: Unstacks the first two values on the stack, calculates the modulus, then
stacks the result. If the number of values on the stack is strictly inferior to 2, the
program execution must stop with an error. Moreover, if the divisor is equal to 0,
the program execution must stop with an error too. Same note as above about fp
values.
• print: Asserts that the value at the top of the stack is an 8-bit integer. (If not,
see the instruction assert), then interprets it as an ASCII value and displays the
corresponding character on the standard output.
• exit: Terminate the execution of the current program. If this instruction does not
appears while all others instruction has been processed, the execution must stop
with an error.
When a computation involves two operands of different types, the value returned has
the type of the more precise operand. Please do note that because of the extensibility of
the machine, the precision question is not a trivial one. This is covered more in details
later in this document.
5
C++ Project Abstract VM
II.1.3 Grammar
The assembly language of AbstractVM is generated from the following grammar (# cor-
responds to the end of the input, not to the character ’#’):
II.1.4 Errors
When one of the following cases is encountered, AbstractVM must raise an exception
and stop the execution of the program cleanly. It is forbidden to raise scalar exceptions.
Moreover your exception classes must inherit from std::exception.
• The assembly program includes one or several lexical errors or syntactic errors.
• An instruction is unknown
• Overflow on a value
• Underflow on a value
• Instruction pop on an empty stack
• Division/modulo by 0
• The program doesn’t have an exit instruction
• An assert instruction is not true
• The stack is composed of strictly less that two values when an arithmetic instruction
is executed.
Perhaps there are more errors cases. However, you machine must never crash (segfault,
bus error, infinite loop, unhandled exception, ...).
6
C++ Project Abstract VM
II.1.5 Execution
Your machine must be able to run programs from a file passed as a parameter and from
the standard input. When reading from the standard input, the end of the program is
indicated by the special symbol ";;" otherwise absent.
1 $>cat sample.avm
2 ; -------------
3 ; sample.avm -
4 ; -------------
5
6 push int32(42)
7 push int32(33)
8 add
9 push float(44.55)
10 mul
11 push double(42.42)
12 push int32(42)
13 dump
14 pop
15 assert double(42.42)
16 exit
17 $>./avm ./sample.avm
18 42
19 42.42
20 3341.25
21 $>
1 $>./avm
2 pop
3 ;;
4 Line 1 : Error : Pop on empty stack
5 $>
7
Chapter III
Mandatory part
In order to help you with your project, we provide you with the following instructions
that you MUST respect.
8
C++ Project Abstract VM
Each one of these operand classes MUST implement the following IOperand interface:
class IOperand {
public:
virtual int getPrecision( void ) const = 0; // Precision of the type of the instance
virtual eOperandType getType( void ) const = 0; // Type of the instance
virtual IOperand const * operator+( IOperand const & rhs ) const = 0; // Sum
virtual IOperand const * operator-( IOperand const & rhs ) const = 0; // Difference
virtual IOperand const * operator*( IOperand const & rhs ) const = 0; // Product
virtual IOperand const * operator/( IOperand const & rhs ) const = 0; // Quotient
virtual IOperand const * operator%( IOperand const & rhs ) const = 0; // Modulo
virtual std::string const & toString( void ) const = 0; // String representation of the instance
};
9
C++ Project Abstract VM
IOperand const * createOperand( eOperandType type, std::string const & value ) const;
The eOperandType type is an enum defining the following values: Int8, Int16, Int32,
Float and Double.
Depending on the enum value passed as a parameter, the member function createOperand
creates a new IOperand by calling one of the following private member functions:
In order to choose the right member function for the creation of the new IOperand,
you MUST create and use an array (here, a vector shows little interest) of pointers on
member functions with enum values as index.
The pure method getPrecision from the interface IOperand allows to get the preci-
sion of an operand. When an operation uses two operands from two different types, the
comparison of theirs precisions allows to figure out the result type of the operation.
10
Chapter IV
Bonus part
Once you’re done with the mandatory part and sure you’ll get the maximum grade for
it, consider doing the following bonuses :
• Making your VM capable of diagnosing all errors in a file without stopping at the
first error encountered.
• Having a well structured lexer/parser couple, with clearly defined roles.
You can add some bonuses of your own creation if you like, but most of the bonus
points will be reserved for the above bonuses.
11