我写scf的目标是:
1,在C语言的基础上,做一门更完善的、语法好看的编程语言。
语法不能像go语言那么难看[捂脸]
2,给出一套完全自主知识产权的编译器框架,
这个框架要尽可能简单,并且可以作为开发其他编程语言的基础框架。
类似llvm那样,只是我懒得去看llvm的文档,我嫌它太麻烦了。
所以,scf前端的语法跟C语言几乎一样,但有点差别:
1,我还没给它支持switch case语句[呲牙]
因为if else的使用范围更广,所以我就先支持了if else,把switch case暂时放到以后了。
2,支持while,但不支持do while。
因为根据我写C代码的经验,do while用到的特别少。
3,for循环是肯定支持的。
4,编译器不再区分头文件和源文件,而是只有一种文件。
可以使用include关键字包含其他的代码文件。
可以把类型定义和函数声明都写在一个文件里,把它当作头文件去包含。
代码在文件里怎么分布,完全交给了程序员。
5,不需要考虑文件的重复包含问题。
我在语法分析时做了去重处理,不需要像C语言那样使用ifndef去防止重复包含。
6,没有支持宏,
宏的展开还是比较麻烦的,不想把语法分析做得太复杂。
7,没有格式限制,
回车、换行、Tab都一律当空格。
语句的结束以分号为标志,语句块的结束以(右边的)大括号为标志。
对于scf编译器来说,换行符的作用只是在debug信息里记录行号[捂脸]
8,源文件的扩展名暂时设置为.c,在scf的main()函数的第65行可以修改。
之所以设置为.c,是因为大多数的文本编辑器都对C语言有语法高亮功能,例如vim。
除了这里之外,其他模块都不会检查扩展名,而是一律当成文本文件处理。
编译时输入的文件扩展名只能是这4种:
.c表示源文件,
.o表示目标文件,
.a表示静态库,
.so表示动态库,
只会编译源文件.c,其他3种在连接时处理。
默认连接的“库文件”如上图:
1)_start.o,启动main()函数用的,也是程序的真正入口。
2)scf_object.o,自动内存管理用的,
scf_atomic.o,自动内存管理用的,引用计数的原子操作。
3)最后那2个so库,都是C语言的动态库。
下面的3个例子都在scf/examples目录:
1,hello.c,
它打印hello world。
因为要使用C标准库的printf()函数,可以直接把它声明在文件的开头。
没有支持宏,没法包含C语言的stdio.h,把用到的函数声明一下就行了。
也可以把C库的常用函数(例如printf, malloc, free)都声明到一个文件里,以后只包含那个文件就行。
假设当前目录是scf/parse,那么编译命令是:./scf ../examples/hello.c
2,qsort.c,
因为最后要用printf()打印结果,所以也把它声明在开头。
快速排序的sort()函数有2层循环+2个递归,并且还有指针和数组的使用。
大多数情况下,我都是拿它来检测scf编译的代码对不对。
3,mat.c,
一个简单的矩阵类。
因为使用了自动内存管理,先包含../lib/scf_capi.c,这个文件里有几个自动内存管理的函数声明,如下图:
include在scf里作为关键字之一,用来包含其他的文件。
然后声明mat类,并且声明它的成员变量。
scf对类的成员没有权限控制,在类内和类外都可以访问。
构造函数:名字是__init(),返回值是int,第一个参数是this指针,明确地写在第一个位置。
构造函数的返回值可以返回错误码,成功返回0。
加号的重载operator+()函数:
operator也是关键字,跟C++一样。
它的2个参数都明确地写出来:
第一个是this,位于加号左边的操作数,
第2个是that,加号右边的操作数。
返回值有2个,mat*是计算结果,int是错误码(成功为0)。
析构函数:名字是__release(),只有1个参数this,明确地写出来。
mat类的成员变量里只有uint8_t* data是指针,需要申请内存,所以在析构函数里只释放它就可以。
它是需要自动内存管理的,使用scf__auto_freep()释放:这样如果它指向的内存被其他指针引用了的话,不会出现错误释放。
例如这样的代码:
mat* a = create mat(); // 这时a->data的内存引用计数是1,
uint8_t* p = a->data; // 这时a->data的内存引用计数是2,因为指针p也指向了同一块内存,
释放a之后,p指向的内存应该还能用:这时a->data的引用计数只是减1,并没有真正free内存。
释放p之后,这块内存才被真正释放,因为没有指针指向它了。
自动内存管理的代码都在scf/lib/scf_object.c里,连接scf_object.o就行。
最后是main()函数:
用3个double数组作为参数,创建了3个mat矩阵的对象。
然后进行了一个加法运算。
最后打印结果:
我没有关闭自动内存管理模块的日志,所以连内存申请和释放的过程都打出来了。
红框里才是main()函数打印的运算结果。
创业项目群,学习操作 18个小项目,添加 微信:jjs406 备注:小项目!
如若转载,请注明出处:https://www.jjsgsy.com/9335.html