【Suatin】不学编译原理就制作语言7——改进判断运算和逻辑运算

前言

虽然只是改进,但是还是很复杂的任务!之前写的判断运算和逻辑运算,其中的限制是不少!特定位置不能加括号这个毛病我不解决了,其他要解决的毛病还有
判断式子中,两边返回都是数字!
逻辑式子中,两边都要是判断式子!
意思我必须在简单表达式之上,构造判断式,然后在判断式之上,构造逻辑式。这种限制太多了,改进后允许在简单表达式之上,就可以构造逻辑式!!!允许简单表达式单元为字符串!!!


1.构造语法树(回顾之前的内容)

简单表达式在第二篇里详细介绍过,可以是五则运算(+ - * / ^)和括号构造的计算式子,也可以是字符串、字符串类型的id和加号构造的式子!

  • 赋值式、判断式、逻辑式、简单表达式并不是并列的关系!!!
  • 在没有改进判断运算和逻辑运算前,几个式子的关系是:赋值式>逻辑式>判断式>简单表达式
  • 在改进了判断运算和逻辑运算后,逻辑式和判断式是几乎并列的!
  • 是否是赋值式由root是否为空决定,判断式和逻辑式由exprType的类型决定!
  • exprType默认是五则运算,每次exprRoot为空时遇到的第一个如果是字符串,就会将exprType置为字符串拼接模式
  • 每次遇到>,<,>=,<=,~=,==就会将exprType置为判断模式
  • 每次遇到and,not,or就会将exprType置为逻辑模式(好晕啊^_^,exprType的已经名存实亡了,具体表达式模式的判断由几个指针是否为空和expr_compare_flag,expr_logic_flag区分了)
op = >|<|>=|<=|~=|==
E  = 简单表达式
id = 变量
【根节点】 = 传入的子语法树的根节点


1.赋值式
E ::= id = E;
E ::= id = id = id =...= E;
1.1第一次遇到=后式子变成【赋值式】,第一个赋值节点挂在root上,exprRoot即前面的id挂在
	root左孩子上,置空exprRoot
1.2第N此遇到=,将exprRoot挂在新的赋值节点的左孩子上,将新的赋值节点挂在root语法树
	最右的赋值节点的右孩子上,置空exprRoot
1.3遇到; 将exprRoot挂在root语法树最右赋值节点的右孩子上,然后置空exprRoot




2.判断式
E ::= E op E;
2.1遇到op后式子变成【判断式】,第一个op节点挂在judgeRoot上,exprRoot即op前面的简单表达式挂在judgeRoot
	左孩子上,置空exprRoot
2.2遇到; 将exprRoot挂在judgeRoot右孩子上,然后用exprRoot替换掉judgeRoot,置空judgeRoot





3.逻辑式
E ::= [not] E op E;
E ::= [not] E op E (and|or) E op E (and|or) E op E;
3.1遇到not后式子变成【逻辑式】,not节点挂在logicRoot上,置空exprRoot
3.2遇到and后式子变成【逻辑式】,
	>>>如果judgeRoot不为空,执行2.2操作
	>>>如果logicRoot为空,将exprRoot挂在新的and节点左孩子上,置空exprRoot
	>>>如果logicRoot下面是not节点,就往下取其内容,
		————如果内容为空,将exprRoot挂在新的and节点左孩子上,将and节点挂在not,置空exprRoot
		————如果内容不为空,对not的内容执行and_chunk操作
	>>>如果logicRoot下面不是not节点,对logicRoot执行and_chunk操作
  	

  	>and_chunk操作为
  		————如果【根节点】是and,将exprRoot挂在【根节点】右孩子上,再将【根节点】挂在新的and节点左孩子上
  		————如果【根节点】是or,取or右孩子,
  				————如果内容为空,将exprRoot挂在新的and节点左孩子上,再将and节点挂在【根节点】右孩子上
  				————如果内容不为空,将exprRoot挂在【根节点】右孩子的右孩子上,再讲【根节点】的右孩子挂在新的and节点左孩子上,将and节点挂在【根节点】右孩子上
  	>and_chunk结束时,置空exprRoot


3.3遇到or后式子变成【逻辑式】,
	>>>如果judgeRoot不为空,执行2.2操作
	>>>如果logicRoot为空,将exprRoot挂在新的的or节点左孩子上,置空exprRoot
	>>>如果logicRoot下面是not节点,就往下取其内容,
		————如果内容为空,将exprRoot挂在新的or节点左孩子上,将or节点挂在【根节点】右孩子上,置空exprRoot
		————如果内容不为空,对not的内容执行or_chunk操作
	>>>如果logicRoot下面不是not节点,对logicRoot执行or_chunk操作
  	

  	>or_chunk操作为
  		————如果【根节点】是and,将exprRoot挂在【根节点】右孩子上,将【根节点】挂在新的or节点的左孩子上
  		————如果【根节点】是or,取or右孩子
  				————如果内容为空,将exprRoot挂在or右孩子上,将【根节点】挂在新的or节点左孩子上
  				————如果内容不为空,将exprRoot挂在or右孩子的右孩子上,将【根节点】挂在新的or节点左孩子上
  	>or_chunk结束时,置空exprRoot


3.4遇到; 接下来
	>>>如果judgeRoot不为空,执行2.2操作
	>>>如果logicRoot下面是not节点,就往下取其内容,
		————如果内容为空,将exprRoot挂在not的下面
		————如果内容不为空,对not的内容执行logic_chunk操作
	>>>如果logicRoot下面不是not节点,对logicRoot执行logic_chunk操作
  	

  	>logic_chunk操作为
  		————如果【根节点】是and,将exprRoot挂在and右边
  		————如果【根节点】是or,or的右孩子
  				————如果内容是空,将exprRoot挂在【根节点】右孩子上
  				————如果内容不是空,将exprRoot挂在【根节点】右孩子的右孩子上


	>>>做完上面的操作后,用exprRoot替换logicRoot,置空logicRoot
	>
	>
	>>>如果root不为空,还要执行1.3操作
	>>>如果root为空,用root替换exprRoot,置空exprRoot
	
	

>
>
>最后上面执行完,无论是什么语法树,都会挂在root上,另外的exprRoot\judgeRoot\logicRoot都为空!!!		
>之后解释语法树、销毁语法树都从root开始!!!	  		

2.确定要调用解释接口类型(改进判断、逻辑运算)

之前判断运算调用的解释接口都是interpret,都是通过值来判断!
改进之后~= 和 == 中不止可以通过值来判断,还可以通过字符串或是布尔来判断!
同样的,改进之后逻辑运算的单元就不一定是判断式了,可以是简单表达式,逻辑运算的三种节点的解释接口中,也可以通过值、字符串、布尔来判断!

想要实现这种实在不容易,我开始怀疑自己前几天为了这个解释器模式写了三种解释接口的操作是否使项目复杂化了!我觉得是的,但是正是没有其他好方法,才写了三种接口——所以不能动接口,要实现上面的改进,需要让~= == and not or这5种节点得到某种信息,得到他们该调用哪种接口的信息!

	//该判断类或逻辑类中,单元(简单表达式)该使用的解释接口
	enum Unit_InterfaceType {
    
    
		Unit_InterfaceType_number,     //调用interpret接口
		Unit_InterfaceType_string,     //调用interpret_str接口
		Unit_InterfaceType_bool,       //调用interpret_bool接口
	};
解释器的类

目前有25个类。
引入了一个中间类,记录左右的解释接口类型!Not节点是单独一个,所以解释接口类型的标志就让Not类中!
在这里插入图片描述

为Not\And\Or\Neq\EqEq确定解释接口类型
  • 在创建~=/==/and/or/not节点时,要确定语法树某个位置上的解释接口类型
  1. 在遇到~=/==时,确定judgeRoot左孩子的解释接口类型
  2. 在遇到and/or时,如果judgeRoot不为空,就要为judgeRoot右孩子确定解释接口类型。在logicRoot语法树中没有确定过接口类型的分支上,确定接口类型!
  3. 遇到分号后,如果judgeRoot不为空,为judgeRoot右孩子确定解释接口类型。如果logicRoot不为空,为logicRoot语法树中没有确定过接口类型的分支上,确定接口类型!如果logicRoot根节点是NOT节点,确定NOT节点的解释接口类型!
Not\And\Or\Neq\EqEq的解释
	bool AndExpr::interpret_bool() {
    
    
		if (left_i_type == Unit_InterfaceType_bool) {
    
    
			if (right_i_type == Unit_InterfaceType_bool) {
    
    
				return left->interpret_bool() && right->interpret_bool();
			}
			else {
    
    
				return left->interpret_bool();//右边的为true,所以只用判断左边的
			}
		}
		else {
    
    
			if (right_i_type == Unit_InterfaceType_bool) {
    
    
				return right->interpret_bool();//左边的为true,所以只用判断右边的
			}
		}
		return true;
	}
	
	bool OrExpr::interpret_bool() {
    
    
		//除了bool和bool需要考虑外,其他分支的都有一方是真,这就够了
		if (left_i_type == Unit_InterfaceType_bool) {
    
    
			if (right_i_type == Unit_InterfaceType_bool) {
    
    
				return left->interpret_bool() || right->interpret_bool();
			}
		}
		return true;
	}

	bool NotExpr::interpret_bool() {
    
    
		if (i_type == Unit_InterfaceType_bool) {
    
    
			return !(content->interpret_bool());//not后面的内容返回真假
		}
		return false;//当not后面的内容返回字符串或数字时,其内容是true
		
	}

	bool NeqExpr::interpret_bool() {
    
    
		if (left_i_type == Unit_InterfaceType_bool) {
    
    
			if (right_i_type == Unit_InterfaceType_bool) {
    
    
				return left->interpret_bool() != right->interpret_bool();
			}
			return !(left->interpret_bool());//右边是true,所以只用判断左边
		}
		else if (left_i_type == Unit_InterfaceType_number) {
    
    
			if (right_i_type == Unit_InterfaceType_bool) {
    
    
				return !(right->interpret_bool());//左边是true,所以只用判断右边
			}
			else if (right_i_type == Unit_InterfaceType_number) {
    
    
				return left->interpret() != right->interpret();
			}
		}
		else if(left_i_type==Unit_InterfaceType_string){
    
    
			if (right_i_type == Unit_InterfaceType_bool) {
    
    
				return !(right->interpret_bool());//左边是true,所以只用判断右边
			}
			else if (right_i_type == Unit_InterfaceType_string) {
    
    
				return left->interpret_str() != right->interpret_str();
			}
		}

		//ThrowException<SuatinErrorType_Value>("Neq interpret error");
		return true;
	}


	bool EqEqExpr::interpret_bool() {
    
    
		if (left_i_type == Unit_InterfaceType_bool) {
    
    
			if (right_i_type == Unit_InterfaceType_bool) {
    
    
				return left->interpret_bool() == right->interpret_bool();
			}
			return left->interpret_bool();//右边是true,所以只用判断左边
		}
		else if (left_i_type == Unit_InterfaceType_number) {
    
    
			if (right_i_type == Unit_InterfaceType_bool) {
    
    
				return right->interpret_bool();//左边是true,所以只用判断右边
			}
			else if (right_i_type == Unit_InterfaceType_number) {
    
    
				return left->interpret() == right->interpret();
			}
		}
		else if (left_i_type==Unit_InterfaceType_string) {
    
    
			if (right_i_type == Unit_InterfaceType_bool) {
    
    
				return right->interpret_bool();//左边是true,所以只用判断右边
			}
			else if (right_i_type == Unit_InterfaceType_string) {
    
    
				return left->interpret_str() == right->interpret_str();
			}
		}

		//ThrowException<SuatinErrorType_Value>("EqEq interpret error");
		return false;
	}
通过传入的小树根节点,得到该小树的解释接口类型
	/*返回_node该调用的解释接口类型
	 一个Unit返回三种数据:字符串、数字、id
	*/
	Unit_InterfaceType Parser::GetTree_InterfaceType(Expr** _node) {
    
    
		//字符串处理
		if (typeid(*((*_node)->GetClassType())) == typeid(StrExpr)) {
    
     
			return Unit_InterfaceType_string;
		}

		//id处理
		if (typeid(*((*_node)->GetClassType())) == typeid(IDExpr)) {
    
     
			IDExpr* tmp = dynamic_cast<IDExpr*>(*_node);
			if (tmp->GetType() == SuatinIDType_bool || tmp->GetType() == SuatinIDType_nil ) {
    
    
				return Unit_InterfaceType_bool;
			}
			else  if (tmp->GetType() == SuatinIDType_string) {
    
    
				return Unit_InterfaceType_string;
			}
			else if (tmp->GetType() == SuatinIDType_int || tmp->GetType() == SuatinIDType_number) {
    
    
				return Unit_InterfaceType_number;
			}
		}

		//Num处理
		if (typeid(*((*_node)->GetClassType())) == typeid(NumExpr)) {
    
     
			return Unit_InterfaceType_number;
		}


		//~=/==处理
		if (typeid(*((*_node)->GetClassType())) == typeid(NeqExpr) || typeid(*((*_node)->GetClassType())) == typeid(EqEqExpr)) {
    
    
			return Unit_InterfaceType_bool;
		}

		//返回计算结果或拼接结果
		if (typeid(*((*_node)->GetClassType())) == typeid(AddExpr)) {
    
     
			SymbolExpr* node_tmp = dynamic_cast<SymbolExpr*>(*_node);
			if (node_tmp->GetRight() == NULL) {
    
    
				ThrowException<SuatinErrorType_NoDefined>("error in GetTree_InterfacceType");
				return Unit_InterfaceType_number;
			}

			//字符串拼接处理
			if (typeid(*(node_tmp->GetLeft()->GetClassType())) == typeid(StrExpr) && typeid(*(node_tmp->GetRight()->GetClassType())) == typeid(StrExpr)) {
    
    
				return Unit_InterfaceType_string;
			}
	
			//五则运算处理,基本就是不处理,因为默认就是使用五则运算接口
		}

		return Unit_InterfaceType_number;
	}


项目演示

项目地址在这!!!!!!!!!!!!!!!!!!!

输入:a= b = c = not “hh” and 1 == “” or TRUE and 2 == 3 + 1;

词法分析 time consumed 456 ms
初始化语言环境 time consumed 1 ms
语法分析·构造语法树 time consumed 4 ms
=
├── a
└── =
    ├── b
    └── =
        ├── c
        └── not
            └── or
                ├── and
                │   ├── "hh"
                │   └── ==
                │       ├── 1
                │       └── ""
                └── and
                    ├── TRUE
                    └── ==
                        ├── 2
                        └── +
                            ├── 3
                            └── 1
语法分析·显示语法树 time consumed 982 ms
语法树是否完全==>true
last result = true
语法分析·解释语法树 time consumed 9 ms
语言环境>
                name   isconst    type      funcPtr     flag             num   str
                 NIL    true       nil     00000000    false               0
              TEST_C    true       int     00000000     true               7
               FALSE    true      bool     00000000    false               0
              TEST_D    true      bool     00000000    false               0
                TRUE    true      bool     00000000     true               0
                   a   false      bool     00000000     true               0
                   b   false      bool     00000000     true               0
                   c   false      bool     00000000     true               0
              TEST_B    true    number     00000000     true     1.22323e+06
              TEST_A    true    string     00000000     true               0   author@Demllie
显示环境信息 time consumed 1732 ms
释放环境 time consumed 0 ms

项目代码地址CSDN
https://download.csdn.net/download/weixin_41374099/12222491
项目代码地址BDWP
链接:https://pan.baidu.com/s/1bJrucz35cEA5JBt_xjuIAw
提取码:40ha

猜你喜欢

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