/**
 * PowerPC版 固有の変換規則
 * <p>TargetMethodインタフェースを実装している。
 */

class PowerPCMethod implements TargetMethod {

  /*****************/
  /* PRIVATE FIELD */
  /*****************/
  /**
   * 汎用レジスタに対応するアトムの配列
   */
  private static Cell[] gprCell = {
    List.atom("r0"), List.atom("r1"), List.atom("r2"), List.atom("r3"),
    List.atom("r4"), List.atom("r5"), List.atom("r6"), List.atom("r7"),
    List.atom("r8"), List.atom("r9"), List.atom("r10"), List.atom("r11"),
    List.atom("r12"), List.atom("r13"), List.atom("r14"), List.atom("r15"),
    List.atom("r16"), List.atom("r17"), List.atom("r18"), List.atom("r19"),
    List.atom("r20"), List.atom("r21"), List.atom("r22"), List.atom("r23"),
    List.atom("r24"), List.atom("r25"), List.atom("r26"), List.atom("r27"),
    List.atom("r28"), List.atom("r29"), List.atom("r30"), List.atom("r31")
  };
  /**
   * 汎用レジスタ名称の配列
   */
  private static String[] gpr = {
    "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
    "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
    "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
    "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
  };

  /**
   * ベクタ・レジスタに対応するアトムの配列
   */
  private static Cell[] vrCell = {
    List.atom("vr0"), List.atom("vr1"), List.atom("vr2"), List.atom("vr3"),
    List.atom("vr4"), List.atom("vr5"), List.atom("vr6"), List.atom("vr7"),
    List.atom("vr8"), List.atom("vr9"), List.atom("vr10"), List.atom("vr11"),
    List.atom("vr12"), List.atom("vr13"), List.atom("vr14"), List.atom("vr15"),
    List.atom("vr16"), List.atom("vr17"), List.atom("vr18"), List.atom("vr19"),
    List.atom("vr20"), List.atom("vr21"), List.atom("vr22"), List.atom("vr23"),
    List.atom("vr24"), List.atom("vr25"), List.atom("vr26"), List.atom("vr27"),
    List.atom("vr28"), List.atom("vr29"), List.atom("vr30"), List.atom("vr31")
  };
  /**
   * ベクタ・レジスタ名称の配列
   */
  private static String[] vr = {
    "vr0", "vr1", "vr2", "vr3", "vr4", "vr5", "vr6", "vr7",
    "vr8", "vr9", "vr10", "vr11", "vr12", "vr13", "vr14", "vr15",
    "vr16", "vr17", "vr18", "vr19", "vr20", "vr21", "vr22", "vr23",
    "vr24", "vr25", "vr26", "vr27", "vr28", "vr29", "vr30", "vr31"
  };

  /**
   * 浮動小数点レジスタ(64ビット)に対応するアトムの配列
   */
  private static Cell[] fprCell = {
    List.atom("fp0"), List.atom("fp1"), List.atom("fp2"), List.atom("fp3"),
    List.atom("fp4"), List.atom("fp5"), List.atom("fp6"), List.atom("fp7"),
    List.atom("fp8"), List.atom("fp9"), List.atom("fp10"), List.atom("fp11"),
    List.atom("fp12"), List.atom("fp13"), List.atom("fp14"), List.atom("fp15"),
    List.atom("fp16"), List.atom("fp17"), List.atom("fp18"), List.atom("fp19"),
    List.atom("fp20"), List.atom("fp21"), List.atom("fp22"), List.atom("fp23"),
    List.atom("fp24"), List.atom("fp25"), List.atom("fp26"), List.atom("fp27"),
    List.atom("fp28"), List.atom("fp29"), List.atom("fp30"), List.atom("fp31")
  };
  /**
   * 浮動小数点レジスタ(64ビット)名称の配列
   */
  private static String[] fpr = {
    "fp0", "fp1", "fp2", "fp3", "fp4", "fp5", "fp6", "fp7",
    "fp8", "fp9", "fp10", "fp11", "fp12", "fp13", "fp14", "fp15",
    "fp16", "fp17", "fp18", "fp19", "fp20", "fp21", "fp22", "fp23",
    "fp24", "fp25", "fp26", "fp27", "fp28", "fp29", "fp30", "fp31"
  };

  /**
   * 状態レジスタ
   */
  private static Cell[] crCell = {
    List.atom("cr0"), List.atom("cr1"), List.atom("cr2"), List.atom("cr3"),
    List.atom("cr4"), List.atom("cr5"), List.atom("cr6"), List.atom("cr7")
  };
  /**
   * 状態レジスタ名称の配列
   */
  private static String[] cr = {
    "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7"
  };

  /* 定数定義 */
  private static Cell labelCell = List.atom("LABEL");
  private static Cell addCell = List.atom("ADD");
  private static Cell subCell = List.atom("SUB");
  private static Cell intconstCell = List.atom("INTCONST");

  /* デバッグ */
  private static final int debMode = 0;

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

  /**
   * 中間形式ファイル(バイナリ形式)読み込み後の再初期化処理を行う。
   */
  public void init() {
    for ( int i=0; i<gpr.length; i++ )
      gprCell[i] = List.atom(gpr[i]);
    for ( int i=0; i<vr.length; i++ )
      vrCell[i] = List.atom(vr[i]);
    for ( int i=0; i<fpr.length; i++ )
      fprCell[i] = List.atom(fpr[i]);
    for ( int i=0; i<cr.length; i++ )
      crCell[i] = List.atom(cr[i]);
    labelCell = List.atom("LABEL");
    addCell = List.atom("ADD");
    subCell = List.atom("SUB");
    intconstCell = List.atom("INTCONST");
  }

  /*****************/
  /* PUBLIC METHOD */
  /*****************/
  /**
   * S式を指定の方法で文字列に変換する。
   * @param arg		HOLEにマッチするS式
   * @param spec	変換指定文字
   * @return		変換後の文字列
   */
  public String convertHole(Cell arg, char spec) {
    if ( debMode>0 ) {
      System.out.println("convertHole: arg "+arg+" spec "+spec);
    }
    switch ( spec ) {
    case 'r':			// 汎用レジスタ
      return gpr[gprNum(arg)];
    case 'e':			// 汎用レジスタ(r0以外)
      return gpr[gprNum(arg)+1];

    case 'v':			// ベクタ・レジスタ
      return vr[vrNum(arg)];

    case 'o':			// 状態レジスタ
      return cr[crNum(arg)];

    case 'f':			// 64ビット浮動小数点レジスタ
      return fpr[fprNum(arg)];

    case 'c':			// アセンブラ定数(即値)
      return immediate(arg);
    case 'l':
      return arg.toString();	// アセンブラ定数(絶対番地、変位)(LABEL)
// 2001/07/10: 削除
//   ASMCONSTはマクロ・テンプレートで、LABEL式とINTCONST式の演算の変更した。
//    case 'a':
//      return asmconst(arg);	// アセンブラ定数(絶対番地、変位)(ASMCONST)
//
    default:
      Util.abort("PowerPCMethod: bad conversion specifier: "+spec);
    }
    return "";
  }

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

  /**
   * S式表現からベクタ・レジスタ番号に変換する。
   */
  private static int vrNum(Cell arg) {
    for(int i=0; i<vrCell.length; i++) if( vrCell[i]==arg ) return i;
    Util.abort("PowerPCMethod: bad vector register: "+arg);
    return -1;
  }

  /**
   * S式表現から浮動小数点レジスタ(64ビット)番号に変換する。
   */
  private static int fprNum(Cell arg) {
    for(int i=0; i<fprCell.length; i++) if( fprCell[i]==arg ) return i;
    Util.abort("PowerPCMethod: bad floating point register: "+arg);
    return -1;
  }

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

  /**
   * S式表現からアセンブラ定数(即値)に変換する。
   */
  private static String immediate(Cell arg) {
    return "("+arg.toString()+")";
  }

// 2001/07/10: 削除
//   ASMCONSTはマクロ・テンプレートで、LABEL式とINTCONST式の演算の変更した。
//  /**
//   * S式表現からアセンブラ定数(絶対番地、変位)に変換する。
//   */
//  private static String asmconst(Cell arg) {
//    if ( arg.isAtom() ) {
//      Util.abort("PowerPCMethod: illegal ASMCONST expression: "+arg);
//      return null;
//    } else {
//      String v = asmcSub(arg);
//      if ( v==null ) {
//	Util.abort("PowerPCMethod: illegal ASMCONST expression: "+arg);
//      }
//      return v;
//    }
//  }
//
//  /**
//   * アセンブラ定数の変換
//   */
//  private static String asmcSub(Cell arg) {
//    if ( arg.isAtom() ) {
//      return arg.toString();
//    } else {
//      if ( arg.car().isAtom() ) {
//	if ( arg.car()==labelCell ) {
//	  return arg.nth(2).toString();
//	} else if ( arg.car()==addCell ) {
//	  if ( arg.nth(2).car()!=labelCell || arg.nth(3).car()!=intconstCell ) return null;
//	  return asmcSub(arg.nth(2))+"+"+asmcSub(arg.nth(3));
//	} else if ( arg.car()==subCell ) {
//	  if ( arg.nth(2).car()!=labelCell ||
//	       (arg.nth(3).car()!=intconstCell && arg.nth(3).car()!=labelCell) ) return null;
//	  return asmcSub(arg.nth(2))+"-"+asmcSub(arg.nth(3));
//	} else if ( arg.car()==intconstCell ) {
//	  return arg.nth(2).toString();
//	} else {
//	  return null;
//	}
//      } else {
//	return null;
//      }
//    }
//  }

}

