用LLVM来开发自己的编译器(三)——对象和数组

##对象 借鉴java的思想,这里对象要有继承和多态的特性,而且只能单继承。这里的类包含了构造函数、属性和方法的定义。例子如下:

class Worker{
	void work(){
		printS("...");println();
	}
}

class Coder : Worker{
	long age;
	Coder(){
		printS("create a coder");
		this.age = 30;
	}

	void work(){
		printS("fuck code");println();
	}	
}

class CivilServant : Worker{
	void work(){
		printS("!@#$%^&");println();
	}
}

long main(char[][] args){
	Worker worker = new Worker();
	worker.work();
	worker = new Coder();
	worker.work();
	worker = new CivilServant();
	worker.work();

	return 0;
}

这里就用指针来实现对象,对应ir的i8*型,这个指针指向从GC上申请的一段数据。要实现多态的特性,这段数据就要包含类的信息,所以这段数据的开始是一个指向类信息的指针,跟着是父对象的指针,后面才是各属性的值。由于各项数据最长是64位,所以这里用64位来对齐。对象的内存布局如下面的样子: 在此输入图片描述

方法是动态查找的,通过调用一个函数sysObjectMethod,传入对象本身和方法的名字,得到方法的指针。方法其实就是函数,只是编译时会增加了一个参数,用来保存对象本身,方法里的this关键字就是第一个参数。例如obj.abc(arg1,arg2)会转换成类似method = sysObjectMethod(obj,"abc"); method(obj,arg1,arg2)的效果。对象的属性也是动态获得的,它和方法类似,通过调用sysObjectField,传入对象本身和属性名,得到属性的指针。

##数组 数组的语法也类似于java,数组的大小只是个属性,跟类型无关。下标访问从0开始,下标会先与数组大小求余再进行访问来防止越界,如array[-1]是最后一个元素,array[length]是第一个元素array[0]。数组创建后大小固定不能动态增加。数组的类型表示是基本类型后加"[]"结尾,下面是使用数组的例子:

long main(char[][] args){
	long size = 100;
	long[] array = new long[size];
	printL(array.length);println(); // 100
	
	array = {1,2,3,4};
	array[1] = 99;
	printL(array.length);println(); // 4
	printL(array[3]);println(); // 4
	printL(array[5]);println(); // 99
	char[] str = "ABC\u66ef";
	printS(str);println();
}

数组不同对象,没用继承和多态,类型的安全直接在编译时保证。数组也是用指针实现,数据在堆上动态分配,没有保留类型的信息,只保留长度和元素宽度的信息。下标访问是sysArrayElement函数的调用,传入数组和下标,返回元素的指针,函数里面用上面的方法保证防止越界访问。内存布局如下: 在此输入图片描述

这里字符串就是一个字符数组,它和其他数组是一样的,只是在语法上提供了便利而已。

##自动垃圾回收 这里集成Boehm GC来管理内存,因为Boehm GC的保守机制最容易集成。对象和数组的内存都要向BoehmGC申请,这样对象和数组都不用手动释放内存。

##完整代码 https://github.com/linlifengx/step3

##例子 ####linkedlist.sp class List { Node head; Node tail;

	void print(){
		for(Node node = head;node != null; ){
			printL(node.v);println();
			node = node.next;
		}
	}
	
	void add(Node node){
		if(head == null) {
			head = node;
			tail = node;
		} else {
			tail.next = node;
			tail = node;
		}
	}
}

class Node {
	long v;
	Node next;
	
	Node(long v){
		this.v = v;
	}
}

long main(char[][] args){
	List list = new List();
	for(long i = 0; i < 100; i++){
		list.add(new Node(i));
	}
	list.print(); // 0 - 99
}

转载于:https://my.oschina.net/linlifeng/blog/114255

非常有趣的问题!使用Flex Bison和LLVM编写自己的编译器是一项非常有挑战性的任务,但也是一项非常有成就感的任务。下面是一些关于如何实现这个目标的建议: 1. 学习Flex和Bison Flex和Bison是用于生成词法分析器和语法分析器的工具。学习这些工具是编写编译器的第一步。您可以通过阅读官方文档或参考书籍来学习这些工具,例如《Flex和Bison》这本书。 2. 设计语言文法 在编写编译器之前,您需要设计您的编程语言的语法。这涉及到识别您的语言中的关键字、表达式、语句和程序结构等方面。您可以使用BNF或EBNF等形式化语言来描述您的语言。 3. 实现词法分析器和语法分析器 使用Flex和Bison生成词法分析器和语法分析器是实现编译器的关键。您需要编写词法规则和语法规则来识别您的语言中的语法结构,并将其转换为抽象语法树(AST)表示。您还需要为您的语言实现语义分析和错误检查。 4. 生成LLVM IR 一旦您的编译器可以将输入源代码转换为AST,您需要将AST转换为LLVM IR。 LLVM是一种开放源代码编译器框架,可以将AST转换为LLVM IR,这是一种通用的低级表示形式,可以用于生成本机代码或其他目标代码。 5. 生成目标代码 最后,您需要将LLVM IR转换为目标代码。这可以通过LLVM提供的工具链来完成,例如LLVM汇编器或LLVM链接器。您还可以将LLVM IR转换为机器代码,以生成与特定硬件体系结构兼容的目标代码。 希望这些建议对您有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值