【Suatin】不学编译原理就制作语言--------谈谈自制编程语言1

前言

目前很有野心,打算做个大事。虽然编程水平还不高,看《编译原理》也看不下去,看视频教程看了十几节课发现笔记上全是数学符号。就——暂时不看了吧!我之前因为好奇买了本《两周自制脚本语言》,的确学了一些知识。但是其中从第五天开始,都使用了一个Parser库,看知乎知道了难点不在这个库上,所以一般都用现成的。而书的问题是代码没多少注释!!!实在搞不明白,再加上java用起来实在不爽!于是这条路也抛弃了,最后我打算先从一个中缀表达式转后缀表达式搞起——因为机器识别不了式子,只能识别符号和数字,所以可以先转换成后缀表达式,然后通过这个表达式求解。

一般在语法分析的时候,需要构造AST语法树。而中后缀这条路不用,需要利用

形成语法树可以把各种符号涵盖进去,而中后缀只能计算数字直接的加、减、乘、除、乘方等简单的一元或二元操作,最后也只能得到一个计算结果(一般是double类型的数)。

我觉得中后缀这条路挺好用的,凡是表达式都可以用这种方法得到结果,如果有函数在其中,就把函数替换为函数的返回结果!

虽然这么说!但是这只是对表达式而言!对于其他语句和语句块,还是要构造AST的!

我目前的项目进度到了分割语句和分类语句上,已经完成了分割Token和分类Token,因为项目中变化太多,加上现在已经有了31个文件,实在没办法放上来。但是可以把一些概念贴上!

上层语言与下层语言的关系

上层语言是我的自制语言Suatin-lang,下层语言是C++。
上层语言方法都是小写,下层语言方法大部分都是驼峰

上层语言的类型,如int/number/BigNumber/complex/string/bool/function/array/file都继承于object,不是因为我想搞面向对象和高阶函数什么的,而是这样后面创建对象和传递对象时比较方便!!!

下层语言C++中有对应的类,如SuaInt/SuaNumber/SuaBigNumber/SuaComplex/SuaString/SuaFunction/SuaBool/SuaArray/SuaFile/SuaObject,这些类专门对应着处理上层语言的数据对象——变量、函数等。

//SuaUtil.h
class SuaObject {
    
    
protected:
	bool isconst = false;///是否是常量。const可以修饰SuaObject
	std::string name="";///标识符名称
	int zoneIndex;//作用域索引,和pos一起用的。只有SuaObject才有这个

public:
	//返回类型名的字符串,因为源码是字符串,输入输出都是字符串处理
	virtual std::string getname()const = 0;

	//返回类型
	virtual std::string gettype()const = 0;



	///常量操作
	bool is_constant()const;
	void setconst();
	void resetconst();

};

解释器中的类

下层语言还有其他的类,如Token。源码中所有的符号被分类,每个符号或标识符都放入一个Token,所有的Token都会放入全局的容器中,即放入全局中缀表达式中。特殊的Token会包含SuaObject对象——即自定义变量或函数。

Expr——只有四则加乘方的运算才能算作表达式,这个我还没认真修改。只有个空壳。表达式里关键是两个变量,start&end,表示表达式在全局中缀表达式的中范围。

Pool——存储池,自定义的变量或函数,即SuaObject对象,会放入这个池子里。暂时不想搞类型推导,所以暂时打算做静态类型的语言。每次遇到一个标识符都会和池子里的进行比对,看看池子里是否有。检查标识符靠的是标识符的名称,不是地址。

在上层语言中,一个变量或函数只有两个关键的点,一是它的值,放在底层的SuaObject中。二是它字符串的名称,这意味着在此上层语言中,不能对关键字创建变量!!!

Parser——用来遍历中缀表达式,分割语句和分类语句。其中有几个关键变量:start&end&三个作用域计数器&作用域容器。

  • start&end从头开始遍历到尾,来分割不同的语句。
  • 作用域计数器就厉害了。每遇到一个左括号就加一,遇到右括号就减一,即当计数为n时的位置是A时,再到了计数为n-1的位置为B后,A-B之间就是一个作用域!!!识别不同作用域靠n的值。
  • 三个作用域计数器就是三个int,分别计数小括号、中括号、大括号。
  • 作用域容器放一个结构体,用来表示一个作用域。内容是作用域索引、作用域开头、作用域结尾。每个SuaObject内存放一个自己的作用域索引,Token中有该符号的位置,把位置和索引都传入Parser的作用域检测方法,就能知道此变量是否在该作用域内
  • 但是当两个作用域并行时,他们的索引是一样的,所以需要再引入一个变量number。区分并行的作用域!
//Parser.h
//这个类暂时的样子
class Parser
{
    
    
private:
	//一个语句的起始就是start到end-1
	int start;//语句开头,可以是标识符、数字
	int end;//语句结尾,可以是\ n   ;   }    {
    
    
	//一个作用域的起始就是count_zoneQ_xxx=n到count_zoneQ_xxx=n-1时,对应的两个位置之间
	//下面三个计数器都是遇到左括号加一,遇到右括号减一。不同的作用域间的数不同。这个数指的就是作用域索引。
	static int count_zoneQ_little;//小括号作用域计数
	static int count_zoneQ_middle;//中括号作用域计数
	static int count_zoneQ_big;//大括号作用域计数
	

	//花括号作用域索引,在使用语句前,先经过检查是否在对应的作用域内—— GetVal()
	//索引小的作用域大!!!所以如果是作用域1的数,可以在作用域2/3内使用
	typedef struct _ZONE{
    
    
		int index;//作用域索引
		int number;//区分并行作用域
		int start;//作用域开头
		int end;//作用域结尾
	}ZONE;
	static std::vector<ZONE*> zone;


public:
	
	//分割语句
	static void SyntaxSeparate();
	//分类语句
	static void SyntaxClassify();

	//检查变量的位置是否在其作用域内
	static bool InZone(int index,int number,int pos);
	

};

shell——解释器的交互面。从文件中读入字符串、Token的分割与分类、显示Pool池子的内容、显示中缀表达式的内容、显示语句分类的内容等等直接得到处理效果或是运行效果的函数。

SuaUtil——最底层的仓库。自定义异常处理、各种枚举、基类的定义等等。既然是最底层的类,那么绝对不能放太多的东西来增加依赖,应该不依赖其他自定义的文件!

SuaMath——一些数学操作的集合。
SuaExcept——自定义异常类,枚举了一些能想到的错误。具体请见之前的文章lang:C++自定义异常类——用来处理自制编程语言的异常信息

文件的引用关系

项目大了要分好文件,不能有交叉引用。因为如果后续我使用模板、友元的话会很麻烦。
在这里插入图片描述

解释器的结构

目前脑子里的解释器是下面这样,以后完成了肯定会不同的。

解释器运行流程

  1. 传入 .suatin文件的路径,并运行解释器。
  2. .suatin文件中读取字符串,一行行地组成一个字符串,每读取一行就在后面添加一个\n——也可以添加\r\n,那样的话稍微有点不同而已
  3. 对整个字符串进行正则匹配,把关键字、标识符、五则运算符(+ - * / ^ )、判断运算符(> < <= >= == ~=)、小括号、中括号、大括号、数字(含小数、指数)、注释(含单行注释、多行注释)、换行\n、分号、等于号、逗号运算符都分割出来,然后得到分组索引,映射为优先级后,除了注释外的符号都创建Token
  4. 把Token放入全局中缀表达式中。
  5. 遍历中缀表达式,分割语句,确定标识符(即变量、函数)作用域,把作用域信息保存到ParserSuaObject上。分类语句,把一条条的语句放入语句链中——放语句在中缀表达式中的范围就行——执行代码就是执行这条语句链!
  6. 根据代码中的变量定义语句,创建SuaObject对象的实例,并把指针放入Pool池子中。
  7. 构造语法树AST
  8. 求解语法树

在这里插入图片描述
因为是直接运行的,没有中间代码,所以与其说是解释器,不如说是直译器!

项目现在做到了那个位置?

下面是测试Suatin-lang的源码,C++项目就省略了。

//test.suatin
int sum=0.0e0
const int i=0
string str="hello world suatin-l
	ang programmer!"
if str == null 
{
    
     print("yes") }
else
{
    
    
	i=i+1      //zhushi
	sum=sum+i /*duohangzhushi
         */
	sum=sum/2;sum=sum+sum*i
}
print(sum+i)//zhushi

显示结果:

welcome to suatin interpretor interface

C:\Users\LX\Desktop\test.suatin内代码为>
int sum=0.0e0
const int i=0
string str="hello world suatin-l
        ang programmer!"
if str == null
{
    
     print("yes") }
else
{
    
    
        i=i+1      //zhushi
        sum=sum+i /*duohangzhushi
         */
        sum=sum/2;sum=sum+sum*i
}
print(sum+i)//zhushi
--------------代码结束!--------------
中缀表达式>
           name     pos  priority
            int      0       1
            sum      1      12
              =      2       8
          0.0e0      3      18
             \n      4       6
          const      5       1
            int      6       1
              i      7      12
              =      8       8
              0      9      18
             \n     10       6
         string     11       1
            str     12      12
              =     13       8
        "hello world suatin-l
        ang programmer!"     14       5
             \n     15       6
             if     16       1
            str     17      12
             ==     18      11
           null     19       1
             \n     20       6
              {
    
         21       3
          print     22      12
              (     23      10
          "yes"     24       5
              )     25      10
              }     26       4
             \n     27       6
           else     28       1
             \n     29       6
              {
    
         30       3
             \n     31       6
              i     32      12
              =     33       8
              i     34      12
              +     35      15
              1     36      18
             \n     37       6
            sum     38      12
              =     39       8
            sum     40      12
              +     41      15
              i     42      12
             \n     43       6
            sum     44      12
              =     45       8
            sum     46      12
              /     47      14
              2     48      18
              ;     49       7
            sum     50      12
              =     51       8
            sum     52      12
              +     53      15
            sum     54      12
              *     55      14
              i     56      12
             \n     57       6
              }     58       4
             \n     59       6
          print     60      12
              (     61      10
            sum     62      12
              +     63      15
              i     64      12
              )     65      10
             \n     66       6
第1条语句>sum=0.0e0
第2条语句>i=0
第3条语句>str="hello world suatin-l
        ang programmer!"
第4条语句>str==null
第5条语句>print("yes")
第6条语句>i=i+1
第7条语句>sum=sum+i
第8条语句>sum=sum/2
第9条语句>sum=sum+sum*i
第10条语句>print(sum+i)
作用域信息>
index = 1,number=1,start=21,end=26
index = 1,number=2,start=30,end=58
请按任意键继续. . .

CSDN
项目在我的资源里(要多少C币不是我决定的,明明设置的需要0C币,但是之后看被改了555)!

项目代码地址BDWP
链接:https://pan.baidu.com/s/1yX7j69kpbr4a5kd-V-LyRg
提取码:2agq
复制这段内容后打开百度网盘手机App,操作更方便哦

猜你喜欢

转载自blog.csdn.net/weixin_41374099/article/details/104150012