Compiler implementation

本文详细介绍了编译器的实现过程,包括源码的各个部分,如链表、符号表、抽象语法树的节点类型等。此外,还讨论了在CgenNode和CgenClassTable类中的关键功能,如建立继承树和生成代码。最后,文中记录了一个关于类型转换错误的bug修复,涉及符号表和类型转换函数的改进。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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
  1. CgenClassTable class_table为program_class的一个成员变量,在program_class::cgen()中初始化:
class_table = new CgenClassTable(classes, os);
  1. 在CgenClassTable的构造函数中会初始化一些内置的class,如Int, Bool, String,同时会构造一棵继承树:
CgenClassTable::CgenClassTable(Classes classes) {
   enterscope();
   install_basic_classes();
   install_classes(classes);
   build_inheritance_tree();
   setup();
   code_module();
   exitscope();
}
  1. 在CgenClassTable::install_basic_classes()中会install所有的basic classes,其中包括Int, Bool,String,Object以及IO class
  2. CgenClassTable::install_classes(Classes cs)会install cs中的所有class
  3. CgenClassTable::install_class(CgenNode *nd),查看是否已存在该class,若没有则将nd加入到nds中,并添加该class的名字
  4. CgenClassTable::build_inheritance_tree():遍历nds上的所有CgenNode*,并调用set_relations()
  5. CgenClassTable::set_relations(CgenNode *nd):获取nd的parent,获取nd的parent的名字,通过probe来获取parent的CgenNode,为nd设置parent_node,为parent_node设置child nd
  6. CgenClassTable::setup():声明一些llvm ir中存在的函数
  7. 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
  1. cool.flex中TYPEID的Action中未添加cool_yylval.symbol = stringtable.add_string(yytext);,解析bison_test_good.cl时发生段错误
    原因:StrTable stringtable在stringtab.cc中

  2. 执行到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:

  1. 实现除了面向对象的部分(方法,方法调用,类内成员,继承,构造函数,SELF_TYPE,new和case),需要实现:Int和Bool类型,String暂时不用实现,因为String的实现要求类。

  2. test的运行
    /test-1/Makefile中include了…/Makefile.common,编译顺序:在src中make(或者make cgen-1只生成cgen-1),再到test中执行make生成.ast,.ll,.s文件

  3. 不使用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

  1. coort.c
    runtime在这个文件中实现,在这个文件中需要为builtin classes定义vtables
  • 关于类的继承:
    子类中应该出现父类类型的成员
  • 每个对象中应该只有一个vtable
  • 在方法调用和获得成员变量的过程中,应该要避免使用bitcast instruction,bitcast只有在获取vtable的指针时才需要使用
  1. 在llvm中生成的函数名为class_method,如
class A {
	run() : Int 
}

生成的llvm的函数为A_run,如果要扩展到多态,那么需要根据函数的参数生成不同的函数名

  1. 在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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值