[CS143-PA4] Code Generator

[CS143-PA4] Code Generator

produce MIPS assembly code

full file link https://github.com/Aria461863631/cs143/tree/master/PA5


0. pointers

accumulator : $a0

SELF object : $s0

FP (Frame Pointer) : $fp

  • point to current activation record, use to find variables

SP (Stack Pointer) : $sp


Object layout

offset
grabage collector tag -4
class tag 0
object size 4
dispatch ptr 8
attributes 12

class tag : identifier of class

objecy size : size of object in words

dispactch ptr : pointer to dispatch table

class attributes


Activation Record

used on function calls

AR structure pointer
Argument 1
Argument 2
Argument n
old frame pointer
old self pointer
return address
temp n
temp 2
temp 1 cur fp
cur sp


Temporaries

  • are kept in AR in my implementation
  • size of temps are computed before each methods
  • didn’t use registers $s1 for optimization as coolc sample in my implementation
  • how to compute


Environment

cool-manual 13.1

An environment is a mapping of variable identifiers to locations.

if $E = [a : l_1]$ and $S = [l_1 → 55] $, it means a has value 55


implementation

According to the structure of Objects and AR, I divide my environment into three parts

  • Attributes (in Objects, start from self pointer )
  • Arguments (in AR, start from current frame pointer + temp size )
  • Local variables (let, case …) (in AR, start from current frame pointer )

each part has function enterscope, add, get and exitscope


Program Entrance

One reasonable strategy is to perform code generation in two passes.

  • The first pass decides the object layout for each class, particularly the offset at which each attribute is stored in an object. Using this information
  • the second pass recursively walks each feature and generates stack machine code for each expression.
1
2
3
4
5
6
7
8
9
10
11
void program_class::cgen(ostream &os) {
  // spim wants comments to start with '#'
  os << "# start of generated code\n";
  cgen_debug = 0;

  initialize_constants();
  codegen_classtable = new CgenClassTable(classes, os);
  codegen_classtable->execute();

  os << "\n# end of generated code\n";
}

CgenClassTable

I changed the order of install_basic_classes to fit the class tags : Object, Int, Bool, Str, IO

1
2
3
4
5
6
7
8
9
10
11
12
13
14
CgenClassTable::CgenClassTable(Classes classes, ostream &s)
    : nds(NULL), str(s) {
  stringclasstag = 3 /* Change to your String class tag here */;
  intclasstag = 1 /* Change to your Int class tag here */;
  boolclasstag = 2 /* Change to your Bool class tag here */;

  enterscope();

  install_basic_classes();
  install_classes(classes);
  build_inheritance_tree();

  code();
}

code headers

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
void CgenClassTable::code() {
  str << "# coding global data" << endl;
  code_global_data();

  str << "# choosing gc" << endl;
  code_select_gc();

  str << "# coding constants" << endl;
  code_constants();

  //                 Add your code to emit
  //                   - prototype objects
  //                   - class_nameTab
  //                   - dispatch tables
  //
  str << "# coding class name table" << endl;
  code_class_nameTab();
  str << "# coding class obj table" << endl;
  code_class_objTab();
  str << "# coding dispatch tables" << endl;
  code_class_dispTab();
  str << "# coding prototype object" << endl;
  code_class_protObj();

  str << "# coding global text" << endl;
  code_global_text();
}


Class Tags

used to find class, especially in typcase

Case expressions provide runtime type tests on objects.

From among the branches the branch with the least type K such that C ≤ K is selected.

Ordering class tags so that they can reflect to structure of the tree


forexample

1
2
3
4
5
6
7
8
9
10
class A{};
class B inherits A{};
class C inherits A{};
class D inherits B{};
class E inherits C{};
class F inherits D {};
class G inherits IO{};
class Main inherits IO {
  main() : Object { 1 };
};

class_nameTab

  • a table, which at index (class tag) ∗ 4 contains a pointer to a String object containing the name of the
    class associated with the class tag

DFS the inheritance tree from root

result

1
2
3
4
5
6
7
8
9
class_nameTab:
	.word	str_const5  # Object
	.word	str_const6  # Int
	.word	str_const7  # Bool
	.word	str_const8  # Str
	.word	str_const9  # IO
	.word	str_const16 # G inherits IO
	.word	str_const17 # Main inherits IO
	.......


Object Table

result

1
2
3
4
5
6
7
class_objTab:
	.word	Object_protObj
	.word	Object_init
	.word	Int_protObj
	.word	Int_init
	.word	Bool_protObj
	...


Dispatch Table

Method in each class must have a fixed index, for further searching

Pay attention to overriding : overriding method have the old index but new class names

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
void CgenClassTable::code_class_dispTab() {
  std::vector<std::pair<Symbol, Symbol>> mp;
  // dfs from root, easy to find override method  
  root()->code_dispTab(mp, str);
}

/*
 * vector mp maps method name to class name at index i
 * pass down this vector to children for inherited methods
 */
void CgenNode::code_dispTab(std::vector<std::pair<Symbol, Symbol>> mp,
                            ostream &s) {
  emit_disptable_ref(name, s);
  s << LABEL;

  // save method_index map, member of CgenNode
  method_index = get_parentnd()->method_index; 
  int m_size = method_index.size();

  for (int i = features->first(); features->more(i); i = features->next(i)) {
    if (!features->nth(i)->is_method())
      continue;

    method_class *m = (method_class *)features->nth(i);
    Symbol method_name = m->name;
    //get index of the method  
    if (method_index.find(method_name) == method_index.end()) {
      //it's a new method  
      method_index.insert(std::make_pair(method_name, m_size++));
      mp.push_back(std::make_pair(method_name, name));
    } else {
      // override
      int index = method_index[method_name];
      mp[index].second = name;
    }
  }

  //output all methods from root class ( saved in vector mp )  
  for (int i = 0; i < (int)mp.size(); ++i) {
    s << WORD;
    emit_method_ref(mp[i].second, mp[i].first, s);
    s << endl;
  }

  //dfs to children  
  for (List<CgenNode> *l = children; l; l = l->tl())
    l->hd()->code_dispTab(mp, s);
}

example

1
2
3
4
5
6
7
8
9
class A {
    method_one():Object {1};
    method_two():Object {1};
};

class B inherits A {
    method_one():Object {2}; //override method
    method_three():Object{3};
};

result

1
2
3
4
5
6
7
B_dispTab:
	.word	Object.abort
	.word	Object.type_name
	.word	Object.copy
	.word	B.method_one # override method at same index but has new class name
	.word	A.method_two # inherited method
	.word	B.method_three


Prototype Object

The only way to allocate a new object in the heap is to use the Object.copy method. Thus, there must
be an object of every class that can be copied. For each class X in the Cool program, the code generator
should produce a skeleton X object in the data area; this object is the prototype of class X.

Attribute in each object must have a fixed index, for further searching

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
void CgenClassTable::code_class_protObj() {
  std::vector<Symbol> mp;
  root()->code_protObj(mp, str);
}
/*
 * vector mp saves attributes at index i
 * pass down this vector to children for inherited attributes
 */
void CgenNode::code_protObj(std::vector<Symbol> mp, ostream &s) {
  //map attribute to index, member of CgenNode
  attr_index = get_parentnd()->attr_index;
  int a_size = attr_index.size();

  for (int i = features->first(); features->more(i); i = features->next(i)) {
    if (!features->nth(i)->is_attr())
      continue;

    //attibutes cannot override, just add them
    attr_class *a = (attr_class *)features->nth(i);
    attr_index.insert(std::make_pair(a->name, a_size++));
    mp.push_back(a->type_decl);
  }

  s << WORD << "-1" << endl; // the garbage tage is -1
  emit_protobj_ref(name, s);
  s << LABEL; //class tag at offset 0, object size at offset 4
  s << WORD << tag << endl << WORD << (DEFAULT_OBJFIELDS + a_size) << endl;
  s << WORD; //dispatch table pointer at offset 8
  emit_disptable_ref(name, s);
  s << endl;

 /* 
  * attributes start at offset 12
  *
  * basic classes: cool-manual 13.3
  * The default of Int is 0, 
  * the default of String is "",
  * the default of Bool is false,
  */
  if (name == Int || name == Bool) {
    s << WORD << "0" << endl;
  } else if (name == Str) {
    s << WORD;
    inttable.lookup_string("0")->code_ref(s);
    s << endl << WORD << "0" << endl;
      
//others
  } else {
    for (int i = 0; i < (int)mp.size(); ++i) {
      Symbol type = mp[i];
        
      /* The default initialization for variables
       * of type Int and Bool is 0 (not void) */ 
      if (type == Int) {
        s << WORD;
        inttable.lookup_string("0")->code_ref(s);
        s << "\t# int(0)" << endl;
      } else if (type == Bool) {
        s << WORD;
        falsebool.code_ref(s);
        s << "\t# bool(0)" << endl;
          
      /* The default initialization for variables
       * of type String is "" (not void)  */  
      } else if (type == Str) {
        s << WORD;
        stringtable.lookup_string("")->code_ref(s);
        s << "\t# s(\"\")" << endl;
          
      /* others set to void by default */    
      } else {
        s << WORD << "0\t# void" << endl;
      }
    }
  }
  /* dfs children */
  for (List<CgenNode> *l = children; l; l = l->tl())
    l->hd()->code_protObj(mp, s);
}

result

1
2
3
4
5
6
	.word	-1
A_protObj:
	.word	6
	.word	4
	.word	A_dispTab
	.word	int_const1	# int(0)


Execute & Environment

execute after obtaining global std::map<Symbol, int> class_tags

1
2
3
4
5
6
7
8
9
10
11
12
void CgenClassTable::execute() {
  //                 Add your code to emit
  //                   - object initializer
  //                   - the class methods
  //                   - etc...
  str << "# coding init" << endl;
  code_class_init();
  str << "# code method" << endl;
  code_methods();

  exitscope();
}


Init

code that initializes an object of classes, used in new

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
void CgenClassTable::code_class_init() { root()->code_init(str); }
// init-----------
void CgenNode::code_init(ostream &s) {
  current_class = name;

  /*
   * build up environment!
   * assignment of new attr may envolve previous ones
   * so we need to know their positions
   */
  env.add_Attribute(this);

  /*
   * compute the number of temps required
   * for attributes assignment
   * start from the root of init expr
   */
  temp_size = 0;
  for (int i = features->first(); features->more(i); i = features->next(i)) {
    if (!features->nth(i)->is_attr())
      continue;
    attr_class *a = (attr_class *)features->nth(i);
    temp_size = std::max(temp_size, a->tmp_Num());
  }
  used_temp = 0;/* remember used temps globally */

  emit_init_ref(name, s);
  s << LABEL;

  /*
   * push fp, s0, ra on stack
   * and reserve places for temps
   */
  emit_push_stack(temp_size, s);

  /*
   * Call Parent_Init
   * Initialize parent object and attributes first
   */
  Symbol parent_name = parentnd->name;
  if (parent_name != No_class) {
    s << JAL;
    emit_init_ref(parent_name, s);
  }

  /* Initialize attribute assignment */
  for (int i = features->first(); features->more(i); i = features->next(i)) {
    if (!features->nth(i)->is_attr())
      continue;
    attr_class *a = (attr_class *)features->nth(i);

    if (a->init->isempty()) {
    } else {
      s << "\t# initialize argument " << a->name << endl;
      a->init->code(s);

      /* store init result on attribute position */
      int indx = attr_index[a->name];
      emit_store(ACC, DEFAULT_OBJFIELDS + indx, SELF, s);

      /* Garbage Collector */
      if (cgen_Memmgr == 1) {
        emit_addiu(A1, SELF, 4 * (indx + DEFAULT_OBJFIELDS), s);
        emit_gc_assign(s);
      }
    }
  }

  /* return self object after init */
  s << "\t# return self" << endl;
  emit_move(ACC, SELF, s);
  emit_pop_stack(temp_size, s);

  /* go to child */
  for (List<CgenNode> *l = children; l; l = l->tl())
    l->hd()->code_init(s);
}


Methods

root: build up attribute env

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void CgenClassTable::code_methods() {
  /* Generate methods code of all classes */
  for (List<CgenNode> *l = nds; l; l = l->tl()) {
    CgenNodeP cur = l->hd();

    /* build up attribute environment and
     * self object in each class */
    env.add_Attribute(cur);
    current_class = cur->name;
  
    /* skip basic classes */

    /* generate code from method expr */  
  }
}

before coding method body

  • compute temp size for stack reservation
  • build up argument env
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void method_class::code(ostream &s) {
  /* compute temp size and push stack */

  /* build up argument environment in each method */
  env.args_enter();
  install_args();

  /* coding method body! */  
  expr->code(s);

  env.args_exit();

  /* pop stack including attributes */
}


object & assign

find / store value in the environment

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
void object_class::code(ostream &s) {
  s << "\t# It's Object " << name << endl;
  int indx;

  /*
   * due to the standard of scopes
   * we must find name from variables first
   * then argument, last attribute
   * 
   * ASSIGN_CLASS: only to change emit_load into emit_store 
   */
  if ((indx = env.get_Var(name)) != -1) {
    s << "\t# find in " << indx << " position in let variables\n";
    emit_load(ACC, indx, FP, s);
    if (cgen_Memmgr == 1) {
      emit_addiu(A1, FP, 4 * indx, s);
      emit_gc_assign(s);
    }

  } else if ((indx = env.get_Argument(name)) != -1) {
    s << "\t# find in " << indx << " position in argument\n";
    emit_load(ACC, DEFAULT_FPFIELDS + temp_size + indx, FP, s);
    if (cgen_Memmgr == 1) {
      emit_addiu(A1, FP, 4 * (DEFAULT_FPFIELDS + temp_size + indx), s);
      emit_gc_assign(s);
    }

  } else if ((indx = env.get_Attribute(name)) != -1) {
    s << "\t# find in " << indx << " position in attribute\n";
    emit_load(ACC, DEFAULT_OBJFIELDS + indx, SELF, s);
    if (cgen_Memmgr == 1) {
      emit_addiu(A1, SELF, 4 * (DEFAULT_OBJFIELDS + indx), s);
      emit_gc_assign(s);
    }

  } else if (name == self) {
    s << "\t# It is self." << endl;
    emit_move(ACC, SELF, s);
  } else {
    s << "\t#obj not found! ERRORRRRRRRRRRRRRRRRRRRRRRRR\n";
  }
}


dispatch & static_dispatch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
void dispatch_class::code(ostream &s) {
  s << "# dispatch exp " << name << "\n";

  for (int i = actual->first(); actual->more(i); i = actual->next(i)) {
    actual->nth(i)->code(s);
    s << "\t# push arguments on stack\n";
    emit_push(ACC, s);
  }

  s << "\t# then eval e0 and save in a0\n";
  expr->code(s);

  s << "\t# if e0 is void \n";
  int e0_not_zero = label_num++;
  emit_bne(ACC, ZERO, e0_not_zero, s);
  s << "\t# abort\n\t#loading filename to a0 and linenumber to t1\n";
  s << LA << ACC << " str_const0" << endl;
  emit_load_imm(T1, 1, s);
  emit_jal("_dispatch_abort", s);

  s << "\t# continue dispatching\n";
  emit_label_def(e0_not_zero, s);

  //------------------------

  Symbol old_class = current_class;

  if (expr->get_type() != SELF_TYPE)
    current_class = expr->get_type();
  CgenNodeP c = codegen_classtable->probe(current_class);

  int indx = c->method_index[name];
  s << "\t# locate method " << name << " of class " << current_class << endl;
  
  s << "\t# get self's dispatch table\n";
  emit_load(T1, 2, ACC, s);

  s << "\t# find method in index " << indx << endl;
  emit_load(T1, indx, T1, s);

  current_class = old_class;

  s << "\t# jump to method " << name << endl;
  emit_jalr(T1, s);
}


let

using variable environment

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
void let_class::code(ostream &s) {
  s << "# let exp\n";
  s << "\t# first eval init exps\n";
  init->code(s);

  if (init->isempty()) {
    // We still need to deal with basic types.
    if (type_decl == Str) {
      emit_load_string(ACC, stringtable.lookup_string(""), s);
    } else if (type_decl == Int) {
      emit_load_int(ACC, inttable.lookup_string("0"), s);
    } else if (type_decl == Bool) {
      emit_load_bool(ACC, BoolConst(0), s);
    }
  }

  s << "\t# push let var " << identifier << " onto temp\n";
  emit_push_temp(ACC, s);
  env.vars_enter();
  env.add_Variable(identifier, used_temp - 1);

  s << "\t# eval let body\n";
  body->code(s);

  env.vars_exit();

  s << "\t# pop let var " << endl;
  s << "\t# used_temp--;" << endl;
  used_temp--;
}


typcase

using our definition of class tags

  • start from the node with the maximum tag
  • if current object has between node’s tag and its deepest children’s tag

as the class tag example above

1
2
3
4
5
6
7
8
9
10
11
12
13
main() : Object { 
    case thing of
      o : Object => 1;
      a : A => 1;
      b : B => 1;
      c : C => 1;
      d : D => 1;
      e : E => 1;
      f : F => 1;
      g : G => 1;
   m : Main => 1;
    esac
  };


we generate from

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
label1:
	# T2 = class tag of e0
	lw	$t2 0($a0)
	blt	$t2 12 label2 # type E
	bgt	$t2 12 label2 # with the maximum tag
	la	$a0 int_const0 # and it's a leaf
	b	label0
label2:
	blt	$t2 11 label3 # type C -> child E
	bgt	$t2 12 label3 # but we've already checked whether E 
	la	$a0 int_const0 # is the closest to our object tag
	b	label0 # so the children won't bother when we search their parents
	# however, if we don't have type E in our cases 
	# although E might be the type of our object
	# than C will be the least common ancestor 

label3:
	blt	$t2 10 label4 # type F next
	bgt	$t2 10 label4
	la	$a0 int_const0
	b	label0
label4:
	blt	$t2 9 label5 # than type D -> F
	bgt	$t2 10 label5
	la	$a0 int_const0
	b	label0
label5:
	blt	$t2 8 label6 # type B -> F
	bgt	$t2 10 label6
	la	$a0 int_const0
	b	label0
label6:
	blt	$t2 7 label7 # type A -> E
	bgt	$t2 12 label7
	la	$a0 int_const0
	b	label0
label7:
	blt	$t2 6 label8 # type Main
	bgt	$t2 6 label8
	la	$a0 int_const0
	b	label0
label8:
	blt	$t2 5 label9 # type G
	bgt	$t2 5 label9
	la	$a0 int_const0
	b	label0
label9:
	blt	$t2 0 label10 # Object!
	bgt	$t2 12 label10
	la	$a0 int_const0
	b	label0
label10:
	jal	_case_abort # no type matches
label0:
	lw	$fp 16($sp)
	lw	$s0 12($sp)
	lw	$ra 8($sp)
	addiu	$sp $sp 16
	jr	$ra

implementation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
int branch_class::get_child_tag() {
	/* return the maximum tag of its children */
}

void typcase_class::code(ostream &s) {
  s << "# typcase expr\n";
  int finish_label = label_num++;

  s << "\t# eval e0\n";
  expr->code(s);
  s << "\t# save expr on temp\n";
  emit_push_temp(ACC, s);

  s << "\t# abort if void\n";
  emit_bne(ACC, ZERO, label_num, s);
  emit_load_address(ACC, "str_const0", s);
  emit_load_imm(T1, 1, s);
  emit_jal("_case_abort2", s);
  emit_label_def(label_num++, s);

  s << "\t# T2 = class tag of e0\n";
  emit_load(T2, 0, ACC, s);

  //-------------------------------
  //计算所有case 的tag
  //计算所有case的孩子最大tag
  //按照大到小的顺序排序,输出
  std::vector<std::pair<int, int>> case_tag;
  std::map<int, Expression> mp;
  env.vars_enter();
  for (int i = cases->first(); cases->more(i); i = cases->next(i)) {
    branch_class *b = (branch_class *)cases->nth(i);

    //局部变量,let覆盖?
    env.add_Variable(b->name, used_temp - 1);
    int fs = class_tags[b->type_decl];
    int se = b->get_child_tag();
    if (cgen_debug)
      cout << "[ " << fs << " , " << se << " ]\n";
    case_tag.push_back(std::make_pair(fs, se));
    mp.insert(std::make_pair(fs, b->expr));
  }

  auto sortbysec = [&](const std::pair<int, int> &a,
                       const std::pair<int, int> &b) {
    return (a.first > b.first);
  };

  /* sort class tags in decreasing order */  
  std::sort(case_tag.begin(), case_tag.end(), sortbysec);

  for (int i = 0; i < (int)case_tag.size(); ++i) {
    int fs = case_tag[i].first, se = case_tag[i].second;
    int next_case = label_num++;
    emit_blti(T2, fs, next_case, s);
    emit_bgti(T2, se, next_case, s);

    mp[fs]->code(s);

    emit_branch(finish_label, s);
    emit_label_def(next_case, s);
  }
  emit_jal("_case_abort", s);

  used_temp--;
  env.vars_exit();
  emit_label_def(finish_label, s);
}


new

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void new__class::code(ostream &s) {
  s << "# new exp\n";
  if (type_name == SELF_TYPE) {
    s << "\t# new selftype, find it out\n";
    emit_load_address(T1, "class_objTab", s);
    s << "\t# get class by tag\n";
    emit_load(T2, 0, SELF, s);
    emit_sll(T2, T2, 3, s);
    s << "\t# get self prototype addr\n";
    emit_addu(T1, T1, T2, s);

    s << "\t# push addr on temp\n";
    emit_push_temp(T1, s);
    emit_load(ACC, 0, T1, s);
    emit_jal("Object.copy", s);

    s << "\t# pop addr from temp\n";
    emit_pop_temp(T1, s);
    s << "\t# get self init addr\n";
    emit_load(T1, 1, T1, s);
    s << "\t# goto init\n";
    emit_jalr(T1, s);

    return;
  }


cond & loop

using labels

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void cond_class::code(ostream &s) {
  s << "# if_else exp\n";
  s << "\t# eval predicate\n";
  pred->code(s);
  s << "\t# extract bool value of predicate to T1\n";
  emit_fetch_int(T1, ACC, s);

  int false_label = label_num++;
  int finish_label = label_num++;
  s << "\t# if false, goto else\n";
  emit_beq(T1, ZERO, false_label, s);

  s << "\t# coding then exp\n";
  then_exp->code(s);
  s << "\t# jump to finish label\n";
  emit_branch(finish_label, s);

  s << "\t# coding else exp\n";
  emit_label_def(false_label, s);
  else_exp->code(s);

  s << "\t# finish\n";
  emit_label_def(finish_label, s);
}


add & sub & mul & div & lt & eq & leq

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void plus_class::code(ostream &s) {
  s << "# Plus\n";
  s << "\t# start eval e1" << endl;
  e1->code(s);
  s << "\t# e1 save to temp var" << endl;
  emit_push_temp(ACC, s);

  s << "\t# start eval e2 and copy" << endl;
  e2->code(s);
  emit_jal("Object.copy", s);

  s << "\t# pop e1 to t1, move e2 to t2\n"
    << "\t# a0 has true and a1 has false to call equality_test\n";
  emit_pop_temp(T1, s);

  s << "\t# extract int value inside the object\n";
  emit_load(T1, 3, T1, s);
  emit_load(T2, 3, ACC, s);

  s << "\t# modify int into t1\n";
  emit_add(T1, T1, T2, s);
  emit_store(T1, 3, ACC, s);
}


neg & comp & block & isvoid & no_expr