expression except case done

This commit is contained in:
ridethepig 2023-03-31 15:09:48 +00:00
parent d279a73fb5
commit 7140f01bb0
3 changed files with 279 additions and 22 deletions

View File

@ -26,6 +26,7 @@
#include "cgen_gc.h" #include "cgen_gc.h"
#include "cool-tree.h" #include "cool-tree.h"
#include <cassert> #include <cassert>
#include <cstddef>
#include <iostream> #include <iostream>
#include <utility> #include <utility>
@ -623,9 +624,9 @@ void CgenClassTable::code_dispatchTable() {
} }
void CgenClassTable::code_prototypeObject() { void CgenClassTable::code_prototypeObject() {
auto int_default = inttable.lookup_string("0"); this->_int_default = inttable.lookup_string("0");
auto str_default = stringtable.lookup_string(""); this->_str_default = stringtable.lookup_string("");
auto bool_default = &falsebool; this->_bool_default = &falsebool;
for (auto node : nodes) { for (auto node : nodes) {
str << WORD << "-1\n"; // GC tag str << WORD << "-1\n"; // GC tag
@ -636,15 +637,15 @@ void CgenClassTable::code_prototypeObject() {
for (auto attr : *node->get_attributes()) { for (auto attr : *node->get_attributes()) {
if (attr->type_decl == Int) { if (attr->type_decl == Int) {
str << WORD; str << WORD;
int_default->code_ref(str); _int_default->code_ref(str);
str << endl; str << endl;
} else if (attr->type_decl == Bool) { } else if (attr->type_decl == Bool) {
str << WORD; str << WORD;
bool_default->code_ref(str); _bool_default->code_ref(str);
str << endl; str << endl;
} else if (attr->type_decl == Str) { } else if (attr->type_decl == Str) {
str << WORD; str << WORD;
str_default->code_ref(str); _str_default->code_ref(str);
str << endl; str << endl;
} else { } else {
// for other types(including _prim_slot type), set to void(null pointer) // for other types(including _prim_slot type), set to void(null pointer)
@ -656,6 +657,14 @@ void CgenClassTable::code_prototypeObject() {
} }
} }
void CgenClassTable::code_objectTab() {
str << CLASSOBJTAB << LABEL;
for (auto node : nodes) {
str << WORD << node->get_name() << PROTOBJ_SUFFIX << endl;
str << WORD << node->get_name() << CLASSINIT_SUFFIX << endl;
}
}
CgenClassTable::CgenClassTable(Classes classes, ostream &s) : str(s) { CgenClassTable::CgenClassTable(Classes classes, ostream &s) : str(s) {
enterscope(); enterscope();
if (cgen_debug) if (cgen_debug)
@ -665,6 +674,11 @@ CgenClassTable::CgenClassTable(Classes classes, ostream &s) : str(s) {
build_inheritance_tree(); build_inheritance_tree();
if (cgen_debug) if (cgen_debug)
dump_inheritance_tree(); dump_inheritance_tree();
root()->traverse_generate_object();
// nodes[0] is the Object class
stringclasstag = get_node(Str)->get_class_tag();
intclasstag = get_node(Int)->get_class_tag();
boolclasstag = get_node(Bool)->get_class_tag();
code(); code();
exitscope(); exitscope();
} }
@ -787,10 +801,6 @@ void CgenClassTable::install_basic_classes() {
Str, no_expr()))), Str, no_expr()))),
filename), filename),
Basic)); Basic));
stringclasstag = get_node(Str)->get_class_tag();
intclasstag = get_node(Int)->get_class_tag();
boolclasstag = get_node(Bool)->get_class_tag();
} }
// CgenClassTable::install_class // CgenClassTable::install_class
@ -861,6 +871,19 @@ CgenNode *CgenClassTable::get_node(Symbol class_name) {
return nullptr; return nullptr;
} }
int CgenClassTable::get_method_index(Symbol class_name, Symbol method_name) {
auto class_node = get_node(class_name);
auto methods = class_node->get_methods();
for (size_t i = 0; i < methods->size(); ++i) {
auto method = (*methods)[i];
if (method.second->name == method_name) {
return i;
}
}
assert(0);
return -1;
}
void CgenClassTable::code() { void CgenClassTable::code() {
if (cgen_debug) if (cgen_debug)
cout << "coding global data" << endl; cout << "coding global data" << endl;
@ -878,10 +901,12 @@ void CgenClassTable::code() {
cout << "coding class_nameTab" << endl; cout << "coding class_nameTab" << endl;
code_class_nameTable(); code_class_nameTable();
if (cgen_debug)
cout << "coding object table" << endl;
code_objectTab();
if (cgen_debug) if (cgen_debug)
cout << "coding dispatch tables" << endl; cout << "coding dispatch tables" << endl;
nodes[0]->traverse_generate_object();
// nodes[0] is the Object class
code_dispatchTable(); code_dispatchTable();
if (cgen_debug) if (cgen_debug)
@ -936,6 +961,7 @@ void CgenClassTable::code() {
} }
} }
#endif #endif
// Add your code to emit // Add your code to emit
// - object initializer // - object initializer
// - the class methods // - the class methods
@ -1045,11 +1071,104 @@ void CgenNode::traverse_generate_object() {
#pragma region ExpressionCoding #pragma region ExpressionCoding
void assign_class::code(ostream &s, CgenClassTable *classtab) {} /*
Assignment actually does little. First evaluate its rhs. Then look up the lhs
identifier's location and simply store into the location.
*/
void assign_class::code(ostream &s, CgenClassTable *classtab) {
this->expr->code(s, classtab);
auto loc = classtab->loctab.lookup(this->name);
if (loc->location == Stack) {
emit_store(ACC, loc->offset, FP, s);
} else {
emit_store(ACC, loc->offset, SELF, s);
}
}
/*
static dispatch is a little bit simpler than normal dispatch
Intuitively, first evaluate all the parameter expression and push stack. Note
that, by design, the caller doesn't clear up the params, the callee do the
clear up on return.
Then evaluate the expr before `.`, which serves as the self object when
invoking the method. Thus it resides in $a0.
Before the flow goes to the method, check whether the object is void. This is
mentioned near the end of section 13 in the manual. If void, set $t1 and $a0
and call _dispatch_abort.
Finally, invoke the method by looking up its address from the dispatch table
and jalr.
*/
void static_dispatch_class::code(ostream &s, CgenClassTable *classtab) {
for (auto actual_i = this->actual->first(); this->actual->more(actual_i);
actual_i = this->actual->next(actual_i)) {
auto actual_expr = this->actual->nth(actual_i);
actual_expr->code(s, classtab);
emit_push(ACC, s); // push param to stack
}
this->expr->code(s, classtab);
auto label_index_dispatch = classtab->alloc_label_index();
// use bne to save a label, because we'll never come back if abort
emit_bne(ACC, ZERO, label_index_dispatch, s);
// Prints the line number, from $t1, and filename, from $a0, at which the
// dispatch occurred, and aborts.
emit_load_imm(T1, this->line_number, s);
emit_partial_load_address(ACC, s);
stringtable.lookup_string(classtab->cur_class->get_filename()->get_string())
->code_ref(s);
s << endl;
emit_jal("_dispatch_abort", s);
// ready to call the method
emit_label_def(label_index_dispatch, s);
// load dispatch table
emit_partial_load_address(T1, s);
emit_disptable_ref(this->type_name, s);
s << endl;
// load method address
emit_load(T1, classtab->get_method_index(this->type_name, this->name), T1, s);
// call the method whose address is in $t1, with self object in $a0
emit_jalr(T1, s);
}
void static_dispatch_class::code(ostream &s, CgenClassTable *classtab) {} /*
Normal dispatch is only different from static dispatch in deciding the
void dispatch_class::code(ostream &s, CgenClassTable *classtab) {} dispatch table. Normal dispatch extract the dispatch table from the object's
dispTab feild(offset 8) instead of querying method address at compile time.
*/
void dispatch_class::code(ostream &s, CgenClassTable *classtab) {
for (auto actual_i = this->actual->first(); this->actual->more(actual_i);
actual_i = this->actual->next(actual_i)) {
auto actual_expr = this->actual->nth(actual_i);
actual_expr->code(s, classtab);
emit_push(ACC, s); // push param to stack
}
this->expr->code(s, classtab);
auto label_index_dispatch = classtab->alloc_label_index();
// use bne to save a label, because we'll never come back if abort
emit_bne(ACC, ZERO, label_index_dispatch, s);
// Prints the line number, from $t1, and filename, from $a0, at which the
// dispatch occurred, and aborts.
emit_load_imm(T1, this->line_number, s);
emit_partial_load_address(ACC, s);
stringtable.lookup_string(classtab->cur_class->get_filename()->get_string())
->code_ref(s);
s << endl;
emit_jal("_dispatch_abort", s);
// ready to call the method
emit_label_def(label_index_dispatch, s);
// load dispatch table
emit_load(T1, DISPTABLE_OFFSET, ACC, s);
// load method address
int method_index = -1;
if (this->expr->type == SELF_TYPE) {
method_index =
classtab->get_method_index(classtab->cur_class->name, this->name);
// if the expr is SELF_TYPE, look up the method from current classs
} else {
method_index = classtab->get_method_index(this->expr->type, this->name);
}
emit_load(T1, method_index, T1, s);
// call the method whose address is in $t1, with self object in $a0
emit_jalr(T1, s);
}
/* /*
There's nothing special for if-then-else. Write at your convenience. There's nothing special for if-then-else. Write at your convenience.
@ -1102,9 +1221,18 @@ void block_class::code(ostream &s, CgenClassTable *classtab) {
} }
void let_class::code(ostream &s, CgenClassTable *classtab) { void let_class::code(ostream &s, CgenClassTable *classtab) {
classtab->expr_type_decl = this->type_decl;
this->init->code(s, classtab); this->init->code(s, classtab);
emit_push(ZERO, s); // make space for let's new object emit_push(ZERO, s); // make space for let's new object
emit_store(ACC, -rel_stack_depth, FP, s);
// set initial value to the new ident
classtab->loctab.enterscope();
classtab->loctab.add(
LocationTableItem(this->identifier, Stack, -rel_stack_depth));
this->body->code(s, classtab);
classtab->loctab.exitscope();
emit_pop(s); // balacnce stack
// the value of let is body's value, so leave $a0 unmodified
} }
/* /*
@ -1332,7 +1460,59 @@ void bool_const_class::code(ostream &s, CgenClassTable *classtab) {
emit_load_bool(ACC, BoolConst(val), s); emit_load_bool(ACC, BoolConst(val), s);
} }
void new__class::code(ostream &s, CgenClassTable *classtab) {} /*
Create a normal type object is quite simple, which could be done by 3
instructions:
la $a0, T_protoObj
call Object.copy
call T_init
Create SELF_TYPE object is very very tricky, because the real type is decided
at run time. I managed to get this done by looking at the target code
generated by the reference compiler.
We need a table indexed by class tag, which contains T[i]_protoObj and
T[i]_init. When creating such objects, we look up the actual protoObj and
init method by the self object's class tag. This involves dereferencing
pointers for multiple times, which is hard to get right.
*/
void new__class::code(ostream &s, CgenClassTable *classtab) {
if (this->type_name == SELF_TYPE) {
// first get the class tag at offset 0, $a0 <- 0($s0)
emit_load(ACC, 0, SELF, s);
// load the address of class_objTab, $t1 <- &class_objTab
emit_load_address(T1, CLASSOBJTAB, s);
// convert class tag to index, index = tag * 8, $a0 <- $a0 << 3
emit_sll(ACC, ACC, 3, s);
// get the address of so_protoObj, $a0 <- $t1 + $a0(base + index)
emit_addu(ACC, ACC, T1, s);
// save index on stack, we are to use $a0 for param
emit_push(ACC, s);
// get the so_protoObj, $a0 <- 0($a0)
emit_load(ACC, 0, ACC, s);
// call Object.copy
emit_jal("Object.copy", s);
// recover the addresss of so_protoObj, $t1 <- stack top
emit_load(T1, 1, SP, s);
emit_pop(s); // pop
// load address of so_init, $t1 <- 4($t1)
emit_load(T1, 1, T1, s);
// with $a0 storing the new object's ref, call so_init whose address is in
// $t1, which accepts $a0 as the parameter
emit_jalr(T1, s);
// initialized brand new object already has its ref in $a0
} else {
// load address: $a0 <- T_protObj
emit_partial_load_address(ACC, s);
emit_protobj_ref(this->type_name, s);
s << endl;
// call Object.copy
emit_jal("Object.copy", s);
// call T_init
s << JAL;
emit_init_ref(this->type_name, s);
s << endl;
// initialized brand new object already has its ref in $a0
}
}
/* /*
`isvoid` operation is quite simple and stack-operation free, since we only `isvoid` operation is quite simple and stack-operation free, since we only
@ -1350,10 +1530,37 @@ void isvoid_class::code(ostream &s, CgenClassTable *classtab) {
} }
/* /*
The control flow should not reach here by design No_expr means the init expression is omitted. However, the object has to be
assigned to some value. CgenClassTable::expr_type_decl is set for this
method to generate a propriate default initial value.
*/ */
void no_expr_class::code(ostream &s, CgenClassTable *classtab) { assert(0); } void no_expr_class::code(ostream &s, CgenClassTable *classtab) {
if (classtab->expr_type_decl == Int) {
emit_load_int(ACC, classtab->int_default(), s);
} else if (classtab->expr_type_decl == Bool) {
emit_load_bool(ACC, *classtab->bool_default(), s);
} else if (classtab->expr_type_decl == Str) {
emit_load_string(ACC, classtab->str_default(), s);
} else {
assert(classtab->expr_type_decl);
emit_move(ACC, ZERO, s);
}
}
void object_class::code(ostream &s, CgenClassTable *classtab) {} /*
ObjectID simply perform a load from store to $a0
Note that `self` is not in location table, add a special case and $a0<-$s0
*/
void object_class::code(ostream &s, CgenClassTable *classtab) {
if (this->name == self) {
emit_move(ACC, SELF, s);
} else {
auto loc = classtab->loctab.lookup(this->name);
if (loc->location == Stack)
emit_load(ACC, loc->offset, FP, s);
else
emit_load(ACC, loc->offset, SELF, s);
}
}
#pragma endregion #pragma endregion

View File

@ -21,6 +21,8 @@ typedef CgenClassTable *CgenClassTableP;
class CgenNode; class CgenNode;
typedef CgenNode *CgenNodeP; typedef CgenNode *CgenNodeP;
class BoolConst;
typedef std::vector<std::pair<class__class *, method_class *>> MethodListT; typedef std::vector<std::pair<class__class *, method_class *>> MethodListT;
typedef std::vector<attr_class *> AttrListT; typedef std::vector<attr_class *> AttrListT;
@ -44,6 +46,7 @@ public:
return &*itr; return &*itr;
} }
} }
assert(0);
return nullptr; return nullptr;
} }
void add(LocationTableItem item) { void add(LocationTableItem item) {
@ -76,6 +79,9 @@ private:
int stringclasstag; int stringclasstag;
int intclasstag; int intclasstag;
int boolclasstag; int boolclasstag;
IntEntry* _int_default = nullptr;
StringEntry* _str_default = nullptr;
BoolConst* _bool_default = nullptr;
int label_count = 0; // an incremental counter to avoid label conflicts int label_count = 0; // an incremental counter to avoid label conflicts
// The following methods emit code for // The following methods emit code for
@ -103,15 +109,22 @@ private:
void code_dispatchTable(); void code_dispatchTable();
void code_prototypeObject(); void code_prototypeObject();
CgenNode *get_node(Symbol); CgenNode *get_node(Symbol);
void code_objectTab();
void gen_init_code(); void gen_init_code();
public: public:
LocationTable loctab; LocationTable loctab;
Symbol expr_type_decl;
CgenNode* cur_class;
CgenClassTable(Classes, ostream &str); CgenClassTable(Classes, ostream &str);
void code(); void code();
CgenNode* root() { return nodes[0]; } CgenNode* root() { return nodes[0]; }
/* aquire an unused label index */ /* aquire an unused label index */
int alloc_label_index() { return label_count++; } int alloc_label_index() { return label_count++; }
IntEntry* int_default() const { return _int_default; };
StringEntry* str_default() const { return _str_default; };
BoolConst* bool_default() const { return _bool_default; };
int get_method_index(Symbol class_name, Symbol method_name);
}; };
class CgenNode : public class__class { class CgenNode : public class__class {

View File

@ -53,6 +53,31 @@ class D inherits C {
method_common(x1: Int) : SELF_TYPE { method_common(x1: Int) : SELF_TYPE {
self self
}; };
method_new() : D {
new D
};
method_new_SELF() : D {
new SELF_TYPE
};
method_new2() : Object {
(new SELF_TYPE).method_2(false, self)
};
method_staticdispath() : Object {
(new SELF_TYPE)@D.method_2(false, self)
};
method_case(x1 : Object) : Int {
case (x1) of
t1: Bool => 1;
t2: Int => 2;
t3: String => 3;
t4: Object => 4;
t5: A => 5;
t6: C => 6;
t7: B => 7;
t8: D => 8;
t9: E => 9;
esac
};
}; };
class E { class E {
@ -79,6 +104,18 @@ class E {
let x2 : Int <- x1 in let x2 : Int <- x1 in
x2 <- x1 + 100 x2 <- x1 + 100
}; };
method_2(x1: Bool, x2: C) : Object {
{
if (x1) then
x2 <- x2.method_common(20)
else
"hello world"
fi;
}
};
method_SELF() : SELF_TYPE {
self
};
}; };
class Main inherits IO { class Main inherits IO {