/*****************************************************************************

  Project:	STACK-MACHINE SIMULATOR
  Filename:	Instruction.java
  Written by:	Ettore Pasquini, 1999

Accanto alla gerarchia Machine vi è la gerarchia Instruction. Ogni sottoclasse di Machine avrà una relativa classe (astratta) nella gerarchia Instruction. Ad es. alla StackMachine è associata la classe astratta StackMachineInstruction, che raggruppa tutte le proprietà comuni delle istruzioni della StackMachine.

******************************************************************************/

import StackMachine;
import MachineSignal;

public abstract class Instruction implements Cloneable{
  // uno stesso CodeSegment potrebbe essere condiviso da molte CPU, quindi si
  // passa un rif. alla macchina su cui si intende eseguire l'istruzione
  public abstract void exec( Machine m ) throws MachineSignal;
  public String toString(){ return this.getClass().getName();}
  public static Instruction make(String opcode, int[] operands){
	return new NotRecognizedInstruction();
  }
  public Instruction copia(){
    Object x = new Object();
    try{

	/*
	System.out.println( "cloning Instruction of class" + 
	    this.getClass().getName() + "; Object: "+ this.toString());
	*/

	x= (Instruction)this.clone();

	/*
	System.out.println( "cloned Instruction of class" + 
	    this.getClass().getName() + "; Cloned Object: " + x.toString());
	*/

    }catch(CloneNotSupportedException e){
	System.out.println( "CloneNotSupportedException intercepted while "
	    + "cloning object: " + this.toString() );
    }
    return (Instruction)x; /***ATTENZIONE***/
  }
}//Instruction

abstract class StackMachineInstruction extends Instruction{
  public static Instruction make( String opcode, int[] operands){
	if (opcode.equals("push"))	return( new Push(operands[0]) );
	if (opcode.equals("pushc"))	return( new Pushc(operands[0]) );
	if (opcode.equals("pushadd"))	return( new Pushadd(operands[0]) );
	if (opcode.equals("pop"))	return( new Pop() );
	if (opcode.equals("store"))	return( new Store() );
	if (opcode.equals("add"))	return( new Add() );
	if (opcode.equals("sub"))	return( new Sub() );
	if (opcode.equals("mul"))	return( new Mul() );
	if (opcode.equals("div"))	return( new Div() );
	if (opcode.equals("and"))	return( new And() );
	if (opcode.equals("or" ))	return( new Or()  );	
	if (opcode.equals("impl"))	return( new Impl());
	if (opcode.equals("jump"))	return( new Jump(operands[0]) );
	if (opcode.equals("jumple"))	return( new Jumple(operands[0]) );
	if (opcode.equals("jumplt"))	return( new Jumplt(operands[0]) );
	if (opcode.equals("jumpge"))	return( new Jumpge(operands[0]) );
	if (opcode.equals("jumpgt"))	return( new Jumpgt(operands[0]) );
	if (opcode.equals("jumpeq"))	return( new Jumpeq(operands[0]) );
	if (opcode.equals("jumpne"))	return( new Jumpne(operands[0]) );
	if (opcode.equals("nop"))	return( new Nop()  );
	if (opcode.equals("halt"))	return( new Halt() );
	return Instruction.make(opcode, operands);
  }
}//StackMachineInstruction

class OneOpStackMachineInstruction extends StackMachineInstruction {
  int operand;
  public OneOpStackMachineInstruction(int op){ operand=op; }
  public void exec( Machine m ) throws MachineSignal{}
  public int operand(){ return operand;}
  public String toString(){
	return this.getClass().getName() + "\t" + Integer.toString(operand);
  }
}

class ZeroOpStackMachineInstruction extends StackMachineInstruction{
  public void exec(Machine m) throws MachineSignal{}
}

class Push extends OneOpStackMachineInstruction{
  public Push(int a){ super(a); }
  public void exec( Machine m ) throws InvalidDataReadAddressException{ 
	((StackMachine) m).PUSH(operand());
  }
}//Push

class Pushc extends OneOpStackMachineInstruction{
  public Pushc(int x){ super(x); }
  public void exec( Machine m ){ ((StackMachine) m).PUSHC(operand()); }
}//Pushc

class Pushadd extends OneOpStackMachineInstruction{
  public Pushadd(int a){ super(a);}
  public void exec( Machine m ){ ((StackMachine) m).PUSHADD(operand()); }
}//Pushadd

class Pop extends ZeroOpStackMachineInstruction{
  public void exec( Machine m ) throws EmptyMachineStackException{ 
	((StackMachine) m).POP();
  }
}//Pop

class Store extends ZeroOpStackMachineInstruction{
  public void exec( Machine m ) throws EmptyMachineStackException,
					InvalidDataWriteAddressException{ 
	((StackMachine) m).STORE();
  }
}//Store

class Add extends ZeroOpStackMachineInstruction{
  public void exec( Machine m ) throws EmptyMachineStackException{ 
	((StackMachine) m).ADD();
  }
}//Add

class Sub extends ZeroOpStackMachineInstruction{
  public void exec( Machine m ) throws EmptyMachineStackException{ 
	((StackMachine) m).SUB();
  }
}//Sub

class Mul extends ZeroOpStackMachineInstruction{
  public void exec( Machine m ) throws EmptyMachineStackException{ 
	((StackMachine) m).MUL();
  }
}//Mul

class Div extends ZeroOpStackMachineInstruction{
  public void exec( Machine m ) throws EmptyMachineStackException{ 
	((StackMachine) m).DIV();
  }
}//Div

class And extends ZeroOpStackMachineInstruction{
  public void exec( Machine m ) throws EmptyMachineStackException{
	((StackMachine) m).AND();
  }
}//And

class Or extends ZeroOpStackMachineInstruction{
  public void exec( Machine m ) throws EmptyMachineStackException{ 
	((StackMachine) m).OR();
  }
}//Or

class Impl extends ZeroOpStackMachineInstruction{
  public void exec( Machine m ) throws EmptyMachineStackException{ 
	((StackMachine) m).IMPL();
  }
}//Impl

class Jump extends OneOpStackMachineInstruction{
  public Jump(int a){ super(a); }
  public void exec( Machine m ){ ((StackMachine) m).JUMP(operand()); }
}//Jump

class Jumple extends OneOpStackMachineInstruction{
  public Jumple(int a){ super(a);}
  public void exec( Machine m ){ ((StackMachine) m).JUMPLE(operand()); }
}//Jumple

class Jumplt extends OneOpStackMachineInstruction{
  public Jumplt(int a){ super(a);}
  public void exec( Machine m ){ ((StackMachine) m).JUMPLT(operand()); }
}//Jumplt

class Jumpge extends OneOpStackMachineInstruction{
  public Jumpge(int a){ super(a);}
  public void exec( Machine m ){ ((StackMachine) m).JUMPGE(operand()); }
}//Jumpge

class Jumpgt extends OneOpStackMachineInstruction{
  public Jumpgt(int a){ super(a);}
  public void exec( Machine m ){ ((StackMachine) m).JUMPGT(operand()); }
}//Jumpgt

class Jumpeq extends OneOpStackMachineInstruction{
  public Jumpeq(int a){ super(a);}
  public void exec( Machine m ){ ((StackMachine) m).JUMPEQ(operand()); }
}//Jumpeq

class Jumpne extends OneOpStackMachineInstruction{
  public Jumpne(int a){ super(a);}
  public void exec( Machine m ){ ((StackMachine) m).JUMPNE(operand()); }
}//Jumpne

class Nop extends ZeroOpStackMachineInstruction{
  public void exec( Machine m ){ ((StackMachine) m).NOP(); }
}//Nop

class Halt extends ZeroOpStackMachineInstruction{
  public void exec( Machine m ) throws HaltMessage{
	((StackMachine) m).HALT();
  }
}//Halt

class NotRecognizedInstruction extends Instruction {
  public void exec( Machine m ) throws NotRecognizedInstructionException{
	throw new NotRecognizedInstructionException();
  }
}//NotRecognizedInstruction 

