Last active
November 28, 2015 23:22
-
-
Save flisboac/feb4b3c6cd459b8b2182 to your computer and use it in GitHub Desktop.
Uma máquina virtual bem simples...
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
SET 1 2 | |
SET 2 5 | |
MUL 1 2 3 | |
SET 4 2 | |
ADD 3 4 5 | |
SET 6 2 | |
DIV 5 6 7 | |
SET 8 4 | |
SUB 7 8 9 | |
PRL 9 | |
DMP | |
END |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.BufferedInputStream; | |
import java.io.File; | |
import java.io.FileInputStream; | |
import java.io.FileNotFoundException; | |
import java.io.InputStream; | |
import java.util.ArrayList; | |
import java.util.List; | |
import java.util.Scanner; | |
// 256 bytes de memória volátil endereçável | |
// 256 registradores de inteiros | |
// 256 bytes de programa | |
public class Vm { | |
public static final int FINALIZADO = -1; | |
public static final int NAO_INICIADO = -2; | |
public static enum Opcode { | |
END(0, "END", 0), | |
ADD(1, "ADD", 3), | |
SUB(2, "SUB", 3), | |
MUL(3, "MUL", 3), | |
DIV(4, "DIV", 3), | |
SET(5, "SET", 2), | |
PRL(6, "PRL", 1), | |
DMP(7, "DMP", 0); // DUMP de memoria e registros | |
public final int valor; | |
public final String mnemonico; | |
public final int numeroArgumentos; | |
private Opcode(int valor, String mnemonico, int numeroArgumentos) { | |
this.valor = valor; | |
this.mnemonico = mnemonico; | |
this.numeroArgumentos = numeroArgumentos; | |
} | |
public static Opcode buscarPorMnemonico(String mnemonico) { | |
Opcode opcode = null; | |
if (mnemonico != null) { | |
for (Opcode elem : values()) { | |
if (elem.mnemonico.compareToIgnoreCase(mnemonico) == 0) { | |
opcode = elem; | |
break; | |
} | |
} | |
} | |
return opcode; | |
} | |
public static Opcode buscarPorValor(int valor) { | |
Opcode opcode = null; | |
for (Opcode elem : values()) { | |
if (elem.valor == valor) { | |
opcode = elem; | |
break; | |
} | |
} | |
return opcode; | |
} | |
} | |
public static class Instrucao { | |
public final Opcode opcode; | |
public final Integer[] argumentos; | |
public Instrucao() { | |
this.opcode = null; | |
this.argumentos = new Integer[0]; | |
} | |
public Instrucao(Opcode opcode) { | |
this.opcode = opcode; | |
this.argumentos = new Integer[0]; | |
} | |
public Instrucao(Opcode opcode, Integer... argumentos) { | |
this.opcode = opcode; | |
this.argumentos = argumentos; | |
if (argumentos.length != opcode.numeroArgumentos) { | |
throw new IllegalArgumentException( | |
opcode.mnemonico + " deve possuir " | |
+ opcode.numeroArgumentos + " argumentos."); | |
} | |
} | |
} | |
private List<Instrucao> programa = new ArrayList<>(); | |
private int[] registradores = new int[16]; | |
private int pc = NAO_INICIADO; | |
private boolean finalizado; | |
public void lerPrograma(InputStream stream) { | |
Opcode opcode = null; | |
Scanner scanner = new Scanner(stream); | |
String regex = "[^\\s]+"; | |
while (scanner.hasNext()) { | |
if (opcode == null) { | |
String valor = scanner.next(); | |
opcode = Opcode.buscarPorMnemonico(valor); | |
// OPCODE invalido | |
if (opcode == null) { | |
throw new UnsupportedOperationException("Mnemônico " + valor + " inválido."); | |
} else { | |
//System.err.println("** Encontrado Mnemonico: " + valor); | |
} | |
// Caso o opcode nao receba argumentos, a leitura do arquivo nao | |
// precisa continuar a buscar argumentos; sendo assim, a rotina | |
// nao vai executar o else deste if. | |
// Neste caso, deve-se adicionar o opcode de imediato. | |
if (opcode.numeroArgumentos == 0) { | |
programa.add(new Instrucao(opcode)); | |
opcode = null; | |
} | |
} else { | |
// Pegar o número de argumentos necessários | |
Integer[] argumentos = new Integer[opcode.numeroArgumentos]; | |
for (int numeroArgumento = 0; numeroArgumento < opcode.numeroArgumentos; numeroArgumento++) { | |
int argumento = scanner.nextInt(); | |
//System.err.println("*** " + opcode.mnemonico + " ARG[" + numeroArgumento + "] = " + argumento); | |
argumentos[numeroArgumento] = argumento; | |
} | |
programa.add(new Instrucao(opcode, argumentos)); | |
opcode = null; | |
} | |
} | |
} | |
// "dispatcher" | |
public void executarInstrucao(Instrucao instrucao) { | |
int r1, r2, r3, v; | |
switch (instrucao.opcode) { | |
case END: | |
this.finalizado = true; | |
//System.err.println("*** FINALIZADO! this.pc == " + this.pc); | |
break; | |
case ADD: | |
// ADD R1 R2 R3 -> R3 = R1 + R2 | |
r1 = instrucao.argumentos[0]; | |
r2 = instrucao.argumentos[1]; | |
r3 = instrucao.argumentos[2]; | |
this.registradores[r3] = this.registradores[r1] + this.registradores[r2]; | |
break; | |
case SUB: | |
r1 = instrucao.argumentos[0]; | |
r2 = instrucao.argumentos[1]; | |
r3 = instrucao.argumentos[2]; | |
this.registradores[r3] = this.registradores[r1] - this.registradores[r2]; | |
break; | |
case MUL: | |
r1 = instrucao.argumentos[0]; | |
r2 = instrucao.argumentos[1]; | |
r3 = instrucao.argumentos[2]; | |
this.registradores[r3] = this.registradores[r1] * this.registradores[r2]; | |
break; | |
case DIV: | |
r1 = instrucao.argumentos[0]; | |
r2 = instrucao.argumentos[1]; | |
r3 = instrucao.argumentos[2]; | |
this.registradores[r3] = this.registradores[r1] / this.registradores[r2]; | |
break; | |
case SET: | |
// SET R1 V -> R1 = V | |
r1 = instrucao.argumentos[0]; | |
v = instrucao.argumentos[1]; | |
this.registradores[r1] = v; | |
break; | |
case PRL: | |
r1 = instrucao.argumentos[0]; | |
System.out.println(this.registradores[r1]); | |
break; | |
case DMP: | |
System.out.println("- PC = " + this.pc); | |
for (int i = 0; i < this.registradores.length; i++) { | |
System.out.println("- R[" + i + "] = " + this.registradores[i]); | |
} | |
for (int i = 0; i < this.programa.size(); i++) { | |
Instrucao instrucaoExibicao = this.programa.get(i); | |
Integer[] argumentos = instrucaoExibicao.argumentos; | |
Opcode opcode = instrucaoExibicao.opcode; | |
String texto = "- I[" + i + "]: " + opcode.mnemonico; | |
String sep = " "; | |
for (int indiceArgumento = 0; indiceArgumento < argumentos.length; indiceArgumento++) { | |
texto += sep + argumentos[indiceArgumento]; | |
sep = " "; | |
} | |
System.out.println(texto); | |
} | |
break; | |
} | |
} | |
public void continuar() { | |
Instrucao instrucao = this.programa.get(this.pc); | |
executarInstrucao(instrucao); | |
incrementarContador(); | |
} | |
private void incrementarContador() { | |
this.pc++; | |
} | |
public boolean isFinalizado() { | |
return this.finalizado; | |
} | |
public boolean isIniciado() { | |
return this.pc > NAO_INICIADO; | |
} | |
public void iniciar() { | |
this.pc = 0; | |
} | |
public void executar() { | |
if (!isIniciado()) { | |
iniciar(); | |
} | |
while (!isFinalizado()) { | |
continuar(); | |
} | |
} | |
public static void main(String[] args) throws FileNotFoundException { | |
InputStream stream; | |
if (args.length == 0) { | |
stream = new BufferedInputStream(System.in); | |
} else { | |
File arquivo = new File(args[0]); | |
stream = new BufferedInputStream(new FileInputStream(arquivo)); | |
} | |
Vm vm = new Vm(); | |
vm.lerPrograma(stream); | |
vm.executar(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment