一个小型的软件项目,代码大概1000行左右,包括了很多知识(继承、多态、前向声明、虚函数、动态内存、引用、指针等等),从头到尾写完花了些时间,但觉得很受用。 (1)计算器程序的目的是接受用户提供的算术表达式(例:1+2*3),求其值显示结果。 (2)每个算术表达式由解析器分析,将输入的算法表达式(一串字符)转换成一个算术树。 (3)算术树(一种数据结构):算术表达式可以转换为一个二叉树结构。 如:(a+b×(c-d))-e/f 二叉树结构为:
解析式寻找一个表达式,语法定义如下: 1. An exPRession is(一个表达式是) a. 一个后面有加号或减号的项,加号或减号后面是另一个表达式。例:表达式2-3,2是一个项(后面是减号),3是一个表达式。 b. 如果表达式不含有加号、减号,它等于项。 (例:上例中的3是一个表达式,它也是一个项)
2. A term is(一个项是) a. 被另一个项乘除的因子。 (例:表达式1+2*3,2*3是一个表达式,满足1b条件,2*3是一个项,满足2a条件,2是一个因子) b.项如果不包含乘除,它等于此因子。
3. A factor can be(一个因子是) a. 数字 b. 对应某变量的标识符 c. 后面带有一个因子的减号 d. 小括号中的整个表达式
配合实例理解解析器的语法定义: 1+x*(2-y)
计算器由以下几个对象组成: (1)扫描器,扫描用户输入的字符串。 (2)符号表,使计算器可以处理符号变量,如(x=1,变量x代表1) (3)存储器,让计算器具有记忆能力,可以保存用户自定义变量的值。 (4)函数表,让计算器事先具有一些函数(如sin、cos、log、exp) (5)结点,对应算术树的每个结点(使用继承实现)。关于结点的简化版本参看C++多态 (6)解析器,实现算数表达式的解析。
代码:只给出主函数、解析器代码,剩下的代码可以从github下载。 计算器Github 主函数 calculator.cpp
#include"SymbolTable.h"#include"FunctionTable.h"#include"Store.h"#include"Scanner.h"#include"Parser.h"const int maxBuf = 100;const int maxSymbols = 40;int main(){ char buf[maxBuf]; //状态位 Status status; //符号表 SymbolTable symTab(maxSymbols); //函数表 FunctionTable funTab(symTab, funArr); //存储器 Store store(maxSymbols, symTab); do { std::cout << "> "; std::cin.getline(buf, maxBuf); //扫描器 Scanner scanner(buf); //解析器 Parser parser(scanner, store, funTab, symTab); status = parser.Eval(); } while (status != stQuit); return 0;}解析器 Parser.h
#ifndef PARSER_H#define PARSER_Hclass Node;class Scanner;class SymbolTable;class Store;class FunctionTable;//枚举:状态enum Status{ stOK, stQuit, stError};//解析器类class Parser{public: Parser(Scanner & scanner, Store& store, FunctionTable& funTab, SymbolTable & symTab); ~Parser(); Status Eval();private: void Parse(); Node* Expr(); Node* Term(); Node* Factor(); void Execute(); Scanner & _scanner;//扫描器 SymbolTable & _symTab;//符号表 Node* _pTree;//算术树 Status _status;//状态位 Store& _store;//存储器 FunctionTable& _funTab;//函数表};#endifParser.cpp
#include "Parser.h"#include<iostream>#include"Store.h"#include"Node.h"#include"FunctionTable.h"#include"SymbolTable.h" #include"Scanner.h"#include"AddNode.h"#include "AssignNode.h"#include"SubNode.h"#include"MultNode.h"#include"DivideNode.h"#include"NumNode.h"#include"FunNode.h"#include"VarNode.h"#include"UMinusNode.h"Parser::~Parser(){ delete _pTree;} Parser::Parser(Scanner & scanner, Store& store, FunctionTable& funTab, SymbolTable & symTab) :_scanner(scanner), _pTree(0), _status(stOK), _funTab(funTab), _store(store), _symTab(symTab){ std::cout << "Parser Created" << std::endl;}//解析记号Status Parser::Eval(){ Parse(); if (_status == stOK) Execute(); else _status == stQuit; return _status; //for (EToken token = _scanner.Token(); // token != tEnd; // _scanner.Accept()) //{ // token = _scanner.Token(); // switch (token) // { // case tMult: // std::cout << "Times" << std::endl; // break; // case tPlus: // std::cout << "Plus" << std::endl; // break; // case tNumber: // std::cout << "Number: " << _scanner.Number() << std::endl; // break; // case tEnd: // std::cout << "End" << std::endl; // return stQuit; // case tError: // std::cout << "Error" << std::endl; // return stQuit; // default: // std::cout << "Error: bad token" << std::endl; // return stQuit; // } //} //return stOK;}void Parser::Execute(){ if (_pTree) { double result = _pTree->Calc(); std::cout << " " << result << std::endl; }}void Parser::Parse(){ _pTree = Expr();}//表达式Node* Parser::Expr(){ Node* pNode = Term(); EToken token = _scanner.Token(); //加 if (token == tPlus) { //识别下一个记号 _scanner.Accept(); Node* pRight = Expr(); pNode = new AddNode(pNode, pRight); } //减 else if (token==tMinus) { _scanner.Accept(); Node* pRight = Expr(); pNode = new SubNode(pNode, pRight); } //赋值 else if (token == tAssign) { _scanner.Accept(); Node* pRight = Expr(); //左值 if (pNode->IsLvalue()) { pNode = new AssignNode(pNode, pRight); } else { _status = stError; delete pNode; pNode = Expr(); } } return pNode;}//项Node* Parser::Term(){ Node* pNode = Factor(); //Term is Factor * Term if (_scanner.Token() == tMult) { _scanner.Accept(); Node* pRight = Term(); pNode = new MultNode(pNode, pRight); } //Term is Factor/Term else if (_scanner.Token()==tDivide) { _scanner.Accept(); Node* pRight = Term(); pNode = new DivideNode(pNode, pRight); } //Term is Factor return pNode;}//因子Node* Parser::Factor(){ Node* pNode; EToken token = _scanner.Token(); //左括号 if (token == tLParen) { _scanner.Accept();//accept '(' pNode = Expr(); if (_scanner.Token() != tRParen) _status = stError; _scanner.Accept();//accept ')' } //数字 else if (token == tNumber) { pNode = new NumNode(_scanner.Number()); _scanner.Accept(); } //符号变量 else if (token == tIdent) { char strSymbol[maxSymLen + 1]; int lenSym = maxSymLen; //复制symbol到strSymbol _scanner.GetSymbolName(strSymbol, lenSym); int id = _symTab.Find(strSymbol); _scanner.Accept(); //函数调用 如sin(x) if (_scanner.Token() == tLParen) { _scanner.Accept(); pNode = Expr(); if (_scanner.Token() == tRParen) _scanner.Accept(); else _status = stError; if (id != idNotFound && id < _funTab.Size()) { //函数结点 pNode = new FunNode(_funTab.GetFun(id), pNode); } else { std::cout << "Unknow function/""; std::cout << strSymbol << "/"/n"; } } else { if (id == idNotFound) id = _symTab.ForcAdd(strSymbol, lenSym); pNode = new VarNode(id, _store); } } //一元减 else if (token == tMinus) { _scanner.Accept(); pNode = new UMinusNode(Factor()); } else { _scanner.Accept(); _status = stError; pNode = 0; } return pNode;}
新闻热点
疑难解答