#include <stdio.h>
#include <stdlib.h>

#define TOP_LEVEL_BEGIN_OP  0  
#define FUNCTION_PROC_BEGIN_OP  1  
#define FUNCTION_END_OP  2  
#define PROC_END_OP  3  
#define FRAME_OFFSET_OP  4  
#define STACK_REF_OP  5  
#define STACK_SET_OP  6  
#define PUSH_OP  7  
#define POP_OP  8  
#define ADD_OP  9  
#define SUB_OP  10  
#define MUL_OP  11  
#define DIV_OP  12  
#define MOD_OP  13  
#define ABS_OP  14  
#define NEGATE_OP  15  
#define SHL_OP  16  
#define SHR_OP  17  
#define BITOR_OP  18  
#define BITAND_OP  19  
#define BITNOT_OP  20  
#define BTR_OP  21  
#define BFL_OP  22  
#define BR_OP  23  
#define EQ_OP  24  
#define LT_OP  25  
#define GT_OP  26  
#define LE_OP  27  
#define GE_OP  28  
#define NE_OP  29  
#define NOT_OP  30  
#define AND_OP  31  
#define OR_OP  32  
#define CALL_OP  33  
#define RETURN_OP  34  
#define READ_CHAR_OP  35  
#define EOF_OBJECT_OP  36  
#define DISPLAY_OP  37  
#define NEWLINE_OP  38  
#define HALT_OP  39  
#define WRITE_CHAR_OP  40  
#define BRTABLE_OP  41  
#define STACK_REF_N_OP  42  
#define STACK_SET_N_OP  43  
#define WRITE_STRING_OP  44  
#define BITXOR_OP  45  

  int stack[21000000];
  int code[50000];
  int return_stack[50000];

  int ch;

// routines made primitive for use by javascript
// they will be optimized as inline functions in the case of seqwint

int __mult(int x, int y) {
  return x * y;
}

int __div(int x, int y) {
  return x / y;
}

// primitive io functions

void my_putchar(int ch) {
  ch = ch & 0xff;
  putchar(ch);
  return;
}

int my_fgetc() {
  return getchar();
}

void read_char_() {
  if (ch == -1)
    return;
  else {
    ch = my_fgetc();
    return;
  }
}

void skip_blanks() {
  while (ch == ' ' || ch == '\n' || ch == 13)
    ch = my_fgetc();
  return;
}

int my_scan_int() {
  int sum;
  int negative;

  sum = 0; // initialize sum
  negative = 0; // initialize sign as positive

  skip_blanks();

  if (ch == '-') { // '-'
    negative = 1;
    read_char_();
  }

  while (ch >= '0' && ch <= '9') {
    sum = __mult(sum, 10) + ch - '0';
    read_char_();
  }

  if (negative == 1)
    sum = - sum;
  return sum;
}

int main() {
  int idx;
  int word;
  int pc;
  int opcode;
  int stack_idx;
  int frame_start;
  int return_stack_idx;
  int val;
  int cc;
  int n;
  int formals_offset;
  int all_vars_size;
  int dynamic_link;
  int temp;
  int temp2;
  int temp3;
  int count;
  int done_displaying_int;
  int eof_reached;

// JS // this has to be done for the javascript version
// JS for (idx = 0; idx < 21000000; idx++)
// JS   stack[idx] = 0;

  ch = ' ';

  stack_idx = 1;
  return_stack_idx = 0;
  eof_reached = 0;

  frame_start = 0; // java needs this

  temp = my_scan_int(); // number of code words
  for (idx = 0; idx < temp; idx++) {
    word = my_scan_int();
    code[idx] = word;
  }

  pc = 0;
  opcode = code[pc];
  while (1) {
//temp = opcode;
//printf("%d", temp);
//my_putchar(10);
  switch (opcode) {
  case TOP_LEVEL_BEGIN_OP :
    frame_start = code[pc + 1];
    stack_idx = frame_start + code[pc + 2];
    pc = pc + 3;
    opcode = code[pc];
    break;
  case FUNCTION_PROC_BEGIN_OP :
    formals_offset = code[pc + 1];
    all_vars_size = code[pc + 2];
    dynamic_link = code[pc + 3];
    temp = frame_start;
    frame_start = stack_idx - formals_offset;
    stack_idx = frame_start + all_vars_size;
    stack[frame_start + dynamic_link] = temp;
    pc = pc + 4;
    opcode = code[pc];
    break;
  case FUNCTION_END_OP :
//  _return = code[pc + 1];
    // zero offset. return value clobbers first input arg at return
    dynamic_link = code[pc + 1];
    temp = stack[frame_start];
    stack_idx = frame_start;
    frame_start = stack[frame_start + dynamic_link];
    stack[stack_idx] = temp; // push(temp)
    stack_idx = stack_idx + 1;
    pc = pc + 2;
    opcode = code[pc];
    break;
  case PROC_END_OP :
    dynamic_link = code[pc + 1];
    stack_idx = frame_start;
    frame_start = stack[frame_start + dynamic_link];
    pc = pc + 2;
    opcode = code[pc];
    break;
  case FRAME_OFFSET_OP :
    stack[stack_idx] = frame_start + code[pc + 1];
    stack_idx = stack_idx + 1;
    pc = pc + 2;
    opcode = code[pc];
    break;
  case STACK_REF_OP :
    temp = stack_idx - 1;
    stack[temp] = stack[stack[temp]];
    pc = pc + 1;
    opcode = code[pc];
    break;
  case STACK_SET_OP :
    temp = stack_idx - 2;
    stack[stack[stack_idx - 1]] = stack[temp];
    stack_idx = temp;
    pc = pc + 1;
    opcode = code[pc];
    break;
  case PUSH_OP :
    stack[stack_idx] = code[pc + 1];
    stack_idx = stack_idx + 1;
    pc = pc + 2;
    opcode = code[pc];
    break;
  case POP_OP :
    stack_idx = stack_idx - 1;
    pc = pc + 1;
    opcode = code[pc];
    break;
  case ADD_OP :
    temp = stack_idx - 2;
    temp2 = stack_idx - 1;
    stack[temp] = stack[temp2] + stack[temp];
    stack_idx = temp2;
    pc = pc + 1;
    opcode = code[pc];
    break;
  case SUB_OP :
    temp = stack_idx - 2;
    temp2 = stack_idx - 1;
    stack[temp] = stack[temp2] - stack[temp];
    stack_idx = temp2;
    pc = pc + 1;
    opcode = code[pc];
    break;
  case MUL_OP :
    temp = stack_idx - 2;
    temp2 = stack_idx - 1;
    stack[temp] =
      __mult(stack[temp2], stack[temp]);
    stack_idx = temp2;
    pc = pc + 1;
    opcode = code[pc];
    break;
  case DIV_OP :
    temp = stack_idx - 2;
    temp2 = stack_idx - 1;
    stack[temp] =
      __div(stack[temp2], stack[temp]);
    stack_idx = temp2;
    pc = pc + 1;
    opcode = code[pc];
    break;
  case MOD_OP :
    temp = stack_idx - 2;
    temp2 = stack_idx - 1;
    stack[temp] = stack[temp2] % stack[temp];
    stack_idx = temp2;
    pc = pc + 1;
    opcode = code[pc];
    break;
  case ABS_OP :
    temp = stack_idx - 1;
    stack[temp] = abs(stack[temp]);
    pc = pc + 1;
    opcode = code[pc];
    break;
  case NEGATE_OP :
// JJS if (stack[stack_idx - 1] != -2147483648)) // TODO resolve
    temp = stack_idx - 1;
    stack[temp] = -stack[temp];
    pc = pc + 1;
    opcode = code[pc];
    break;
  case SHL_OP :
    temp = stack_idx - 2;
    temp2 = stack_idx - 1;
    stack[temp] = stack[temp2] << stack[temp];
    stack_idx = temp2;
    pc = pc + 1;
    opcode = code[pc];
    break;
  case SHR_OP :
    temp = stack_idx - 2;
    temp2 = stack_idx - 1;
    stack[temp] = stack[temp2] >> stack[temp];
    stack_idx = temp2;
    pc = pc + 1;
    opcode = code[pc];
    break;
  case BITOR_OP :
    temp = stack_idx - 2;
    temp2 = stack_idx - 1;
    stack[temp] = stack[temp2] | stack[temp];
    stack_idx = temp2;
    pc = pc + 1;
    opcode = code[pc];
    break;
  case BITAND_OP :
    temp = stack_idx - 2;
    temp2 = stack_idx - 1;
    stack[temp] = stack[temp2] & stack[temp];
    stack_idx = temp2;
    pc = pc + 1;
    opcode = code[pc];
    break;
  case BITNOT_OP :
    temp = stack_idx - 1;
    stack[temp] = ~(stack[temp]);
    pc = pc + 1;
    opcode = code[pc];
    break;
  case BTR_OP :
    temp = stack_idx - 1;
    cc = stack[temp];
    stack_idx = temp;
    if (cc != 0)
      pc = code[pc + 1];
    else
      pc = pc + 2;
    opcode = code[pc];
    break;
  case BFL_OP :
    temp = stack_idx - 1;
    cc = stack[temp];
    stack_idx = temp;
    if (cc == 0)
      pc = code[pc + 1];
    else
      pc = pc + 2;
    opcode = code[pc];
    break;
  case BR_OP :
    pc = code[pc + 1];
    opcode = code[pc];
    break;
  case EQ_OP :
    temp = stack_idx - 2;
    temp2 = stack_idx - 1;
    if (stack[temp2] == stack[temp])
      stack[temp] = 1;
    else
      stack[temp] = 0;
    stack_idx = temp2;
    pc = pc + 1;
    opcode = code[pc];
    break;
  case LT_OP :
    temp = stack_idx - 2;
    temp2 = stack_idx - 1;
    if (stack[temp2] < stack[temp])
      stack[temp] = 1;
    else
      stack[temp] = 0;
    stack_idx = temp2;
    pc = pc + 1;
    opcode = code[pc];
    break;
  case GT_OP :
    temp = stack_idx - 2;
    temp2 = stack_idx - 1;
    if (stack[temp2] > stack[temp])
      stack[temp] = 1;
    else
      stack[temp] = 0;
    stack_idx = temp2;
    pc = pc + 1;
    opcode = code[pc];
    break;
  case LE_OP :
    temp = stack_idx - 2;
    temp2 = stack_idx - 1;
    if (stack[temp2] <= stack[temp])
      stack[temp] = 1;
    else
      stack[temp] = 0;
    stack_idx = temp2;
    pc = pc + 1;
    opcode = code[pc];
    break;
  case GE_OP :
    temp = stack_idx - 2;
    temp2 = stack_idx - 1;
    if (stack[temp2] >= stack[temp])
      stack[temp] = 1;
    else
      stack[temp] = 0;
    stack_idx = temp2;
    pc = pc + 1;
    opcode = code[pc];
    break;
  case NE_OP :
    temp = stack_idx - 2;
    temp2 = stack_idx - 1;
    if (stack[temp2] != stack[temp])
      stack[temp] = 1;
    else
      stack[temp] = 0;
    stack_idx = temp2;
    pc = pc + 1;
    opcode = code[pc];
    break;
  case NOT_OP :
    temp = stack_idx - 1;
    stack[temp] = (~stack[temp]) & 1;
    pc = pc + 1;
    opcode = code[pc];
    break;
  case AND_OP :
    temp = stack_idx - 2;
    temp2 = stack_idx - 1;
    stack[temp] = stack[temp2] & stack[temp];
    stack_idx = temp2;
    pc = pc + 1;
    opcode = code[pc];
    break;
  case OR_OP :
    temp = stack_idx - 2;
    temp2 = stack_idx - 1;
    stack[temp] = stack[temp2] | stack[temp];
    stack_idx = temp2;
    pc = pc + 1;
    opcode = code[pc];
    break;
  case CALL_OP :
    return_stack[return_stack_idx] = pc + 2;
    pc = code[pc + 1];
    return_stack_idx = return_stack_idx + 1;
    if (return_stack_idx == 50000) {
      printf("stack overflow");
      my_putchar(10);
      exit(0);
    }
    opcode = code[pc];
    break;
  case RETURN_OP :
    pc = return_stack[return_stack_idx - 1];
    return_stack_idx = return_stack_idx - 1;
    opcode = code[pc];
    break;
  case READ_CHAR_OP :
    val = 0;
    if (eof_reached == 0) {
      val = my_fgetc();
      if (val == -1)
        eof_reached = 1;
      else
        val = val & 0xff;
    }
    stack[stack_idx] = val;
    stack_idx = stack_idx + 1;
    pc = pc + 1;
    opcode = code[pc];
    break;
  case EOF_OBJECT_OP :
    if (eof_reached == 1)
      stack[stack_idx] = 1;
    else
      stack[stack_idx] = 0;
    stack_idx = stack_idx + 1;
    pc = pc + 1;
    opcode = code[pc];
    break;
  case DISPLAY_OP :
    temp = stack[stack_idx - 1];
  //write_int();
    done_displaying_int = 0;
    if (temp < 0) {
      my_putchar(45); // '-'
      // have to do following gyrations to support riscv
      if (((temp & 65535) == 0) && ((temp >> 16) == -32768)) { // -2147483648
        // printf("2147483648");
        stack[stack_idx] = '8';
        stack_idx = stack_idx + 1;
        stack[stack_idx] = '4';
        stack_idx = stack_idx + 1;
        stack[stack_idx] = '6';
        stack_idx = stack_idx + 1;
        stack[stack_idx] = '3';
        stack_idx = stack_idx + 1;
        stack[stack_idx] = '8';
        stack_idx = stack_idx + 1;
        stack[stack_idx] = '4';
        stack_idx = stack_idx + 1;
        stack[stack_idx] = '7';
        stack_idx = stack_idx + 1;
        stack[stack_idx] = '4';
        stack_idx = stack_idx + 1;
        stack[stack_idx] = '1';
        stack_idx = stack_idx + 1;
        stack[stack_idx] = '2';
        stack_idx = stack_idx + 1;
        count = 10;
      //write_char_n(); // write count digits from the stack
        for (temp = 0; temp < count; temp++) {
          my_putchar(stack[stack_idx - 1]);
          stack_idx = stack_idx - 1;
        }
        done_displaying_int = 1;
      }
      if (!done_displaying_int)
        temp = - temp;
    }
    if (!done_displaying_int) {
      count = 0; // count digits
      do {
        stack[stack_idx] = temp % 10 + '0';
        temp = __div(temp, 10);
        stack_idx = stack_idx + 1;
        count = count + 1;
      }
      while (temp != 0);
    //write_char_n(); // write count digits from the stack
      for (temp = 0; temp < count; temp++) {
        my_putchar(stack[stack_idx - 1]);
        stack_idx = stack_idx - 1;
      }
    }
    stack_idx = stack_idx - 1;
    pc = pc + 1;
    opcode = code[pc];
    break;
  case NEWLINE_OP :
    my_putchar(10);
    pc = pc + 1;
    opcode = code[pc];
    break;
  case HALT_OP :
    exit(0);
    break;
  case WRITE_CHAR_OP :
    temp = stack_idx - 1;
    my_putchar(stack[temp]);
    stack_idx = temp;
    pc = pc + 1;
    opcode = code[pc];
    break;
  case BRTABLE_OP :
    temp = stack_idx - 1;
    n = stack[temp];
    stack_idx = temp;
    pc = code[pc + n + 1];
    opcode = code[pc];
    break;
  case STACK_REF_N_OP :
    stack[stack_idx] = stack[frame_start + code[pc + 1]];
    stack_idx = stack_idx + 1;
    pc = pc + 2;
    opcode = code[pc];
    break;
  case STACK_SET_N_OP :
    stack[frame_start + code[pc + 1]] = stack[stack_idx - 1];
    stack_idx = stack_idx - 1;
    pc = pc + 2;
    opcode = code[pc];
    break;
  case WRITE_STRING_OP :
  //write_string
    pc = pc + 1;
    count = code[pc];
    temp2 = 0;
    pc = pc + 1;
    while (temp2 < (count - 2)) {
      temp3 = code[pc];
      my_putchar(temp3 & 0xff);
      my_putchar((temp3 >> 8) & 0xff);
      temp2 = temp2 + 2;
      pc = pc + 1;
    }
    // process last word separately because of odd even last bytes
    temp3 = code[pc];
    my_putchar(temp3 & 0xff);
    if ((count & 1) == 0) // even
      my_putchar((temp3 >> 8) & 0xff);
    pc = pc + 1;
    opcode = code[pc];
    break;
  case BITXOR_OP :
    temp = stack_idx - 2;
    temp2 = stack_idx - 1;
    stack[temp] = stack[temp2] ^ stack[temp];
    stack_idx = temp2;
    pc = pc + 1;
    opcode = code[pc];
    break;

  } // switch
  } // while

  return 0;

}
