/**
   * Here Starts the code of a function according to the given function name that has the given
   * number of local variables.
   *
   * @param numberOfLocals The number of local variables
   */
  public void function(short numberOfLocals) throws ProgramException {

    short newSP = (short) (getSP() + numberOfLocals);
    checkSP(newSP);
    workingStackSegment.setStartAddress(newSP);

    // disable non relevant range of the local segment - enable only the number
    // of locals of this function.
    localSegment.setEnabledRange(getSP(), newSP - 1, true);

    for (int i = 0; i < numberOfLocals; i++) {
      pushValue(MAIN_STACK, (short) 0);
    }

    String functionName = currentInstruction.getStringArg();

    // adds the new function to the top of the call stack.
    callStack.pushFunction(functionName);

    // sets the static segment range
    setStaticRange(functionName);
  }
  /**
   * Executes the current instruction (Program at pc). Returns false if END command, true otherwise.
   */
  public void executeInstruction() throws ProgramException {
    currentInstruction = program.getNextInstruction();

    if (currentInstruction == null) throw new ProgramException("No more instructions to execute");

    switch (currentInstruction.getOpCode()) {
      case HVMInstructionSet.ADD_CODE:
        add();
        break;
      case HVMInstructionSet.SUBSTRACT_CODE:
        substract();
        break;
      case HVMInstructionSet.NEGATE_CODE:
        negate();
        break;
      case HVMInstructionSet.EQUAL_CODE:
        equal();
        break;
      case HVMInstructionSet.GREATER_THAN_CODE:
        greaterThan();
        break;
      case HVMInstructionSet.LESS_THAN_CODE:
        lessThan();
        break;
      case HVMInstructionSet.AND_CODE:
        and();
        break;
      case HVMInstructionSet.OR_CODE:
        or();
        break;
      case HVMInstructionSet.NOT_CODE:
        not();
        break;

      case HVMInstructionSet.PUSH_CODE:
        push(currentInstruction.getArg0(), currentInstruction.getArg1());
        break;
      case HVMInstructionSet.POP_CODE:
        pop(currentInstruction.getArg0(), currentInstruction.getArg1());
        break;

      case HVMInstructionSet.GOTO_CODE:
        goTo(currentInstruction.getArg0());
        break;
      case HVMInstructionSet.IF_GOTO_CODE:
        ifGoTo(currentInstruction.getArg0());
        break;

      case HVMInstructionSet.FUNCTION_CODE:
        if (program.getCurrentPC() == program.getPreviousPC() + 1)
          throw new ProgramException("Missing return in " + callStack.getTopFunction());

        function(currentInstruction.getArg0());
        break;
      case HVMInstructionSet.RETURN_CODE:
        returnFromFunction();
        break;
      case HVMInstructionSet.CALL_CODE:
        callFunction(
            currentInstruction.getArg0(),
            currentInstruction.getArg1(),
            currentInstruction.getStringArg(),
            false);
        break;
    }
  }