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