source code
- list.h
实现了链表,插入操作在constructor中实现
template <class T>
class List {
T *head; // 指向节点内容
List<T>* tail; // 指向下一个节点
public:
List(T *h,List<T>* t = NULL): head(h), tail(t) { } // 构造时使用头插法将新的结点插入到list
};
- stringtab.h:
class Entry(str, len, index)
// 以下*Entry皆为Entry的子类
class StringEntry
class IntEntry
class IdEntry
class IdTable : public StringTable<IdEntry> // store indentifier
class StrTable : public StringTable<StringEntry> // store string constant
class IntTable : public StringTable<IntEntry> // store int constant as string form
- stringtab_functions.h :
StringTable::add_string()
StringTable::add_int() // 将int转化成string存储在StringTable中
-
cool-parse.h
定义了lexer中一部分token的值 -
symtab.h
符号表的实现
template<class SYM, class DAT>
class SymtabEntry { SYM id; DAT *info }
class SymbolTable {
typedef List<ScopeEntry> Scope; // Scope是Entry的链表
typedef List<Scope> ScopeList; // ScopeList是Scope的链表,一个ScopeList中可以有多个Scope
ScopeList *tbl; // 指向当前的Scope
enterscope(); // 新建一个Scope(该Scope的hd为NULL)并且进入这个Scope
exitscope(); // 退出当前Scope
addid(); // 为当前的Scope添加一个item
lookup(); // 在全局的范围内寻找一个特定的item
probe(); // 在当前的Scope寻找一个特定的item
dump(); // 打印SymbolTable的所有内容
}
- tree.h
// 所有node都有copy_list函数,为深拷贝
class tree_node {
int line_number; // 记录对应源代码的行数
}
class list_node {
nil(); //返回一个空的结点(class nil_node)
single(); // 返回只有单个结点的list
append(l1, l2); //return append_node(l1, l2)
}
class nil_node {
len(); // return 0
nth_length(); // return NULL
}
class single_list_node {
len(); // return 1
nth_length(n, len); // 如果n!=0 return elem,如果n==0 return NULL;
}
class append_node {
list_node<Elem> *some, *rest; // append_node将some和rest连接起来
len(); return len(some) + len(rest)
nth_length(n, len); // 返回some和rest组成的list中的第n个元素
}
list(Elem x); // 返回一个single_list_node*
cons(Elem x, list_node *l); // 返回一个连接x和l的append_node,为x->l
xcons(list_node* l, Elem x); // 返回一个连接l和x的append_node,为l->x
- cool-tree.h
定义AST的结点类型
// 基类定义,有typedef Xx_class *Xx
// typedef list_node<Xx> Xxs_class
// typedef Xxs_class *Xxs
class Program_class {
CgenClassTable* class_table; // 只有Program_class有
copy_Program(); // 返回Program_class*
tree_node* copy(); // 调用copy_Program(),并将Program_class*转化为tree_node*
}
class Class_class {
copy_Class(); // 返回Class_class*
tree_node* copy(); // 调用copy_Class(),并将Class_class*转化为tree_node*
}
class Feature_class {
copy_Feature(); // 返回Feature_class*
tree_node* copy(); // 调用copy_Class(),并将Feature_class*转化为tree_node*
}
class Formal_class {
copy_Formal(); // 返回Formal_class*
tree_node* copy(); // 调用copy_Formal(),并将Formal_class*转化为tree_node*
}
class Expression_class {
copy_Expression(); // 返回Expression_class*
tree_node* copy(); // 调用copy_Class(),并将Class_class*转化为tree_node*
}
class Case_class {
copy_Case(); // 返回Case_class*
tree_node* copy(); // 调用copy_Class(),并将Case_class*转化为tree_node*
}
// AST结点具体实现
class program_class : Program_class {
Classes classes;
}
class class_class : Class_class {
Symbol name; // 类名
Symbol parent; // 父类名
Features features; // 成员变量和成员函数
Symbol filename; // 所在文件的名字
}
class method_class : Feature_class { // method属于Feature
Symbol name; // 方法名
Formals formals; // 参数
Symbol return type; // 返回类型
Expression expr; // 方法的body
}
class attr_class : Feature_class { // 成员变量属于类型
Symbol name; // 属性名
Symbol type_decl; // 变量类型
Expression init; // 初始化值
}
class formal_class : Formal_class {
Symbol name; //参数名
Symbol type_decl; //参数类型
}
class branch_class : Case_class { // case的一个分支
Symbol name; // name : type_decl => expr;
Symbol type_decl;
Expression expr;
}
class assign_class : Expression_class {
Symbol name; // 变量名
Expression expr; // 要赋的值
}
class static_dispatch_class : Expression_class { // 方法调用
Expression expr; // expr@type_name.name(actual)
Symbol type_name;
Symbol name;
Expression actual;
}
class dispatch_class : Expression_class {
Expression expr; // expr.name(actual)
Symbol name;
Expression actual;
}
class cond_class : Expression_class {
Expression pred; // 条件
Expression then_exp; //真值链
Expression else_exp; //假值链
}
class loop_class : Expression { // while循环
Expression pred; // 条件
Expression body; // 循环执行语句
}
class typecase_class : Expression_class { // case语句
Expression expr; // case expr of
//...cases...
// esac
Cases cases;
}
class block_class : Expression_class {
Expressions body; // block里面的语句
}
class let_class : Expression_class {
Symbol identifier; // 标识符名字
Symbol type_decl; // 变量类型
Expression init; // 初始化值
Expression body; // 要执行的语句
}
class plus_class : Expression_class {
Expression e1; // e1 + e2
Expression e2;
}
class sub_class : Expression_class {
Expression e1; // e1 - e2
Expression e2;
}
class mul_class : Expression_class {
Expression e1; // e1 * e2
Expression e2;
}
class divide_class : Expression_class {
Expression e1; // e1 / e2
Expression e2;
}
class neg_class : Expression_class {
Expression e1; // -e1
}
class lt_class : Expression_class {
Expression e1; // e1 < e2
Expression e2;
}
class eq_class : Expression_class {
Expression e1; // e1 == e2
Expression e2;
}
class leq_class : Expression_class {
Expression e1; // e1 <= e2
Expression e2;
}
class comp_class : Expression_class {
Expression e1;
// TODO
}
class int_const_class : Expression_class {
Symbol token; // 整型常量
}
class bool_const_class : Expression_class {
Boolean val; // 真值常量
}
class string_const_class : Expression_class {
Symbol token; // 字符串常量
}
class new__ class : Expression_class {
Symbol type_name; // 要分配的变量类型
}
class isvoid_class : Expression_class {
Expression e1; // 要检查的表达式
}
class no_expr_class : Expression_class {
// 用于optional_assign,当optional_assign为空时,optional_assign = no_expr()
}
class object_class : Expression_class {
// 表达式中的变量
}
给Bison用的接口
// 注意这些函数接收的参数
Classes nil_Classes();
Classes single_Classes(Class_);
Classes append_Classes(Classes, Classes);
Features nil_Features();
Features single_Features(Feature);
Features append_Features(Features, Features);
Formals nil_Formals();
Formals single_Formals(Formal);
Formals append_Formals(Formals, Formals);
Expressions nil_Expressions();
Expressions single_Expressions(Expression);
Expressions append_Expressions(Expressions, Expressions);
Cases nil_Cases();
Cases single_Cases(Case);
Cases append_Cases(Cases, Cases);
Program program(Classes);
Class_ class_(Symbol, Symbol, Features, Symbol);
Feature method(Symbol, Formals, Symbol, Expression);
Feature attr(Symbol, Symbol, Expressioyoun);
Formal formal(Symbol, Symbol);
Case branch(Symbol, Symbol, Expression);
Expression assign(Symbol, Expression);
Expression static_dispatch(Expression, Symbol, Symbol, Expressions);
Expression dispatch(Expression, Symbol, Expressions);
Expression cond(Expression, Expression, Expression);
Expression loop(Expression, Expression);
Expression typcase(Expression, Cases);
Expression block(Expressions);
Expression let(Symbol, Symbol, Expression, Expression);
Expression plus(Expression, Expression);
Expression sub(Expression, Expression);
Expression mul(Expression, Expression);
Expression divide(Expression, Expression);
Expression neg(Expression);
Expression lt(Expression, Expression);
Expression eq(Expression, Expression);
Expression leq(Expression, Expression);
Expression comp(Expression);
Expression int_const(Symbol);
Expression bool_const(Boolean);
Expression string_const(Symbol);
Expression new_(Symbol);
Expression isvoid(Expression);
Expression no_expr();
Expression object(Symbol);
- Expression_EXTRAS用于Expression类的声明,Expression_SHARED_EXTRAS用于Expression子类的声明。在cool-tree.handcode.h中定义,由cool-tree.h引用
cool-tree.h中的AST结点的code()函数在cgen.cc中实现
*cgen.h
class CgenClassTable : public cool::SymbolTable<Symbol,CgenNode>
{
private:
// Class list
List<CgenNode> *nds;
List<CgenNode> *special_nds;
int current_tag;
public:
ostream *ct_stream;
CgenClassTable(Classes, ostream& str);
~CgenClassTable();
CgenNode *root();
int get_num_classes() const { return current_tag; }
private:
void setup_external_functions(); // 声明一些内置的函数
void setup_classes(CgenNode *c, int depth);
void code_classes(CgenNode *c);
void install_basic_classes();
void install_class(CgenNode *nd);
void install_special_class(CgenNode *nd);
void install_classes(Classes cs);
void build_inheritance_tree();
void set_relations(CgenNode *nd);
void setup();
void code_module();
void code_constants();
void code_main();
};
CgenNode:每个CgenNode都对应一个class,负责为class创建Type,以及生成每个method的代码
class CgenNode : public class__class
{
public:
enum Basicness
{ Basic, NotBasic };
private:
CgenNode *parentnd; // Parent of class
List<CgenNode> *children; // Children of class
Basicness basic_status; // `Basic' or 'NotBasic'
CgenClassTable *class_table;
// Class tag. Should be unique for each class in the tree
int tag;
int max_child;
public:
// COMPLETE FUNCTIONS
// Relationships with other nodes in the tree
CgenNode *get_parentnd() { return parentnd; }
void add_child(CgenNode *child);
void set_parentnd(CgenNode *p);
int basic() { return (basic_status == Basic); }
List<CgenNode> *get_children() { return children; }
// Accessors for other provided fields
int get_tag() const { return tag; }
CgenClassTable *get_classtable() { return class_table; }
void set_max_child(int mc) { max_child = mc; }
int get_max_child() const { return max_child; }
// INCOMPLETE FUNCTIONS
// Constructs a CgenNode from a Class
CgenNode(Class_ c, Basicness bstatus, CgenClassTable *class_table);
virtual ~CgenNode() { }
void setup(int tag, int depth);
void code_class();
private:
void layout_features();
};
CgenEnvironment:一个CgenEnvironment对应一个method,负责维护一个method中的符号表,将每一个源代码中的变量映射为Value*
class CgenEnvironment
{
private:
// mapping from variable names to memory locations
cool::SymbolTable<Symbol,Value> var_table;
// Keep counters for unique name generation in the current method
int block_count;
int tmp_count;
int ok_count;
CgenNode *cur_class;
public:
std::ostream *cur_stream;
// Used in provided code for the (case..of) construct
string next_label;
operand branch_operand;
void add_local(Symbol name, Value *vb);
void kill_local();
// end of helpers for provided code
CgenEnvironment(ostream &strea, CgenNode *cur_class);
Value* lookup(Symbol name) { return var_table.lookup(name); }
CgenNode *get_class() { return cur_class; }
void set_class(CgenNode *c) { cur_class = c; }
// INCOMPLETE FUNCTIONS
CgenNode *type_to_class(Symbol t);
// ADD CODE HERE
};
- cgen.cc
注意CgenClassTable是SymbolTable的子类,CgenNode是class_class的子类
CgenClass
- CgenClassTable class_table为program_class的一个成员变量,在program_class::cgen()中初始化:
class_table = new CgenClassTable(classes, os);
- 在CgenClassTable的构造函数中会初始化一些内置的class,如Int, Bool, String,同时会构造一棵继承树:
CgenClassTable::CgenClassTable(Classes classes) {
enterscope();
install_basic_classes();
install_classes(classes);
build_inheritance_tree();
setup();
code_module();
exitscope();
}
- 在CgenClassTable::install_basic_classes()中会install所有的basic classes,其中包括Int, Bool,String,Object以及IO class
- CgenClassTable::install_classes(Classes cs)会install cs中的所有class
- CgenClassTable::install_class(CgenNode *nd),查看是否已存在该class,若没有则将nd加入到nds中,并添加该class的名字
- CgenClassTable::build_inheritance_tree():遍历nds上的所有CgenNode*,并调用set_relations()
- CgenClassTable::set_relations(CgenNode *nd):获取nd的parent,获取nd的parent的名字,通过probe来获取parent的CgenNode,为nd设置parent_node,为parent_node设置child nd
- CgenClassTable::setup():声明一些llvm ir中存在的函数
- CgenClassTable::code_module():在MP1中负责生成Main_main()函数,和在main()函数中调用Main_main()
CgenNode
10. CgenNode::setup():调用layout_features()(调用attr和method的layout_feature(CgenNode*)),调用setup_class()
11.
- ValuePrinter
void declare(op_type ret_type, string name, vector<op_type> args); // 声明函数,参数依次为返回类型,函数名,传入的操作数类型的vector
void type_define(string class_name, vector<op_type> attributes); // 定义type,参数为这种type的名字(%struct.xx),
这种type的成员的操作数类型的vector
// 支持的一些运算类型
operand add(operand op1, operand op2);
operand sub(operand op1, operand op2);
operand mul(operand op1, operand op2);
operand div(operand op1, operand op2);
operand xor_in(operand op1, operand op2);
operand alloca_mem(op_type type); // alloca操作,参数为操作数类型
operand load(operand op); // load操作,参数为操作数
void store(operand op, operand op2); // store op to op2
operand call(vector<op_type> arg_types, op_type result_type,
string fn_name, bool is_global, vector<operand> args); // 参数:形参类型vector,返回类型,函数名,是否为global,实参vector
operand bitcast(operand op, op_type new_type); // bitcast op_type op_name to new_type
operand ptrtoint(operand op, op_type new_type); // ptrtoint op_type op_name to new_type
bug fixed log
-
cool.flex中TYPEID的Action中未添加
cool_yylval.symbol = stringtable.add_string(yytext);
,解析bison_test_good.cl时发生段错误
原因:StrTable stringtable在stringtab.cc中 -
执行到method_class::layout_feature中出现segement fault
原因: 在convert_symbol_to_type中只支持Int和Bool两种类型,而在
CgenClassTable::install_basic_classes中会isntall Object等基本的class,这些class中存在一些builtin method,所以method::layout_feature()会处理到Object等return_type,调用了convert_symbol_to_type返回了指向nullptr的Type*,所以发生了错误。
解决方法:在convert_symbol_to_type中增加了Object,SELF_TYPE和String的处理。
Part 2
part 2 goal:
-
实现除了面向对象的部分(方法,方法调用,类内成员,继承,构造函数,SELF_TYPE,new和case),需要实现:Int和Bool类型,String暂时不用实现,因为String的实现要求类。
-
test的运行
/test-1/Makefile中include了…/Makefile.common,编译顺序:在src中make(或者make cgen-1只生成cgen-1),再到test中执行make生成.ast,.ll,.s文件 -
不使用ValuePrinter,使用LLVM C++ API,因此需要修改Makefile.common
修改后的Makefile.common如下:
MPDIR = $(LEVEL)
CS426 = /class/cs426
LLVM_DIR = /usr/lib/llvm-3.9
#LLVMLIBDIR = $(LLVMDIR)/Release+Asserts/lib
OPT = opt -O3
LEXER = $(MPDIR)/tools-bin/lexer
PARSER = $(MPDIR)/tools-bin/parser
SEMANT = $(MPDIR)/tools-bin/semant
ifdef MP3
COOLRT = $(MPDIR)/src/coolrt.o
else
COOLRT =
endif
debug = false
ifeq ($(debug),true)
EXTRAFLAGS = -DDEBUG
CGENOPTS = -c
else
EXTRAFLAGS =
CGENOPTS =
endif
CPPFLAGS = -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS $(EXTRAFLAGS) \
-I. -I$(MPDIR)/cool-support/include
#LDFLAGS = -L$(LLVMDIR)/Release+Asserts/lib
LDLIBS =
CXXFLAGS = -g -std=c++11 -Wall -Wno-deprecated -Wno-unused -fpermissive -Wno-write-strings
CXXFLAGS += `${LLVM_DIR}/bin/llvm-config --cxxflags`
LDFLAGS += `${LLVM_DIR}/bin/llvm-config --ldflags`
LLVMLIBS = `${LLVM_DIR}/bin/llvm-config --libs`
LLVMLIBS += `${LLVM_DIR}/bin/llvm-config --system-libs`
CXX = clang++
CC = clang
.PRECIOUS: %.ast %.bc %.ll %.s %.exe
%.ast: %.cl
$(LEXER) $< | $(PARSER) | $(SEMANT) > $@
%.ll: %.ast $(CGEN)
$(CGEN) $(CGENOPTS) < $< > $@
%.bc: %.ll
llvm-as $< -o $@
%.s: %.bc
llc --filetype=asm $< -o $@
%.out: %.s $(COOLRT) // 生成可执行文件
$(CC) -g $+ -o $@
%.verify: %.bc
$(OPT) -verify $< | llvm-dis -o $@
%-opt.bc: %.bc
$(OPT) -basicaa -instcombine -simplifycfg -sroa -early-cse -jump-threading \
-reassociate -loop-simplify -loop-rotate -licm -loop-unswitch -instcombine -loop-simplify -loop-deletion \
-loop-unroll -gvn -sccp -instcombine -jump-threading -dse -adce -simplifycfg -instcombine \
$< -f -o $*-opt.bc
%-optmax.bc: %.bc
$(OPT) -tbaa -basicaa -globalopt -ipsccp -deadargelim -instcombine -simplifycfg -basiccg -inline \
-argpromotion -sroa -early-cse -jump-threading -correlated-propagation \
-simplifycfg -instcombine -tailcallelim -simplifycfg -reassociate -loop-simplify -loop-rotate -licm \
-loop-unswitch -instcombine -loop-simplify -loop-idiom -loop-deletion -loop-unroll -gvn -memcpyopt -sccp \
-instcombine -jump-threading -dse -adce -simplifycfg -instcombine -strip-dead-prototypes -globaldce -constmerge \
$< -f -o $*-optmax.bc
%.output: %
./$< > $@ || true
clean:
-rm -f core *.bc *.ll *.out *.ast *.s *.o *.verify *.dwo
$(CLEAN_LOCAL)
Part 3
- coort.c
runtime在这个文件中实现,在这个文件中需要为builtin classes定义vtables
- 关于类的继承:
子类中应该出现父类类型的成员 - 每个对象中应该只有一个vtable
- 在方法调用和获得成员变量的过程中,应该要避免使用bitcast instruction,bitcast只有在获取vtable的指针时才需要使用
- 在llvm中生成的函数名为class_method,如
class A {
run() : Int
}
生成的llvm的函数为A_run,如果要扩展到多态,那么需要根据函数的参数生成不同的函数名
- 在CgenNode::layout_features()中声明class和vtable的StructType,class type的第一个元素的类型为%vtable*,在函数中对所有的feature遍历调用layout_feature,在attr_class::layout_feature中收集attr的Type,在method_class::中声明函数,并收集这些函数的类型以及它们的指针,函数的类型用于创建vtable的StructType,指针用于定义一个global %vtable constant以此在创建对象时对vtable进行初始化。
创建虚表生成的llvm ir的一个例子:
class Main {
a1 : Int;
a2 : Bool;
main(): Int {
let a : Int in {
if 1 <= 1 then
{
a <- 1+2;
}
else {
a <- 2+3;
}
fi;
}
};
add() : Int {
let a : Int in 1
};
};
;生成的StructType
%Main = type { %Main_vtable*, i32, i1 }
%Main_vtable = type { i32 (%Main*), i32 (%Main*) }
- 如果一个类中有其他类的成员,那么这个成员在StructType中是以指针的形式存在的。在函数的方法中,一开始就会通过getelementptr将this指针中的所有成员装入符号表中,此时非primitive type成员在符号表中是一个二重指针,如:
class A {
a : Int;
}
class B {
b : A;
c : Int;
test();
}
那么它的llvm ir的形式为
%A = type { i32 }
%B = type { %A*, i32}
在test()的符号表中,变量b的类型为%A**,每次b作为expression出现时,都会执行load b,最终返回一个%A类型的Value
-
添加Colletion类,在Collection类中定义的函数,只会声明该函数,不会生成body,生成的LLVM IR中的function name为原始的函数名,而不是Collection_xxx()。实现Collection类的目的是为了可以和C语言链接,在cgen.cc中的method_layout中判断是否为Collection类,如果是则无需加入this指针,只需保持函数的原貌,在method_class::code()中如果为Collection class无需生成body(),在dispatch中先判断是否为builtin function再判断是否为Collection中function,再判断是否为方法。
-
静态多态(函数重载):在生成函数名时加入参数类型,如A::add(Int, Int)生成的函数为A_add_Int_Int_2(不包括this指针),其中2是参数的个数,需要修改method_class::layout_feature()在method_name后面加入suffix,在method_class中加入private member:poly_method_name,在method_class::code()中通过poly_method_name获取函数指针(修改期间出现bug,poly_method_name在构造函数中初始化为"",否则会出现segmentfault)。由于生成的函数名出现了变化,那么dispatch和static_dispatch也要进行修改,主要的修改为:先要生成传入参数的Value,再生成要调用的函数,因为只有知道传入参数的类型才能获取到要调用函数的名字。
-
先声明malloc函数,获取类型,通过DataLayout::getAllocaSize()来获取该类型需要的字节数,调用malloc函数,注意malloc函数的返回值为i8*,所以还需要用bitcast将类型转换为该类型的指针。//TODO assign::code()中对primitive type的处理
-
添加Void type,对于nil object::code()返回nullptr