Newer
Older
zweic / sources / zweic / Generator.scala
@glproj03 glproj03 on 19 Jan 2006 6 KB dontknow
/*  zweic -- a compiler for zwei
 *
 *  Stephane Micheloud & LAMP
 *
 *  $Id$
 */

package zweic;

class Generator(analyzer: Analyzer) {
  import RISC._;
  import scala.collection.mutable.{Map, HashMap};

  val code = new Code();

  private def genTmp(gen: Int => Unit) = {
    val tmpReg = code.getRegister();
    gen(tmpReg);
    code.freeRegister(tmpReg);
  }

  def emitLoadConstant(r: Int, value: Int) = {
	if (value > (Math.pow(2,16) - 1)) {
	  code.emit(ADDI, r, ZERO, value >> 16, value.toString());
	  //TODO: SHIFT
	  code.emit(ADDI, r, r, value << 16 >> 16);
	} else {
	  code.emit(ADDI, r, ZERO, value, value.toString());
	}
  }

  def gen(tree: Tree): Unit = tree match {
    case Program(classes, main) =>
      val init = code.getLabel();
      code.emit(BEQ,ZERO,init);

      // go initialize the VMTs
      // ... à compléter ...

      // generate class and function definitions
      // ... à compléter ...

      // generate main expression
      val start = code.getLabel();
      code.anchorLabel(start);
      genTmp { tmpReg => genLoad(main, tmpReg) }

      // exit
      code.emit(RET, ZERO);

      // the following code is placed here because the space that
      // it occupies can be used after initialization.

      code.anchorLabel(init);
      // initialise stack pointer
      code.emit(SYSCALL, SP, 0, SYS_GET_TOTAL_MEM_SIZE); 
      // initialise garbage collector:
      // the heap starts at init and 
      // its size is 2/3 * (total_mem_size - init) words
      val r1 = code.getRegister();
      val r2 = code.getRegister();
      val r3 = code.getRegister();
      emitLoadConstant(r1,init.getAnchor());
      code.emit(SUB,r2,SP,r1); 
      code.emit(DIVIU,r2,r2,3*WORD_SIZE);
      code.emit(LSHI,r2,r2,1); // r2 now contains the size of the heap
      emitLoadConstant(r3,SP << 27);
      code.emit(ADD, r2, r2, r3);
      code.emit(SYSCALL, r1, r2, SYS_GC_INIT);
      code.freeRegister(r3);
      code.freeRegister(r2);
      code.freeRegister(r1);

      // populate VMTs	  
      // ... à compléter ...

      // jump to main expression
      code.emit(BEQ, ZERO, start);

    case ClassDef(_, _, members) =>
      // ... à compléter ...

    //TODO: case FieldDecl(_, _) => ;
	case FieldDecl(_) => ;

    case method @ MethodDef(name, params, _, body) =>
      // ... à compléter ...

    case While(cond, stats) =>
      // ... à compléter ...

    case Var(varname, _, init) =>
      // ... à compléter ...

    case Set(name, expr) =>
      // ... à compléter ...

    case Do(expr) =>

    case PrintInt(expr) =>
      genTmp { tmpReg =>
        genLoad(expr, tmpReg);
        code.emit(SYSCALL, tmpReg, ZERO, SYS_IO_WR_INT, "printInt");
        code.emit(SYSCALL, ZERO, ZERO, SYS_IO_FLUSH, "flush");
      }

    case PrintChar(expr) =>
	  genTmp { tempReg =>
		genLoad(expr, tempReg);
		code.emit(SYSCALL, tempReg, ZERO, SYS_IO_WR_CHR, "printChar");
		// TODO: do we flush all day long?
		code.emit(SYSCALL, ZERO, ZERO, SYS_IO_FLUSH, "flush");
	  }

    case _ =>
	  Console.println("gen __________________________________");

  } // def gen(Tree): Unit

  def genLoad(tree: Expr, targetReg: Int): Unit = {
    def caseDefault(tree: Expr): Unit = genLoad(
      new If(tree, new IntLit(1), new IntLit(0)),
      targetReg);

    assert(code.usedRegisters()(targetReg),
      "invariant violated: target register R"
      + targetReg + " not allocated");

    tree match {
      case NullLit() =>
        // ... à compléter ...

      case IntLit(value) =>
		emitLoadConstant(targetReg, value)

      case ReadInt() =>
		code.emit(SYSCALL, targetReg, ZERO, SYS_IO_RD_INT, "readInt")

      case ReadChar() =>
		code.emit(SYSCALL, targetReg, ZERO, SYS_IO_RD_CHR, "readChar")
		
      case Unop(op, expr) =>
		genTmp { tmpReg =>
		  op match {
			case Operators.NOT => 
			  genTmp { allOnes => 
				code.emit(XOR, allOnes, ZERO, ZERO);
				genLoad(expr, tmpReg);
				code.emit(BIC, targetReg, allOnes, tmpReg);
			  }			  

		  case Operators.NEG => 
			  genLoad(expr, tmpReg);
			  code.emit(SUB, targetReg, ZERO, tmpReg, "-");
		  }
		}

      case Binop(op, left, right) =>
		genTmp { tmpLeft =>
		  genLoad(left, tmpLeft);
		  genTmp { tmpRight =>
			genLoad(right, tmpRight);
			op match {
			  case Operators.ADD =>
				code.emit(ADD, targetReg, tmpLeft, tmpRight, "+");
			  case Operators.SUB => 
				code.emit(SUB, targetReg, tmpLeft, tmpRight, "-");
			  case Operators.MUL =>
				code.emit(MUL, targetReg, tmpLeft, tmpRight, "*");
			  case Operators.DIV =>
				code.emit(DIV, targetReg, tmpLeft, tmpRight, "/");
			  case Operators.MOD =>
				code.emit(MOD, targetReg, tmpLeft, tmpRight, "%");
			  case _ =>
				Console.println("unsupported BinOp: "+op);
			  //TODO: does AND fit in here? what about other logic operations?
			}
		  }
		}

      case Block(stats, main) =>
        // ... à compléter ...

      case Ident(name) =>
        // ... à compléter ...

      case New(name, args) =>
        // ... à compléter ...

      case Select(prefix, selector) =>
        // ... à compléter ...

      case Call(receiver, method, args) =>
        // ... à compléter ...

      case If(cond, thenp, elsep) =>
		//TODO: this is absolutely wrong
		val thenpos = code.getLabel();
		val elsepos = code.getLabel();
		genCond(cond, thenpos, true);
		
		genTmp { leftret =>
		  genTmp { rightret =>			
			genLoad(thenp, leftret);
			genLoad(elsep, rightret);			
		  }
		}		
      case _ =>
		Console.println("LoadGen________________");
        // ... à compléter ...
    }
  } // genLoad



  /**
   * Generates code for conditions, that is constructs
   * which jump somewhere on the result of a test.
   */
  private def genCond(tree: Expr, targetLabel: code.Label, when: Boolean): Unit = {
    // ... à compléter ...
	
	//genTmp { tmpLeft =>

    tree match {	  
        case Binop(op, left, right) => 
		  //op match {
          // ... à compléter ...
		
        case Unop(op, expr) => ()
          // ... à compléter ...

        case _ => ()
          //TODO: caseDefault(tree)
/*
			  case Operators.EQ =>
				code.emit(CMP, targetReg, tmpLeft, tmpRight, "*");

			  case Operators.LT =>
				//TODO
			  case Operators.LE =>
				//TODO				
			  case Operators.GT =>
				//TODO
			  case Operators.GE =>
				//TODO

			  case Operators.AND =>
				code.emit(AND, targetReg, tmpLeft, tmpRight, "*");
*/		
    }
  } // genCond


}