context independent code generation done
This commit is contained in:
parent
3ef6812784
commit
2db8b1f4e7
@ -316,6 +316,15 @@ static void emit_store_int(char *source, char *dest, ostream &s) {
|
|||||||
emit_store(source, DEFAULT_OBJFIELDS, dest, s);
|
emit_store(source, DEFAULT_OBJFIELDS, dest, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Fetch the boolean value in an Bool object.
|
||||||
|
// Emits code to fetch the boolean value of the Bool object pointed
|
||||||
|
// to by register source into the register dest
|
||||||
|
//
|
||||||
|
static void emit_fetch_bool(char *dest, char *source, ostream &s) {
|
||||||
|
emit_load(dest, DEFAULT_OBJFIELDS, source, s);
|
||||||
|
}
|
||||||
|
|
||||||
static void emit_test_collector(ostream &s) {
|
static void emit_test_collector(ostream &s) {
|
||||||
emit_push(ACC, s);
|
emit_push(ACC, s);
|
||||||
emit_move(ACC, SP, s); // stack end
|
emit_move(ACC, SP, s); // stack end
|
||||||
@ -976,61 +985,311 @@ CgenNode::CgenNode(Class_ nd, Basicness bstatus, CgenClassTableP ct)
|
|||||||
|
|
||||||
#pragma region ExpressionCoding
|
#pragma region ExpressionCoding
|
||||||
|
|
||||||
void assign_class::code(ostream &s) {}
|
void assign_class::code(ostream &s, CgenClassTable *classtab) {}
|
||||||
|
|
||||||
void static_dispatch_class::code(ostream &s) {}
|
void static_dispatch_class::code(ostream &s, CgenClassTable *classtab) {}
|
||||||
|
|
||||||
void dispatch_class::code(ostream &s) {}
|
void dispatch_class::code(ostream &s, CgenClassTable *classtab) {}
|
||||||
|
|
||||||
void cond_class::code(ostream &s) {}
|
/*
|
||||||
|
There's nothing special for if-then-else. Write at your convenience.
|
||||||
|
Note that value of the predicate is a Bool object, not a boolean, so, dont
|
||||||
|
forget to extract its value from the object
|
||||||
|
*/
|
||||||
|
void cond_class::code(ostream &s, CgenClassTable *classtab) {
|
||||||
|
this->pred->code(s, classtab);
|
||||||
|
emit_fetch_bool(ACC, ACC, s); // fetch the boolean value into $a0
|
||||||
|
auto label_index_false = classtab->alloc_label_index();
|
||||||
|
auto label_index_exit = classtab->alloc_label_index();
|
||||||
|
emit_beqz(ACC, label_index_false, s); // $a0==0, pred is false, goto else
|
||||||
|
this->then_exp->code(s, classtab); // pred is true, eval then branch
|
||||||
|
emit_branch(label_index_exit, s); // $a0 <- then, and we goto exit
|
||||||
|
emit_label_def(label_index_false, s);
|
||||||
|
// the label is preserved in advance so that we can define it here safely
|
||||||
|
this->else_exp->code(s, classtab); // $a0 <- else
|
||||||
|
emit_label_def(label_index_exit, s);
|
||||||
|
}
|
||||||
|
|
||||||
void loop_class::code(ostream &s) {}
|
/*
|
||||||
|
The code for loop is also straightforward. The only thing special is that,
|
||||||
|
loop always evaluate to void, so remember to set $a0<-0
|
||||||
|
*/
|
||||||
|
void loop_class::code(ostream &s, CgenClassTable *classtab) {
|
||||||
|
auto label_index_predicate = classtab->alloc_label_index();
|
||||||
|
emit_label_def(label_index_predicate, s);
|
||||||
|
// predefine a label and our loop could restart and check predicate from here
|
||||||
|
this->pred->code(s, classtab); // check predicate, which sets $a0<-Bool object
|
||||||
|
emit_fetch_bool(ACC, ACC, s); // extrace 0 or 1 from Bool object in $a0
|
||||||
|
auto label_index_exit = classtab->alloc_label_index();
|
||||||
|
emit_beqz(ACC, label_index_exit, s); // if predicate is false, goto exit
|
||||||
|
this->body->code(s, classtab); // if predicate is true, move on with our loop
|
||||||
|
emit_branch(label_index_predicate, s); // anyways, go back and check predicate
|
||||||
|
emit_label_def(label_index_exit, s);
|
||||||
|
emit_load_imm(ACC, 0, s); // whatever the case, loop expr evaluates to void!
|
||||||
|
}
|
||||||
|
|
||||||
void typcase_class::code(ostream &s) {}
|
void typcase_class::code(ostream &s, CgenClassTable *classtab) {}
|
||||||
|
|
||||||
void block_class::code(ostream &s) {}
|
/*
|
||||||
|
For block expression, generate code expression by expression, nothing else
|
||||||
|
*/
|
||||||
|
void block_class::code(ostream &s, CgenClassTable *classtab) {
|
||||||
|
for (auto expr_i = this->body->first(); this->body->more(expr_i);
|
||||||
|
expr_i = this->body->next(expr_i)) {
|
||||||
|
auto expr = this->body->nth(expr_i);
|
||||||
|
expr->code(s, classtab);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void let_class::code(ostream &s) {}
|
void let_class::code(ostream &s, CgenClassTable *classtab) {}
|
||||||
|
|
||||||
void plus_class::code(ostream &s) {}
|
/*
|
||||||
|
Operations for Int objects is the most simple one, let's start here
|
||||||
|
In previous stages, we have make sure that both ends are Int type. Thus, some
|
||||||
|
hard-coded stuff is acceptable.
|
||||||
|
First, we evaluate the left part and the result, the address of the Int
|
||||||
|
object, is in $a0. In the very beginning, I think it is a good idea to keep
|
||||||
|
it simple, so I'd prefer not to allocate temporary space on stack ahead.
|
||||||
|
The solution here is to push $a0 to stack.
|
||||||
|
Then evaluate the right part.
|
||||||
|
At this time, we have addr(e1) on stack top and addr(e2) in $a0. According to
|
||||||
|
imagination (>_<), the right thing to do is to extract the value attributes
|
||||||
|
of the two Int objects (at offset 12), add them up, create a new Int
|
||||||
|
object and set its value attribute to the result. Finally store the address
|
||||||
|
of the new Int in $a0 as the return value.
|
||||||
|
To actually perform these operations, assuming that we are not going to use
|
||||||
|
any registers other than $a0 and $t0, we need to write some MIPS assembly.
|
||||||
|
*/
|
||||||
|
void plus_class::code(ostream &s, CgenClassTable *classtab) {
|
||||||
|
this->e1->code(s, classtab);
|
||||||
|
emit_fetch_int(ACC, ACC, s); // load value of e1 to a0
|
||||||
|
emit_push(ACC, s); // push the 32bit int value instead of object ref
|
||||||
|
this->e2->code(s, classtab);
|
||||||
|
emit_jal("Object.copy", s); // copy e2 as the new Int object
|
||||||
|
emit_push(ACC, s); // save new object's addr, will need it later
|
||||||
|
emit_fetch_int(ACC, ACC, s); // load value of e2 to a0
|
||||||
|
emit_load(T1, 2, SP, s);
|
||||||
|
// load value of e1 to t1, remind we have pushed again, so -8($sp) is val(e1)
|
||||||
|
emit_add(T1, T1, ACC, s); // $t1 <- val(e1) + val(e2)
|
||||||
|
emit_load(ACC, 1, SP, s); // load new object addr
|
||||||
|
emit_store_int(T1, ACC, s); // store result(now in $t1) to the object
|
||||||
|
emit_addiu(SP, SP, 8, s); // maintain stack balance
|
||||||
|
}
|
||||||
|
|
||||||
void sub_class::code(ostream &s) {}
|
/*
|
||||||
|
Substraction is quite the same as addition, the only thing to note is to get
|
||||||
|
the substraction order right. e1-e2 != e2-e1, but e1+e2 == e2+e1
|
||||||
|
*/
|
||||||
|
void sub_class::code(ostream &s, CgenClassTable *classtab) {
|
||||||
|
this->e1->code(s, classtab);
|
||||||
|
emit_fetch_int(ACC, ACC, s);
|
||||||
|
emit_push(ACC, s);
|
||||||
|
this->e2->code(s, classtab);
|
||||||
|
emit_jal("Object.copy", s);
|
||||||
|
emit_push(ACC, s);
|
||||||
|
emit_fetch_int(ACC, ACC, s); // $a0 <- val(e2)
|
||||||
|
emit_load(T1, 2, SP, s); // $t1 <- val(e1)
|
||||||
|
emit_sub(T1, T1, ACC, s); // $t1 <- val(e1),$t1 + val(e2),$a0
|
||||||
|
emit_load(ACC, 1, SP, s);
|
||||||
|
emit_store_int(T1, ACC, s);
|
||||||
|
emit_addiu(SP, SP, 8, s);
|
||||||
|
}
|
||||||
|
|
||||||
void mul_class::code(ostream &s) {}
|
/*
|
||||||
|
Thanks to pseudo-instruction in spim emulator, we dont need to deal with
|
||||||
|
hi/lo registers by hand, so the overall code is just the same as addition
|
||||||
|
*/
|
||||||
|
void mul_class::code(ostream &s, CgenClassTable *classtab) {
|
||||||
|
this->e1->code(s, classtab);
|
||||||
|
emit_fetch_int(ACC, ACC, s);
|
||||||
|
emit_push(ACC, s);
|
||||||
|
this->e2->code(s, classtab);
|
||||||
|
emit_jal("Object.copy", s);
|
||||||
|
emit_push(ACC, s);
|
||||||
|
emit_fetch_int(ACC, ACC, s); // $a0 <- val(e2)
|
||||||
|
emit_load(T1, 2, SP, s); // $t1 <- val(e1)
|
||||||
|
emit_mul(T1, T1, ACC, s); // $t1 <- val(e1),$t1 + val(e2),$a0
|
||||||
|
emit_load(ACC, 1, SP, s);
|
||||||
|
emit_store_int(T1, ACC, s);
|
||||||
|
emit_addiu(SP, SP, 8, s);
|
||||||
|
}
|
||||||
|
|
||||||
void divide_class::code(ostream &s) {}
|
void divide_class::code(ostream &s, CgenClassTable *classtab) {
|
||||||
|
this->e1->code(s, classtab);
|
||||||
|
emit_fetch_int(ACC, ACC, s);
|
||||||
|
emit_push(ACC, s);
|
||||||
|
this->e2->code(s, classtab);
|
||||||
|
emit_jal("Object.copy", s);
|
||||||
|
emit_push(ACC, s);
|
||||||
|
emit_fetch_int(ACC, ACC, s); // $a0 <- val(e2)
|
||||||
|
emit_load(T1, 2, SP, s); // $t1 <- val(e1)
|
||||||
|
emit_div(T1, T1, ACC, s); // $t1 <- val(e1),$t1 + val(e2),$a0
|
||||||
|
emit_load(ACC, 1, SP, s);
|
||||||
|
emit_store_int(T1, ACC, s);
|
||||||
|
emit_addiu(SP, SP, 8, s);
|
||||||
|
}
|
||||||
|
|
||||||
void neg_class::code(ostream &s) {}
|
/*
|
||||||
|
Things are even simpler for unary operations: No need for stack!
|
||||||
|
Just copy the Int object in $a0 generated by e1 to $a0 (we dont need the e1's
|
||||||
|
object any more), since we have a temp reg, fetch value into $t1, negate it
|
||||||
|
and send it back to the new Int object. That's all!
|
||||||
|
*/
|
||||||
|
void neg_class::code(ostream &s, CgenClassTable *classtab) {
|
||||||
|
this->e1->code(s, classtab);
|
||||||
|
emit_jal("Object.copy", s);
|
||||||
|
emit_fetch_int(T1, ACC, s);
|
||||||
|
emit_neg(T1, ACC, s);
|
||||||
|
emit_store_int(T1, ACC, s);
|
||||||
|
}
|
||||||
|
|
||||||
void lt_class::code(ostream &s) {}
|
/*
|
||||||
|
Though involving two different types, it doesn't make things harder.
|
||||||
|
We first deal with Int comparsion.
|
||||||
|
Quite similar to arithmetic operations, evaluate and extract the value
|
||||||
|
attributes from the sub-expressions.
|
||||||
|
Things afterwards are different. We need a label and branch instruction to
|
||||||
|
generate true or false for the expression.
|
||||||
|
Since there are only 2 registers available, occupied by two operands, we need
|
||||||
|
two labels (if more registers are available, then only 1 label should
|
||||||
|
suffice). The logic looks like this:
|
||||||
|
......(evaluate e1, e2)
|
||||||
|
if val(e1) < val(e2) goto label1;
|
||||||
|
$a0 = bool_const0;
|
||||||
|
goto label2;
|
||||||
|
label1:
|
||||||
|
$a0 = bool_const1;
|
||||||
|
label2:
|
||||||
|
......(clean up the expression)
|
||||||
|
*/
|
||||||
|
void lt_class::code(ostream &s, CgenClassTable *classtab) {
|
||||||
|
this->e1->code(s, classtab);
|
||||||
|
emit_fetch_int(ACC, ACC, s);
|
||||||
|
emit_push(ACC, s); // $sp+4 == val(e1)
|
||||||
|
this->e2->code(s, classtab);
|
||||||
|
emit_fetch_int(ACC, ACC, s); // $a0 <- val(e2)
|
||||||
|
emit_load(T1, 1, SP, s); // $t1 <- val(e1)
|
||||||
|
auto label_index_true = classtab->alloc_label_index();
|
||||||
|
auto label_index_exit = classtab->alloc_label_index();
|
||||||
|
emit_blt(T1, ACC, label_index_true, s);
|
||||||
|
// after the branch, val(e2) in $a0 is no more needed, making space for result
|
||||||
|
emit_load_bool(ACC, falsebool, s);
|
||||||
|
// didn't jump in last instruction, so it is false
|
||||||
|
emit_branch(label_index_exit, s); // dont want it to be overridden
|
||||||
|
emit_label_def(label_index_true, s); // first branch goes to here
|
||||||
|
emit_load_bool(ACC, truebool, s); // branch means true
|
||||||
|
emit_label_def(label_index_exit, s); // second jump goes to here
|
||||||
|
emit_addiu(SP, SP, 4, s); // cleanup anyway, only one push is made
|
||||||
|
}
|
||||||
|
|
||||||
void eq_class::code(ostream &s) {}
|
/*
|
||||||
|
<= operation is exactly the same as < operation except the operator
|
||||||
|
*/
|
||||||
|
void leq_class::code(ostream &s, CgenClassTable *classtab) {
|
||||||
|
this->e1->code(s, classtab);
|
||||||
|
emit_fetch_int(ACC, ACC, s);
|
||||||
|
emit_push(ACC, s);
|
||||||
|
this->e2->code(s, classtab);
|
||||||
|
emit_fetch_int(ACC, ACC, s);
|
||||||
|
emit_load(T1, 1, SP, s);
|
||||||
|
auto label_index_true = classtab->alloc_label_index();
|
||||||
|
auto label_index_exit = classtab->alloc_label_index();
|
||||||
|
emit_bleq(T1, ACC, label_index_true, s);
|
||||||
|
emit_load_bool(ACC, falsebool, s);
|
||||||
|
emit_branch(label_index_exit, s);
|
||||||
|
emit_label_def(label_index_true, s);
|
||||||
|
emit_load_bool(ACC, truebool, s);
|
||||||
|
emit_label_def(label_index_exit, s);
|
||||||
|
emit_addiu(SP, SP, 4, s);
|
||||||
|
}
|
||||||
|
|
||||||
void leq_class::code(ostream &s) {}
|
/*
|
||||||
|
Unary Bool operation `not` is more complicated than its Int counterpart
|
||||||
|
It uses branch, in that we doesn't want to generate bool objects other than
|
||||||
|
the two predefined constants.
|
||||||
|
*/
|
||||||
|
void comp_class::code(ostream &s, CgenClassTable *classtab) {
|
||||||
|
this->e1->code(s, classtab); // this must be a Bool object in $a0
|
||||||
|
emit_fetch_bool(T1, ACC, s); // extract boolean value 0 or 1 to $t1
|
||||||
|
emit_load_bool(ACC, truebool, s); // default load true(assume val(e1)==false)
|
||||||
|
auto label_index = classtab->alloc_label_index();
|
||||||
|
emit_beqz(T1, label_index, s); // val(e1)==false, skip the next load
|
||||||
|
emit_load_bool(ACC, falsebool, s); // val(e1)==true, load false to $a0
|
||||||
|
emit_label_def(label_index, s); // no clean up needed, just exit here
|
||||||
|
}
|
||||||
|
|
||||||
void comp_class::code(ostream &s) {}
|
/*
|
||||||
|
Equality operator is much more complicated than others.
|
||||||
|
According to the manual, when comparing two objects, their pointersn first get
|
||||||
|
compared.
|
||||||
|
If they resides in the same address, they are definitely equal, return true
|
||||||
|
at once.
|
||||||
|
Otherwise, call primitive procedure `equality_test`. As the Runtime System
|
||||||
|
tour says, it accepts 2 params which resides in $t1 and $t2. The procedure
|
||||||
|
checks the following condition:
|
||||||
|
typeid($t1) in {Int, Bool, String}
|
||||||
|
&& typeid($t1)==typeid($t2)
|
||||||
|
&& value($1) == value($t2)
|
||||||
|
The return value is in $a0. If condition is true, $a0<-$a0, else $a0<-$a1,
|
||||||
|
where $a0, $a1 remain unmodified until return. Utilizing this feature,
|
||||||
|
we can set $a0<-truebool, $a1<-falsebool before calling the procedure.
|
||||||
|
Understanding the stuff above, the assembly is just there.
|
||||||
|
*/
|
||||||
|
void eq_class::code(ostream &s, CgenClassTable *classtab) {
|
||||||
|
this->e1->code(s, classtab);
|
||||||
|
emit_push(ACC, s); // e1 can evaluate to anything, so simply push the ref
|
||||||
|
this->e2->code(s, classtab); // $a0<-&e2
|
||||||
|
emit_load(T1, 1, SP, s); // $t1<-&e1
|
||||||
|
emit_move(T2, ACC, s); // $t2<-&e2
|
||||||
|
// there's no choice but to break our 2 register rule ~_~
|
||||||
|
emit_load_bool(ACC, truebool, s); // load true in advance in case &e1==&e2
|
||||||
|
auto label_index_exit = classtab->alloc_label_index();
|
||||||
|
emit_beq(T1, T2, label_index_exit, s); // if &e1==&e2, then we are done here
|
||||||
|
emit_load_bool(A1, falsebool, s); // prepare a false choice for equality_test
|
||||||
|
emit_jal("equality_test", s);
|
||||||
|
// at this point, $t1=&e1, $t2=&e2, $a0=true, $a1=false. ready to call
|
||||||
|
// $a0 will be either true or false, so just keep it as the result
|
||||||
|
emit_label_def(label_index_exit, s);
|
||||||
|
emit_addiu(SP, SP, 4, s); // balance stack, 1 push in this expression
|
||||||
|
}
|
||||||
|
|
||||||
void int_const_class::code(ostream &s) {
|
void int_const_class::code(ostream &s, CgenClassTable *classtab) {
|
||||||
//
|
//
|
||||||
// Need to be sure we have an IntEntry *, not an arbitrary Symbol
|
// Need to be sure we have an IntEntry *, not an arbitrary Symbol
|
||||||
//
|
//
|
||||||
emit_load_int(ACC, inttable.lookup_string(token->get_string()), s);
|
emit_load_int(ACC, inttable.lookup_string(token->get_string()), s);
|
||||||
}
|
}
|
||||||
|
|
||||||
void string_const_class::code(ostream &s) {
|
void string_const_class::code(ostream &s, CgenClassTable *classtab) {
|
||||||
emit_load_string(ACC, stringtable.lookup_string(token->get_string()), s);
|
emit_load_string(ACC, stringtable.lookup_string(token->get_string()), s);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bool_const_class::code(ostream &s) {
|
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) {}
|
void new__class::code(ostream &s, CgenClassTable *classtab) {}
|
||||||
|
|
||||||
void isvoid_class::code(ostream &s) {}
|
/*
|
||||||
|
`isvoid` operation is quite simple and stack-operation free, since we only
|
||||||
|
test the reference is zero or not. A straightforward beqz should suffice.
|
||||||
|
*/
|
||||||
|
void isvoid_class::code(ostream &s, CgenClassTable *classtab) {
|
||||||
|
this->e1->code(s, classtab);
|
||||||
|
emit_move(T1, ACC, s); // $t1 <- &e1
|
||||||
|
emit_load_bool(ACC, truebool, s);
|
||||||
|
auto label_index_exit = classtab->alloc_label_index();
|
||||||
|
emit_beqz(T1, label_index_exit, s);
|
||||||
|
// &e1 == nullptr ?, if so skip the next load false
|
||||||
|
emit_load_bool(ACC, falsebool, s);
|
||||||
|
emit_label_def(label_index_exit, s);
|
||||||
|
}
|
||||||
|
|
||||||
void no_expr_class::code(ostream &s) {}
|
/*
|
||||||
|
The control flow should not reach here by design
|
||||||
|
*/
|
||||||
|
void no_expr_class::code(ostream &s, CgenClassTable *classtab) { assert(0); }
|
||||||
|
|
||||||
void object_class::code(ostream &s) {}
|
void object_class::code(ostream &s, CgenClassTable *classtab) {}
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|||||||
@ -29,6 +29,7 @@ private:
|
|||||||
int stringclasstag;
|
int stringclasstag;
|
||||||
int intclasstag;
|
int intclasstag;
|
||||||
int boolclasstag;
|
int boolclasstag;
|
||||||
|
int label_count = 0; // an incremental counter to avoid label conflicts
|
||||||
|
|
||||||
// The following methods emit code for
|
// The following methods emit code for
|
||||||
// constants and global declarations.
|
// constants and global declarations.
|
||||||
@ -55,11 +56,14 @@ private:
|
|||||||
void code_dispatchTable();
|
void code_dispatchTable();
|
||||||
void code_prototypeObject();
|
void code_prototypeObject();
|
||||||
CgenNode *get_node(Symbol);
|
CgenNode *get_node(Symbol);
|
||||||
|
void gen_init_code();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CgenClassTable(Classes, ostream &str);
|
CgenClassTable(Classes, ostream &str);
|
||||||
void code();
|
void code();
|
||||||
CgenNodeP root();
|
CgenNodeP root();
|
||||||
|
/* aquire an unused label index */
|
||||||
|
int alloc_label_index() { return label_count++; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class CgenNode : public class__class {
|
class CgenNode : public class__class {
|
||||||
|
|||||||
@ -11,6 +11,8 @@
|
|||||||
#include "cool-tree.handcode.h"
|
#include "cool-tree.handcode.h"
|
||||||
#include "tree.h"
|
#include "tree.h"
|
||||||
|
|
||||||
|
class CgenClassTable;
|
||||||
|
|
||||||
// define the class for phylum
|
// define the class for phylum
|
||||||
// define simple phylum - Program
|
// define simple phylum - Program
|
||||||
typedef class Program_class *Program;
|
typedef class Program_class *Program;
|
||||||
|
|||||||
@ -84,13 +84,13 @@ typedef Cases_class *Cases;
|
|||||||
type = s; \
|
type = s; \
|
||||||
return this; \
|
return this; \
|
||||||
} \
|
} \
|
||||||
virtual void code(ostream &) = 0; \
|
virtual void code(ostream &, CgenClassTable *) = 0; \
|
||||||
virtual void dump_with_types(ostream &, int) = 0; \
|
virtual void dump_with_types(ostream &, int) = 0; \
|
||||||
void dump_type(ostream &, int); \
|
void dump_type(ostream &, int); \
|
||||||
Expression_class() { type = (Symbol)NULL; }
|
Expression_class() { type = (Symbol)NULL; }
|
||||||
|
|
||||||
#define Expression_SHARED_EXTRAS \
|
#define Expression_SHARED_EXTRAS \
|
||||||
void code(ostream &); \
|
void code(ostream &, CgenClassTable *); \
|
||||||
void dump_with_types(ostream &, int);
|
void dump_with_types(ostream &, int);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -20,7 +20,7 @@ class B inherits A {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class C inherits A {
|
class C inherits A {
|
||||||
attr_C_1 : String <- "This is C\n";
|
attr_C_1 : String <- "This is C\n".concat(new A.method_common2());
|
||||||
attr_C_2 : SELF_TYPE;
|
attr_C_2 : SELF_TYPE;
|
||||||
method_common(x1: Int) : SELF_TYPE {
|
method_common(x1: Int) : SELF_TYPE {
|
||||||
self
|
self
|
||||||
@ -31,6 +31,22 @@ class C inherits A {
|
|||||||
method_1(x1: Int) : Bool {
|
method_1(x1: Int) : Bool {
|
||||||
true
|
true
|
||||||
};
|
};
|
||||||
|
method_3(x1: Int, x2: A, x3: String) : Object {
|
||||||
|
{
|
||||||
|
x1 <- x1 + 00010 - x1 / 10;
|
||||||
|
x2 <- x2.method_common(x1);
|
||||||
|
x3 <- x3.concat("schade");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
method_2(x1: Bool, x2: C) : Object {
|
||||||
|
{
|
||||||
|
if (x1) then
|
||||||
|
x2 <- x2.method_common(20)
|
||||||
|
else
|
||||||
|
"hello world"
|
||||||
|
fi;
|
||||||
|
}
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
class D inherits C {
|
class D inherits C {
|
||||||
@ -39,6 +55,24 @@ class D inherits C {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class E {
|
||||||
|
method_compare(x1: Int, x2: Int) : Bool {
|
||||||
|
x1 < x2
|
||||||
|
};
|
||||||
|
method_compare_eq(x1: String, x2: String) : Bool {
|
||||||
|
x1 = x2
|
||||||
|
};
|
||||||
|
method_compare_eq2(x1: D, x2: D) : Bool {
|
||||||
|
x1 = x2
|
||||||
|
};
|
||||||
|
method_not(x1: Bool) : Bool {
|
||||||
|
not x1
|
||||||
|
};
|
||||||
|
method_isvoid(x1: Object) : Bool {
|
||||||
|
isvoid x1
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
class Main inherits IO {
|
class Main inherits IO {
|
||||||
main():Int { 0 };
|
main():Int { 0 };
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user