从本节开始,要写代码了,我会把我开发menthol的所有过程,详细的写出来
1.开发语言的选择
开发一个编程语言,作为开发这个语言所使用的开发语言,可选择性比较多,比如java、c#,还有运行在服务器上的JS 都没有问题。但作为一个编程语言,需要考虑的是程序的稳定、效率、和使用的便捷性、运行环境等,使用JAVA,C#等语言固然可以降低开发的难度,但效率和运行环境就有了一些限制,这些语言本身是运行在一个虚拟的环境中,也就是说,当你开发完一个新的编程语言后,要运行它,还需要把开发他的环境也运行才可以,这样,你的语言复杂度又高了一点,所以还是要选择直接可以在操作系统中运行的语言才可以。不过,就是编译型语言,也有一些选择,比如,如果直接用汇编开发,开发难度过大,调试也麻烦,如果用其他编译型语言,例如Pascal,也有一点的麻烦,比如你要给你的语言加入某个第三方库,它的源码是用C开发而成的,对于使用来说,可能就存在需要移植的工作,这样麻烦了很多。
如果采用C/C++开发,以上问题,可能就解决了,从效率上来说,C/C++的指针,可以让你直接操作内存,这样就节省了很多计算过程,从环境上来说,C/C++直接运行于操作系统,CPU直接操作代码,效率很高,最主要的flex,bison目前最流行的就是用c++开发,你能找到的教程,大部分也是C/C++写成的,从第三方库来说,目前流行的很多库基本都是基于C/c++开发而成,即使不编译源码,也有提供静态库和头文件,使用还是很方便
所以,我在开发menthol时候选择c/c++
2.语言运行方式的选择
目前我们使用的语言,就那么几种,见下图
我来解释一下
- 编译型语言:这个好理解,就是用编译器,把你写的源代码,转换为CPU可以直接操作的代码,然后运行
- 解释型语言:分为两类
完全解析型:这个就类似与分析字符串了,把分析出的字符串按照你规定好的方法解释,然后解析,这种一般用于玩,实际操作中,不会有人这么搞
半编译型:这目前比较常见,比如java,C#,JS,python,这些都是,它们通常把首先把源码分析一次,把分析出的字符串进行一次编译,编译为可以在自己的虚拟环境中运行的二进制代码,然后利用自己的VM进行运行。还有更进一步的做法,把自己的二进制代码在做一次翻译,翻译为CUP可以直接运行的代码,映射至内存,然后运行,这个就叫JIT,比如JAVA,C#,PYPY,v8就是采用这个模式
解释型语言既有优点,也有缺点,优点就是,它本身不直接运行于操作系统,它的运行,是依赖解析它的运行环境,这样的话,只要运行环境可以跨平台运行的话,语言就可以运行。但它的缺点同样也有,因为基于了一个虚拟环境中解析,所以运行速度在一定上收到影响,即使采用了JIT,但在某些操作中,还是需要依赖运行环境,运行速度依然无法和编译型语言相比,但是,相比较优缺点的话,解释型语言的好处,是编译型语言无法相比的,从最终开发角度来说,不用考虑内存管理,编译过程也没有编译型语言那么复杂
所以,我们选择基于半编译型
好,基本概念完成后,现在就跟我,就开始一步步开始编写代码
开发规划
1.开发工具的选择
vs(vistual stuido),windows下C/C++开发不二工具,调试功能强大,对新的语法支持还不错,并且还有一些辅助功能,比如在编译前执行你需要的操作,这个比较使用,因为我们可能随时更改biosn,flex,要生成新的文件,这个功能就很好的解决了问题。
2.工程项目搭建
- 既然选择了要开发半编译型语言,也就意味着,需要个编译器来编译源代码,所以至少需要两个分开的项目,一个编译器的入口,一个运行编译后文件的入口,
- 核心项目,一个语言开发完成,它也仅仅是个文本分析结果,要想真的应用于开发,以来的第三方库、其他类库,不可能少,为了方便第三方开发调试,和二次开发、核心功能要尽可能的简单方便,要把核心代码都放在一个项目搞定,例如VM,编译,分析等过程等
- 扩展库:为了结构清晰,扩展类库,如字符串操作,数学、多线程等库,每一个是一个项目,采用C/C++编写
- 其他的辅助项目:例如用户要自行编译内置类库,为了方便用户,还要有一个工具让用户执行就可以生成
这个是menthol的项目定义
3.项目定义
我们常见的windows应用程序,通常是单个的EXE或者exe文件,还有其他一大堆的dll,我们运行程序的时候,直接点击exe就可以了,这个exe里面有程序运行的入口,dll是它的依赖库,有些时候你会发先exe特别小,dll特变大,有时候dll也很小,但特别多,有时候,exe特别大,dll小或者少,这个都是因为项目定义的时候,一个功能较为集中的缘故。
我比较喜欢但一个功能各自独占方式,如数学库、字符串库、他们就是单独的两个,这样,即使你要修改某个类库也不需要对其他文件重新编译和修改。这样的话,事实上,你的入口文件就可以很小,其他的业务功能都分散到类库中去。
所以,我们定义也定义两种文件类型,一个是入口文件类型,一种是类库文件类型,因为语言名叫menthol,所以取头两个字母me,以me作为可执行文件的源文件扩展名,以mee,作为编译后可执行文件名,第二个e代表execute的意思。
程序要有个入口函数,比如C,就有main函数,我们也定义一个入口函数mmain.(本处请查看mmain在bison定义)
类库文件的话,我把一个库定义为一个包,一个包就是一个文件,一个包里还有多个模块,模块就是方法和变量的集合,使用的时候导入包,指定要使用的模块,然后调用,库的源文件的扩展名为mep,同样是取menthol的头两个字符,p为package的意思,编译后的扩展名为med,d代表动态的意思(本处请查看import、use的bison定义)
你要开发一个语言,就不能再使用已有的其他类型后缀了,起名也是很重要的,这名字起码可以代表你的语言,这个过程要考虑一个问题,在用户眼中,用C/C++开而成的,或者用你的语言开发而成的库,都是库,不存在区别,所以,基于这个理念,我们要让C++开发的库的后缀名和用你的语言开发而成的库扩展名相同,例如我开发menthol的时候,所有库的扩展名都叫med,具体如何判断是哪种类型的库、如何执行,后面会介绍
好,概念及规划全部完成后,用VS创建项目等操作较为简单,不再演示,如果你想看看具体的工程项目安排,请下载mentol源文件查看
下一节,开始一步步写代码实现