// Path: src/chap13/Opcode.java
// public class Opcode {
//     public static final byte ICONST = 1;    // load an integer
//     public static final byte BCONST = 2;    // load an 8bit (1byte) integer
//     public static final byte SCONST = 3;    // load a character string
//     public static final byte MOVE = 4;      // move a value
//     public static final byte GMOVE = 5;     // move a value (global variable)
//     public static final byte IFZERO = 6;    // branch if false
//     public static final byte GOTO = 7;      // always branch
//     public static final byte CALL = 8;      // call a function
//     public static final byte RETURN = 9;    // return
//     public static final byte SAVE = 10;     // save all registers
//     public static final byte RESTORE = 11;  // restore all registers
//     public static final byte NEG = 12;      // arithmetic negation
//     public static final byte ADD = 13;      // add
//     public static final byte SUB = 14;      // subtract
//     public static final byte MUL = 15;      // multiply
//     public static final byte DIV = 16;      // divide
//     public static final byte REM = 17;      // remainder
//     public static final byte EQUAL = 18;    // equal
//     public static final byte MORE = 19;     // more than
//     public static final byte LESS = 20;     // less than
// 
//     public static byte encodeRegister(int reg) {
//         if (reg > StoneVM.NUM_OF_REG)
//             throw new StoneException("too many registers required");
//         else
//             return (byte)-(reg + 1);
//     } 
//     public static int decodeRegister(byte operand) { return -1 - operand; }
//     public static byte encodeOffset(int offset) {
//         if (offset > Byte.MAX_VALUE)
//             throw new StoneException("too big byte offset");
//         else
//             return (byte)offset;
//     }
//     public static short encodeShortOffset(int offset) {
//         if (offset < Short.MIN_VALUE || Short.MAX_VALUE < offset)
//             throw new StoneException("too big short offset");
//         else
//             return (short)offset;
//     }
//     public static int decodeOffset(byte operand) { return operand; }
//     public static boolean isRegister(byte operand) { return operand < 0; }
//     public static boolean isOffset(byte operand) { return operand >= 0; }
// }
// 
// Path: src/chap8/NativeFunction.java
// public class NativeFunction {
//     protected Method method;
//     protected String name;
//     protected int numParams;
//     public NativeFunction(String n, Method m) {
//         name = n;
//         method = m;
//         numParams = m.getParameterTypes().length;
//     }
//     @Override public String toString() { return "<native:" + hashCode() + ">"; }
//     public int numOfParameters() { return numParams; } 
//     public Object invoke(Object[] args, ASTree tree) {
//         try {
//             return method.invoke(null, args);
//         } catch (Exception e) {
//             throw new StoneException("bad native function call: " + name, tree);
//         }
//     }
// }
// 
// Path: src/stone/StoneException.java
// public class StoneException extends RuntimeException {
//     public StoneException(String m) { super(m); }
//     public StoneException(String m, ASTree t) {
//         super(m + " " + t.location());
//     }
// }
// 
// Path: src/stone/ast/ASTree.java
// public abstract class ASTree implements Iterable<ASTree> {
//     public abstract ASTree child(int i);
//     public abstract int numChildren();
//     public abstract Iterator<ASTree> children();
//     public abstract String location();
//     public Iterator<ASTree> iterator() { return children(); }
// }
// 
// Path: src/stone/ast/ASTList.java
// public class ASTList extends ASTree {
//     protected List<ASTree> children;
//     public ASTList(List<ASTree> list) { children = list; }
//     public ASTree child(int i) { return children.get(i); }
//     public int numChildren() { return children.size(); }
//     public Iterator<ASTree> children() { return children.iterator(); }
//     public String toString() {
//         StringBuilder builder = new StringBuilder();
//         builder.append('(');
//         String sep = "";
//         for (ASTree t: children) {
//             builder.append(sep);
//             sep = " ";
//             builder.append(t.toString());
//         }
//         return builder.append(')').toString();
//     }
//     public String location() {
//         for (ASTree t: children) {
//             String s = t.location();
//             if (s != null)
//                 return s;
//         }
//         return null;
//     }
// }


import static chap13.Opcode.*;
import chap8.NativeFunction;
import stone.StoneException;
import stone.ast.ASTree;
import stone.ast.ASTList;
import java.util.ArrayList;
            break;
        case IFZERO : {
            Object value = registers[decodeRegister(code[pc + 1])];
            if (value instanceof Integer && ((Integer)value).intValue() == 0)
                pc += readShort(code, pc + 2);
            else
                pc += 4;
            break;
        }
        case GOTO :
            pc += readShort(code, pc + 1);
            break;
        case CALL :
            callFunction();
            break;
        case RETURN :
            pc = ret;
            break;
        case SAVE :
            saveRegisters();
            break;
        case RESTORE :
            restoreRegisters();
            break;
        case NEG : {
            int reg = decodeRegister(code[pc + 1]);
            Object v = registers[reg];
            if (v instanceof Integer)
                registers[reg] = -((Integer)v).intValue();
            else
// Path: src/chap13/Opcode.java
// public class Opcode {
//     public static final byte ICONST = 1;    // load an integer
//     public static final byte BCONST = 2;    // load an 8bit (1byte) integer
//     public static final byte SCONST = 3;    // load a character string
//     public static final byte MOVE = 4;      // move a value
//     public static final byte GMOVE = 5;     // move a value (global variable)
//     public static final byte IFZERO = 6;    // branch if false
//     public static final byte GOTO = 7;      // always branch
//     public static final byte CALL = 8;      // call a function
//     public static final byte RETURN = 9;    // return
//     public static final byte SAVE = 10;     // save all registers
//     public static final byte RESTORE = 11;  // restore all registers
//     public static final byte NEG = 12;      // arithmetic negation
//     public static final byte ADD = 13;      // add
//     public static final byte SUB = 14;      // subtract
//     public static final byte MUL = 15;      // multiply
//     public static final byte DIV = 16;      // divide
//     public static final byte REM = 17;      // remainder
//     public static final byte EQUAL = 18;    // equal
//     public static final byte MORE = 19;     // more than
//     public static final byte LESS = 20;     // less than
// 
//     public static byte encodeRegister(int reg) {
//         if (reg > StoneVM.NUM_OF_REG)
//             throw new StoneException("too many registers required");
//         else
//             return (byte)-(reg + 1);
//     } 
//     public static int decodeRegister(byte operand) { return -1 - operand; }
//     public static byte encodeOffset(int offset) {
//         if (offset > Byte.MAX_VALUE)
//             throw new StoneException("too big byte offset");
//         else
//             return (byte)offset;
//     }
//     public static short encodeShortOffset(int offset) {
//         if (offset < Short.MIN_VALUE || Short.MAX_VALUE < offset)
//             throw new StoneException("too big short offset");
//         else
//             return (short)offset;
//     }
//     public static int decodeOffset(byte operand) { return operand; }
//     public static boolean isRegister(byte operand) { return operand < 0; }
//     public static boolean isOffset(byte operand) { return operand >= 0; }
// }
// 
// Path: src/chap8/NativeFunction.java
// public class NativeFunction {
//     protected Method method;
//     protected String name;
//     protected int numParams;
//     public NativeFunction(String n, Method m) {
//         name = n;
//         method = m;
//         numParams = m.getParameterTypes().length;
//     }
//     @Override public String toString() { return "<native:" + hashCode() + ">"; }
//     public int numOfParameters() { return numParams; } 
//     public Object invoke(Object[] args, ASTree tree) {
//         try {
//             return method.invoke(null, args);
//         } catch (Exception e) {
//             throw new StoneException("bad native function call: " + name, tree);
//         }
//     }
// }
// 
// Path: src/stone/StoneException.java
// public class StoneException extends RuntimeException {
//     public StoneException(String m) { super(m); }
//     public StoneException(String m, ASTree t) {
//         super(m + " " + t.location());
//     }
// }
// 
// Path: src/stone/ast/ASTree.java
// public abstract class ASTree implements Iterable<ASTree> {
//     public abstract ASTree child(int i);
//     public abstract int numChildren();
//     public abstract Iterator<ASTree> children();
//     public abstract String location();
//     public Iterator<ASTree> iterator() { return children(); }
// }
// 
// Path: src/stone/ast/ASTList.java
// public class ASTList extends ASTree {
//     protected List<ASTree> children;
//     public ASTList(List<ASTree> list) { children = list; }
//     public ASTree child(int i) { return children.get(i); }
//     public int numChildren() { return children.size(); }
//     public Iterator<ASTree> children() { return children.iterator(); }
//     public String toString() {
//         StringBuilder builder = new StringBuilder();
//         builder.append('(');
//         String sep = "";
//         for (ASTree t: children) {
//             builder.append(sep);
//             sep = " ";
//             builder.append(t.toString());
//         }
//         return builder.append(')').toString();
//     }
//     public String location() {
//         for (ASTree t: children) {
//             String s = t.location();
//             if (s != null)
//                 return s;
//         }
//         return null;
//     }
// }


// Path: src/chap13/StoneVM.java
import static chap13.Opcode.*;
import chap8.NativeFunction;
import stone.StoneException;
import stone.ast.ASTree;
import stone.ast.ASTList;
import java.util.ArrayList;

            break;
        case IFZERO : {
            Object value = registers[decodeRegister(code[pc + 1])];
            if (value instanceof Integer && ((Integer)value).intValue() == 0)
                pc += readShort(code, pc + 2);
            else
                pc += 4;
            break;
        }
        case GOTO :
            pc += readShort(code, pc + 1);
            break;
        case CALL :
            callFunction();
            break;
        case RETURN :
            pc = ret;
            break;
        case SAVE :
            saveRegisters();
            break;
        case RESTORE :
            restoreRegisters();
            break;
        case NEG : {
            int reg = decodeRegister(code[pc + 1]);
            Object v = registers[reg];
            if (v instanceof Integer)
                registers[reg] = -((Integer)v).intValue();
            else
                throw new StoneException("bad operand value");