计算器的github下载地址:https://github.com/ljian1992/calculator
概述
有了构建语法的类,存储符号的类,现在就可以对表达式进行扫描,解析了。扫描可以抽象出一个Scanner类来完成这一个功能,而解析可以抽象出一个Parser类来完成这一个功能。这两个类存在一定的关系,扫描与解析的互动是这样子的:扫描到一个标识符,然后解析它是什么标识符。由于该表达式计算器是要支持一些命令的,命令的解析和表达式的解析过程完全不一样,所有呢,又要设置一个CommandParser类,来解析命令。
Scanner类,Parser类,CommandParser类的设计
Scanner类
enum EToken { TOKEN_COMMAND, TOKEN_ERROR, TOKEN_END, TOKEN_NUMBER, TOKEN_IDENTIFIER, TOKEN_PLUS, TOKEN_MINUS, TOKEN_MUTIPLY, TOKEN_DIVIDE, TOKEN_LPARENTHESIS, TOKEN_RPARENTHESIS, TOKEN_ASSIGN, }; class Scanner { private: std::istream& in_; //标准输入流 bool isEmpty_; //是否为空 EToken token_; //记录扫描结果 double number_; //扫描到的数字 std::string symbol_; //扫描到标识符 int look_; //扫描到的字符 void ReadChar(); //从标准输入流中读取字符 public: explicit Scanner(std::istream& in); void Accept(); //扫描一个标识符or操作数or操作数 void AcceptCommand(); //扫描命令 void CleanIstream(); //清除标准输入流缓存 double Number() const; //获取扫描到的数字 bool IsEmpty()const; //判断是否为空 bool IsDone() const; //判断是否扫描完毕 bool IsCommand() const; //判断是否是命令 std::string GetSymbol() const; //获取扫描到的标识符 EToken Token() const; //获取扫描结果 };
Parser类
enum STATUS { STATUS_OK, STATUS_ERROR, STATUS_QUIT, }; class Parser { private: Scanner& scanner_; std::auto_ptr<Node> tree_; //表达式语法树 STATUS status_; //状态 Calc &calc_; //要处理的符号信息 public: Parser(Scanner& scanner, Calc& calc); /*与scanner类相关联*/ ~Parser(); STATUS Parse(); //解析一个表达式生成表达式树 std::auto_ptr<Node> Expr(); //解析表达式 std::auto_ptr<Node> Term(); //解析项 std::auto_ptr<Node> Factor(); //解析因子 double Calculate() const; //计算出表达式的值 };
CommandParser类
class CommandParser { private: enum Ecommand //由于该宏只会在CommandParser类内部用到,故定义在内部 { CMD_HELP, CMD_QUIT, CMD_VAR, CMD_FUN, CMD_LOAD, CMD_SAVE, CMD_ERROR, }; private: Scanner& scanner_; Calc &calc_; ECommand cmd_; //解析到的命令 std::string cmdName_; //命令名 void Help() const; //帮助命令 void ListVar() const; //打印出变量表 void ListFun() const; //打印出函数表 STATUS Load(const std::string& fileName);//从文件中加载内容到变量表和函数表中 STATUS Save(const std::string& fileName);//存储变量表和函数表到文件中 public: CommandParser(Scanner& scanner, Calc& calc_); /*与scanner类相关联*/ STATUS Execute(); //根据解析到的命令执行命令 };