20170225C++项目班03_parser实现/调试/

parser实现:

1:parser解析器,解析类和我们的扫面类是依赖的关系。解析类使用扫面类得到的信息来解析具体是什么节点(Node)。
2:扫面类每次都要使用到扫面类,没有扫面类就不行,他们最适合的就是依赖关系。
3:解析器里面要用到scanner,参数里面如果使用scanner的类对象,那么就需要在parser.h里面包含头文件,如果使用引用或者指针的话,可以只做前置申明就可以了,构造函数里面必须在初始化列表做scanner的赋值。从外部传递进来。
4:对外开放接口:parse();,来进行解析,还需要calc的接口,解析完成后就计算。下面为库文件的内容:
#ifndef PARSER_H_
#define PARSER_H_

namespace PoEdu {
	class Scanner;
	class Node;
	class SymbolHelper;
	class Parser
	{
	public:
		Parser(Scanner &scanner);
		~Parser();
		void Parse();
		double Calculate() const;
	private:
		Node* Expr();
		Node* Term();
		Node* Factor();
		Scanner &scanner_;
		SymbolHelper &symbol_hepler_;
		Node *tree_;
	};
}
#endif//!PARSER_H_

Parser调试:

1:每次等待用户输入的时候,可以输出一个>或者\等,这样看起来会比较好(逼格高)。
2:在还没把程序写好的情况下,尽量少考虑bug的问题,先把基本功能实现了,在很好的情况下可以正常运行之后在考虑修改bug的问题。
3:调试的技巧:在可能出bug的里面单步调试,在不符合预期执行效果的地方找逻辑错误(bug)。
4:当执行1-2+7的时候,我们会发现他会先执行2+7,然后1-9。因为我们使用的递归下降法目前还是右递归,默认从右边开始执行,需要解决。

解决右递归:

1:之所以会产生右结合是因为我们的表达式 = 项+表达式的时候,会默认地将后面的平级的运算符加上了括号,使他的优先级变高了。
2:解决方式:可以使用不同的算法实现左递归。我们使用平行复合Node来解决,将同一优先级的保存为一个复合Node,这个Node使用vector老保存,这种Node的Calc方法就是将里面保存的数据按从前往后执行,顺序执行求结果,这样将右递归变成了平行的复合Node来计算,这样解决起来也是比较简单的,而且会废弃原来的+-*/Node,直接使用复合Node。这样相当于是一个平行树。
    实现方式:使用两个vector分别保存平行树的NumberNode和对应的符号。Calc方法就取出里面的数据和符号进行运算,得出结果,后面的就和之前的思路一样。调用解析器的Calculate方法计算总结果。注意:即使只有一个+或者同级的运算符,也会使用平行复合Node,只不过里面只有一个数据和一个符号。
    还是使用复合类作为数据管理类,派生两个类分别用来实现+-优先级和*/优先级的处理。
#include "Parser.h"
#include <iostream>
#include "Node.h"
#include "Scanner.h"
#include "SymbolHelper.h"

namespace PoEdu {
	Parser::Parser(Scanner& scanner, SymbolHelper &symbol_helper):scanner_(scanner),symbol_hepler_(symbol_helper)
	{	
	}
	Parser::~Parser()
	{
	}
	void Parser::Parse()
	{
		tree_ = Expr();
	}
	double Parser::Calculate() const
	{
		return  tree_->Calc();
	}
	Node* Parser::Expr()
	{
		Node *node = Term();	//项 + 表达式
		EToken token = scanner_.Token();
		if(token == TOKEN_PLUS || token == TOKEN_MINUS)
		{
			MultipleNode *multipleNode = new SumNode(node);
			do
			{
				scanner_.Accept();
				Node *nextNode = Term();
				multipleNode->AppendChild(nextNode, token == TOKEN_PLUS);
				token = scanner_.Token();
			}
			while (token == TOKEN_PLUS || token == TOKEN_MINUS);
			node = multipleNode;
		}
		else if(token == TOKEN_ASSIGN)
		{
			scanner_.Accept();
			Node *nextNode = Expr();
			node = new AssignNode(node, nextNode);
		}
	/*	if(token == TOKEN_PLUS)
		{
			scanner_.Accept();
			Node *rightNode = Expr();
			node = new AddNode(node, rightNode);

		}
		else if (token == TOKEN_MINUS)
		{
			scanner_.Accept();
			Node *rightNode = Expr();
			node = new SubNode(node, rightNode);
		}*/
		return node;
	}

	Node* Parser::Term()
	{
		Node *node = Factor();
		EToken token = scanner_.Token();
		if (token == TOKEN_MULTIPLY || token == TOKEN_DIVIDE)
		{
			MultipleNode *multipleNode = new ProductNode(node);
			do
			{
				scanner_.Accept();
				Node *nextNode = Factor();
				multipleNode->AppendChild(nextNode, token == TOKEN_MULTIPLY);
				token = scanner_.Token();
			} while (token == TOKEN_MULTIPLY || token == TOKEN_DIVIDE);
			node = multipleNode;
		}
		/*if (token == TOKEN_MULTIPLY)
		{
			scanner_.Accept();
			Node *rightNode = Term();
			node = new MultipNode(node, rightNode);
		}
		else if (token == TOKEN_DIVIDE)
		{
			scanner_.Accept();
			Node *rightNode = Term();
			node = new DivisionNode(node, rightNode);
		}*/
		return node;
	}

	Node* Parser::Factor()
	{
		//((1 + 2) * 3 + 4) / 5

		Node *node = nullptr;
		EToken token = scanner_.Token();
		if(token == TOKEN_LPARENTEESES)
		{
			scanner_.Accept();
			node = Expr();
			if(scanner_.Token() == TOKEN_RPARENTEESES)
				scanner_.Accept();
			else
				std::cout << "缺少右括弧" << std::endl;	//异常
		}
		else if(token == TOKEN_NUMBER)
		{
			node = new NumberNode(scanner_.NumBer());
			scanner_.Accept();
		}
		else if(token == TOKEN_IDENTIFIER)
		{
			std::string symbol = scanner_.Symbol();
			unsigned int id = symbol_hepler_.FindSymbol(symbol);
			if(id == 0xFFFFFFFF)
			{
				id = symbol_hepler_.AddSymbol(symbol);
			}
			node = new VariableNode(id, symbol_hepler_.GetStorage());
			scanner_.Accept();
		}
		else if(token == TOKEN_MINUS)
		{
			scanner_.Accept();
			node = new MinusNode(Factor());
		}
		return node;
	}
}

讲解:

一个函数=default代表这个函数就和默认函数一样。
auto:自动类型推导。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值