[Suatin] Make a language without learning the principles of compilation 6-the syntax tree introduces logical operations and keyword methods

Preface

Three thousand lines of code, wrote a lonely.
I have done several projects and have been working on the syntax tree. I don’t know how to write it well. The previous tasks were completed because I skipped the complicated ones (Khan) Thanks to the powerful debugging of VS. Only those who know how to use SHIFT+F9 can master C++ memory management (error).

I took tricks in the previous judgment calculations, so that the judgment formula can only have one judgment symbol, which is generally no problem, but the introduction of logical calculations is a problem! An expression (without assignment) can have multiple predicate symbols, multiple logical symbols, five arithmetic operations, strings, predicate symbols, and logical symbols mixed together. These situations must be carefully considered-it is not time to change the direction. , Groping a little! ! !


Improve string concatenation

The previous string splicing mode was set when completedName_flag was true, that is, after the variable was defined, the first Token encountered was Str. And in string splicing mode, there can be no other symbols in the string splicing expression except for the plus sign and the string itself!

After improvement, 1. The first Token after the variable is allowed to be defined is Id. When this Id is a string type, set the expression to string splicing mode.
2. The expression in string splicing mode can have an Id of type string!

void Parser::DealToken_Id(int& _t) {
    
    
		if (exprType == ExprType_StringConnect) {
    
    
			/*即出现了这种情况:"xxx"+a
				其中a是字符串类型
				       +           ->             +
				    /    \                      /   \
		    	"xxx"      None             "xxx"    a
			*/
			if (expTmp == NULL) {
    
     //不存在待处理的节点
				ThrowException<SuatinErrorType_NoDefined>("[Id] string connect expression wrong");
				return;
			}
            //字符串拼接模式,不处理非Str类型的id
			if (SuatinEnv[global_infix[_t]->name]->type != SuatinIDType_string) {
    
    
				return;
			}


			SymbolExpr* node_tmp = dynamic_cast<SymbolExpr*>(expTmp);
			node_tmp->SetRight(new IDExpr(global_infix[_t]->name));
			expTmp = NULL;

			return;
		}



		//处理关键字
		if (global_infix[_t]->k_type != SuatinKeyWordType_NOT_KEYWORD) {
    
    
			(this->*k_funcMap[global_infix[_t]->k_type])(_t);
			return;
		}


		//存在待处理的节点
		if (expTmp) {
    
    
			if (typeid(*(expTmp->GetClassType())) == typeid(LLeftExpr)) {
    
    //待处理节点是左括号节点
				LLeftExpr* node_tmp = dynamic_cast<LLeftExpr*>(expTmp);
				node_tmp->SetContent(new IDExpr(global_infix[_t]->name));
			}
			else {
    
    
				SymbolExpr* node_tmp = dynamic_cast<SymbolExpr*>(expTmp);
				node_tmp->SetRight(new IDExpr(global_infix[_t]->name));
				expTmp = expTmpLeft;//上移待处理节点的指针
			}
			return;
		}

		
		//不存在待处理的节点
		exprRoot = new IDExpr(global_infix[_t]->name);
		
		//检查一下,表达式的开头第一个id的类型,如果是字符串类型就转变表达式类型为字符串拼接模式
		if (firstId_is_string_flag) {
    
    
			if (SuatinEnv[global_infix[_t]->name]->type == SuatinIDType_string) {
    
    
				exprType = ExprType_StringConnect;
				firstId_is_string_flag = false;
			}
		}
	}

Interpreter class

There are currently 24 classes. It doesn't matter if there are too many classes, but the code is really messy! ! !
Insert picture description here

Parser class

This time, more than 20 functions have been added to process keywords! When performing lexical analysis, I regard keywords and variables as identifiers. When traversing the infix expression, I will enter the DealToken_Id function when encountering Id, and judge whether it is a keyword and enter the corresponding function!

#pragma once
#ifndef _PARSER_H_
#define _PARSER_H_
#include"Expr.h"



namespace sua {
    
    

	//成员函数指针,如果不加上Parser::修饰,就只能把对应的成员函数都改成静态的!!!
	class Parser;
	typedef void(Parser::*DealFuncPtr)(int&);



	//语法解析器
	class Parser {
    
    
	private:

		//处理Token的函数
		void DealToken_Num(int& _t);
		void DealToken_Id(int& _t);
		void DealToken_Str(int& _t);
		void DealToken_Pow(int& _t);
		void DealToken_Mul(int& _t);
		void DealToken_Div(int& _t);
		void DealToken_Add(int& _t);
		void DealToken_Sub(int& _t);
		void DealToken_Gre(int& _t);
		void DealToken_GreEq(int& _t);
		void DealToken_Les(int& _t);
		void DealToken_LesEq(int& _t);
		void DealToken_Neq(int& _t);
		void DealToken_EqEq(int& _t);
		void DealToken_Eq(int& _t);
		void DealToken_Com(int& _t);
		void DealToken_ML(int& _t);
		void DealToken_MR(int& _t);
		void DealToken_LL(int& _t);
		void DealToken_LR(int& _t);
		void DealToken_BL(int& _t);
		void DealToken_BR(int& _t);
		void DealToken_Dot(int& _t);
		void DealToken_Sem(int& _t);
		//void DealToken_Eol(int& _t);


		
		//处理关键字的函数
		void Deal_k_if(int& _t);
		void Deal_k_elif(int& _t);
		void Deal_k_else(int& _t);
		void Deal_k_for(int& _t);
		void Deal_k_break(int& _t);
		void Deal_k_continue(int& _t);
		void Deal_k_do(int& _t);
		void Deal_k_until(int& _t);
		void Deal_k_while(int& _t);
		void Deal_k_local(int& _t);
		void Deal_k_const(int& _t);
		void Deal_k_and(int& _t);
		void Deal_k_or(int& _t);
		void Deal_k_not(int& _t);
		void Deal_k_function(int& _t);
		void Deal_k_end(int& _t);
		void Deal_k_return(int& _t);

					

		
		//创建语法树
		void SetupASTree(int start, int end);//实际的创建函数
		//打印漂亮的二叉树
		void DisplayASTree(Expr* _node, int _num = 0);//实际打印的函数
		//删除二叉树
		void DelTree(Expr* _expr);
		
	public:
		Parser();
		~Parser();


		//创建语法树
		void CreateASTree();//留给外面的接口
		//打印漂亮的语法树
		void ShowASTree();//留给外面的接口
		//解释语法树
		void interpret();
		//是否已经构造完成
		bool GetCompletedASTreeFlag()const;


	private:
		bool   completedASTree_flag = false;//是否已经完成语法树的构造
		int  v_forDisplayASTree[100] = {
    
     0 };//打印语法树要用的工具
		bool firstEq_flag = true;//是否第一次遇到等于号
		bool firstId_is_string_flag = true;	//表达式的第一个Id是否是flag
		std::map<SuatinTokenType, DealFuncPtr> funcMap;//为了减少if-else的个数,使用查表的方法,根据不同的枚举来调用不同的函数
		std::map<SuatinKeyWordType, DealFuncPtr> k_funcMap;//处理keyword的函数表


		ExprType exprType = ExprType_NumberCalculate;//表达式类型,默认是数字运算模式,只有第一个Token是字符串时会变为字符串拼接模式
		
		
		bool   completedName_flag = false;//是否完成左边的变量的声明		
	
		

								 
		
		/*root不为空时语句是赋值语句,exprRoot不为空时是表达式,root和exprRoot在构造完语法树后不能同时为空也不能同时不为空*/
		//与exprRoot进行交互
		Expr* root = NULL;											//语法树根节点
		

		/*logicRoot不为空时语句和exprRoot不为空时一样,都是表达式!!!*/
		//与judgeRoot进行交互,最后用exprRoot去替换掉logicRoot
		Expr*  logicRoot = NULL;								//逻辑式语法树根节点


		/*judgeRoot不为空时语句和exprRoot不为空时语句一样,都是表达式!!!	*/
		//judgeRoot与exprRoot进行交互,最后用exprRoot去替换掉judgeRoot
		Expr* judgeRoot = NULL;								//判断式语法树根节点
											



		//普通表达式要构造语法树用得到的指针
		Expr* exprRoot = NULL;													//表达式语法树根节点
		Expr* expTmp = NULL;													//待处理的节点(为空)的父节点
		Expr* expTmpLeft = NULL;												//最下层的没匹配到右括号的左括号节点
		std::stack<Expr*>  v_NoMatchedLLeft;							//保存所有的未匹配到右括号的左括号节点
			
		
	};

};
#endif

The current logic of constructing the syntax tree

  1. A statement, not an assignment statement, that is, root is empty
  2. Assignment statement can be followed by assignment statement, the last statement is an expression
  3. A statement ends with a semicolon
  4. There are 4 modes of expressions, which are five arithmetic operations, string concatenation, judgment operations, and logical operations
  5. Almost every Token must distinguish several expression modes
  6. In addition to specific signs, the expression mode is related to whether exprRoot, judgeRoot, and logicRoot are empty
  7. Every time you encounter an equal sign, you must mount the equal sign in the root syntax tree. In the assignment syntax tree, except the first assignment is left associative, the other assignments that follow are all right associative, that is, if an assignment is to be found, the rightmost assignment node of the root syntax tree is searched, and the new tree is hung on its right child on.
  8. The left side of the assignment node must be a variable node
  9. The last child of the assignment node, after the semicolon appears, hang exprRoot (simple expression) in the root syntax tree
  10. There can only be one judgment node in a formula without logical operation, and the six judgment nodes have the same priority
  11. When the judgment node appears , hang exprRoot on the left child of the judgment node. When a logical node or semicolon appears , hang the new exprRoot on the child of the judgment node.
  12. After the sentence of the judgment mode encounters a semicolon, it will load the judeRoot syntax tree first, and then replace the judgeRoot with exprRoot, so that the judgment mode will not directly interact with the assignment statement! ! !
  13. When a logical node appears , hang exprRoot on the left child of the logical node. When a logical node or semicolon appears , execute item 11 first, and then hang the new exprRoot on the child with this logical node
  14. After the sentence in the logic mode encounters a semicolon, execute item 12 first, then load the logicRoot syntax tree, and then replace the logicRoot with exprRoot, so that the logic mode will not interact directly with the assignment statement! ! !
  15. Regardless of whether it is the judgment mode or the logic mode, except that the expression can have parentheses, there can be no parentheses in other positions!
  16. In logical mode, there can only be one not, and it must be the first at the beginning of the expression
  17. In logic mode, or has a lower priority than and
//下面的语句都是合法的
1 + 2 * (3 / 4) ^5 - 100;
a = TEST_C + "AAAAA" +"SSSSS";//TEST_C是预定义变量,用了测试的,前一篇有提到   
//返回author@DemllieAAAAASSSSS
a = b = c = 2;
a = b = 3 + 1 > 5 * 8 ;//返回false
a = 1 >2 and 2 ~= 3 or 4<5 and 5 ==6;//返回false
a = not 1 > 3;//返回true
not 1~=2 and 3~= 4;//返回false

Project demo

The project code is in the resources I uploaded! ! !

The content of the file: a = not 1 <2 + 1 and 4 == 5 or 2~=1;

词法分析 time consumed 211 ms
初始化语言环境 time consumed 1 ms
语法分析·构造语法树 time consumed 1 ms
------------------------------------------------------------
=
├── a
└── not
    └── or
        ├── and
        │   ├── <
        │   │   ├── 1
        │   │   └── +
        │   │       ├── 2
        │   │       └── 1
        │   └── ==
        │       ├── 4
        │       └── 5
        └── ~=
            ├── 2
            └── 1
------------------------------------------------------------
语法分析·显示语法树 time consumed 39 ms
result = false
语法分析·解释语法树 time consumed 1 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    false               0
              TEST_B    true    number     00000000     true     1.22323e+06
              TEST_A    true    string     00000000     true               0   author@Demllie
显示环境信息 time consumed 650 ms

Project code address CSDN
http://download.csdn.net/download/weixin_41374099/12203591
Project code address BDWP
link: https://pan.baidu.com/s/1S4e1KvZ5uv8XBAkwUvklEA
Extraction code: i72f

Guess you like

Origin blog.csdn.net/weixin_41374099/article/details/104563204