📄 a_cal.cpp
字号:
/* Copyright is licensed under GNU LGPL. by I.J.Wang 2005 Command line calculator Read arithmetic expression from standard input and write along with the evaluated result, to standard output. Build: 1. decide the result type RTYPE as double, long..,etc. 2. make a_cal Note: A small calculator program deserves reference: e-0.02718.tar.gz, http://freshmeat.net/projects/e-expr/*/#include "../src/wy_uty.h"#include "../src/wy__rdbuf.h"#include <unistd.h>#include <limits>#include <cmath>//#define PARSE_DUMP#ifndef RTYPE#define RTYPE double#endif/* The followings are functions evaluating arithmetic expression of s The main function is eva_expr(WyCSeg, ResType&) [Grammar] T-> T*F | T/F ; Search for the last * or / (ignore parenthesized text) F E-> E+T | E-T ; Search for the last + or - (ignore parenthesized text) T | -T | +T F-> D | (E) sin(E) cos(E) tan(E) asin(E) acos(E) atan(E) log(E) log10(E) exp(E) exp10(E) sqrt(E) D-> digit ; no scientific notation (_strnum dependant) D digit digit-> [0-9] [Ret] Ok Result is stored in res Wym_EBADMSG Wym_ENOENT*/typedef RTYPE ResType;static WyRet eva_E(WyCSeg s, ResType& res);inline static bool is_digit(char ch) { return (ch>='0')&&(ch<='9');};inline static bool is_blank(char ch) { return (ch==' ')||(ch=='\t');};// [Syn] Scan backward from buf_s for the opening parenthesis symbol och// in string indicated by [buf_a,buf_s]. *buf_s must be the closing// parenthesis symbol.//// [Ret] pointer to the opening parenthesis symbol (identical to och)// or zero if end of search.//static const char* bscan_closing(const char* buf_a,const char* buf_s,char och){ if((buf_a==NULL)||(buf_s==NULL)) { WY_THROW( WyRet(Wym_EFAULT) ); } if(buf_a>=buf_s) { if(buf_a==buf_s) { return NULL; } WY_THROW( WyRet(Wym_EINVAL) ); } const char cch(*buf_s); int diff_cnt(1); const char* sptr(buf_s-1); for(;; --sptr) { if(*sptr==och) { --diff_cnt; if(diff_cnt==0) { return(sptr); } } else if(*sptr==cch) { ++diff_cnt; } else { // Ignore other character } if(sptr==buf_a) { return (const char*)0; } }};static WyRet eva_F(WyCSeg s, ResType& res){#ifdef PARSE_DUMP Wy::cout << "F:" << s << '\n';#endif WyRet r; if(s.size()<=0) { WY_RETURN( Wym_ENOENT ); } if(is_digit(s.front())) { const char* endptr; if((r=Wy::_strnum(res,&endptr,s,10))!=Ok) { WY_RETURN(r); } return(Ok); } if(s.front()=='(') { if(s.back()!=')') { WY_RETURN( Wym_EBADMSG ); } return eva_E( s.cseg(1,s.size()-2),res ); } if(s.back()!=')') { WY_RETURN( Wym_EBADMSG ); } if(std::numeric_limits<ResType>::is_integer) { } else { ResType tmp; if(s.cseg(0,4)=="sin(") { if((r=eva_E(s.cseg(4,s.size()-2),tmp))!=Ok) { WY_RETURN(r); } res=std::sin(tmp); return(Ok); } if(s.cseg(0,4)=="cos(") { if((r=eva_E(s.cseg(4,s.size()-2),tmp))!=Ok) { WY_RETURN(r); } res=std::cos(tmp); return(Ok); } if(s.cseg(0,4)=="tan(") { if((r=eva_E(s.cseg(4,s.size()-2),tmp))!=Ok) { WY_RETURN(r); } res=std::tan(tmp); return(Ok); } if(s.cseg(0,5)=="asin(") { if((r=eva_E(s.cseg(5,s.size()-2),tmp))!=Ok) { WY_RETURN(r); } res=std::asin(tmp); return(Ok); } if(s.cseg(0,5)=="acos(") { if((r=eva_E(s.cseg(5,s.size()-2),tmp))!=Ok) { WY_RETURN(r); } res=std::acos(tmp); return(Ok); } if(s.cseg(0,5)=="atan(") { if((r=eva_E(s.cseg(5,s.size()-2),tmp))!=Ok) { WY_RETURN(r); } res=std::atan(tmp); return(Ok); } if(s.cseg(0,4)=="log(") { if((r=eva_E(s.cseg(4,s.size()-2),tmp))!=Ok) { WY_RETURN(r); } res=std::log(tmp); return(Ok); } if(s.cseg(0,6)=="log10(") { if((r=eva_E(s.cseg(6,s.size()-2),tmp))!=Ok) { WY_RETURN(r); } res=std::log10(tmp); return(Ok); } if(s.cseg(0,4)=="exp(") { if((r=eva_E(s.cseg(4,s.size()-2),tmp))!=Ok) { WY_RETURN(r); } res=std::exp(tmp); return(Ok); } if(s.cseg(0,6)=="exp10(") { if((r=eva_E(s.cseg(6,s.size()-2),tmp))!=Ok) { WY_RETURN(r); } res=exp10(tmp); return(Ok); } if(s.cseg(0,5)=="sqrt(") { if((r=eva_E(s.cseg(5,s.size()-2),tmp))!=Ok) { WY_RETURN(r); } res=std::sqrt(tmp); return(Ok); } } WY_RETURN( Wym_EBADMSG );};static WyRet eva_T(WyCSeg s, ResType& res){#ifdef PARSE_DUMP Wy::cout << "T:" << s << '\n';#endif if(s.size()<=0) { WY_RETURN( Wym_ENOENT ); } const char* aptr(s.begin()); const char* zptr(s.end()); const char* sptr(zptr-1); for( ; ; --sptr) { if((*sptr=='*')||(*sptr=='/')) { // operator */ WyRet r; ResType res1,res2; r=eva_T(WyCSeg(aptr,sptr),res1); if(r!=Ok) { WY_RETURN(r); } r=eva_F(WyCSeg(sptr+1,zptr),res2); if(r!=Ok) { WY_RETURN(r); } if(*sptr=='*') { res=res1*res2; } else { res=res1/res2; } return(Ok); } if(*sptr==')') { sptr=bscan_closing(aptr,sptr,'('); if(sptr==0) { WY_RETURN( Wym_EBADMSG ); } } if(sptr==aptr) { return eva_F(WyCSeg(aptr,zptr),res); } } // UNREACHABLE};static WyRet eva_E(WyCSeg s, ResType& res){#ifdef PARSE_DUMP Wy::cout << "E:" << s << '\n';#endif if(s.size()<=0) { WY_RETURN( Wym_ENOENT ); } const char* aptr(s.begin()); const char* zptr(s.end()); const char* sptr(zptr-1); for( ; ; --sptr) { if((*sptr=='-')||(*sptr=='+')) { // operator +- WyRet r; if(sptr==aptr) { r=eva_T(WyCSeg(sptr+1,zptr),res); if(r!=Ok) { WY_RETURN(r); } if(*sptr=='-') { res=-res; } return(Ok); } else { ResType res1,res2; r=eva_E(WyCSeg(aptr,sptr),res1); if(r!=Ok) { WY_RETURN(r); } r=eva_T(WyCSeg(sptr+1,zptr),res2); if(r!=Ok) { WY_RETURN(r); } if(*sptr=='-') { res=res1-res2; } else { res=res1+res2; } return(Ok); } } if(*sptr==')') { sptr=bscan_closing(aptr,sptr,'('); if(sptr==0) { WY_RETURN( Wym_EBADMSG ); } } if(sptr==aptr) { return eva_T(WyCSeg(aptr,zptr),res); } } // UNREACHABLE};WyRet eva_expr(WyCSeg s, ResType& res){ // Copy s to str and remove blanks. Call eva_E(..) with this no blank copy // of expression. // WyStr str; for(const char* aptr=s.begin(); aptr!=s.end(); ++aptr) { if(is_blank(*aptr)==true) { continue; } const WyRet r( str.append(*aptr) ); if(r!=Ok) { WY_RETURN(r); } } return eva_E(str.cseg(),res);};int main(int argc, char* argv[])try { static const char* cmd_syntax= "Command line calculator\n" " Read arithmetic expression from standard input and write,\n" " along with the evaluated result, to standard output\n" "Usage: $./a_cal\n" "\n"; // Command-line options // { const char optstr[]="h"; int optch; while((optch=::getopt(argc,argv,optstr))!=-1) { switch(optch) { case 'h': Wy::cout << cmd_syntax; return(0); case ':': // missing parameter case '?': // unknown option Wy::cerr << "parameter error\n"; Wy::cerr << cmd_syntax; return(-1); default: Wy::cerr << "parameter fault\n"; return(-1); } } for( ; optind<argc; optind++) { Wy::cerr << "parameter error\n"; return(-1); } } WyRet r; Wy__RdBuf inbf(&Wy::cin); WyCSeg rseg; ResType res; for(;;) { if((r=inbf.getdata(rseg,1024,'\n'))!=Ok) { WY_THROW(r); } if(rseg.size()==0) { return(0); } // not show the trailing '\n' if(rseg.back()=='\n') { rseg._move_end(-1); } if(rseg.size()==0) { continue; // blank line } Wy::cout << rseg; if((r=eva_expr(rseg,res))!=Ok) { Wy::cout << " --- " << Wy::wrd(r) << '\n'; } else { Wy::cout << " = " << Wy::wrd(res) << '\n'; } } return(0);}catch(const WyRet& e) { if(e!=Ok) { Wy::cerr << Wy::wrd(e) << '\n'; } return e->c_repcode();}catch(...) { Wy::cerr << "main caught(...)\n"; return(-1);};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -