⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 addop.java

📁 A framework written in Java for implementing high-level and dynamic languages, compiling them into J
💻 JAVA
字号:
// Copyright (c) 2000, 2001, 2003, 2005  Per M.A. Bothner.// This is free software;  for terms and warranty disclaimer see ./COPYING.package gnu.kawa.functions;import gnu.math.*;import java.math.*;import gnu.mapping.*;import gnu.expr.*;import gnu.bytecode.*;import gnu.kawa.lispexpr.LangPrimType;/** * Implement the Scheme standard functions "+" and "-". * @author Per Bothner */public class AddOp extends ProcedureN implements CanInline, Inlineable{  int plusOrMinus = 1;  public AddOp(String name, int plusOrMinus)  {    setName(name);    this.plusOrMinus = plusOrMinus;  }  public static final AddOp $Pl = new AddOp("+", 1);  public static final AddOp $Mn = new AddOp("-", -1);  public static Object apply2(int plusOrMinus, Object arg1, Object arg2)  {    int code1 = Arithmetic.classifyValue(arg1);    int code2 = Arithmetic.classifyValue(arg2);    /*    if (code1 < 0 || code2 < 0)    throw new ClasscastException(); // FIXME    */    int code = code1 < code2 ? code2 : code1;    switch (code)      {      case Arithmetic.INT_CODE:	int i1 = Arithmetic.asInt(arg1);	int i2 = Arithmetic.asInt(arg2);	return new Integer(plusOrMinus > 0 ? i1 + i2 : i1 - i2);      case Arithmetic.LONG_CODE:	long l1 = Arithmetic.asLong(arg1);	long l2 = Arithmetic.asLong(arg2);	return new Long(plusOrMinus > 0 ? l1 + l2 : l1 - l2);      case Arithmetic.BIGINTEGER_CODE:	BigInteger bi1 = Arithmetic.asBigInteger(arg1);	BigInteger bi2 = Arithmetic.asBigInteger(arg2);	return plusOrMinus > 0 ? bi1.add(bi2) : bi1.subtract(bi2);      case Arithmetic.INTNUM_CODE:	return IntNum.add(Arithmetic.asIntNum(arg1), Arithmetic.asIntNum(arg2),			  plusOrMinus);      case Arithmetic.BIGDECIMAL_CODE:	BigDecimal bd1 = Arithmetic.asBigDecimal(arg1);	BigDecimal bd2 = Arithmetic.asBigDecimal(arg2);	return plusOrMinus > 0 ? bd1.add(bd2) : bd1.subtract(bd2);      case Arithmetic.RATNUM_CODE:	return RatNum.add(Arithmetic.asRatNum(arg1), Arithmetic.asRatNum(arg2),			  plusOrMinus);      case Arithmetic.FLOAT_CODE:	float f1 = Arithmetic.asFloat(arg1);	float f2 = Arithmetic.asFloat(arg2);	return new Float(plusOrMinus > 0 ? f1 + f2 : f1 - f2);      case Arithmetic.DOUBLE_CODE:	double d1 = Arithmetic.asDouble(arg1);	double d2 = Arithmetic.asDouble(arg2);	return new Double(plusOrMinus > 0 ? d1 + d2 : d1 - d2);      case Arithmetic.FLONUM_CODE:	d1 = Arithmetic.asDouble(arg1);	d2 = Arithmetic.asDouble(arg2);	return new DFloNum(plusOrMinus > 0 ? d1 + d2 : d1 - d2);      default:	Numeric num1 = Arithmetic.asNumeric(arg1);	Numeric num2 = Arithmetic.asNumeric(arg2);	return num1.add(num2, plusOrMinus);      }  }  public static Object $Pl(Object arg1, Object arg2)  {    return apply2(1, arg1, arg2);  }  public static Object $Mn(Object arg1, Object arg2)  {    return apply2(-1, arg1, arg2);  }  public static Object $Mn(Object arg1)  {    return ((Numeric) arg1).neg();  }  public static Object $Pl$V (Object arg1, Object arg2,			       Object arg3, Object[] rest)  {    return applyN(1, apply2(1,apply2(1, arg1, arg2), arg3), rest);  }  public static Object $Mn$V (Object arg1, Object arg2,			       Object arg3, Object[] rest)  {    return applyN(-1, apply2(-1,apply2(-1, arg1, arg2), arg3), rest);  }  public static Object applyN(int plusOrMinus, Object[] args)  {    int len = args.length;    if (len == 0)      return IntNum.zero ();    Object result = args[0];    if (len == 1 && plusOrMinus < 0)      return $Mn(result);    for (int i = 1; i < len; i++)      result = apply2(plusOrMinus, result, args[i]);    return result;  }  public static Object applyN(int plusOrMinus, Object init, Object[] args)  {    int len = args.length;    Object result = init;    for (int i = 0; i < len; i++)      result = apply2(plusOrMinus, result, args[i]);    return result;  }  public Object applyN (Object[] args)  {    return applyN(plusOrMinus, args);  }  /** Convert (PROC A B C) to (PROC (PROC A B) C) etc. */  public static Expression pairwise(Procedure proc,                                    Expression rproc, Expression[] args,				    ExpWalker walker)  {    int len = args.length;    Expression prev = args[0];    for (int i = 1;  i < len;  i++)      {        Expression[] args2 = new Expression[2];        args2[0] = prev;        args2[1] = args[i];        ApplyExp next = new ApplyExp(rproc, args2);        if (proc instanceof CanInline)          prev = ((CanInline) proc).inline(next, walker);        else          prev = next;      }    return prev;  }  public Expression inline (ApplyExp exp, ExpWalker walker)  {    // Inlining may yield PrimProcedure instructions of bytecode instructions    // which we don't know how to interpret (yet).    if (! walker.getCompilation().mustCompile)      return exp;    Expression folded = exp.inlineIfConstant(this, walker);    if (folded != exp)      return folded;    Expression[] args = exp.getArgs();    if (args.length > 2)      return pairwise(this, exp.getFunction(), args, walker);    if (args.length == 1 && plusOrMinus < 0)      {        Type type0 = args[0].getType();        if (type0 instanceof PrimType)          {            char sig0 = type0.getSignature().charAt(0);            Type type = null;            int opcode = 0;            if (sig0 == 'V' || sig0 == 'Z' || sig0 == 'C')              {                // error              }            else if (sig0 == 'D')              {                opcode = 119 /* dneg */;                type = LangPrimType.doubleType;              }            else if (sig0 == 'F')              {                opcode = 118 /* fneg */;                type = LangPrimType.floatType;              }            else if (sig0 == 'J')              {                opcode = 117 /* lneg */;                type = LangPrimType.longType;              }            else              {                opcode = 116 /* ineg */;                type = LangPrimType.intType;              }            if (type != null)              {                PrimProcedure prim                  = PrimProcedure.makeBuiltinUnary(opcode, type);                return new ApplyExp(prim, args);              }          }      }    if (args.length == 2)      {	return primInline(plusOrMinus > 0 ? 96 /* iadd */ : 100 /* isub */,			  exp);      }    return exp;  }  public static Expression primInline (int opcode, ApplyExp exp)  {    Expression[] args = exp.getArgs();    if (args.length == 2)      {        Type type0 = args[0].getType();        Type type1 = args[1].getType();        if (type0 instanceof PrimType && type1 instanceof PrimType)          {            char sig0 = type0.getSignature().charAt(0);            char sig1 = type1.getSignature().charAt(0);            Type type = null;            if (sig0 == 'V' || sig0 == 'Z' || sig0 == 'C'                || sig1 == 'V' || sig1 == 'Z' || sig1 == 'C')              {                // error              }            else if (sig0 == 'D' || sig1 == 'D')              {                opcode += 3;                type = LangPrimType.doubleType;              }            else if (sig0 == 'F' || sig1 == 'F')              {                opcode += 2;                type = LangPrimType.floatType;              }            else if (sig0 == 'J' || sig1 == 'J')              {                opcode += 1;                type = LangPrimType.longType;              }            else              {                type = LangPrimType.intType;              }            if (type != null)              {                PrimProcedure prim                  = PrimProcedure.makeBuiltinBinary(opcode, type);                return new ApplyExp(prim, args);              }          }      }    return exp;  }  /*  static ClassType typeInteger = ClassType.make("java.lang.Integer");  static ClassType typeLong = ClassType.make("java.lang.Long");  */  static ClassType typeIntNum = ClassType.make("gnu.math.IntNum");  static ClassType typeDFloNum = ClassType.make("gnu.math.DFloNum");  static ClassType typeRealNum = ClassType.make("gnu.math.RealNum");  static ClassType typeNumeric = ClassType.make("gnu.math.Numeric");  public void compile (ApplyExp exp, Compilation comp, Target target)  {    Expression[] args = exp.getArgs();    int len = args.length;    if (len == 0)      {	comp.compileConstant(IntNum.zero(), target);	return;      }    Type type = getReturnType(args);    Type ttype = target.getType();    if (len == 1 || target instanceof IgnoreTarget)      {	// FIXME implement optimization for unary	ApplyExp.compile(exp, comp, target);	return;      }    PrimType ptype = null;    if (ttype instanceof PrimType)      {	char sig = type.getSignature().charAt(0);	if (sig == 'V' || sig == 'Z' || sig == 'C')	 ptype = null; // error	else if (sig == 'D' || sig == 'F')	  {	    if (type.isSubtype(typeRealNum))	      ptype = LangPrimType.doubleType;	  }	else	  {	    if (type.isSubtype(typeIntNum))	      ptype = sig == 'J' ? LangPrimType.longType : LangPrimType.intType;	  }      }    if (ptype != null)      {	CodeAttr code = comp.getCode();	// FIXME would be nice to use iinc when appropriate!	// We would need to use a special LocalVariableTarget,	// created by SetExp when dest is a local variable.	// Then if len==2 && ptype==LangPrimType.intType	// && target instanceof LocalVariableTarget	// && one arg is QuoteExp && other arg is same local as target	// => then emit iinc.	args[0].compile(comp, ttype);	for (int i = 1;  i < len;  i++)	  {	    args[i].compile(comp, ptype);	    if (plusOrMinus > 0)	      code.emitAdd(ptype);	    else	      code.emitSub(ptype);	  }	target.compileFromStack(comp, ttype);      }    else if (type.isSubtype(typeDFloNum))      {	PrimType dtype = LangPrimType.doubleType;	Target dtarget = new StackTarget(dtype);	CodeAttr code = comp.getCode();	args[0].compile(comp, dtarget);	for (int i = 1;  i < len;  i++)	  {	    args[i].compile(comp, dtarget);	    if (plusOrMinus > 0)	      code.emitAdd(dtype);	    else	      code.emitSub(dtype);	  }	target.compileFromStack(comp, dtype);      }    else      ApplyExp.compile(exp, comp, target);  }  /** Classify an expression according to its numeric type.   * kind==0:  not a number.   * kind==1:  a non-real number   * kind==2:  real number   * kind==3:  floating-point   * kind==4:  exact integer   */  public static int classify (Type type)  {    int kind = 0;    if (type instanceof PrimType)      {	char sig = type.getSignature().charAt(0);	if (sig == 'V' || sig == 'Z' || sig == 'C')	  return 0;	else if (sig == 'D' || sig == 'F')	  return 3;	else	  return 4;      }    else if (type.isSubtype(typeIntNum))      return 4;    else if (type.isSubtype(typeDFloNum))      return 3;    else if (type.isSubtype(typeRealNum))      return 2;    else if (type.isSubtype(typeNumeric))      return 1;    else      return 0;  }  public Type getReturnType (Expression[] args)  {    int len = args.length;    if (len == 0)      return typeIntNum;    Type type = Type.pointer_type;    int kind0 = 0;    for (int i = 0;  i < len;  i++)      {	Expression arg = args[i];	int kind = classify(arg.getType());	if (kind == 0)	  return Type.pointer_type;	if (i == 0)	  kind0 = kind;	if (kind0 == 4 && kind == 4)	  type = typeIntNum;	else if (kind0 >= 2 && kind >= 2)	  {	    if (kind0 == 3 || kind == 3)	      {		type = typeDFloNum;		kind0 = 3;	      }	    else	      {		type = typeRealNum;		kind0 = 2;	      }	  }	else if (kind0 >= 1 && kind >= 1)	  {	    type = typeNumeric;	    kind0 = 1;	  }	else	  return Type.pointer_type;      }    return type;  }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -