Newer
Older
zweic / sources / zweic / Generator.scala
/*  zweic -- a compiler for zwei
 *
 *  Stephane Micheloud & LAMP
 *
 *  $Id$
 */

package zweic;
import Operators._;

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) = {
	code.emit(ADDI, r, ZERO, value, value.toString());
	//TODO: immediats bigger than 2^16 have to be shifted
  }

  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) =>
	  Console.println("DO");
	  genTmp { tempReg =>
		genLoad(tree.asInstanceOf[Expr], tempReg)
	  }

    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) =>
		op match {
		  case NOT => 
			//TODO

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

		  case _ =>
			Console.println("unop _________");
		}

      case Binop(op, left, right) =>
        // ... à compléter ...

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

      case If(cond, thenp, elsep) =>
        // ... à 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 _ =>
		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 ...
    tree match {
        case Binop(op, left, right) => ()//op match {
          // ... à compléter ...
		
        case Unop(op, expr) => ()
          // ... à compléter ...

        case _ => ()
          //TODO: caseDefault(tree)
		
    }
  } // genCond


}