310 lines
9.1 KiB
Java
Executable File
310 lines
9.1 KiB
Java
Executable File
import java.io.File;
|
|
import java.util.ArrayList;
|
|
import java.util.Scanner;
|
|
import java.util.StringTokenizer;
|
|
|
|
public class VPL
|
|
{
|
|
static String fileName;
|
|
static Scanner keys;
|
|
|
|
static int max;
|
|
static int[] mem;
|
|
static int ip, bp, sp, rv, hp, numPassed, gp;
|
|
static int step;
|
|
|
|
public static void main(String[] args) throws Exception {
|
|
|
|
keys = new Scanner( System.in );
|
|
|
|
if( args.length != 2 ) {
|
|
System.out.println("Usage: java VPL <vpl program> <memory size>" );
|
|
System.exit(1);
|
|
}
|
|
|
|
fileName = args[0];
|
|
|
|
max = Integer.parseInt( args[1] );
|
|
mem = new int[max];
|
|
|
|
// load the program into the front part of
|
|
// memory
|
|
Scanner input = new Scanner( new File( fileName ) );
|
|
String line;
|
|
StringTokenizer st;
|
|
int opcode;
|
|
|
|
ArrayList<IntPair> labels, holes;
|
|
labels = new ArrayList<IntPair>();
|
|
holes = new ArrayList<IntPair>();
|
|
int label;
|
|
|
|
// load the code
|
|
|
|
int k=0;
|
|
while ( input.hasNextLine() ) {
|
|
line = input.nextLine();
|
|
System.out.println("parsing line [" + line + "]");
|
|
if( line != null )
|
|
{// extract any tokens
|
|
st = new StringTokenizer( line );
|
|
if( st.countTokens() > 0 )
|
|
{// have a token, so must be an instruction (as opposed to empty line)
|
|
|
|
opcode = Integer.parseInt(st.nextToken());
|
|
|
|
// load the instruction into memory:
|
|
|
|
if( opcode == labelCode )
|
|
{// note index that comes where label would go
|
|
label = Integer.parseInt(st.nextToken());
|
|
labels.add( new IntPair( label, k ) );
|
|
}
|
|
else if( opcode == noopCode ){
|
|
}
|
|
else
|
|
{// opcode actually gets stored
|
|
mem[k] = opcode; k++;
|
|
|
|
if( opcode == callCode || opcode == jumpCode ||
|
|
opcode == condJumpCode )
|
|
{// note the hole immediately after the opcode to be filled in later
|
|
label = Integer.parseInt( st.nextToken() );
|
|
mem[k] = label; holes.add( new IntPair( k, label ) );
|
|
++k;
|
|
}
|
|
|
|
// load correct number of arguments (following label, if any):
|
|
for( int j=0; j<numArgs(opcode); ++j )
|
|
{
|
|
mem[k] = Integer.parseInt(st.nextToken());
|
|
++k;
|
|
}
|
|
|
|
}// not a label
|
|
|
|
}// have a token, so must be an instruction
|
|
}// have a line
|
|
}// loop to load code
|
|
|
|
//System.out.println("after first scan:");
|
|
//showMem( 0, k-1 );
|
|
|
|
// fill in all the holes:
|
|
int index;
|
|
for( int m=0; m<holes.size(); ++m )
|
|
{
|
|
label = holes.get(m).second;
|
|
index = -1;
|
|
for( int n=0; n<labels.size(); ++n )
|
|
if( labels.get(n).first == label )
|
|
index = labels.get(n).second;
|
|
mem[ holes.get(m).first ] = index;
|
|
}
|
|
|
|
System.out.println("after replacing labels:");
|
|
showMem( 0, k-1 );
|
|
|
|
// initialize registers:
|
|
bp = k; sp = k+2; ip = 0; rv = -1; hp = max;
|
|
numPassed = 0;
|
|
|
|
int codeEnd = bp-1;
|
|
|
|
System.out.println("Code is " );
|
|
showMem( 0, codeEnd );
|
|
|
|
gp = codeEnd + 1;
|
|
|
|
// start execution:
|
|
boolean done = false;
|
|
int op, a=0, b=0, c=0;
|
|
int actualNumArgs;
|
|
|
|
int step = 0;
|
|
|
|
int oldIp = 0;
|
|
|
|
// repeatedly execute a single operation
|
|
// *****************************************************************
|
|
|
|
do {
|
|
|
|
/* // show details of current step
|
|
System.out.println("--------------------------");
|
|
System.out.println("Step of execution with IP = " + ip + " opcode: " +
|
|
mem[ip] +
|
|
" bp = " + bp + " sp = " + sp + " hp = " + hp + " rv = " + rv );
|
|
System.out.println(" chunk of code: " + mem[ip] + " " +
|
|
mem[ip+1] + " " + mem[ip+2] + " " + mem[ip+3] );
|
|
System.out.println("--------------------------");
|
|
System.out.println( " memory from " + (codeEnd+1) + " up: " );
|
|
showMem( codeEnd+1, sp+3 );
|
|
System.out.println("hit <enter> to go on" );
|
|
keys.nextLine();
|
|
*/
|
|
|
|
oldIp = ip;
|
|
|
|
op = mem[ ip ]; ip++;
|
|
// extract the args into a, b, c for convenience:
|
|
a = -1; b = -2; c = -3;
|
|
|
|
// numArgs is wrong for these guys, need one more!
|
|
if( op == callCode || op == jumpCode ||
|
|
op == condJumpCode )
|
|
{
|
|
actualNumArgs = numArgs( op ) + 1;
|
|
}
|
|
else
|
|
actualNumArgs = numArgs( op );
|
|
|
|
if( actualNumArgs == 1 )
|
|
{ a = mem[ ip ]; ip++; }
|
|
else if( actualNumArgs == 2 )
|
|
{ a = mem[ ip ]; ip++; b = mem[ ip ]; ip++; }
|
|
else if( actualNumArgs == 3 )
|
|
{ a = mem[ ip ]; ip++; b = mem[ ip ]; ip++; c = mem[ ip ]; ip++; }
|
|
|
|
// implement all operations here:
|
|
// ********************************************
|
|
|
|
// put your work right here!
|
|
|
|
if ( op == oppCode ) {
|
|
mem[ bp+2 + a ] = - mem[ bp+2 + b ];
|
|
}
|
|
|
|
|
|
else
|
|
{
|
|
System.out.println("Fatal error: unknown opcode [" + op + "]" );
|
|
System.exit(1);
|
|
}
|
|
|
|
step++;
|
|
|
|
}while( !done );
|
|
|
|
|
|
}// main
|
|
|
|
// use symbolic names for all opcodes:
|
|
|
|
// op to produce comment
|
|
private static final int noopCode = 0;
|
|
|
|
// ops involved with registers
|
|
private static final int labelCode = 1;
|
|
private static final int callCode = 2;
|
|
private static final int passCode = 3;
|
|
private static final int allocCode = 4;
|
|
private static final int returnCode = 5; // return a means "return and put
|
|
// copy of value stored in cell a in register rv
|
|
private static final int getRetvalCode = 6;//op a means "copy rv into cell a"
|
|
private static final int jumpCode = 7;
|
|
private static final int condJumpCode = 8;
|
|
|
|
// arithmetic ops
|
|
private static final int addCode = 9;
|
|
private static final int subCode = 10;
|
|
private static final int multCode = 11;
|
|
private static final int divCode = 12;
|
|
private static final int remCode = 13;
|
|
private static final int equalCode = 14;
|
|
private static final int notEqualCode = 15;
|
|
private static final int lessCode = 16;
|
|
private static final int lessEqualCode = 17;
|
|
private static final int andCode = 18;
|
|
private static final int orCode = 19;
|
|
private static final int notCode = 20;
|
|
private static final int oppCode = 21;
|
|
|
|
// ops involving transfer of data
|
|
private static final int litCode = 22; // litCode a b means "cell a gets b"
|
|
private static final int copyCode = 23;// copy a b means "cell a gets cell b"
|
|
private static final int getCode = 24; // op a b means "cell a gets
|
|
// contents of cell whose
|
|
// index is stored in b"
|
|
private static final int putCode = 25; // op a b means "put contents
|
|
// of cell b in cell whose offset is stored in cell a"
|
|
|
|
// system-level ops:
|
|
private static final int haltCode = 26;
|
|
private static final int inputCode = 27;
|
|
private static final int outputCode = 28;
|
|
private static final int newlineCode = 29;
|
|
private static final int symbolCode = 30;
|
|
private static final int newCode = 31;
|
|
|
|
// global variable ops:
|
|
private static final int allocGlobalCode = 32;
|
|
private static final int toGlobalCode = 33;
|
|
private static final int fromGlobalCode = 34;
|
|
|
|
// debug ops:
|
|
private static final int debugCode = 35;
|
|
|
|
// return the number of arguments after the opcode,
|
|
// except ops that have a label return number of arguments
|
|
// after the label, which always comes immediately after
|
|
// the opcode
|
|
private static int numArgs( int opcode )
|
|
{
|
|
// highlight specially behaving operations
|
|
if( opcode == labelCode ) return 1; // not used
|
|
else if( opcode == jumpCode ) return 0; // jump label
|
|
else if( opcode == condJumpCode ) return 1; // condJump label expr
|
|
else if( opcode == callCode ) return 0; // call label
|
|
|
|
// for all other ops, lump by count:
|
|
|
|
else if( opcode==noopCode ||
|
|
opcode==haltCode ||
|
|
opcode==newlineCode ||
|
|
opcode==debugCode
|
|
)
|
|
return 0; // op
|
|
|
|
else if( opcode==passCode || opcode==allocCode ||
|
|
opcode==returnCode || opcode==getRetvalCode ||
|
|
opcode==inputCode ||
|
|
opcode==outputCode || opcode==symbolCode ||
|
|
opcode==allocGlobalCode
|
|
)
|
|
return 1; // op arg1
|
|
|
|
else if( opcode==notCode || opcode==oppCode ||
|
|
opcode==litCode || opcode==copyCode || opcode==newCode ||
|
|
opcode==toGlobalCode || opcode==fromGlobalCode
|
|
|
|
)
|
|
return 2; // op arg1 arg2
|
|
|
|
else if( opcode==addCode || opcode==subCode || opcode==multCode ||
|
|
opcode==divCode || opcode==remCode || opcode==equalCode ||
|
|
opcode==notEqualCode || opcode==lessCode ||
|
|
opcode==lessEqualCode || opcode==andCode ||
|
|
opcode==orCode || opcode==getCode || opcode==putCode
|
|
)
|
|
return 3;
|
|
|
|
else
|
|
{
|
|
System.out.println("Fatal error: unknown opcode [" + opcode + "]" );
|
|
System.exit(1);
|
|
return -1;
|
|
}
|
|
|
|
}// numArgs
|
|
|
|
private static void showMem( int a, int b )
|
|
{
|
|
for( int k=a; k<=b; ++k )
|
|
{
|
|
System.out.println( k + ": " + mem[k] );
|
|
}
|
|
}// showMem
|
|
|
|
}// VPL
|