package com.atilika.kuromoji.fst.vm;

public class VirtualMachine {

    private boolean useCache;

    public VirtualMachine() {
        this.useCache = true;
    }

    public VirtualMachine(boolean useCache) {
        this.useCache = useCache;
    }

    public int run(Program program, String input) {
        int pc = program.size() - 1; // Compiled in a reverse order
        int accumulator = 0; // CPU register
        int position = 0; // CPU register

        boolean done = false;
        boolean isFirstArc = true;

        while (!done) {

            // Referring to the cache
            if (useCache && isFirstArc && input.charAt(position) < program.getCacheFirstAddresses().length) {
                char inputChar = input.charAt(position);

                if (program.getCacheFirstAddresses()[inputChar] == -1) {
                    accumulator = -1;
                    break;
                }

                pc = program.getCacheFirstAddresses()[inputChar];
                accumulator += program.getCacheFirstOutputs()[inputChar];

                if (input.length() == position + 1 && program.cacheFirstIsAccept[inputChar]) {
                    // last character
                    done = true;
                }

                position++;

                isFirstArc = false;
                continue;
            }

            long instruction = program.instructions[pc];
            boolean fail = program.isFail(instruction);
            boolean accept = program.isAccept(instruction);

            if (fail) {
                done = true;
                accumulator = -1;
            } else {
                char label = program.getLabel(instruction);
                int targetAddress = program.getTargetAddress(instruction);
                int output = program.getOutput(instruction);

                if (accept) {
                    if (input.length() == position + 1 && label == input.charAt(position)) {
                        // last character
                        accumulator += output;
                        done = true;
                    } else {
                        if (position < input.length() && label == input.charAt(position)) {
                            accumulator += output;
                            pc = targetAddress + 1; // JUMP to Address i.arg2
                            position++; // move the input char pointer
                        } else {
                            // We're at the end of input and we didn't match, which means a prefix match
                            if (position == input.length()) {
                                accumulator = 0;
                                done = true;
                            }
                        }
                    }
                } else if (position <= input.length()) {
                    // We're at the end of input and we didn't match, which means a prefix match
                    if (position == input.length()) {
                        accumulator = 0;
                        done = true;
                    } else if (label == input.charAt(position)) {
                        accumulator += output;
                        pc = targetAddress + 1; // JUMP to Address i.arg2
                        position++; // move the input char pointer
                    }
                }
            }

            pc--;
        }

        return accumulator;
    }
}

@@ -1457,68 +1457,8 @@
 on);
-%0A            boolean accept = program.isAccept(instruction);
 %0A%0A  
@@ -1555,32 +1555,96 @@
        %7D else %7B%0A
+                boolean accept = program.isAccept(instruction);%0A
                 
@@ -1854,70 +1854,49 @@
 cept
-) %7B%0A                    if (input.length() == position + 1
+ && (position + 1 == input.length())
  && 
+(
 labe
@@ -1915,39 +1915,36 @@
 harAt(position))
+)
  %7B%0A
-    
                 
@@ -1977,36 +1977,32 @@
                 
-    
 accumulator += o
@@ -2020,36 +2020,32 @@
                 
-    
 done = true;%0A   
@@ -2033,36 +2033,32 @@
    done = true;%0A
-    
                 
@@ -2078,36 +2078,32 @@
                 
-    
 if (position %3C i
@@ -2170,36 +2170,32 @@
                 
-    
 accumulator += o
@@ -2193,36 +2193,32 @@
 ator += output;%0A
-    
                 
@@ -2291,36 +2291,32 @@
                 
-    
 position++; // m
@@ -2366,417 +2366,53 @@
     
-    
 %7D else 
-%7B%0A                            // We're at the end of input and we didn't match, which means a prefix match%0A                            if (position == input.length()) %7B%0A                                accumulator = 0;%0A                                done = true;%0A                            %7D%0A                        %7D%0A                    %7D%0A                %7D else if (position %3C= input.length()) %7B%0A
+if (position == input.length()) %7B%0A    
     
@@ -2508,62 +2508,8 @@
 tch%0A
-                    if (position == input.length()) %7B%0A
     
@@ -2586,262 +2586,8 @@
 ue;%0A
-                    %7D else if (label == input.charAt(position)) %7B%0A                        accumulator += output;%0A                        pc = targetAddress + 1; // JUMP to Address i.arg2%0A                        position++; // move the input char pointer%0A
     

Implement LongArrayIO and replace FST Program IO and use long[] throughout. Tidied up bits and bobs.