您的位置:首页 > 编程语言 > C语言/C++

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

2017-02-25 23:02 190 查看

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:自动类型推导。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息