計算器的github下載地址:https://github.com/ljian1992/calculator
有了構建語法的類,存儲符號的類,現在就可以對表達式進行掃描,解析了。掃描可以抽象出一個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(); //根據解析到的命令執行命令 };