/**
 * 中間表現のhash値を計算する。
 */

public class InstHash {

  /*****************/
  /* PRIVATE FIELD */
  /*****************/

  /*  副作用素 */
  private static Cell parallelCell = List.atom("PARALLEL");
  private static Cell clobberCell = List.atom("CLOBBER");
  private static Cell jumpCell = List.atom("JUMP");
  private static Cell jumpcCell = List.atom("JUMPC");
  private static Cell setCell = List.atom("SET");

  /***************/
  /* INITIALIZER */
  /***************/
  /**
   * 中間形式ファイル(バイナリ形式)読み込み時の事前準備を行う。
   */
  public static void cleanUp() {
  }

  /**
   * 中間形式ファイル(バイナリ形式)読み込み後の再初期化処理を行う。
   */
  public static void init() {
    parallelCell = List.atom("PARALLEL");
    clobberCell = List.atom("CLOBBER");
    jumpCell = List.atom("JUMP");
    jumpcCell = List.atom("JUMPC");
    setCell = List.atom("SET");
  }

  /*****************/
  /* PUBLIC METHOD */
  /*****************/
  /**
   * 中間表現のハッシュ値計算
   * @param c		中間表現のリスト
   * @return		ハッシュ値
   */
  public static Integer hashValue(Cell c) {

    /*
      ATOMの場合はhashCode値をそのまま返す。
     */
    if ( c.isAtom() ) return new Integer(c.hashCode());
    /*
      リスト先頭の作用素を取り出す。
     */
    Cell p = c.car();
    /*
      PARALLELは、サブリストのhashValue()のEx-ORをとる。
     */
    if ( p==parallelCell )
      {
	int code = 0;

	c = c.cdr();
	while ( c!=List.nil ) {
	  code ^= hashValue(c.car()).intValue();
	  c = c.cdr();
	}
	return new Integer(code);
      }
    /*
      CLOBBERは、CLOBBERリストのhashCode値をそのまま返す。
     */
    else if ( p==clobberCell ) {
	return new Integer(p.hashCode());
    }
    /* 
       JUMP、JUMPCは、リストのcar部(作用素名)のhashCode値を返す。
     */
    else if ( p==jumpCell || p==jumpcCell ) {
      return new Integer(p.hashCode());
    }
    /*
      SETは、第1引数(REG、MEM等)のhashCodeと第2引数(REG、MEM、演算等)のEx-ORを返す。
     */
    else if ( p==setCell ) {
      //
      // 第1引数、第2引数が裸のHOLEだとハッシュできない。
      //
      //      int arg1, arg2;
      //      if ( c.nth(1).isAtom() ) {
      //	arg1 = c.nth(1).hashCode();
      //      } else {
      //	arg1 = c.nth(1).car().hashCode();
      //      }
      //      if ( c.nth(2).isAtom() ) {
      //	arg2 = c.nth(2).hashCode();
      //      } else {
      //	arg2 = c.nth(2).car().hashCode();
      //      }
      //      return new Integer(arg1^arg2);
      return new Integer(p.hashCode());
    }
    /*
      不正リストのはず…
     */
    else {
      return new Integer(p.hashCode());
    }
  }

}

