📄 编译原理.cpp
字号:
#include<iostream>
#include<setjmp.h>
#include<sstream>
#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
#define LIANXU 7 //预期外的算术表达式结束
using namespace std;
const string ErrCodeStr[]= //表达式出错信息
{
"表达式后跟有非法字符!",
"右括号后连接非法字符!",
"常量后非法直接连接左括号!",
"表达式中含有非法字符!",
"缺少右括号!",
"括号内无表达式或表达式不完整!",
"表达式非法结束或表达式不完整!",
"表达式中有连续字符!"
};
static char expr[EXP_LEN],opt; //算术表达式输入字符缓冲区
static int pos,line=0; //字符指示器标志:用来保存正在分析的字符的位置
static jmp_buf errjb; //出错跳转缓冲器
//********以下是函数声明*********
//执行或运算。
bool E_Or();
//执行与运算。
bool T_And();
//执行非运算。
bool F_Not();
//判断输入符号是不是布尔
int Isbool(char ch);
//出错处理函数,可以指出错误位置,出错信息。
void Error(int ErrCode);
//主函数
int main()
{
bool ans; //保存算术表达式的计算结果
char quit[1]={0};
bool esc=false; //是否退出计算
MENU: //主菜单显示。
cout<<" * ** ** ** ** ** ** ** ** ** ** *"<<endl;
cout<<"* *"<<endl;
cout<<"* 请输入选择项(1或2): *"<<endl;
cout<<"* *"<<endl;
cout<<"* 1:输入布尔表达式 *"<<endl;
cout<<"* *"<<endl;
cout<<"* 2:程序退出。 *"<<endl;
cout<<"* *"<<endl;
cout<<" * ** ** ** ** ** ** ** ** ** ** *"<<endl;
while(1)
{
cin>>opt;
if(opt=='1')
{
//在此设定一个跳转目标,如果本程序的其他函数调用longjmp,
//执行指令就跳转到这里,从这里继续执行。
OPT:if(setjmp(errjb)==0) //如果没有错误
{
pos=0; //初始化字符指示器为0,即指向输入字符串的第一个字符。
cout<<"提示:"<<endl;
cout<<" 运算符:与(&),或(^),非(!). 常量:true(t或T),false(f或F)."<<endl<<endl;
cout<<"请输入一个布尔表达式:"<<endl;
cin>>expr; //接受表达式。
ans=E_Or();
//此时,程序认为对表达式的语法分析已经完毕,下面判断出错的原因:
//如果表达式中的某个右括号后直接跟着字符,则报错。
if(expr[pos-1]==')'&&expr[pos]!='\0')
Error(CHAR_AFTER_RIGHT);
//如果表达式中的右括号后直接跟着左括号,
//则报错
if(expr[pos]=='(')
Error(LEFT_AFTER_NUM);
//如果结尾有其他非法字符
if(expr[pos]!='\0')
Error(INVALID_CHAR_TAIL);
cout<<"计算得出表达式的值为:"<<boolalpha<<ans<<endl;
}
else
{
//setjmp(errjb)!=0的情况:
cout<<"请重新输入!"<<endl;
}
cout<<"表达式处理完毕!"<<endl;
cout<<"1:继续计算:"<<endl;
cout<<"2:回到主选单:"<<endl;
cout<<endl;
//while(1){
cin>>quit;
//if(sizeof(quit)==1){
if(quit[0]=='1')goto OPT;
else /*if(quit[0]=='2')*/goto MENU;//返回主菜单。
//else cout<<"请重新选择:"<<endl;}
//继续输入表达式运算。
}
if(opt=='2') exit(0);//退出程序。
else
cout<<"输入有误,请从新输入!"<<endl;
}
return 0;
}
bool E_Or()
{
bool rtn=T_And(); //计算“或”表达式的左元
while(expr[pos]=='^')
{
char op=expr[pos++]; //取字符缓冲区中当前位置的符号到op
bool opr2=T_And(); //计算“或”算术表达式的右元
//计算求值
if(op=='^') //如果是"|"号
rtn|=opr2; //则用或计算
}
return rtn;
}
bool T_And()
{
bool rtn=F_Not(); //计算“与”表达式的左元
while(expr[pos]=='&')
{
char op=expr[pos++]; //取字符缓冲区中当前位置的符号到op
bool opr2=F_Not(); //计算与布尔表达式的右元
//计算求值
if(op=='&') //如果是"&"号
rtn&=opr2; //则用"与"计算
}
return rtn;
}
bool F_Not()
{
bool rtn; //声明存储返回值的变量
//用产生式F->!F推导:
if(expr[pos]=='!')
{
pos++;
rtn=!F_Not();
return rtn;
}
//用产生式F->(E)推导:
if(expr[pos]=='(') //如果字符缓冲区当前位置的符号是"("
{
pos++; //则指示器加一指向下一个符号
rtn=E_Or(); //调用产生式“E -> T^E | T&E | T”的分析函数
if(expr[pos++]!=')') //如果没有与"("匹配的")"
Error(NO_RIGHT); //则产生错误
return rtn;
}
if(Isbool(expr[pos])!=-1) //如果字符缓冲区中当前位置的布尔值
{int i=0;
//则用产生式F -> i推导
//把字符缓冲区中当前位置的字符串转换为整数
//改变指示器的值,跳过字符缓冲区的数字部分,找到下一个输入字符。
while(Isbool(expr[pos])!=-1){
//if(Isbool(expr[pos])==1)
while(Isbool(expr[pos])==1)
{
pos++;
rtn=true;
i++;
}
// if(Isbool(expr[pos])==0)
while(Isbool(expr[pos])==0)
{
pos++;
rtn=false;
i++;
}}
if(i>1) Error(LIANXU);
}
else //如果不是t 和f则产生相应的错误
{
if(expr[pos]==')') //如果发现一个")"
Error(EMPTY_BRACKET); //则是括号是空的,即括号内无布尔表达式。
else if(expr[pos]=='\0') //如果此时输入字符串结束
Error(UNEXPECTED_END); //则布尔表达式非法结束
else
Error(INVALID_CHAR_IN); //否则输入字符串中含有非法字符
}
return rtn;
}
int Isbool(char ch)//布尔常量的判别。
{
if(ch=='t'||ch=='T')
return 1;
if(ch=='f'||ch=='F')
return 0;
else
return -1;
}
//出错处理函数,输入错误代码,可以指出错误位置,出错信息。
void Error(int ErrCode)
{
cout<<endl;//换行
while(pos--)
cout<<' ';
cout<<"^ 语法错误 !!! "<<ErrCodeStr[ErrCode].c_str()<<endl;
longjmp(errjb,1); //跳转到main函数中的setjmp调用处,并设置setjmp(errjb)返回值为1
//longjmp(errjb,r);表示跳转到setjmp的调用处,并设置setjmp(errjb)返回值为r
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -