20170225C++项目班03_parser实现/调试/
2017-02-25 23:02
295 查看
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:自动类型推导。
相关文章推荐
- 20170225C++项目班03_parser实现/调试/
- 20170225C++项目班03_parser实现/调试/
- 20170225C++项目班03_parser实现/调试/
- 20170225C++项目班03_parser实现/调试/
- 20170225C++项目班03_parser实现/调试/
- 20170225C++项目班03_parser实现/调试/
- 20170225C++项目班03_parser实现/调试/
- 20170225C++项目班03_parser实现/调试/
- 项目实战笔记 | C++ 事件驱动模型实现银行排队服务2 代码实现
- 如何在Dev-C++上实现调试功能
- DEV调试C++项目实例
- zhuan 在Linux中使用VS Code编译调试C++项目
- 学C++第一个项目实现
- 20170218C++项目班02_01Node实现
- 20170219C++项目班02_02递归下降算法/解析器/Scanner实现
- 第八周C++上机报告(项目一实现复数类中的运算符重载)
- C++第8周项目1 - 实现复数类中的运算符重载
- 【学习C++】C++项目的头文件和实现文件分别写什么
- VS2010 调试C++项目 fatal error LNK1123 错误解决办法 ,为什么会这样