Select Git revision
      
  Instruction.java
        Forked from
        Toby Murray / swen90006-a2-2020 
 Source project has a limited visibility.
  Instruction.java  6.52 KiB 
// import java.util.Arrays;
// import java.util.ArrayList;
import java.lang.reflect.Array;
import java.util.*;
import java.util.stream.Collectors;
public enum Instruction {
    PLUS("+",new OperandType[]{}, 2, -1, 2),
    SUB("-",new OperandType[]{}, 2, -1, 2),
    MULT("*",new OperandType[]{}, 2, -1, 2),
    DIV("/",new OperandType[]{}, 2, -1, 2),
    PUSH("push",new OperandType[]{OperandType.STRING}, 0, 1, 3),
    POP("pop",new OperandType[]{}, 1, -1, 4),
    LOAD("load",new OperandType[]{OperandType.STRING}, 0, 1, 1), //Note. Check variable existence
    REM("remove",new OperandType[]{OperandType.STRING}, 0, 0, 1), //Note. Check variable existence
    STORE("store",new OperandType[]{OperandType.STRING}, 1, -1, 1),
    SAVE("save",new OperandType[]{OperandType.STRING}, 0, 0, 1),
    LIST("list",new OperandType[]{}, 0, 0, 1),
    PRINT("print",new OperandType[]{}, 0, 0, 1);
    public static String getBNF(){
        String grammar = "<INSTRUCTION> ::= \n";
        Instruction[] INSTS = Instruction.values();
        boolean firstInst = true;
        for (Instruction inst : INSTS){
            if (firstInst){
                grammar += "      \"";
                firstInst = false;
            }else{
                grammar += "    | \"";
            }
            grammar += inst.getOpcode() + "\"";
            for (OperandType op : inst.getOperands()){
                grammar += " <" + op.toString() + ">";
            }
            grammar += "\n";
        }
        return grammar;
    }
    
    static Integer maxProbability = 0;
    private final String opcode;
    private final OperandType[] operands;
    private final Integer minItemsInStack;
    private final Integer changeToStack;
    private final Integer probability;
    Instruction(String opcode, OperandType[] operands, Integer minItemsInStack, Integer changeToStack, Integer probability){
        this.opcode = opcode;
        this.operands = operands;
        this.minItemsInStack = minItemsInStack;
        this.changeToStack = changeToStack;
        this.probability = probability;
    }
    // List of all instructions
    private static final ArrayList<Instruction> ALL_INSTRUCTIONS = new ArrayList<>(Arrays.asList(values()));
    // private static final int ALL_LENGTH = ALL_INSTRUCTIONS.size();
    private static final ArrayList<Integer> ALL_CUML_PROB = new ArrayList<Integer>();
    private static int ALL_MAX_CUML_PROB = 0;
    // List of instructions with zero min stack
    private static final ArrayList<Instruction> MAX_ZERO_INSTRUCTIONS = new ArrayList<>(
            ALL_INSTRUCTIONS.stream().filter(i -> i.minItemsInStack == 0).collect(Collectors.toList()));
    // private static final int ZERO_LENGTH = MAX_ZERO_INSTRUCTIONS.size();
    private static final ArrayList<Integer> ZERO_CUML_PROB = new ArrayList<Integer>();
    private static Integer ZERO_MAX_CUML_PROB = 0;
    // List of instructions with one or less min stack
    private static final ArrayList<Instruction> MAX_ONE_INSTRUCTIONS = new ArrayList<>(
            ALL_INSTRUCTIONS.stream().filter(i -> i.minItemsInStack <= 1).collect(Collectors.toList()));
    // private static final int ONE_LENGTH = MAX_ONE_INSTRUCTIONS.size();
    private static final ArrayList<Integer> ONE_CUML_PROB = new ArrayList<Integer>();
    private static Integer ONE_MAX_CUML_PROB = 0;
    // Random generator
    private static Random rand = new Random(System.currentTimeMillis());
    // Returns a random instruction based on the stack size to prevent repeated
    // requests
    public static Instruction getRandomInstruction(int max, int[] addProb) {
        // Check if cumlative probabilities have been calculated
        checkProbability(addProb);
        ArrayList<Instruction> instructions;
        ArrayList<Integer> instCumlProbs;
        int value;
        if (max == 0) {
            // Select random from instructions with 0 min stack
            instructions = MAX_ZERO_INSTRUCTIONS;
            instCumlProbs = ZERO_CUML_PROB;
            value = rand.nextInt(ZERO_MAX_CUML_PROB);
        } else if (max == 1) {
            // Select random from instructions with 1 or less min stack
            instructions = MAX_ONE_INSTRUCTIONS;
            instCumlProbs = ONE_CUML_PROB;
            value = rand.nextInt(ONE_MAX_CUML_PROB);
        } else {
            // Select random from all
            instructions = ALL_INSTRUCTIONS;
            instCumlProbs = ALL_CUML_PROB;
            value = rand.nextInt(ALL_MAX_CUML_PROB);
        }
        // Determine instruction to return using appropriate cumlative probability array
        int i = 0;
        for (Integer cumlativeProb : instCumlProbs) {
            if (value < cumlativeProb) {
                return instructions.get(i);
            }
            i++;
        }
        return instructions.get(instructions.size() - 1);
    }
    // Called before doing probability calculations to check if the clumulative
    // probabilities have been calculated
    private static void checkProbability(int[] addProb) {
        // Check if cumlative probabilities have been calculated. If not, do so.
        if (Instruction.ALL_MAX_CUML_PROB == 0) {
            Integer cumProb = 0;
            for (Instruction instruction : ALL_INSTRUCTIONS) {
                cumProb += instruction.probability + addProb[instruction.ordinal()];
                ALL_CUML_PROB.add(cumProb);
            }
            ALL_MAX_CUML_PROB = cumProb;
            cumProb = 0;
            for (Instruction instruction : MAX_ZERO_INSTRUCTIONS) {
                cumProb += instruction.probability + addProb[instruction.ordinal()];
                ZERO_CUML_PROB.add(cumProb);
            }
            ZERO_MAX_CUML_PROB = cumProb;
            cumProb = 0;            for (Instruction instruction : MAX_ONE_INSTRUCTIONS) {
                cumProb += instruction.probability + addProb[instruction.ordinal()];
                ONE_CUML_PROB.add(cumProb);
            }
            ONE_MAX_CUML_PROB = cumProb;
        }
    }
    public String getOpcode(){
        return opcode;
    }
    
    public OperandType[] getOperands(){
        return operands;
    }
    public boolean isValid(Integer stackSize) {
        return this.minItemsInStack >= stackSize;
    }
    public Integer getStackChange() {
        return this.changeToStack;
    }
    
    public String toString(){
        String operandsString = "";
        for (OperandType op : operands) {
            operandsString += " " + op.toString();
        }
        return "\"" + opcode + "\"" + operandsString;
    }
    public Integer getProbability() {
        return this.probability;
    }
}