私はそうでした。
そして、その実装は、技術を身につけるにしたがって、どんどん賢くなっていきました。[要出典]
ここでは、その移り変わりを3種類ほど見てみましょう。
1.最初の試み
当時使っていた言語はHSPでした。
ここに載せるコードも当然HSPで書かれていましたが、今回はC++に移植してみました。
当時は「逆ポーランド記法」という言葉は知らず、
「カッコの中→累乗→乗除→加減」という順番で愚直に計算していたようです。
HSPの性質上再帰がうまくできず、工夫したようですが、C++は普通に再帰できるので普通に書いています。
エラーチェックが甘く、例えば「+++」と入力してもエラー扱いにならないようです。
一個だけ変数を処理できるようです。
#include
#include
#include
#include
#include
using namespace std;
//元ファイルのタイムスタンプ 2008/7/22
//HSP互換関数
int instr(string p1,int p2=0,string fstr="") {
int r=p1.find(fstr,p2);
if(rp1.length())return p1;
return p1.substr(p1.length()-p3);
} else {
if(p2>=p1.length())return string("");
if(p3-p2>p1.length())p3=p1.length()-p2;
return p1.substr(p2,p3);
}
}
int strlen(string p1) {
return p1.length();
}
string strf(string format,int p1) {
char buffer[1024];
sprintf(buffer,format.c_str(),p1);
return string(buffer);
}
string strf(string format,double p1) {
char buffer[1024];
sprintf(buffer,format.c_str(),p1);
return string(buffer);
}
int peek(string p1,int p2) {
if(p2=p1.length())return 0;
return p1[p2];
}
double todouble(string p1) {
return atof(p1.c_str());
}
double todouble(int p1) {
return (double)p1;
}
double todouble(double p1) {
return p1;
}
//プログラムの移植
string ketacut(string moto) {
string m="";
m=moto;
string aa="";
if(instr(m,0,".")==-1)return m;
while(true) {
aa=strmid(m,-1,1);
if(aa=="0"){m=strmid(m,0,strlen(m)-1);continue;}
if(aa==".")m=strmid(m,0,strlen(m)-1);
break;
}
return m;
}
int strcalc(double& kekka,string keisann,string hensuu,double value) {
int a,b,c,d,e;
string mozi="",var="",abc="",f="";
int error=0;
mozi=keisann;var=hensuu;
while(true) {
a=instr(mozi,0,hensuu);
if(a==-1 || hensuu=="")break;
mozi=strmid(mozi,0,a)+ketacut(strf("%1.15f",value))+
strmid(mozi,a+strlen(hensuu),strlen(mozi));
}
while(true) {
a=instr(mozi,0,"(");
if(a==-1)break;
b=instr(mozi,a+1,"(")+a+1;
c=instr(mozi,a+1,")")+a+1;
if(c==a){error=1;break;}
/* 訳注:このコメントは原本にもあり */
//if(b==a || cc)break;
b=d;
}
double abc;
if(strcalc(abc,strmid(mozi,b+1,c-b-1),"",0)==0){error=1;break;}
/* 訳注:原本ではabcをそのまま結合している */
mozi=strmid(mozi,0,b)+strf("%f",abc)+strmid(mozi,c+1,strlen(mozi));
/* 訳注:このコメントは原本にもあり */
//}
/* wait 1 */
}
if(error==1)return 0;
while(true) {
a=instr(mozi,0,"^");
if(a==-1)break;
for(c=a-1;c>-1;c+=-1) {
abc=strmid(mozi,c,1);
if((peek(abc,0)'9') && peek(abc,0)!='.'){c++;break;}
}
if(c==-1)c++;
for(d=a+2;d'9') && peek(abc,0)!='.')break;
}
/* 訳注:このコメントは原本にもあり */
//if(d==strlen(mozi))d--;
/* 訳注:原本では実際に^演算子を使用 */
f=ketacut(strf("%1.15f",pow(todouble(strmid(mozi,c,a-c)),todouble(strmid(mozi,a+1,d-a)))));
mozi=strmid(mozi,0,c)+f+strmid(mozi,d,strlen(mozi));
}
while(true) {
a=instr(mozi,0,"*");
b=instr(mozi,0,"/");
if(a==-1 && b==-1)break;
if((a-1;c+=-1) {
abc=strmid(mozi,c,1);
if((peek(abc,0)'9') && peek(abc,0)!='.'){c++;break;}
}
if(c==-1)c++;
for(d=a+2;d'9') && peek(abc,0)!='.')break;
}
/* 訳注:このコメントは原本にもあり */
//if(d==strlen(mozi))d--;
f=ketacut(strf("%1.15f",todouble(strmid(mozi,c,a-c))*todouble(strmid(mozi,a+1,d-a))));
mozi=strmid(mozi,0,c)+f+strmid(mozi,d,strlen(mozi));
/* 訳注:このコメントは原本にもあり */
//}
} else {
for(c=b-1;c>-1;c+=-1) {
abc=strmid(mozi,c,1);
if((peek(abc,0)'9') && peek(abc,0)!='.'){c++;break;}
}
if(c==-1)c++;
for(d=b+2;d'9') && peek(abc,0)!='.')break;
}
/* 訳注:このコメントは原本にもあり */
//if(d==strlen(mozi))d--;
if(todouble(strmid(mozi,b+1,d-b))!=0) {
f=ketacut(strf("%1.15f",todouble(strmid(mozi,c,b-c))/todouble(strmid(mozi,b+1,d-b))));
} else {error=1;break;}
mozi=strmid(mozi,0,c)+f+strmid(mozi,d,strlen(mozi));
}
}
if(error==1)return 0;
while(true) {
a=instr(mozi,0,"+");
b=instr(mozi,0,"-");
if(a==-1 && b-1;c+=-1) {
abc=strmid(mozi,c,1);
if((peek(abc,0)'9') && peek(abc,0)!='.'){c++;break;}
}
if(c==-1)c++;
for(d=a+2;d'9') && peek(abc,0)!='.')break;
}
/* 訳注:このコメントは原本にもあり */
//if(d==strlen(mozi))d--;
f=ketacut(strf("%1.15f",todouble(strmid(mozi,c,a-c))+todouble(strmid(mozi,a+1,d-a))));
mozi=strmid(mozi,0,c)+f+strmid(mozi,d,strlen(mozi));
/* 訳注:このコメントは原本にもあり */
//}
} else {
for(c=b-1;c>-1;c+=-1) {
abc=strmid(mozi,c,1);
if((peek(abc,0)'9') && peek(abc,0)!='.'){c++;break;}
}
if(c==-1)c++;
for(d=b+2;d'9') && peek(abc,0)!='.')break;
}
/* 訳注:このコメントは原本にもあり */
//if(d==strlen(mozi))d--;
f=ketacut(strf("%1.15f",todouble(strmid(mozi,c,b-c))-todouble(strmid(mozi,b+1,d-b))));
mozi=strmid(mozi,0,c)+f+strmid(mozi,d,strlen(mozi));
}
}
kekka=todouble(mozi);
return 1;
}
//テストコード(書き下ろし)
int main(void) {
string query;
double result;
int stat;
while(getline(cin,query)) {
stat=strcalc(result,query,"",0);
if(stat)printf("%f\n",result); else puts("error");
}
return 0;
}
C言語を導入し、複雑な処理なのでライブラリ化しようと思ったようです。
複数の変数や関数を扱うため、巨大なライブラリになってしまいました。
当時のコードはC言語でしたが、ここではC++に移植しました。
逆ポーランド記法が導入されましたが、まだカッコの処理は再帰でやっているようです。
#include
#include
#include
#include
#include
using namespace std;
//元ファイルのタイムスタンプ 2010/11/28
//#define DEBUG
enum {/*type*/
TYPE_NUMBER,
TYPE_ENZANSI,
TYPE_HENSUU,
TYPE_FUNCTION
};
enum {/*enzansi*/
ENZ_PLUS,
ENZ_MINUS,
ENZ_MUL,
ENZ_DIV,
ENZ_POW,
ENZ_INV
};
typedef struct {
int type;
double suuzi;
int enzansi;
int hikisuunum;
}VALUE;
typedef struct _values {
VALUE value;
struct _values* next;
} VALUECHAIN;
typedef struct _vcadmin {
VALUECHAIN* first;
VALUECHAIN* last;
} VCADMIN;
enum {/*status*/
STAT_NUMBER,
STAT_ENZANSI,
STAT_HENSUU,
STAT_FUNCTION,
STAT_KAKKO
};
enum {/*エラーコード*/
ERROR_INVALIDNUM=1,
ERROR_NULLPOINTER,
ERROR_INVALIDNUMBER,
ERROR_INVALIDSIKI,
ERROR_KAKKOERROR,
ERROR_NOSIKIBETUSI,
ERROR_DIV0,
ERROR_FUNCTIONERROR,
ERROR_NOSTACK,
ERROR_OVERSTACK,
ERROR_UNDEFINEDTYPE,
ERROR_UNDEFINEDENZANSI,
ERROR_UNDEFINEDHENSUU,
ERROR_UNDEFINEDFUNCTION
};
typedef struct _numchain {
int num;
struct _numchain* next;
} NUMCHAIN;
inline void* malloc2(unsigned int size) {
//return HeapAlloc(GetProcessHeap(),0,size);
return malloc(size);
}
//inline int free2(void* ptr) {
inline void free2(void* ptr) {
//return HeapFree(GetProcessHeap(),0,ptr);
return free(ptr);
}
inline int str2double(double* result,char* str,int length) {
int error=0;
int i;
double _result=0;
double keta=0.1;
int status=1;
for(i=0;i='0' && str[i]next;
free2(cur);
cur=next;
}
}
int henkan(VCADMIN* result,char* input,int length,
char** hensuuname,int hensuunum,
char** kansuuname,int kansuunum) {
VALUECHAIN* stacklast=NULL;
VALUECHAIN* now;
int i;
int first=0;
int error=0;
int status=-1;
int curenzansi;
int minus=0;
if(length==0) {
return ERROR_INVALIDSIKI;
}
if(input[0]=='-') {
minus=1;
i=1;
} else if(input[0]=='+')i=1; else i=0;
for(;i='0' && input[i]value.type=TYPE_NUMBER;
now->next=NULL;
if(str2double(&(now->value.suuzi),&input[first],i-first)) {
freestack(stacklast);
return ERROR_INVALIDNUMBER;
}
if(result->first==NULL) {
result->first=now;
} else {
result->last->next=now;
}
result->last=now;
if(minus) {
now=(VALUECHAIN*)malloc2(sizeof(VALUECHAIN));
now->value.type=TYPE_ENZANSI;
now->next=NULL;
now->value.enzansi=ENZ_INV;
if(result->first==NULL) {
result->first=now;
} else {
result->last->next=now;
}
result->last=now;
minus=0;
}
}
if(input[i]=='+' || input[i]=='-' ||
input[i]=='*' || input[i]=='/' ||
input[i]=='^') {/*演算子*/
if(status==-1 || status==TYPE_ENZANSI) {
freestack(stacklast);
return ERROR_INVALIDSIKI;
}
curenzansi=code2enz(input[i]);
if(stacklast!=NULL) {
while(stacklast!=NULL &&
tuyosa(stacklast->value.enzansi)
>=tuyosa(curenzansi)) {
/*演算子を式に追加*/
if(result->first==NULL) {
result->first=stacklast;
} else {
result->last->next=stacklast;
}
result->last=stacklast;
stacklast=stacklast->next;
result->last->next=NULL;
}
}
/*演算子をスタックに追加*/
now=(VALUECHAIN*)malloc2(sizeof(VALUECHAIN));
now->value.type=TYPE_ENZANSI;
now->value.enzansi=curenzansi;
now->next=stacklast;
stacklast=now;
/*状態を変更*/
status=STAT_ENZANSI;
} else {
if(status!=-1 && status!=STAT_ENZANSI) {
freestack(stacklast);
return ERROR_INVALIDSIKI;
}
if(input[i]=='(') {/*括弧*/
int kakko;
int rs;
kakko=1;
first=i+1;
for(i++;i0) {
freestack(stacklast);
return ERROR_KAKKOERROR;
}
rs=henkan(result,&input[first],i-first,
hensuuname,hensuunum,kansuuname,kansuunum);
if(rs) {
freestack(stacklast);
return rs;
}
if(minus) {
now=(VALUECHAIN*)malloc2(sizeof(VALUECHAIN));
now->value.type=TYPE_ENZANSI;
now->next=NULL;
now->value.enzansi=ENZ_INV;
if(result->first==NULL) {
result->first=now;
} else {
result->last->next=now;
}
result->last=now;
minus=0;
}
/*状態を変更*/
status=STAT_KAKKO;
} else if(input[i]==')') {/*エラー*/
freestack(stacklast);
return ERROR_KAKKOERROR;
} else {/*変数・関数*/
int ishensuu;
int j;
int dore;
ishensuu=0;
dore=-1;
for(j=0;jlength)continue;
if(i+strlen(hensuuname[j])>length)continue;
/*if(CompareString(LOCALE_USER_DEFAULT,
0,hensuuname[j],lstrlen(hensuuname[j]),
&input[i],lstrlen(hensuuname[j]))
==CSTR_EQUAL) {*/
if(strncmp(hensuuname[j],&input[i],strlen(hensuuname[j]))==0) {
char nxt;
//if(i+lstrlen(hensuuname[j])value.type=TYPE_HENSUU;
now->next=NULL;
now->value.enzansi=dore;
if(result->first==NULL) {
result->first=now;
} else {
result->last->next=now;
}
result->last=now;
if(minus) {
now=(VALUECHAIN*)malloc2(sizeof(VALUECHAIN));
now->value.type=TYPE_ENZANSI;
now->next=NULL;
now->value.enzansi=ENZ_INV;
if(result->first==NULL) {
result->first=now;
} else {
result->last->next=now;
}
result->last=now;
minus=0;
}
/*iを増やす*/
//i+=lstrlen(hensuuname[j])-1;
i+=strlen(hensuuname[j])-1;
/*状態を変更*/
status=STAT_HENSUU;
} else {
for(j=0;j=length)continue;
if(i+strlen(kansuuname[j])>=length)continue;
/*if(CompareString(LOCALE_USER_DEFAULT,
0,kansuuname[j],lstrlen(kansuuname[j]),
&input[i],lstrlen(kansuuname[j]))
==CSTR_EQUAL) {*/
if(strncmp(kansuuname[j],&input[i],strlen(kansuuname[j]))==0) {
char nxt;
//nxt=input[i+lstrlen(kansuuname[j])];
nxt=input[i+strlen(kansuuname[j])];
if(nxt=='(') {
dore=j;
break;
}
}
}
if(dorenum=first;
kamma->next=NULL;
kammanum=0;
for(i=first+1;inum=i;
nowkamma->next=kamma;
kamma=nowkamma;
kammanum++;
}
if(kakko0) {
freestack(stacklast);
return ERROR_KAKKOERROR;
}
nextkamma=(NUMCHAIN*)malloc2(sizeof(NUMCHAIN));
nextkamma->num=i;
nextkamma->next=kamma;
kamma=nextkamma;
hikisuunum=0;
while(kamma!=NULL && kamma->next!=NULL) {
if(kamma->num-kamma->next->num>1) {
rs=henkan(result,
&input[kamma->next->num+1],
kamma->num-kamma->next->num-1,
hensuuname,hensuunum,
kansuuname,kansuunum);
if(rs) {
NUMCHAIN* cur;
NUMCHAIN* next;
cur=kamma;
while(cur!=NULL) {
next=cur->next;
free2(cur);
cur=next;
}
freestack(stacklast);
return rs;
}
hikisuunum++;
} else {
if(kammanum>0) {
NUMCHAIN* cur;
NUMCHAIN* next;
cur=kamma;
while(cur!=NULL) {
next=cur->next;
free2(cur);
cur=next;
}
freestack(stacklast);
return ERROR_INVALIDSIKI;
}
}
nextkamma=kamma->next;
free2(kamma);
kamma=nextkamma;
}
if(kamma!=NULL)free2(kamma);
/*関数を式に追加*/
now=(VALUECHAIN*)malloc2(sizeof(VALUECHAIN));
now->value.type=TYPE_FUNCTION;
now->next=NULL;
now->value.enzansi=dore;
now->value.hikisuunum=hikisuunum;
if(result->first==NULL) {
result->first=now;
} else {
result->last->next=now;
}
result->last=now;
if(minus) {
now=(VALUECHAIN*)malloc2(sizeof(VALUECHAIN));
now->value.type=TYPE_ENZANSI;
now->next=NULL;
now->value.enzansi=ENZ_INV;
if(result->first==NULL) {
result->first=now;
} else {
result->last->next=now;
}
result->last=now;
minus=0;
}
/*状態の変更*/
status=STAT_FUNCTION;
}
}
}
}
}
}
if(status==STAT_ENZANSI) {
freestack(stacklast);
return ERROR_INVALIDSIKI;
}
/*数字を式に追加*/
if(status==STAT_NUMBER) {
now=(VALUECHAIN*)malloc2(sizeof(VALUECHAIN));
now->value.type=TYPE_NUMBER;
now->next=NULL;
if(str2double(&(now->value.suuzi),&input[first],i-first)) {
freestack(stacklast);
return ERROR_INVALIDNUMBER;
}
if(result->first==NULL) {
result->first=now;
} else {
result->last->next=now;
}
result->last=now;
}
if(minus) {
now=(VALUECHAIN*)malloc2(sizeof(VALUECHAIN));
now->value.type=TYPE_ENZANSI;
now->next=NULL;
now->value.enzansi=ENZ_INV;
if(result->first==NULL) {
result->first=now;
} else {
result->last->next=now;
}
result->last=now;
minus=0;
}
/*演算子を式に追加*/
while(stacklast!=NULL) {
if(result->first==NULL) {
result->first=stacklast;
} else {
result->last->next=stacklast;
}
result->last=stacklast;
stacklast=stacklast->next;
result->last->next=NULL;
}
freestack(stacklast);
return 0;
}
int strcalc(double* result,char* input,
char** hensuuname,double* hensuuvalue,int hensuunum,
char** kansuuname,
int(**kansuu)(double* result,double* input,int inputnum),
int kansuunum) {
VCADMIN siki;
VALUECHAIN* stacklast=NULL;
VALUECHAIN* stacktemp;
VALUECHAIN* stackprev;
VALUECHAIN* now;
int henkanresult;
siki.first=NULL;
siki.last=NULL;
/*個数不正でないか、1個以上あるのにNULLでないか*/
if(hensuunum0) {
if(hensuuname==NULL || hensuuvalue==NULL)
return ERROR_NULLPOINTER;
}
if(kansuunum>0) {
if(kansuuname==NULL || kansuu==NULL)
return ERROR_NULLPOINTER;
}
//henkanresult=henkan(&siki,input,lstrlen(input),
// hensuuname,hensuunum,kansuuname,kansuunum);
henkanresult=henkan(&siki,input,strlen(input),
hensuuname,hensuunum,kansuuname,kansuunum);
if(henkanresult!=0) {
VALUECHAIN* cur;
VALUECHAIN* next;
/*メモリ開放*/
cur=siki.first;
while(cur!=NULL) {
next=cur->next;
free2(cur);
cur=next;
}
return henkanresult;
}
#ifdef DEBUG
/*デバッグ*/
now=siki.first;
while(now!=NULL) {
switch(now->value.type) {
case TYPE_NUMBER:
printf("%f\n",now->value.suuzi);
break;
case TYPE_ENZANSI:
switch(now->value.enzansi) {
case ENZ_PLUS:printf("+\n");break;
case ENZ_MINUS:printf("-\n");break;
case ENZ_MUL:printf("*\n");break;
case ENZ_DIV:printf("/\n");break;
case ENZ_POW:printf("^\n");break;
case ENZ_INV:printf("符号反転\n");break;
default:printf("未定義の演算子\n");break;
}
break;
case TYPE_HENSUU:
if(now->value.enzansi>=0 &&
now->value.enzansivalue.enzansi]);
} else {
printf("未定義の変数\n");
}
break;
case TYPE_FUNCTION:
if(now->value.enzansi>=0 &&
now->value.enzansivalue.enzansi],
now->value.hikisuunum);
} else {
printf("未定義の関数\n");
}
break;
default:
printf("未定義のタイプ\n");
break;
}
now=now->next;
}
#endif
/*計算*/
now=siki.first;
while(now!=NULL) {
switch(now->value.type) {
case TYPE_NUMBER:
stacktemp=(VALUECHAIN*)malloc2(sizeof(VALUECHAIN));
stacktemp->value.type=TYPE_NUMBER;
stacktemp->value.suuzi=now->value.suuzi;
stacktemp->next=stacklast;
stacklast=stacktemp;
break;
case TYPE_ENZANSI:
if(stacklast==NULL) {
freestack(siki.first);
return ERROR_NOSTACK;
}
stackprev=stacklast->next;
if(now->value.enzansi!=ENZ_INV && stackprev==NULL) {
freestack(siki.first);
freestack(stacklast);
return ERROR_NOSTACK;
}
switch(now->value.enzansi) {
case ENZ_PLUS:
stackprev->value.suuzi+=stacklast->value.suuzi;
break;
case ENZ_MINUS:
stackprev->value.suuzi-=stacklast->value.suuzi;
break;
case ENZ_MUL:
stackprev->value.suuzi*=stacklast->value.suuzi;
break;
case ENZ_DIV:
if(stacklast->value.suuzi==0) {
freestack(siki.first);
freestack(stacklast);
return ERROR_DIV0;
}
stackprev->value.suuzi/=stacklast->value.suuzi;
break;
case ENZ_POW:
//stackprev->value.suuzi*=stacklast->value.suuzi;
stackprev->value.suuzi=pow(stackprev->value.suuzi,stacklast->value.suuzi);
break;
case ENZ_INV:
stacklast->value.suuzi=-(stacklast->value.suuzi);
break;
default:
freestack(siki.first);
freestack(stacklast);
return ERROR_UNDEFINEDENZANSI;
break;
}
if(now->value.enzansi!=ENZ_INV) {
free2(stacklast);
stacklast=stackprev;
}
break;
case TYPE_HENSUU:
if(now->value.enzansi>=0 &&
now->value.enzansivalue.type=TYPE_NUMBER;
stacktemp->value.suuzi=hensuuvalue[now->value.enzansi];
stacktemp->next=stacklast;
stacklast=stacktemp;
} else {
freestack(siki.first);
freestack(stacklast);
return ERROR_UNDEFINEDHENSUU;
}
break;
case TYPE_FUNCTION:
if(now->value.enzansi>=0 &&
now->value.enzansivalue.hikisuunum*sizeof(double));
for(i=0;ivalue.hikisuunum;i++) {
if(stacklast==NULL) {
freestack(siki.first);
return ERROR_NOSTACK;
}
hikisuu[i]=stacklast->value.suuzi;
stackprev=stacklast->next;
free2(stacklast);
stacklast=stackprev;
}
henkanresult=kansuu[now->value.enzansi](&modoriti,
hikisuu,now->value.hikisuunum);
if(!henkanresult) {
freestack(siki.first);
freestack(stacklast);
return ERROR_FUNCTIONERROR;
}
stacktemp=(VALUECHAIN*)malloc2(sizeof(VALUECHAIN));
stacktemp->value.type=TYPE_NUMBER;
stacktemp->value.suuzi=modoriti;
stacktemp->next=stacklast;
stacklast=stacktemp;
} else {
freestack(siki.first);
freestack(stacklast);
return ERROR_UNDEFINEDFUNCTION;
}
break;
default:
freestack(siki.first);
freestack(stacklast);
return ERROR_UNDEFINEDTYPE;
break;
}
now=now->next;
}
if(stacklast==NULL) {
freestack(siki.first);
return ERROR_NOSTACK;
}
if(stacklast->next!=NULL) {
freestack(siki.first);
freestack(stacklast);
return ERROR_OVERSTACK;
}
*result=stacklast->value.suuzi;
/*開放*/
freestack(siki.first);
freestack(stacklast);
return 0;
}
//テストコード(書き下ろし)
int main(void) {
string query;
double result;
int stat;
while(getline(cin,query)) {
stat=strcalc(&result,(char*)query.c_str(),NULL,NULL,0,NULL,NULL,0);
if(stat==0)printf("%f\n",result); else puts("error");
}
return 0;
}
競技プログラミング、そしてAIZU ONLINE JUDGE。
文字列の計算を要求する問題が数多くあり、それを逆ポーランド記法のコードで解いていきます。
カッコも「普通」に処理し、「近代的」(?)になりました。
しかし、1年後位にみると、やっぱり「うわwww愚直すぎww」と思えるようになるのでしょうか?
それは神のみぞ知ることです。
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
//作成日 2012/5/27
enum operator_type {
OPERATOR_NUMBER,
OPERATOR_ADD,
OPERATOR_SUB,
OPERATOR_MUL,
OPERATOR_MINUS,
OPERATOR_DIV,
OPERATOR_POW,
OPERATOR_KAKKO_START,
OPERATOR_KAKKO_END
};
struct element_t {
double value;
operator_type opType;
};
int getYusendo(operator_type op,bool isLeft) {
int yusendo=0;
bool isLeftFirst=true;
switch(op) {
case OPERATOR_KAKKO_END:
yusendo=0;
isLeftFirst=false;
break;
case OPERATOR_MINUS:
yusendo=1;
isLeftFirst=false;
case OPERATOR_POW:
yusendo=2;
isLeftFirst=false;
break;
case OPERATOR_MUL:
case OPERATOR_DIV:
yusendo=3;
isLeftFirst=true;
break;
case OPERATOR_ADD:
case OPERATOR_SUB:
yusendo=4;
isLeftFirst=true;
break;
case OPERATOR_KAKKO_START:
yusendo=5;
isLeftFirst=true;
break;
default:
return -1;
}
return yusendo*10+(isLeftFirst==isLeft?0:1);
}
operator_type getOperatorType(char c,bool expectValue) {
switch(c) {
case '+': return OPERATOR_ADD;
case '-': return expectValue?OPERATOR_MINUS:OPERATOR_SUB;
case '*': return OPERATOR_MUL;
case '/': return OPERATOR_DIV;
case '^': return OPERATOR_POW;
case '(': return OPERATOR_KAKKO_START;
case ')': return OPERATOR_KAKKO_END;
default : return OPERATOR_NUMBER;
}
}
bool strcalc(double& result,string expression) {
vector reversePorland;
stack operatorStack;
stack calcStack;
bool expectValue=true;
operator_type opType;
for(int i=0;i<expression.length();i++) {
opType=getOperatorType(expression[i],expectValue);
if(opType==OPERATOR_KAKKO_END) {
//かっこの終わり
while(!operatorStack.empty() &&
operatorStack.top()!=OPERATOR_KAKKO_START) {
element_t nowElement;
nowElement.value=0;
nowElement.opType=operatorStack.top();
reversePorland.push_back(nowElement);
operatorStack.pop();
}
if(operatorStack.empty())return false;
operatorStack.pop();
expectValue=false;
} else if(opType==OPERATOR_KAKKO_START) {
//かっこの始まり
operatorStack.push(OPERATOR_KAKKO_START);
expectValue=true;
} else if(opType!=OPERATOR_NUMBER) {
//その他の演算子
while(!operatorStack.empty() &&
getYusendo(operatorStack.top(),true)<getYusendo(opType,false)) {
element_t nowElement;
nowElement.value=0;
nowElement.opType=operatorStack.top();
reversePorland.push_back(nowElement);
operatorStack.pop();
}
operatorStack.push(opType);
expectValue=true;
} else {
//数値
if(!expectValue)return false;
if(!isdigit(expression[i]) && expression[i]!='.')return false;
int j;
bool dotExist=false;
for(j=i;j<expression.length();j++) {
if(isdigit(expression[j]))continue;
else if(expression[j]=='.') {
if(dotExist)break; else dotExist=true;
} else break;
}
element_t nowElement;
nowElement.value=atof(expression.substr(i,j-i).c_str());
nowElement.opType=OPERATOR_NUMBER;
reversePorland.push_back(nowElement);
i=j-1;
expectValue=false;
}
}
if(expectValue)return false;
while(!operatorStack.empty()) {
if(operatorStack.top()==OPERATOR_KAKKO_START)return false;
element_t nowElement;
nowElement.value=0;
nowElement.opType=operatorStack.top();
reversePorland.push_back(nowElement);
operatorStack.pop();
}
for(int i=0;i<reversePorland.size();i++) {
if(reversePorland[i].opType==OPERATOR_NUMBER) {
calcStack.push(reversePorland[i].value);
} else if(reversePorland[i].opType==OPERATOR_MINUS) {
double now;
if(calcStack.empty())return false;
now=calcStack.top();
calcStack.pop();
calcStack.push(-now);
} else {
double d1,d2,next;
if(calcStack.empty())return false;
d2=calcStack.top();
calcStack.pop();
if(calcStack.empty())return false;
d1=calcStack.top();
calcStack.pop();
switch(reversePorland[i].opType) {
case OPERATOR_ADD: next=d1+d2;break;
case OPERATOR_SUB: next=d1-d2;break;
case OPERATOR_MUL: next=d1*d2;break;
case OPERATOR_DIV:
if(d2==0)return false;
next=d1/d2;break;
case OPERATOR_POW: next=pow(d1,d2);break;
default: return false;
}
calcStack.push(next);
}
}
if(calcStack.empty())return false;
result=calcStack.top();
calcStack.pop();
if(!calcStack.empty())return false;
return true;
}
//テストコード
int main(void) {
string query;
double result;
while(getline(cin,query)) {
if(strcalc(result,query))printf("%f\n",result); else puts("error");
}
return 0;
}
但し、言語はできればC++かC言語でお願いします。
(ネタとして他の言語でも構いません、ただしつまらないのでevalやそれに相当する標準関数は禁止)
オフトピック
べ、別にポイント稼ぎのために長文を投稿するわけじゃないんだからね!
勘違いするなよ!(CV:水橋かおり)
勘違いするなよ!(CV:水橋かおり)
掲示板にも似た内容を投稿しました。
一応マルチポスト扱い?