Stack-Based Virtual Machine in JavaScript
This challenge asks you to build a simplified stack-based virtual machine (VM) in JavaScript. Stack-based VMs operate by pushing values onto a stack and executing instructions that manipulate those values. This exercise will help you understand how VMs work at a fundamental level and practice your JavaScript coding skills.
Problem Description
You are to implement a basic stack-based VM that can execute a set of predefined instructions. The VM will receive a program as an array of instructions, where each instruction is a string. The instructions will operate on a stack, pushing and popping values as needed. Your VM should interpret these instructions and produce a final result, which will be the value remaining on the stack after all instructions have been executed.
Key Requirements:
- Stack: Implement a stack data structure to store values.
- Instruction Set: Support the following instructions:
PUSH <value>: Pushes the numerical value<value>onto the stack.ADD: Pops the top two values from the stack, adds them, and pushes the result back onto the stack.SUB: Pops the top two values from the stack, subtracts the second from the first, and pushes the result back onto the stack.MUL: Pops the top two values from the stack, multiplies them, and pushes the result back onto the stack.DIV: Pops the top two values from the stack, divides the first by the second, and pushes the result back onto the stack. Handle division by zero gracefully (see Edge Cases).PRINT: Prints the top value of the stack to the console (for debugging purposes - this value should not be popped).HALT: Stops execution of the program.
- Error Handling: Handle invalid instructions and insufficient values on the stack gracefully. Throw an
Errorwith a descriptive message in these cases. - Execution: Iterate through the instruction array, interpreting and executing each instruction.
Expected Behavior:
The VM should execute the provided program and leave a single value on the stack after the HALT instruction is encountered. This final value is the result of the program. If the program ends without a single value on the stack, or if an error occurs, the VM should throw an error.
Edge Cases to Consider:
- Division by Zero: If a
DIVinstruction is encountered and the second value popped from the stack is zero, throw anErrorwith the message "Division by zero". - Insufficient Values: If an arithmetic instruction (
ADD,SUB,MUL,DIV) is encountered and there are fewer than two values on the stack, throw anErrorwith the message "Insufficient values on stack". - Invalid Instruction: If an unknown instruction is encountered, throw an
Errorwith the message "Invalid instruction: [instruction]". - No HALT: If the program does not contain a
HALTinstruction, throw anErrorwith the message "Program did not halt". - Multiple Values at Halt: If the program halts but there are more than one value on the stack, throw an
Errorwith the message "Too many values on stack at halt".
Examples
Example 1:
Input: ["PUSH 5", "PUSH 3", "ADD", "HALT"]
Output: 8
Explanation: Pushes 5 and 3 onto the stack. Adds them (5 + 3 = 8) and pushes 8. HALT is encountered, and 8 is the final result.
Example 2:
Input: ["PUSH 10", "PUSH 2", "DIV", "HALT"]
Output: 5
Explanation: Pushes 10 and 2 onto the stack. Divides 10 by 2 (10 / 2 = 5) and pushes 5. HALT is encountered, and 5 is the final result.
Example 3:
Input: ["PUSH 7", "PUSH 4", "SUB", "PUSH 2", "MUL", "HALT"]
Output: 10
Explanation: Pushes 7 and 4. Subtracts 4 from 7 (7 - 4 = 3). Pushes 3. Pushes 2. Multiplies 3 by 2 (3 * 2 = 6). Pushes 6. HALT is encountered, and 6 is the final result.
Example 4 (Edge Case):
Input: ["PUSH 8", "PUSH 0", "DIV", "HALT"]
Output: Error: Division by zero
Explanation: Attempts to divide 8 by 0, triggering the division by zero error.
Constraints
- The input program will be an array of strings.
- Values pushed onto the stack will be integers.
- The program will contain at least one instruction.
- The program will contain a
HALTinstruction. - Instruction strings will be properly formatted (e.g., "PUSH 5", "ADD").
- The maximum length of the instruction array is 100.
Notes
- Consider using a helper function to parse instructions and extract their arguments.
- Think about how to represent the stack data structure efficiently.
- Focus on clear error handling and informative error messages.
- The
PRINTinstruction is primarily for debugging and should not affect the final result. It should not pop the value from the stack. - The order of operations is determined by the order of instructions in the program.
- This is a simplified VM; you don't need to implement complex features like variables or control flow. Focus on the core stack-based execution model.