read the doc and format skeleton code
This commit is contained in:
parent
040115e812
commit
b2142969f8
28
CS143体验报告.md
28
CS143体验报告.md
@ -234,3 +234,31 @@ PA 2-5 正式写编译器。PA2 写词法分析器,首先读一遍 README 和
|
||||
- 返回 Object 的情况:objectid 未定义、new 未定义类、函数调用中无法确定被调用函数的情况(类未定义、函数未定义、函数参数个数不对)、loop 返回值。
|
||||
|
||||
剩下的基本上能从手册的12章中比较清晰的看出来。
|
||||
|
||||
|
||||
### PA5
|
||||
|
||||
#### 读文档
|
||||
|
||||
最后一个 PA,那必然是要把剩下来的文档全部读完。需要预先看一遍带是 `cool-tour.pdf` 的第7章 Runtime System 和 PA5 handout,至于 `cool-manual.pdf` 的第13章语义部分倒是可以一边实现一边看。
|
||||
|
||||
先看 handout:
|
||||
- 代码量巨大无比,竟然是 PA4 的2倍(悲
|
||||
- 文件简述:`cgen.{cc|hh}` 大部分需要写的代码,和 PA4 类似的结构,从 AST 的根节点开始进行 `cgen`;`cool-tree.h` 和 PA4 类似;`cgen_supp.cc` 定义辅助函数;`emit.h` 里面有一些 MIPS 汇编和符号宏定义;剩下的都是老熟人了。
|
||||
- 主要任务:
|
||||
- 生成全局常量(prototype objects)
|
||||
- 生成全局表,`class_nameTab` `class_objTab` 还有方法调用表
|
||||
- 生成每个类的初始化代码
|
||||
- 生成方法定义
|
||||
推荐的实现方法还是分两部分,先生成对象布局,然后第二遍在生成每个表达式的代码。
|
||||
- 提醒注意:这次没有必要去“逆向”参考编译器了,因为它实现了一些高级功能比如寄存器分配优化,这个 PA5 并不要求这个。
|
||||
- 运行时错误处理:manual 规定了6种运行时错误,生成的代码需要检测三种:(static) dispatch on void, case on void, missing branch;除零可以交给模拟器;剩下两种由 Runtime 处理。
|
||||
- GC:有一个3个命令行开关控制垃圾回收系统相关的功能。默认情况下不打开 `-g` 开关,此时不启用 GC,也就是说这是一个选做功能;`-t` 迫使 GC 系统在每次分配对象的时候进行回收;`-T` 的功能交给实现,可能会用来实现一些其他的运行时检查。实现 GC 功能的时候,需要认真阅读 Runtime 手册相关内容。这里可以去看看 CS143 课程网站上的那个单独的 `cool-runtime.pdf`,似乎写的更加详细一些。
|
||||
- 测试工具:和 PA4 类似,提供了一个 `-c` 选项来设置全局变量 `cgen_debug`。同时提供了一个第三方实现的 `Coolaid` 工具对生成的 MIPS 汇编进行一些检查,说不定会有帮助。最后关于 `Spim` 的 warning 可能会有用。
|
||||
|
||||
然后看看 Runtime System:
|
||||
- 首先是对象布局:GC Tag 设为-1;Object Size 也得填上;dispatch pointer 因为不会被 runtime 用到,所以需要自己设计 dispatch 表;对于属性,`Int` 只有一个32位整数、`Bool` 也是如此、`String` 有一个32位的长度+后面全部是 ASCII 字节(最后需要 word 对齐),然后还有空指针 void。
|
||||
- 然后是一个叫原型对象(Prototype Object)的东西:COOL 里面新建对象的方法是使用 `Object.copy()`,因此我们需要生成这些供其复制的东西,也就是 prototype object。生成的时候需要正确设置前面的头部,对于属性,三个基本类型有自己的规定,其余类型的属性随意设置。
|
||||
- 栈和寄存器约定:方法调用参数放在栈上、从左到右依次压栈,`a0` 寄存器里面放 `self` 对象指针。指定了一组 Scratch registers 供 runtime routine 存放临时数据,因此需要调用者保存;还有堆指针和堆界限两个寄存器,完全由 runtime 控制。其他的都可以用。
|
||||
- Label:生成的代码需要和 runtime 一起变成最后执行的机器码,因此有一些 label 是指定的,就类似于接口一样的东西。有些 label 是 runtime 提供给我们使用的,也有一些需要我们生成供 runtime 使用。有一句话 `There is no need for code that initializes an object of class Bool if the generated code contains definitions of both Bool objects in the static data area.` 没看懂
|
||||
- 执行初始化:需要生成一些代码来调用 main 方法。首先通过 Main prototype 生成一个 Main 类的对象并用 `Main_init` 初始化,该初始化方法依次执行 Main 的基类的初始化最后初始化 Main;然后调用 `Main.main`,在 `a0` 里面放上 `Main` 的指针并设置 `ra`;执行结束后,`Main.main` 返回,这里打印出提示信息并终止执行。
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,10 +1,11 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include "emit.h"
|
||||
#include "cool-tree.h"
|
||||
#include "emit.h"
|
||||
#include "symtab.h"
|
||||
#include <assert.h>
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
|
||||
enum Basicness {Basic, NotBasic};
|
||||
enum Basicness { Basic, NotBasic };
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
@ -14,67 +15,73 @@ typedef CgenClassTable *CgenClassTableP;
|
||||
class CgenNode;
|
||||
typedef CgenNode *CgenNodeP;
|
||||
|
||||
class CgenClassTable : public SymbolTable<Symbol,CgenNode> {
|
||||
class CgenClassTable : public SymbolTable<Symbol, CgenNode> {
|
||||
private:
|
||||
List<CgenNode> *nds;
|
||||
ostream& str;
|
||||
int stringclasstag;
|
||||
int intclasstag;
|
||||
int boolclasstag;
|
||||
List<CgenNode> *nds;
|
||||
ostream &str;
|
||||
int stringclasstag;
|
||||
int intclasstag;
|
||||
int boolclasstag;
|
||||
|
||||
// The following methods emit code for
|
||||
// constants and global declarations.
|
||||
|
||||
// The following methods emit code for
|
||||
// constants and global declarations.
|
||||
void code_global_data();
|
||||
void code_global_text();
|
||||
void code_bools(int);
|
||||
void code_select_gc();
|
||||
void code_constants();
|
||||
|
||||
void code_global_data();
|
||||
void code_global_text();
|
||||
void code_bools(int);
|
||||
void code_select_gc();
|
||||
void code_constants();
|
||||
// The following creates an inheritance graph from
|
||||
// a list of classes. The graph is implemented as
|
||||
// a tree of `CgenNode', and class names are placed
|
||||
// in the base class symbol table.
|
||||
|
||||
// The following creates an inheritance graph from
|
||||
// a list of classes. The graph is implemented as
|
||||
// a tree of `CgenNode', and class names are placed
|
||||
// in the base class symbol table.
|
||||
void install_basic_classes();
|
||||
void install_class(CgenNodeP nd);
|
||||
void install_classes(Classes cs);
|
||||
void build_inheritance_tree();
|
||||
void set_relations(CgenNodeP nd);
|
||||
//* New Methods
|
||||
void dump_inheritance_tree();
|
||||
|
||||
void install_basic_classes();
|
||||
void install_class(CgenNodeP nd);
|
||||
void install_classes(Classes cs);
|
||||
void build_inheritance_tree();
|
||||
void set_relations(CgenNodeP nd);
|
||||
public:
|
||||
CgenClassTable(Classes, ostream& str);
|
||||
void code();
|
||||
CgenNodeP root();
|
||||
CgenClassTable(Classes, ostream &str);
|
||||
void code();
|
||||
CgenNodeP root();
|
||||
};
|
||||
|
||||
|
||||
class CgenNode : public class__class {
|
||||
private:
|
||||
CgenNodeP parentnd; // Parent of class
|
||||
List<CgenNode> *children; // Children of class
|
||||
Basicness basic_status; // `Basic' if class is basic
|
||||
// `NotBasic' otherwise
|
||||
CgenNodeP parentnd; // Parent of class
|
||||
List<CgenNode> *children; // Children of class
|
||||
Basicness basic_status; // `Basic' if class is basic
|
||||
// `NotBasic' otherwise
|
||||
|
||||
public:
|
||||
CgenNode(Class_ c,
|
||||
Basicness bstatus,
|
||||
CgenClassTableP class_table);
|
||||
CgenNode(Class_ c, Basicness bstatus, CgenClassTableP class_table);
|
||||
|
||||
void add_child(CgenNodeP child);
|
||||
List<CgenNode> *get_children() { return children; }
|
||||
void set_parentnd(CgenNodeP p);
|
||||
CgenNodeP get_parentnd() { return parentnd; }
|
||||
int basic() { return (basic_status == Basic); }
|
||||
void add_child(CgenNodeP child);
|
||||
List<CgenNode> *get_children() { return children; }
|
||||
void set_parentnd(CgenNodeP p);
|
||||
CgenNodeP get_parentnd() { return parentnd; }
|
||||
int basic() { return (basic_status == Basic); }
|
||||
void traverse_dump(int pad) {
|
||||
for (int i = 0; i < pad; ++i)
|
||||
std::cerr << " ";
|
||||
std::cerr << this->name << "\n";
|
||||
for (auto l = children; l; l = l->tl()) {
|
||||
l->hd()->traverse_dump(pad + 2);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class BoolConst
|
||||
{
|
||||
private:
|
||||
class BoolConst {
|
||||
private:
|
||||
int val;
|
||||
public:
|
||||
BoolConst(int);
|
||||
void code_def(ostream&, int boolclasstag);
|
||||
void code_ref(ostream&) const;
|
||||
};
|
||||
|
||||
public:
|
||||
BoolConst(int);
|
||||
void code_def(ostream &, int boolclasstag);
|
||||
void code_ref(ostream &) const;
|
||||
};
|
||||
|
||||
@ -1,30 +1,25 @@
|
||||
#include "stringtab.h"
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "stringtab.h"
|
||||
|
||||
static int ascii = 0;
|
||||
|
||||
void ascii_mode(ostream& str)
|
||||
{
|
||||
if (!ascii)
|
||||
{
|
||||
str << "\t.ascii\t\"";
|
||||
ascii = 1;
|
||||
}
|
||||
void ascii_mode(ostream &str) {
|
||||
if (!ascii) {
|
||||
str << "\t.ascii\t\"";
|
||||
ascii = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void byte_mode(ostream& str)
|
||||
{
|
||||
if (ascii)
|
||||
{
|
||||
str << "\"\n";
|
||||
ascii = 0;
|
||||
}
|
||||
void byte_mode(ostream &str) {
|
||||
if (ascii) {
|
||||
str << "\"\n";
|
||||
ascii = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void emit_string_constant(ostream& str, char* s)
|
||||
{
|
||||
void emit_string_constant(ostream &str, char *s) {
|
||||
ascii = 0;
|
||||
|
||||
while (*s) {
|
||||
@ -39,23 +34,20 @@ void emit_string_constant(ostream& str, char* s)
|
||||
break;
|
||||
case '\\':
|
||||
byte_mode(str);
|
||||
str << "\t.byte\t" << (int) ((unsigned char) '\\') << endl;
|
||||
str << "\t.byte\t" << (int)((unsigned char)'\\') << endl;
|
||||
break;
|
||||
case '"' :
|
||||
case '"':
|
||||
ascii_mode(str);
|
||||
str << "\\\"";
|
||||
break;
|
||||
default:
|
||||
if (*s >= ' ' && ((unsigned char) *s) < 128)
|
||||
{
|
||||
ascii_mode(str);
|
||||
str << *s;
|
||||
}
|
||||
else
|
||||
{
|
||||
byte_mode(str);
|
||||
str << "\t.byte\t" << (int) ((unsigned char) *s) << endl;
|
||||
}
|
||||
if (*s >= ' ' && ((unsigned char)*s) < 128) {
|
||||
ascii_mode(str);
|
||||
str << *s;
|
||||
} else {
|
||||
byte_mode(str);
|
||||
str << "\t.byte\t" << (int)((unsigned char)*s) << endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
s++;
|
||||
@ -63,5 +55,3 @@ void emit_string_constant(ostream& str, char* s)
|
||||
byte_mode(str);
|
||||
str << "\t.byte\t0\t" << endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -4,19 +4,20 @@
|
||||
#ifndef COOL_TREE_HANDCODE_H
|
||||
#define COOL_TREE_HANDCODE_H
|
||||
|
||||
#include <iostream>
|
||||
#include "tree.h"
|
||||
#include "cool.h"
|
||||
#include "stringtab.h"
|
||||
#include "tree.h"
|
||||
#include <iostream>
|
||||
#define yylineno curr_lineno;
|
||||
extern int yylineno;
|
||||
|
||||
inline Boolean copy_Boolean(Boolean b) {return b; }
|
||||
inline Boolean copy_Boolean(Boolean b) { return b; }
|
||||
inline void assert_Boolean(Boolean) {}
|
||||
inline void dump_Boolean(ostream& stream, int padding, Boolean b)
|
||||
{ stream << pad(padding) << (int) b << "\n"; }
|
||||
inline void dump_Boolean(ostream &stream, int padding, Boolean b) {
|
||||
stream << pad(padding) << (int)b << "\n";
|
||||
}
|
||||
|
||||
void dump_Symbol(ostream& stream, int padding, Symbol b);
|
||||
void dump_Symbol(ostream &stream, int padding, Symbol b);
|
||||
void assert_Symbol(Symbol b);
|
||||
Symbol copy_Symbol(Symbol b);
|
||||
|
||||
@ -44,66 +45,52 @@ typedef Expressions_class *Expressions;
|
||||
typedef list_node<Case> Cases_class;
|
||||
typedef Cases_class *Cases;
|
||||
|
||||
#define Program_EXTRAS \
|
||||
virtual void cgen(ostream&) = 0; \
|
||||
virtual void dump_with_types(ostream&, int) = 0;
|
||||
#define Program_EXTRAS \
|
||||
virtual void cgen(ostream &) = 0; \
|
||||
virtual void dump_with_types(ostream &, int) = 0;
|
||||
|
||||
#define program_EXTRAS \
|
||||
void cgen(ostream &); \
|
||||
void dump_with_types(ostream &, int);
|
||||
|
||||
#define Class__EXTRAS \
|
||||
virtual Symbol get_name() = 0; \
|
||||
virtual Symbol get_parent() = 0; \
|
||||
virtual Symbol get_filename() = 0; \
|
||||
virtual void dump_with_types(ostream &, int) = 0;
|
||||
|
||||
#define program_EXTRAS \
|
||||
void cgen(ostream&); \
|
||||
void dump_with_types(ostream&, int);
|
||||
#define class__EXTRAS \
|
||||
Symbol get_name() { return name; } \
|
||||
Symbol get_parent() { return parent; } \
|
||||
Symbol get_filename() { return filename; } \
|
||||
void dump_with_types(ostream &, int);
|
||||
|
||||
#define Class__EXTRAS \
|
||||
virtual Symbol get_name() = 0; \
|
||||
virtual Symbol get_parent() = 0; \
|
||||
virtual Symbol get_filename() = 0; \
|
||||
virtual void dump_with_types(ostream&,int) = 0;
|
||||
#define Feature_EXTRAS virtual void dump_with_types(ostream &, int) = 0;
|
||||
|
||||
#define Feature_SHARED_EXTRAS void dump_with_types(ostream &, int);
|
||||
|
||||
#define class__EXTRAS \
|
||||
Symbol get_name() { return name; } \
|
||||
Symbol get_parent() { return parent; } \
|
||||
Symbol get_filename() { return filename; } \
|
||||
void dump_with_types(ostream&,int);
|
||||
#define Formal_EXTRAS virtual void dump_with_types(ostream &, int) = 0;
|
||||
|
||||
#define formal_EXTRAS void dump_with_types(ostream &, int);
|
||||
|
||||
#define Feature_EXTRAS \
|
||||
virtual void dump_with_types(ostream&,int) = 0;
|
||||
#define Case_EXTRAS virtual void dump_with_types(ostream &, int) = 0;
|
||||
|
||||
#define branch_EXTRAS void dump_with_types(ostream &, int);
|
||||
|
||||
#define Feature_SHARED_EXTRAS \
|
||||
void dump_with_types(ostream&,int);
|
||||
|
||||
|
||||
#define Formal_EXTRAS \
|
||||
virtual void dump_with_types(ostream&,int) = 0;
|
||||
|
||||
|
||||
#define formal_EXTRAS \
|
||||
void dump_with_types(ostream&,int);
|
||||
|
||||
|
||||
#define Case_EXTRAS \
|
||||
virtual void dump_with_types(ostream& ,int) = 0;
|
||||
|
||||
|
||||
#define branch_EXTRAS \
|
||||
void dump_with_types(ostream& ,int);
|
||||
|
||||
|
||||
#define Expression_EXTRAS \
|
||||
Symbol type; \
|
||||
Symbol get_type() { return type; } \
|
||||
Expression set_type(Symbol s) { type = s; return this; } \
|
||||
virtual void code(ostream&) = 0; \
|
||||
virtual void dump_with_types(ostream&,int) = 0; \
|
||||
void dump_type(ostream&, int); \
|
||||
Expression_class() { type = (Symbol) NULL; }
|
||||
|
||||
#define Expression_SHARED_EXTRAS \
|
||||
void code(ostream&); \
|
||||
void dump_with_types(ostream&,int);
|
||||
#define Expression_EXTRAS \
|
||||
Symbol type; \
|
||||
Symbol get_type() { return type; } \
|
||||
Expression set_type(Symbol s) { \
|
||||
type = s; \
|
||||
return this; \
|
||||
} \
|
||||
virtual void code(ostream &) = 0; \
|
||||
virtual void dump_with_types(ostream &, int) = 0; \
|
||||
void dump_type(ostream &, int); \
|
||||
Expression_class() { type = (Symbol)NULL; }
|
||||
|
||||
#define Expression_SHARED_EXTRAS \
|
||||
void code(ostream &); \
|
||||
void dump_with_types(ostream &, int);
|
||||
|
||||
#endif
|
||||
|
||||
@ -3,7 +3,27 @@
|
||||
as possible.
|
||||
*)
|
||||
|
||||
class Main {
|
||||
class A inherits IO {
|
||||
attr_A_1 : Int <- 10;
|
||||
attr_A_2 : Bool <- false;
|
||||
attr_A_3 : A <- self;
|
||||
method_common(x1: Int) : SELF_TYPE {
|
||||
self
|
||||
};
|
||||
};
|
||||
|
||||
class B inherits A {
|
||||
|
||||
};
|
||||
|
||||
class C inherits A {
|
||||
attr_C_1 : String <- "This is C\n";
|
||||
method_common(x1: Int) : SELF_TYPE {
|
||||
self
|
||||
};
|
||||
};
|
||||
|
||||
class Main inherits IO {
|
||||
main():Int { 0 };
|
||||
};
|
||||
|
||||
|
||||
BIN
handouts/cool-runtime.pdf
Normal file
BIN
handouts/cool-runtime.pdf
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user