/**
 * Intel x86 (IA-32) 固有の変換規則
 * <p>TargetMethodインタフェースを実装している。
 */

class Intel8632Method implements TargetMethod {

  /*****************/
  /* PRIVATE FIELD */
  /*****************/
  /**
   * MMXレジスタに対応するアトムの配列
   */
  private static Cell[] mmxCell = {
    List.atom("MM0"), List.atom("MM1"), List.atom("MM2"), List.atom("MM3"),
    List.atom("MM4"), List.atom("MM5"), List.atom("MM6"), List.atom("MM7")
  };
  /**
   * XMMレジスタに対応するアトムの配列
   */
  private static Cell[] xmmCell = {
    List.atom("XMM0"), List.atom("XMM1"), List.atom("XMM2"), List.atom("XMM3"),
    List.atom("XMM4"), List.atom("XMM5"), List.atom("XMM6"), List.atom("XMM7")
  };
  /**
   * 32ビット・レジスタに対応するアトムの配列
   */
  private static Cell[] r32Cell={
    List.atom("EAX"), List.atom("ECX"), List.atom("EDX"), List.atom("EBX"),
    List.atom("ESP"), List.atom("EBP"),
    List.atom("ESI"), List.atom("EDI")
  };
  /**
   * インデックス・レジスタとして使用可能な32ビット・レジスタに対応するアトムの配列
   */
  private static Cell[] i32Cell = {
    List.atom("EAX"), List.atom("ECX"), List.atom("EDX"), List.atom("EBX"),
    List.atom("EBP"),
    List.atom("ESI"), List.atom("EDI"),
  };
  /**
   * 32ビット・レジスタ名称の配列
   */
  private static String[] r32 = {
    "EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI"
  };
  /**
   * インデックス・レジスタとして使用可能な32ビット・レジスタ名称の配列
   */
  private static String[] i32 = {
    "EAX", "ECX", "EDX", "EBX", "EBP", "ESI", "EDI"
  };
  /**
   * インデックス・レジスタとして使用可能な16ビット・レジスタ名称の配列
   */
  private static String[] i16 = {
    "AX", "CX", "DX", "BX", "BP", "SI", "DI"
  };
  /**
   * 16ビット・レジスタ名称の配列
   */
  private static String[] r16 = {
    "AX", "CX", "DX", "BX", "SP", "BP", "SI", "DI"
  };
  /**
   * 8ビット・レジスタ(上位)名称の配列
   */
  private static String[] r8h = {
    "AH", "CH", "DH", "BH"
  };
  /**
   * 8ビット・レジスタ(下位)名称の配列
   */
  private static String[] r8l = {
    "AL", "CL", "DL", "BL"
  };
  /**
   * MMXレジスタ名称の配列
   */
  private static String[] mmx = {
    "MM0", "MM1", "MM2", "MM3",
    "MM4", "MM5", "MM6", "MM7"
  };
  /**
   * XMMレジスタに対応するアトムの配列
   */
  private static String[] xmm = {
    "XMM0", "XMM1", "XMM2", "XMM3",
    "XMM4", "XMM5", "XMM6", "XMM7"
  };

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

  /**
   * 中間形式ファイル(バイナリ形式)読み込み後の再初期化処理を行う。
   */
  public void init() {
    for ( int i=0; i<mmx.length; i++ )
      mmxCell[i] = List.atom(mmx[i]);
    for ( int i=0; i<xmm.length; i++ )
      xmmCell[i] = List.atom(xmm[i]);
    for ( int i=0; i<r32.length; i++ )
      r32Cell[i] = List.atom(r32[i]);
    for ( int i=0; i<i32.length; i++ )
      i32Cell[i] = List.atom(i32[i]);
  }

  /*****************/
  /* PUBLIC METHOD */
  /*****************/
  /**
   * S式を指定の方法で文字列に変換する。
   * @param arg		HOLEにマッチするS式
   * @param spec	変換指定文字
   * @return		変換後の文字列
   */
  public String convertHole(Cell arg, char spec) {

    switch(spec) {
    case 'm':			// MMXレジスタ
      return mmx[mmxnum(arg)];
    case 'x':			// XMMレジスタ
      return xmm[xmmnum(arg)];

    case 'r':			// 32ビット・レジスタ
      return r32[r32num(arg)];

    case 'i':			// 32ビット・インデックス・レジスタ
      return i32[i32num(arg)];
// 2001/06/06: 削除
//   マクロ・テンプレート "t"削除にともない削除した。
//    case 'j':			// 16ビット・インデックス・レジスタ
//      return i16[i32num(arg)];

    case 'w':			// 16ビット・レジスタ
      return r16[r32num(arg)];


    case 'h':			// 8ビット・レジスタ(上位)
      return r8h[r32num(arg)];
    case 'l':			// 8ビット・レジスタ(下位)
      return r8l[r32num(arg)];

// 2001/06/06: 追加、修正
//   定数、ラベルに対するテンプレートを分けた。
//    case 'c':			// 定数およびラベル
//      return arg.toString();
//
    case 'c':			// 定数
      return arg.toString();
    case 'b':			// ラベル
      return arg.toString();
//

// 2001/06/18: 追加
//   ?nvを追加した。
//      
    case 'v':
      return (new Integer(r32num(arg))).toString();

    default:
      Util.abort("Intel8632Method: bad conversion specifier: "+spec);
    }
    return ""; // Dummy
  }

  /******************/
  /* PRIVATE METHOD */
  /******************/
  /**
   * 32ビット・レジスタのS式表現からレジスタ番号に変換する。
   */
  private static int r32num(Cell arg) {
    for ( int i=0; i<r32Cell.length; i++ ) if ( r32Cell[i]==arg ) return i;
    Util.abort("Intel8632Method: bad register: "+arg);
    return -1; // Dummy
  }

  /**
   * 32ビット・レジスタ(インデックス可能)のS式表現からレジスタ番号に変換する。
   */
  private static int i32num(Cell arg) {
    for ( int i=0; i<i32Cell.length; i++ ) if ( i32Cell[i]==arg ) return i;
    Util.abort("Intel8632Method: bad INDEX register: "+arg);
    return -1; // Dummy
  }

  /**
   * MMXレジスタのS式表現からレジスタ番号に変換する。
   */
  private static int mmxnum(Cell arg) {
    for ( int i=0; i<mmxCell.length; i++ ) if ( mmxCell[i]==arg ) return i;
    Util.abort("Intel8632Method: bad MMX register: "+arg);
    return -1; // Dummy
  }

  /**
   * XMMレジスタのS式表現からレジスタ番号に変換する。
   */
  private static int xmmnum(Cell arg) {
    for ( int i=0; i<xmmCell.length; i++ ) if ( xmmCell[i]==arg ) return i;
    Util.abort("Intel8632Method: bad XMM register: "+arg);
    return -1; // Dummy
  }

}

