|
/****算術表達式的分析和計算,文件名:Exp_c.cpp**** ***** 在VC6和Dev-C下調試通過 ****/ #include #include #include #include #include
#define EXP_LEN 100 //定義輸入字符緩沖區的長度
/*------------出錯代碼的宏定義--------------*/ #define INVALID_CHAR_TAIL 0 //表達式后跟有非法字符 #define CHAR_AFTER_RIGHT 1 //右括號后連接非法字符 #define LEFT_AFTER_NUM 2 //數字后非法直接連接左括號 #define INVALID_CHAR_IN 3 //表達式中含有非法字符 #define NO_RIGHT 4 //缺少右括號 #define EMPTY_BRACKET 5 //括號內無表達式 #define UNEXPECTED_END 6 //預期外的算術表達式結束
using namespace std;
const string ErrCodeStr[]= //表達式出錯信息 { "表達式后跟有非法字符!", "右括號后連接非法字符!", "數字后非法直接連接左括號!", "表達式中含有非法字符!", "缺少右括號!", "括號內無表達式或表達式不完整!", "表達式非法結束或表達式不完整!" };
static char expr[EXP_LEN]; //算術表達式輸入字符緩沖區 static int pos; //字符指示器標志:用來保存正在分析的字符的位置 static jmp_buf errjb; //出錯跳轉緩沖器
//********以下是函數聲明********* //產生式“E -> T+E | T-E | T”的函數,用來分析加減算術表達式。 int E_AddSub(); //產生式“T -> F*T | F/T | F”的函數,用來分析乘除算術表達式。 int T_MulDiv(); //產生式“F -> i | (E)”的函數,用來分析數字和括號內的表達式。 int F_Number(); //出錯處理函數,可以指出錯誤位置,出錯信息。 void Error(int ErrCode);
int main() { int ans; //保存算術表達式的計算結果 bool quit=false; //是否退出計算
do { //在此設定一個跳轉目標,如果本程序的其他函數調用longjmp, //執行指令就跳轉到這里,從這里繼續執行。 if(setjmp(errjb)==0) //如果沒有錯誤 { pos=0; //初始化字符指示器為0,即指向輸入字符串的第一個字符。
cout<<"請輸入一個算術表達式(輸入“Q”或“q”退出):"< cin>>expr; //輸入表達式,填充表達式字符緩沖區。
if(expr[0]=='q'||expr[0]=='Q') //檢查第一個字符,是否退出? quit=true;
else { //調用推導式“E -> T+E | T-E | T”的函數, //從起始符號“E”開始推導。 ans=E_AddSub();
//此時,程序認為對表達式的語法分析已經完畢,下面判斷出錯的原因:
//如果表達式中的某個右括號后直接跟著數字或其他字符, //則報錯,因為數字i不屬于FOLLOW())集。 if(expr[pos-1]==')'&&expr[pos]!='\0') Error(CHAR_AFTER_RIGHT);
//如果表達式中的某個數字或右括號后直接跟著左括號, //則報錯,因為左括號不屬于FOLLOW(E)集。 if(expr[pos]=='(') Error(LEFT_AFTER_NUM);
//如果結尾有其他非法字符 if(expr[pos]!='\0') Error(INVALID_CHAR_TAIL);
cout<<"計算得出表達式的值為:"< } } else { //setjmp(errjb)!=0的情況: cout<<"請重新輸入!"< } } while(!quit);
return 0; }
//產生式“E -> T+E | T-E | T”的函數,用來分析加減算術表達式。 //返回計算結果 int E_AddSub() { int rtn=T_MulDiv(); //計算加減算術表達式的左元
while(expr[pos]=='+'||expr[pos]=='-') { int op=expr[pos++]; //取字符緩沖區中當前位置的符號到op int opr2=T_MulDiv();//計算加減算術表達式的右元
//計算求值 if(op=='+') //如果是"+"號 rtn+=opr2; //則用加法計算 else //否則(是"-"號) rtn-=opr2; //用減法計算 } return rtn; }
//推導式“T -> F*T | F/T | F”的函數,用來分析乘除算術表達式。 //返回計算結果 int T_MulDiv() { int rtn=F_Number(); //計算乘除算術表達式的左元
while(expr[pos]=='*'||expr[pos]=='/') { int op=expr[pos++]; //取字符緩沖區中當前位置的符號到op int opr2=F_Number();//計算乘除算術表達式的右元
//計算求值 if(op=='*') //如果是"*"號 rtn*=opr2; //則用乘法計算 else //否則(是"\"號) rtn/=opr2; //用除法計算 } return rtn; }
//產生式“F -> i | (E)”的函數,用來分析數字和括號內的表達式。 int F_Number() { int rtn; //聲明存儲返回值的變量
//用產生式F->(E)推導: if(expr[pos]=='(') //如果字符緩沖區當前位置的符號是"(" { pos++; //則指示器加一指向下一個符號 rtn=E_AddSub(); //調用產生式“E -> T+E | T-E | T”的分析函數
if(expr[pos++]!=')')//如果沒有與"("匹配的")" Error(NO_RIGHT);//則產生錯誤
return rtn; }
if(isdigit(expr[pos]))//如果字符緩沖區中當前位置的字符為數字 { //則用產生式F -> i推導 //把字符緩沖區中當前位置的字符串轉換為整數 rtn=atoi(expr+pos); //改變指示器的值,跳過字符緩沖區的數字部分,找到下一個輸入字符。 while(isdigit(expr[pos])) pos++; } else //如果不是數字則產生相應的錯誤 { if(expr[pos]==')') //如果發現一個")" Error(EMPTY_BRACKET); //則是括號是空的,即括號內無算術表達式。 else if(expr[pos]=='\0') //如果此時輸入串結束 Error(UNEXPECTED_END); //則算術表達式非法結束 else Error(INVALID_CHAR_IN); //否則輸入字符串中含有非法字符 }
return rtn; }
//出錯處理函數,輸入錯誤代碼,可以指出錯誤位置,出錯信息。 void Error(int ErrCode) { cout<<'\r'; //換行 while(pos--) cout<<' '; //打印空格,把指示錯誤的"^"移到輸入字符串的出錯位置 cout<<"^ 語法錯誤 !!! " < < longjmp(errjb,1); //跳轉到main()函數中的setjmp調用處,并設置setjmp(errjb)的返回值為1 }
研究ing,這段時間重新復習數據結構了……
|