package rebelsky.pal;

/**
 * Offset memory locations for PAL, the pseudo-assembly language.  
 * These locations are fairly general: they can be indexed by any kind
 * of container (and not just constants, registers, or temporaries).
 * However, to ease translation to real assembly language, they
 * really should be indexed only by registers.
 *
 * @author Samuel A. Rebelsky
 * @version 1.2 of April 2004
 */
public class Offset
  extends Variable
{
  // +--------+------------------------------------------------------------
  // | Fields |
  // +--------+

  /** The index of the memory location. */
  Variable index;

  /** The offset from that index. */
  int offset;


  // +--------------+------------------------------------------------------
  // | Constructors |
  // +--------------+

  /** Create a new memory location indexed by the specified container. */
  public Offset(Variable index, int offset) {
    this.index = index;
    this.offset = offset;
  } // Offset(Variable)


  // +---------+-----------------------------------------------------------
  // | Methods |
  // +---------+

  /** 
   * Get the integer stored in this memory location.
   *
   * @exception Exception
   *   If the location is invalid.
   */
  public int iget(Computer hal)
    throws Exception
  {
    int pos = index.iget(hal) + this.offset;
    if ((pos < 0) || (pos > hal.memory.length))
      throw new Exception("Invalid memory location: " + pos);
    return hal.memory[pos];
  } // iget(Computer)

  /**
   * Store an integer in this memory location.
   *
   * @exception Exception
   *   If the index is invalid.
   */
  public void iset(Computer hal, int newval)
    throws Exception
  {
    int pos = index.iget(hal) + this.offset;
    if ((pos < 0) || (pos > hal.memory.length))
      throw new Exception("Invalid memory location: " + pos);
    hal.memory[pos] = newval;
  } // iset(Computer,int)

  /**
   * Get the address (as another variable).
   */
  public Variable dereference()
  {
    return this.index;
  } // dereference()

  /**
   * Get the offset from the base.
   */
  public int offset()
  {
    return this.offset;
  } // offset()

  /**
   * Convert to a string (e.g., for printing).
   */
  public String toString() {
    return "MEM[" + index.toString() + " + " + offset + "]";
  } // toString()

} // class Offset

