状态机学习解析四则运算式 语法分析

Posted itdef

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了状态机学习解析四则运算式 语法分析相关的知识,希望对你有一定的参考价值。

将四则运算拆分成一个个数字和符号后

就进行运算分析

使用以下语法规则:(摘录自《自编编程语言》)

expression:

term:

primary expression:

 

 代码如下:

#pragma once
#include <string>
#include <deque>
#include <iostream>

enum TokenType {
	BAD_TOKEN,
	NUM_TOKEN,
	ADD_TOKEN,
	SUB_TOKEN,
	MUL_TOKEN,
	DIV_TOKEN,
	LPAREN_TOKEN,
	RPAREN_TOKEN,
	ENDFILE_TOKEN
};

class Token {
private:
	TokenType type_;
	std::string valueStr_;
public:
	Token() : type_(BAD_TOKEN) {}
	Token(TokenType t,std::string s) : 
		type_(t),valueStr_(s) {}

	bool operator ==(const Token& t) {
		if (type_ == t.type_ &&
			valueStr_ == t.valueStr_) {
			return true;
		}
		return false;
	}
	Token(const Token& t) {
		if (*this != t) {
			type_ = t.type_;
			valueStr_ = t.valueStr_;
		}
	}

	bool operator != (const Token& t) {
		return !(*this == t);
	}

	Token& operator=(const Token& t) {
		if (*this != t) {
			type_ = t.type_;
			valueStr_ = t.valueStr_;
		}
		return *this;
	}
	/*void SetType(TokenType type) { type_ = type; }
	void SetValue(double value) { value_ = value; }
	void SetValStr(std::string valueStr) { valueStr_ = valueStr; }*/
	TokenType GetType() { return type_; }
	std::string GetValStr() { return valueStr_; }
};


class Expression2Tokens {
	
	std::string contentStr_;
	Expression2Tokens& operator=(const Expression2Tokens&) {};
	Expression2Tokens(const Expression2Tokens&);
	enum Status {
		INIT_STATUS,
		NUM_STATUS,
		OPERATOR_STATUS,
		LPAREN_STATUS,
		RPAREN_STATUS,
		END_STATUS,
		ERROR_STATUS
	};
public:
	std::deque<Token> tokenDeque_;
	Expression2Tokens(std::string s):contentStr_(s){}
	bool Analyzer();
	void PrintTokens() {
		for (std::deque<Token>::iterator it = tokenDeque_.begin();
			it != tokenDeque_.end(); it++) {
			std::cout << "type: " << (*it).GetType() << ", string: " << (*it).GetValStr() << std::endl;
		}
		std::cout << std::endl;
	}

};

class ParseExpression {
	Expression2Tokens	express2token_;
	ParseExpression& operator=(const ParseExpression&) {};
	ParseExpression(const ParseExpression&);
	double result_;
	double ParseTerm();
	double ParsePrimaryExpression();
public:
	ParseExpression(std::string s) :
		express2token_(s), result_(0.0){}
	bool StartParse();
	double GetResult() { return result_; }

};

  

#include "token.h"
#include <iostream>

bool Expression2Tokens::Analyzer() {
	bool bRet = false;
	size_t index = 0, valueBeg = 0, valueEnd = 0;
	Status status = INIT_STATUS;
	for (;index < contentStr_.size();index++)
	{
		if (isdigit(contentStr_[index])) {
			if (status != NUM_STATUS) {
				status = NUM_STATUS;
				valueBeg = index;
			}
			continue;
		}
		//对于 非数字进行判断
		if (NUM_STATUS == status ) {
			std::string s(contentStr_.substr(valueBeg, index - valueBeg));
			Token t(NUM_TOKEN,s);
			tokenDeque_.push_back(t);
			valueBeg = 0;
		}

		if (contentStr_[index] == \'+\') {
			Token t(ADD_TOKEN, "+");
			tokenDeque_.push_back(t);
			status = OPERATOR_STATUS;
			continue;
		}else if (contentStr_[index] == \'-\') {
			Token t(SUB_TOKEN, "-");
			tokenDeque_.push_back(t);
			status = OPERATOR_STATUS;
			continue;
		}else if (contentStr_[index] == \'*\') {
			Token t(MUL_TOKEN, "*");
			tokenDeque_.push_back(t);
			status = OPERATOR_STATUS;
			continue;
		}else if (contentStr_[index] == \'/\') {
			Token t(DIV_TOKEN,"/");
			tokenDeque_.push_back(t);
			status = OPERATOR_STATUS;
			continue;
		}else if (contentStr_[index] == \';\')
		{
			Token t(ENDFILE_TOKEN, ";");
			tokenDeque_.push_back(t);
			status = END_STATUS;
			bRet = true;
			return bRet;
		}
		
		else {
			std::cerr << "analyzer error (" << contentStr_[index] << ")" <<  std::endl;
			status = ERROR_STATUS;
			return false;
		}
	}

	return bRet;
}

double ParseExpression::ParsePrimaryExpression() {
	Token token;
	token = express2token_.tokenDeque_.front();
	if (token.GetType() == NUM_TOKEN) {
		//return  atof(token.GetValStr().c_str());
		express2token_.tokenDeque_.pop_front();
		return stod(token.GetValStr());
	}
	std::cerr << "syntax error." << std::endl;
	exit(1);
	return 0.0;
}




double ParseExpression::ParseTerm() {
	double dRet;
	double v;

	Token token;

	dRet = ParsePrimaryExpression();
	for (;;) {
		token = express2token_.tokenDeque_.front();
		if (token.GetType() != MUL_TOKEN
			&& token.GetType() != DIV_TOKEN) {
			break;
		}
		express2token_.tokenDeque_.pop_front();
		v = ParsePrimaryExpression();
		if (token.GetType() == MUL_TOKEN) {
			dRet *= v;
		}
		else if (token.GetType() == DIV_TOKEN) {
			dRet /= v;
		}
	}

	return dRet;
}


bool ParseExpression::StartParse() {
	bool bRet = false;
	if (!express2token_.Analyzer())
		return bRet;
	express2token_.PrintTokens();
	

	double v;
	Token token;

	result_ = ParseTerm();
	for (;;) {
		token = express2token_.tokenDeque_.front();
		if (token.GetType() != ADD_TOKEN &&
			token.GetType() != SUB_TOKEN) {
			break;
		}
		express2token_.tokenDeque_.pop_front();
		v = ParseTerm();
		if (token.GetType() == ADD_TOKEN) {
			result_ += v;
		}
		else if (token.GetType() == SUB_TOKEN) {
			result_ -= v;
		}
	}

	bRet = true;
	return bRet;

}

  测试代码如下:

// MyParse.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "token.h"
#include <iostream>

int main()
{
	
	Expression2Tokens e("1+2/3*45-67-89+999;");
	if (e.Analyzer()) {
		e.PrintTokens();
	}

	ParseExpression p("132+243/7*4455-6-89+34;");
	if(p.StartParse())
		std::cout << "result: " << p.GetResult() << std::endl;
    return 0;
}

  

type: 1, string: 1
type: 2, string: +
type: 1, string: 2
type: 5, string: /
type: 1, string: 3
type: 4, string: *
type: 1, string: 45
type: 3, string: -
type: 1, string: 67
type: 3, string: -
type: 1, string: 89
type: 2, string: +
type: 1, string: 999
type: 8, string: ;

type: 1, string: 132
type: 2, string: +
type: 1, string: 243
type: 5, string: /
type: 1, string: 7
type: 4, string: *
type: 1, string: 4455
type: 3, string: -
type: 1, string: 6
type: 3, string: -
type: 1, string: 89
type: 2, string: +
type: 1, string: 34
type: 8, string: ;

result: 154723
请按任意键继续. . .

 

以上是关于状态机学习解析四则运算式 语法分析的主要内容,如果未能解决你的问题,请参考以下文章

作为有限状态机的通用语言解析器

从零写一个编译器:语法分析之构造有限状态自动机

JAVA中如何高效的实现SQL的like语法?

片段(Java) | 机试题+算法思路+考点+代码解析 2023

编译原理 - 语法分析: 自上而下的语法分析

逆波兰式实现四则运算(加减乘除)