文章目录
- 一、课题内容和要求
- 二、课题需求分析
- 1 过程分析
- 2 设计分析
- 三、课题相关数据结构及算法设计
- 1 主要数据结构
- 2 主要算法流程
- 3 词法分析
- 4 语法分析
- 5 中间代码生成
- 6 LR语法分析程序
- 6.1识别活前缀的DFA
- 6.2 SLR(1)分析表
- 6.3 分析过程
- 四、源程序代码
- 1 源代码层次结构
- 2.1 analyselr.h
- 2.2 const.h
- 2.3 functions.h
- 2.4 mainwindow.h
- 3.2 functions.cpp
- 3.4 mainwindow.cpp
一、课题内容和要求
结合编译原理的词法分析、语法分析及语义分析方法,给出表达式计算器的系统设计过程,并实现表达式计算器。课题要求如下:
(1)计算器中能实现基本功能如下:支持加、减、乘、除等运算;支持括号运算;对用户输入的表达式是否正确进行判断并给出错误提示;可以对上述功能进行扩充,例如增加支持三角函数和对数函数以及幂运算等;
(2)词法分析、语法分析、语义处理模块结构清晰,可以借助Lex、Yacc或JavaCC、Antlr等工具自动生成词法分析和语法分析程序;
(3)界面美观;
(4)可根据自己能力,在完成以上基本要求后,对程序功能进行适当扩充;
(5)撰写报告,对所采用的算法、程序结构和主要函数过程以及关键变量进行详细的说明;对程序的调试过程所遇到的问题进行回顾和分析,对测试和运行结果进行分析;总结软件设计和实习的经验和体会,进一步改进的设想。
(6)提供关键程序的清单、源程序及可执行文件和相关的软件说明。
二、课题需求分析
1 过程分析
(1)根据文法构造LR语法分析程序的Action表和Goto表。
(2)用户输入要计算的表达式
(3)分析程序将输入的表达式送入语法分析程序,首先判断表达式是否合法。
(4)对合法输入的表达式进行词法分析,语法分析,计算表达式结果。
(5)保存语法分析和词法分析的每一步骤。
(6)用户可以查看分析过程,并且可以逐步演示。
2 设计分析
设计需要使用 LR 分析法完成简单计算器的设计,其中算术表达式的文法如下:
表1 产生式和语法含义
产生式 语义规则
S→E E.val := E.val + T.val
E→E+T E.val := E.val + T.val
E→E-T print(T.val)
E→T print(T.val)
T→T*F T.val := T.val * F.val
T→T/F T.val := T.val / F.val
T→F print(F.val)
F→(E) F.val := E.val
F→+i F.val := i.lexval
F→-i F.val := -i.lexval
F→i F.val := i.lexval
三、课题相关数据结构及算法设计
1 主要数据结构
class AnalyseLR
{
private:
int step;
string inputstr; //布尔表达式
stack<int> state; //状态栈
stack<string> symbol; //符号栈
stack<int> data; //数据栈
public:
//构造函数
AnalyseLR();
//初始化两个栈
void Initstack();
//这是一个输出提示函数
void PrintInfo(string str);
//这是两个输出提示函数的增强版
void PrintInfo (string str1, string str2, string str3, string str4, string str5);
void PrintfInfo (int str1, stack<int> state, stack<string> symbol, string str4, string str5);
//初始化界面函数
void InitstageInfo();
//提示输入的函数
void InitInputstr(QString s);
//将终结符和非终结符转换为action和gotol表中对应的列号
int ItrtoInt(string str);
//判断字符是终结符还是非终结符
bool JudgeSymbol(string str);
//根据产生式选择非终结符
int ChooseNoEnds(int num);
//计算字符串中元素的个数
int Calculatenum(string str);
//将vector容器中的字符串连起来
string LinkVectorstr(vector<string> &vecs, vector<string>::iterator iter);
void Start(QString s, int& output);
//LR分析函数
int ActionGoto(string str, string str1,vector<string> vec,bool &flag);
// 打印状态栈
void PrintState(stack<int> s);
//符号栈 输出栈内的所有元素
void PrintSymbol(stack<string> s);
void Print();
};
2 主要算法流程
图1 算法流程图
3 词法分析
词法分析是计算机科学中将字符序列转换为单词(Token)序列的过程。进行语法分析的程序或者函数叫词法分析器(Lexical analyzer)。
词法分析器一般以函数的形式存在,供语法分析器调用。词法分析是编译过程中的第一个阶段,在语法分析前进行。也可以和语法分析结合在一起作为一遍,由语法分析程序调用词法分析程序来获得当前单词供语法分析使用。简化设计、改进编译效率、增加编译系统的可移植性。词法分析是编制一个读单词的过程,从输入的源程序中,识别出各个具有独立意义的单词,即基本保留字、标识符、常数、运算符、分隔符五大类。并依次输出各个单词的内部编码及单词符号自身值。单词的分类主要分为五类:
(1)关键字:由程序语言定义的具有固定意义的标识符,也称为保留字或基本字。
(2)标识符:用来表示程序中各种名字的字符串。
(3)常数:常数的类型一般有整型、实型、布尔型、文字型。
(4)运算符:如+、-、、/等。
(5)界限符:如逗号、分号、括号等。
这里将词法分析程序设计成一个子程序,每当语法分析程序需要一个单词时,则调用该子程序。词法分析程序每调用一次,便从源程序文件中读入一些字符,直到识别出一个单词。
(1)SEPARATER[2] = { ‘(’, ‘)’ }; //分隔符
(2)OPERATOR[5] = { ‘+’, ‘-’, '', ‘/’, ‘=’ }; //运算符
(3)FILTER[4] = { ’ ', ‘\t’, ‘\r’, ‘\n’ }; //过滤符
终结符号集,非终结符号集合产生式如下:
(1)END[9] = { “+”, “-”, ““, “/”, “(”, “)”, “=”,“id”,”#" };
(2)NOENDS[3] = { “E”, “T”, “F” };
(3)PRODUCTS[9] = { “E”, “E+T”, “E-T”, “T”, "TF”, “T/F”, “F”, “(E)”, “id” };
4 语法分析
语法分析是编译程序的核心部分,其主要任务是确定语法结构,检查语法错误,报告错误的性质和位置,并进行适当的纠错工作。
语法分析的主要工作是识别由词法分析给出的单词序列是否是给定的正确句子(程序)。语法分析常用的方法自顶向下的语法分析和自底向上的语法分析两大类。此次设计中语法分析中主要通过LR分析法对语法分析处理过程进行控制,使表达式结果能正确得出,同时识别语法分析中的语法错误。
语法分析是编译过程的一个逻辑阶段。语法分析的任务是在的基础上将单词序列组合成各类语法短语,如“程序”、“语句”、“表达式”等等。语法分析程序判断源程序在结构上是否正确。源程序的结构由上下文无关文法描述。语法分析程序可以用YACC等工具自动生成。
在语法分析的同时可由语法分析程序调用相应的语义子程序进行语义处理,完成附加在所使用的产生式上的语义规则描述,并完成移进—归约过程。
词法分析程序和语法分析程序的关系如图2所示:
图2 词法分析与语法分析的关系
5 中间代码生成
中间代码,也称中间语言,是复杂性介于源程序语言和机器语言的一种表示形式。为了使编译程序有较高的目标程序质量,或要求从编译程序逻辑结构上把与机器无关和与机器有关的工作明显的分开来时,许多编译程序都采用了某种复杂性介于源程序语言和机器语言之间的中间语言。中间代码(语言)是一种特殊结构的语言,编译程序所使用的中间代码有多种形式。按其结构分常见的有逆波兰式(后缀式)、三地址代码(三元式、四元式)和树形表示(抽象语法树)、DAG表示。
6 LR语法分析程序
6.1识别活前缀的DFA
图3 部分DFA活前缀
6.2 SLR(1)分析表
部分产生式存在移进—归约冲突,可用 SLR(1)方法解决冲突。
冲突解决后的SLR(1)分析表如下:
表2 SLR(1)分析表
ACTION GOTO
+ - * / ( ) = # E T F
0 0 0 0 0 4 0 5 0 1 2 3
1 6 7 0 0 0 0 0 100 0 0 0
2 -3 -3 8 9 0 -3 0 -3 0 0 0
3 -6 -6 -6 -6 0 -6 0 -6 0 0 0
4 0 0 0 0 4 0 5 0 10 2 3
5 -8 -8 -8 -8 0 -8 0 -8 0 0 0
6 0 0 0 0 4 0 5 0 0 11 3
7 0 0 0 0 4 0 5 0 0 12 3
8 0 0 0 0 4 0 5 0 0 0 13
9 0 0 0 0 4 0 5 0 0 0 14
10 6 7 0 0 0 15 0 0 0 0 0
11 -1 -1 8 9 0 -1 0 -1 0 0 0
12 -2 -2 8 9 0 -2 0 -2 0 0 0
13 -4 -4 -4 -4 0 -4 0 -4 0 0 0
14 -5 -5 -5 -5 0 -5 0 -5 0 0 0
15 -7 -7 -7 -7 0 -7 0 -7 0 0 0
6.3 分析过程
LR 分析法的规约过程是规范推到的逆过程,所以 LR 分析过程是一种规范规约的过程。其分析过程为:由文法构造出该文法项目集,再根据项目集构造该文法的 DFA,再判断是否有移进—规约和规约—规约冲突,若没有冲突则该文法为 LR(0)的,若有冲突则该文法是 SLR(1)的,最后可以构造出 LR(0)分析表。然后根据 LR(0)分析表进行语法分析,分析过程就是进栈和规约的过程。若能规约出开始符S,则语法正确。反之,语法错误。
LR 分析法过程流程图如下:
图4 LR语法分析流程图
四、源程序代码
1 源代码层次结构
图5 源程序代码层次结构
2.1 analyselr.h
#ifndef ANALYSELR_H
#define ANALYSELR_H
#include <QString>
#include<iostream>
#include<string>
#include<vector> //STL容器,动态数组,序列性容器+动态增长+可定制的内存分配策略
#include<iomanip> //I/O控制流头文件
#include <stack>
#include <map>
using namespace std;
class AnalyseLR
{
private:
int step;
string inputstr; //布尔表达式
stack<int> state; //状态栈
stack<string> symbol; //符号栈
stack<float> data; //数据栈
public: vector<pair<string, string>> all_state;
QString error;
int xxx = 100;
public:
//构造函数
AnalyseLR();
//初始化两个栈
void initstack();
//这是一个输出提示函数
void printInfo(string str);
//这是两个输出提示函数的增强版
void printInfoEX(string str1, string str2, string str3, string str4, string str5);
void printfInfoEX(int str1, stack<int> state, stack<string> symbol, string str4, string str5);
//初始化界面函数
void initstageInfo();
//提示输入的函数
void initInputstr(QString s);
//将终结符和非终结符转换为action和gotol表中对应的列号
int strtoInt(string str);
//判断字符是终结符还是非终结符
bool judgeSymbol(string str);
//根据产生式选择非终结符
int chooseNoEnds(int num);
//计算字符串中元素的个数
int calculatenum(string str);
//将vector容器中的字符串连起来
string linkVectorstr(vector<string> &vecs, vector<string>::iterator iter);
int Start(QString s, float& output);
//LR分析函数
int actionGoto(string str, string str1,vector<string> vec,bool &flag);
// 打印状态栈
void printState(stack<int> s);
//符号栈 输出栈内的所有元素
void printSymbol(stack<string> s);
void Print();
bool Check(QString str0);
public:
vector<string> Lexical;
vector<int> step0;
vector<string> state00;
vector<string> marker;
vector<string> inputstring;
vector<string> oper;
};
#endif // ANALYSELR_H
2.2 const.h
#ifndef CONST_H
#define CONST_H
#include<iostream>
#include<string>
#include <QString>
#include <vector>
using namespace std;
#include <map>
#include<iomanip> //I/O控制流头文件
#include <stack>
//*********************语法分析器******************************//
//Action表
static int action[16][8] = { { 0, 0, 0, 0, 4, 0, 5, 0 },//0
{ 6, 7, 0, 0, 0, 0, 0, 100 },//1
{ -3, -3, 8, 9, 0, -3, 0, -3 },//2
{ -6, -6, -6, -6, 0, -6, 0, -6 },//3
{ 0, 0, 0, 0, 4, 0, 5, 0 },//4
{ -8, -8, -8, -8, 0, -8, 0, -8 },//5
{ 0, 0, 0, 0, 4, 0, 5, 0 },//6
{ 0, 0, 0, 0, 4, 0, 5, 0 },//7
{ 0, 0, 0, 0, 4, 0, 5, 0 },//8
{ 0, 0, 0, 0, 4, 0, 5, 0 },//9
{ 6, 7, 0, 0, 0, 15, 0, 0 },//10
{ -1, -1, 8, 9, 0, -1, 0, -1 },//11
{ -2, -2, 8, 9, 0, -2, 0, -2 },//12
{ -4, -4, -4, -4, 0, -4, 0, -4 },//13
{ -5, -5, -5, -5, 0, -5, 0, -5 },//14
{ -7, -7, -7, -7, 0, -7, 0, -7 }//15
};//17
//Goto表
static int gotol[16][3] = { { 1, 2, 3 },//0
{ 0, 0, 0 }, //1
{ 0, 0, 0 }, //2
{ 0, 0, 0 }, //3
{ 10, 2, 3 }, //4
{ 0, 0, 0 }, //5
{ 0, 11, 3 }, //6
{ 0, 12, 3 }, //7
{ 0, 0, 13 }, //8
{ 0, 0,14 }, //9
{ 0, 0, 0 }, //10
{ 0, 0, 0 }, //11
{ 0, 0, 0 }, //12
{ 0, 0, 0 }, //13
{ 0, 0, 0 }, //14
{ 0, 0, 0 } }; //17
//终结符集合
static string endls[9] = { "+", "-", "*", "/", "(", ")", "=","id","#" };
//非终结符集合
static string noends[3] = { "E", "T", "F" };
//产生式集合
static string products[9] = { "E", "E+T", "E-T", "T", "T*F", "T/F", "F", "(E)", "id" };
/* 文法如下
E=> T+F | T-F |T
T=> F*T | F/T |F
F=> (E) | id
*/
//*********************词法分析器******************************//
static char SEPARATER[2] = { '(', ')' }; //分隔符
static char OPERATOR[5] = { '+', '-', '*', '/', '=' }; //运算符
static char FILTER[4] = { ' ', '\t', '\r', '\n' }; //过滤符
#endif // CONST_H
2.3 functions.h
#ifndef FUNCTIONS_H
#define FUNCTIONS_H
#include "const.h"
/**判断是否为分隔符**/
bool IsSeparater(char ch);
/**判断是否为运算符**/
bool IsOperator(char ch);
/**判断是否为过滤符**/
bool IsFilter(char ch);
/**判断是否为数字**/
bool IsDigit(char ch);
/**词法分析**/
vector<string> analyse(string expression, vector<string>& v);
//*********************中间代码生成器******************************//
string InversePolish(string s_mid);
//*********************后缀表达式计算******************************//
float Op(float a, char op, float b);
float calculate(char *str);
#endif // FUNCTIONS_H
2.4 mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "analyselr.h"
#include <QKeyEvent>
#include <QDebug>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_insert_clicked();
void on_add_clicked();
private:
Ui::MainWindow *ui;
void Init();
public:
AnalyseLR ana;
void InsertLexicalOutput(QString);
void InsertGrammarOutput(QString);
void digitBtn(char ch);
/**词法分析**/
vector<string> analyse00(string expression, vector<string>& v);
private slots:
void on_btn0_clicked();
void on_btn1_clicked();
void on_btn2_clicked();
void on_btn3_clicked();
void on_btn4_clicked();
void on_btn5_clicked();
void on_btn6_clicked();
void on_btn7_clicked();
void on_btn8_clicked();
void on_btn9_clicked();
void keyPressEvent(QKeyEvent *event);
void on_btnAdd_clicked();
void on_btnSub_clicked();
void on_btnMuti_clicked();
void on_btnDivi_clicked();
void on_btnClear_clicked(); // 删除
void on_btnBack_clicked();
void on_btnEqual_clicked(); // 等于
void on_analysis_clicked();
void on_btnLeft_clicked();
void on_btnRight_clicked();
//void on_pushButton_8_clicked();
void on_pushButton_8_clicked();
void on_pushButton_9_clicked();
void PrintStack(string, string, string, string next = "");
void on_showstep_clicked();
void on_backinit_clicked();
void on_dot_clicked();
private:
};
#endif // MAINWINDOW_H
3.1 analyselr.cpp
#include "analyselr.h"
#include <QString>
#include<iostream>
#include<string>
#include<vector> //STL容器,动态数组,序列性容器+动态增长+可定制的内存分配策略
#include<iomanip> //I/O控制流头文件
#include <stack>
#include <map>
using namespace std;
#include <list>
#include "functions.h"
//构造函数
AnalyseLR::AnalyseLR()
{
step = 0;
inputstr = "";
}
//初始化两个栈
void AnalyseLR::initstack()
{
state.push(0);
symbol.push("=");
}
//这是一个输出提示函数
void AnalyseLR::printInfo(string str)
{
cout << str << endl;
}
//这是两个输出提示函数的增强版
void AnalyseLR::printInfoEX(string str1, string str2, string str3, string str4, string str5)
{
//all_state.push_back(make_pair(data, symbol));
cout << setw(6) << setiosflags(ios_base::left) << str1; // setiosflags(ios_base::left) 左对齐值,用填充字符填充右边
cout << setw(15) << setiosflags(ios_base::left) << str2;
cout << setw(15) << setiosflags(ios_base::left) << str3;
cout << setw(30) << setiosflags(ios_base::left) << str4;
cout << setw(10) << setiosflags(ios_base::left) << str5 << endl;
}
void AnalyseLR::printfInfoEX(int str1, stack<int> state, stack<string> symbol, string str4, string str5)
{
cout << setw(6) << setiosflags(ios_base::left) << str1;
step0.push_back(str1);
printState(state);
printSymbol(symbol);
cout << setw(30) << setiosflags(ios_base::left) << str4;
inputstring.push_back(str4);
cout << setw(10) << setiosflags(ios_base::left) << str5 << endl;
oper.push_back(str5);
}
//初始化界面函数
void AnalyseLR::initstageInfo()
{
cout << "\n\t welcome" << endl;
cout << "\t-----------------------------------------" << endl;
cout<<"\t expression as follows \n"<<endl;
cout << "\t\t(0) E’-> E " << endl;
cout << "\t\t(1) E -> E + T" << endl;
cout << "\t\t(2) E -> E - T" << endl;
cout << "\t\t(3) E -> T " << endl;
cout << "\t\t(4) T -> T * F" << endl;
cout << "\t\t(5) T -> T / F" << endl;
cout << "\t\t(6) T -> F " << endl;
cout << "\t\t(7) F -> ( E ) " << endl;
cout << "\t\t(8) F -> id " << endl;
cout << "\t------------------------------------------" << endl;
}
//提示输入的函数
void AnalyseLR::initInputstr(QString s)
{
inputstr = s.toStdString();
}
//将终结符和非终结符转换为action和gotol表中对应的列号
int AnalyseLR::strtoInt(string str)
{
if (str == "+")
return 0;
if (str == "-")
return 1;
if (str == "*")
return 2;
if (str == "/")
return 3;
if (str == "(")
return 4;
if (str == ")")
return 5;
//if (str == "id")
//return 6;
if (str == "=") //$
return 7;
if (str == "E")
return 0;
if (str == "T")
return 1;
if (str == "F")
return 2;
//return 111;
return 6;
}
//判断字符是终结符还是非终结符
bool AnalyseLR::judgeSymbol(string str)
{
for (int i = 0; i<3; i++)
{
if (noends[i] == str)
return false;
}
return true;
}
//根据产生式选择非终结符
int AnalyseLR::chooseNoEnds(int num)
{
if (num == 1 || num == 2 || num == 3)
return 0;//选择“E”
if (num == 4 || num == 5 || num == 6)
return 1;//选择“T”
return 2;//选择“F”
}
//计算字符串中元素的个数
int AnalyseLR::calculatenum(string str)
{
int num = 0;
if (str == "id") num = 1;
else num = str.size();
return num;
}
//将vector容器中的字符串连起来
string AnalyseLR::linkVectorstr(vector<string> &vecs, vector<string>::iterator iter)
{
string str = "";
vector<string>::iterator it;
it = iter;
for (it; it<vecs.end(); it++)
{
//cout<<*it;
str += *it;
}
return str;
}
int AnalyseLR::Start(QString s, float& output)//开始函数.
{
if(!Check(s))
{
this->error = "括号不匹配";
return -999;
}
initstageInfo();
initstack();//初始化两个栈
initInputstr(s);
printInfo("\n---------------------------word analysis----------------------------------");
printInfo("\t\t\t记号名\t属性值");
vector<string> vec = analyse(inputstr, this->Lexical);//分开布尔表达式
if (vec.empty()) {}
else{
vector<string>::iterator iter = vec.begin();
printInfo("\n---------------------------grammar analysis----------------------------------");
printInfoEX("step", "state stack", "marker stack", "input string", "operation");
bool flag;
for (iter; iter != vec.end(); ++iter)//依次遍历字符
{
flag = 1;
string str1 = linkVectorstr(vec, iter);
actionGoto(*iter, str1, vec,flag);
if (!flag)
{
if(this->xxx == -10)
{
this->error= "除数不能为0";
}
else
{
this->error= "运算符错误";
}
return -999;
}
}
iter--;
if (*iter != "=")
{
flag = 0;
cout << "pelase end with '='"<< endl;
}
if (flag)
{
cout << "success!" << endl;
printInfo("\n---------------------------Intermediate code----------------------------------");
vector<string>::iterator iter2 = vec.begin();
string s_mid = linkVectorstr(vec, iter2); //连接成一个字符串
s_mid = s_mid.substr(0, s_mid.length() - 1); //删除最后的等于,用substr实现截取功能
string HZ = InversePolish(s_mid);//转后缀表达式
printInfo("\n---------------------------Calculation results----------------------------------");
char* stringofchar = (char*)HZ.data();//加const 或者用char * p=(char*)str.data();的形式
float Result = calculate(stringofchar);
output = Result;
cout << "result is " << Result << endl;
}
//printForsInfo();
}
return 1;
}
//状态栈
void AnalyseLR::printState(stack<int> s)//输出栈内的所有元素
{
string str = " ";
int* pre;
vector<int> v;
while (!s.empty())
{
v.push_back(s.top());
s.pop();
}
for (int i = s.size(); i >=0; i--)
{
if (v[i] > 9) // 栈中保存的10转换成1、0
{
char ch1 = (v[i] / 10) + 48;
char ch2 = (v[i] % 10) + 48;
str += ch1;
str += ch2;
}
else
{
char ch = v[i] + 48;
str += ch;
}
}
cout << setw(15) << setiosflags(ios_base::left) << str;
this->state00.push_back(str);
}
//符号栈 输出栈内的所有元素
void AnalyseLR::printSymbol(stack<string> s)
{
string str = "";
vector<string> v;
while (!s.empty())
{
v.push_back(s.top());
s.pop();
}
for (int i = v.size() - 1; i >= 0; i--)
{
str += v[i];
}
cout << setw(15) << setiosflags(ios_base::left) << str;
this->marker.push_back(str);
}
void AnalyseLR::Print()
{
for(string s: this->marker)
{
cout << s << endl;
}
}
bool AnalyseLR::Check(QString str0)
{
string str = str0.toStdString();
list<char> lChar;
int nStrLen = str.length();
for (int i = 0; i < nStrLen; i++)
{
if (str[i] == '(')
{
lChar.push_back(str[i]);
}
if (str[i] == ')')
{
if (lChar.empty())
return false;
lChar.pop_back();
}
}
if (lChar.empty())
return true;
return false;
}
//LR分析函数
int AnalyseLR::actionGoto(string str, string str1,vector<string> vec,bool &flag)
{
int x = state.top();//当前栈顶状态
int y = strtoInt(str);//当前将要输入的字符
if (action[x][y] == 0)
{
cout << "grammar analysis fail" << endl;
flag=0;
}
if (action[x][y]>0 && judgeSymbol(str) && (str != "="))//移进
{
printfInfoEX(step, state, symbol, str1, "移入" + str);
state.push(action[x][y]);
symbol.push(str);
++step;
}
if (action[x][y]<0 && judgeSymbol(str))//规约
{
int z = -action[x][y];//用-action[x][y]对应的产生式规约
string lenstr = products[z];//生成需要规约的产生式
int n = calculatenum(lenstr);//计算产生式的长度,进行规约
int c = chooseNoEnds(z);
string ch = noends[c];//生成规约后的非终结符
printfInfoEX(step, state, symbol, str1, "规约" + noends[c] + "->" + products[z]);
switch (z)
{
case 1:
{
int a = data.top();
data.pop();
int b = data.top();
data.pop();
b += a;
data.push(b);
break;
}
case 2:
{
int a = data.top();
data.pop();
int b = data.top();
data.pop();
b -= a;
data.push(b);
break;
}
case 4:
{
int a = data.top();
data.pop();
int b = data.top();
data.pop();
b *= a;
data.push(b);
break;
}
case 5:
{
int a = data.top();
if (a == 0)
{
flag = 0;
cout << "\n除数为0!" << endl;
this->xxx = -10;
return flag;
}
data.pop();
int b = data.top();
data.pop();
b /= a;
data.push(b);
break;
}
case 8:
{
string b = symbol.top();
int c = atoi(b.c_str());
data.push(c);
break;
}
default:
break;
}
for (int i = 0; i < n; i++)
{
state.pop();
symbol.pop();
}
int m = state.top();//获取规约后的栈顶状态
if (gotol[m][c]>0)
{
int g = gotol[m][c];
state.push(g);
symbol.push(ch);
}
++step;
actionGoto(str, str1,vec,flag);
}
//cout << str<<" "<<str1 << endl;
if ((action[x][y] == 100) &&(str1=="="))
{
flag = 1;
printfInfoEX(step, state, symbol, str1, "分析完成");
cout << "\nGrammar analysis calculation results: "<<data.top() << endl;
}
else if ((action[x][y] == 100))
{
cout << "Grammar parsing failed!" << endl;
flag = 0;
}
return flag;
}
3.2 functions.cpp
#ifndef FUNCTIONS_CPP
#define FUNCTIONS_CPP
#include "functions.h"
/**判断是否为分隔符**/
bool IsSeparater(char ch){
for (int i = 0; i<2; i++){
if (SEPARATER[i] == ch){
return true;
}
}
return false;
}
/**判断是否为运算符**/
bool IsOperator(char ch){
for (int i = 0; i<5; i++){
if (OPERATOR[i] == ch){
return true;
}
}
return false;
}
/**判断是否为过滤符**/
bool IsFilter(char ch){
for (int i = 0; i<4; i++){
if (FILTER[i] == ch){
return true;
}
}
return false;
}
/**判断是否为数字**/
bool IsDigit(char ch){
cout << "input\t" << ch<<endl;
if (ch >= '0' && ch <= '9' || ch=='.') return true;
return false;
}
/**词法分析**/
vector<string> analyse(string expression, vector<string>& v){
vector<string> vec;
char ch = ' ';
for (int i = 0; i < expression.length(); i++)
{
string arr = "";
ch = expression[i];
if (IsFilter(ch)){} //判断是否为过滤符
else if (IsDigit(ch)){ //判断是否为数字
while (IsDigit(ch) || IsFilter(ch)){
if (IsDigit(ch))
arr += ch;
i++;
ch = expression[i];
}
i--;
v.push_back(string(arr) + " : number");
cout << "\t\t\t< int, " << arr <<">"<< endl;
vec.push_back(arr); //将一个新的元素加到vector后面,位置为当前最后一个元素的下一个元素
}
else if (IsOperator(ch))
{
arr += ch;
v.push_back(string(arr) + " : operator");
cout << "\t\t\t< operator, " << arr << ">" << endl;
vec.push_back(arr);
}
else if (IsSeparater(ch))
{
arr += ch;
v.push_back(string(arr) + " : delimiter");
cout << "\t\t\t< delimiter, " << arr << ">" << endl;
vec.push_back(arr);
}
else
{
v.push_back(string(arr) + ": operator");
cout << "\t\t\t\"" << ch << "\":Unrecognized characters!" << endl;
vec.clear();
return vec;
}
}
return vec;
}
//*********************中间代码生成器******************************//
string InversePolish(string s_mid)
{
string s_beh = "";
stack<char> stk;
map<char, int> op;//利用map来实现运算符对应其优先级
op['('] = 0;
op[')'] = 0;
op['+'] = 1;
op['-'] = 1;
op['*'] = 2;
op['/'] = 2;
string::iterator it = s_mid.begin();
//迭代器,遍历并选择序列中的对象,他提供了一种访问一个容器对象的中各个元素,而又不必保留该对象内部细节的方法。
while (it != s_mid.end())
{
if (op.count(*it))//判断该元素是否为运算符
{
if (*it == ')')//若为’)‘,把栈中的运算符依次加入后缀表达式,直到出现'(',’(‘出栈,退出该次循环
{
while (stk.top() != '(')
{
s_beh += stk.top(); //取出栈顶元素
s_beh += " ";
stk.pop();
}
stk.pop(); //弹出栈顶元素
}
else if (stk.empty() || *it == '(' || op[*it]>op[stk.top()])
//若为‘(’,入栈 ; 要入栈的运算符优先级大于等于栈顶的运算符的优先级,直接入栈
{
stk.push(*it); //在栈顶增加元素
}
else if (op[*it] <= op[stk.top()])
// 入栈的运算符优先级小于等于栈顶的运算符的优先级,栈顶运算符出栈,再次比较,直到出现优先级低的运算符,或者栈为空,退出
{
while (op[*it] <= op[stk.top()] && (!stk.empty()))
{
s_beh += stk.top();
s_beh += " ";
stk.pop();
if (stk.empty()) break;
}
stk.push(*it);
}
}
else
{
s_beh += *it;
it++;
if (it != s_mid.end() && op.count(*it))
//count,返回被查找元素个数,返回1/0,有/无;find 返回被查找元素的位置,没有返回map.end()
s_beh += " ";
it--;
}
it++;
if (it == s_mid.end())//当中缀表达式输出完成,所有元素出栈
{
while (!stk.empty())
{
s_beh += " ";
s_beh += stk.top();
stk.pop();
}
break;
}
}
cout <<"逆波兰表达式:"<< s_beh << endl;
return s_beh;
}
//*********************后缀表达式计算******************************//
float Op(float a, char op, float b)
{
switch (op)
{
case '+':return a + b; break;
case '-':return a - b; break;
case '*':return a*b; break;
case '/':return a / b; break;
}
}
float calculate(char *str)
{
stack<float> s; //暂存操作数
int i = 0;
int offset = 0;
int flag = 0;
int Length = strlen(str);
float Result;
while (i < Length)
{
string One = "";
for (i; i < Length; i++)
{
One += str[i];
if (((str[i] == ' ')&&(str[i+1]!=' ')) || (i == Length - 1))
{
char* OneNumber = (char*)One.data();
cout << OneNumber <<endl;
float Number = atof(One.c_str());
cout << "NUM = " << Number <<endl;
//atoi字符串转整数,c_str返回一个指向正规c字符串的指针常量,内容与其中string同。(为了与c语言兼容)
if (IsOperator(*OneNumber))
{
Number = 0;
}
cout << "198 " <<Number<<endl;
s.push(Number);
if (IsOperator(*OneNumber))
{
s.pop();
float x = s.top();
s.pop();
float y = s.top();
s.pop();
Result = Op(y, *OneNumber, x);
s.push(Result);
}
offset = i + 1;
break;
}
}
i = offset;
}
return s.top();
}
#endif // FUNCTIONS_CPP
3.3 main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
3.4 mainwindow.cpp
/*
1. 错误检测
1.1 除数不能为0
1.2 运算符错误
1.3 括号不匹配
2. 浮点数
3. 分析演示
1.1 语法分析栈 和 余留符号串栈
4. 全部过程 : 包含词法分析和语法分析
*/
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "functions.h"
#include <QDebug>
#include <windows.h>
const int HEIGHT = 650;
const int WIDTH = 520;
const int SHOWHEIGHT = 1200;
const int SHOWWIDTH = 520;
const int ALLHEIGHT = 1200;
const int ALLWIDTH = 2000;
using namespace std;
int Index = 0;
// 输入的表达式 和 结果
QString s;
float output;
bool InputEnable = true;
bool AnalyseFlag = false;
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->setFixedSize(WIDTH, HEIGHT);
ui->analysis->setEnabled(false);
ui->showstep->setEnabled(false);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_insert_clicked()
{
s = ui->input->toPlainText();
ui->input->setText("插入得内容是"+s);
}
void MainWindow::InsertLexicalOutput(QString s)
{
ui->word->clear();
for(string s: ana.Lexical)
{
ui->word->append(QString::fromStdString(s));
}
}
void MainWindow::InsertGrammarOutput(QString s)
{
ui->step->clear();
ui->state->clear();
ui->marker->clear();
ui->stringleft->clear();
ui->oper->clear();
for(int s: ana.step0)
{
ui->step->append(QString::number(s));
}
for(string s: ana.state00)
{
ui->state->append(QString::fromStdString(s));
}
for(string s: ana.marker)
{
ui->marker->append(QString::fromStdString(s));
}
for(string s: ana.inputstring)
{
ui->stringleft->append(QString::fromStdString(s));
}
for(string s: ana.oper)
{
ui->oper->append(QString::fromStdString(s));
}
}
void MainWindow::on_add_clicked()
{
}
void MainWindow::Init()
{
}
void MainWindow::digitBtn(char ch)
{
cout << "HAHA";
s+= ch;
qDebug(s.toStdString().data());
ui->input->setPlainText(s);
}
void MainWindow::on_btn0_clicked()
{
digitBtn('0');
}
void MainWindow::on_btn1_clicked()
{
digitBtn('1');
}
void MainWindow::on_btn2_clicked()
{
digitBtn('2');
}
void MainWindow::on_btn3_clicked()
{
digitBtn('3');
}
void MainWindow::on_btn4_clicked()
{
digitBtn('4');
}
void MainWindow::on_btn5_clicked()
{
digitBtn('5');
}
void MainWindow::on_btn6_clicked()
{
digitBtn('6');
}
void MainWindow::on_btn7_clicked()
{
digitBtn('7');
}
void MainWindow::on_btn8_clicked()
{
digitBtn('8');
}
void MainWindow::on_btn9_clicked()
{
digitBtn('9');
}
void MainWindow::keyPressEvent(QKeyEvent *event)
{
if(event->key()==Qt::Key_C)
{
on_btnClear_clicked();
}
if(!InputEnable)
return;
if(event->key() == Qt::Key_Enter)
{
qDebug("回车");
}
else if(event->key() == '1' ){
digitBtn('1');
}
else if(event->key() == '.' ){
digitBtn('.');
}
else if(event->key()=='0')
{
digitBtn('0');
}
else if(event->key()=='2')
{
digitBtn('2');
}
else if(event->key()=='3')
{
digitBtn('3');
}
else if(event->key()=='4')
{
digitBtn('4');
}
else if(event->key()=='5')
{
digitBtn('5');
}
else if(event->key()=='6')
{
digitBtn('6');
}
else if(event->key()=='7')
{
digitBtn('7');
}
else if(event->key()=='8')
{
digitBtn('8');
}
else if(event->key()=='9')
{
digitBtn('9');
}
else if(event->key()=='+')
{
digitBtn('+');
}
else if(event->key()=='-')
{
digitBtn('-');
}
else if(event->key()=='*')
{
digitBtn('*');
}
else if(event->key()=='/')
{
digitBtn('/');
}
else if(event->key()=='=')
{
on_btnEqual_clicked();
}
else if(event->key()==Qt::Key_C)
{
on_btnClear_clicked();
}
else if(event->key()=='(')
{
on_btnLeft_clicked();
}
else if(event->key()==')')
{
on_btnRight_clicked();
}
else if(event->key()==Qt::Key_Backspace)
{
on_btnBack_clicked();
}
}
void MainWindow::on_btnAdd_clicked()
{
digitBtn('+');
}
void MainWindow::on_btnSub_clicked()
{
digitBtn('-');
}
void MainWindow::on_btnMuti_clicked()
{
digitBtn('*');
}
void MainWindow::on_btnDivi_clicked()
{
digitBtn('/');
}
//等于号的槽函数。
void MainWindow::on_btnEqual_clicked()
{
InputEnable = false;
digitBtn('=');
ana = AnalyseLR();
int res = ana.Start(s, output);
if(res == -999)
{
ui->result->setText(ana.error);
return;
}
ui->result->setText(QString::number(output));
ui->analysis->setEnabled(true);
ui->showstep->setEnabled(true);
InsertLexicalOutput("");
InsertGrammarOutput("");
}
void MainWindow::on_btnClear_clicked()
{
s = "";
InputEnable = true;
this->setFixedSize(WIDTH, HEIGHT);
ui->analysis->setEnabled(false);
ui->showstep->setEnabled(false);
ui->input->setText(s);
ui->result->setText("");
ui->z_op->clear();
ui->z_yufa->clear();
ui->z_shuzi->clear();
Index = 0;
}
void MainWindow::on_btnBack_clicked()
{
s=s.mid(0,s.size()-1);
ui->input->setText(s);
}
void MainWindow::on_analysis_clicked()
{
//resize(2000, 1200);
this->setFixedSize(ALLWIDTH, ALLHEIGHT);
}
void MainWindow::on_dot_clicked()
{
digitBtn('.');
}
void MainWindow::on_btnLeft_clicked()
{
digitBtn('(');
}
void MainWindow::on_btnRight_clicked()
{
digitBtn(')');
}
void MainWindow::on_pushButton_8_clicked()
{
this->setFixedSize(WIDTH, HEIGHT);
//ui->analysis->setEnabled(false);
}
// 动态过程
void MainWindow::on_pushButton_9_clicked()
{
}
void MainWindow::PrintStack(string yufa, string shuzi, string op, string next)
{
cout <<"414 \t" << yufa<<endl;
vector<string> vvv;
vector<string> vec = analyse(yufa, vvv);//分开布尔表达式
ui->z_yufa->clear();
for(int i = vec.size()-1; i >= 0;i--)
{
cout << vec[i];
ui->z_yufa->append(QString::fromStdString(vec[i]));
}
cout << endl;
ui->z_shuzi->clear();
for(int i = 0; i < shuzi.length(); i++)
{
int st = i;
if(IsDigit(shuzi[i]))
{
while(IsDigit(shuzi[i]))
{
if(i < shuzi.length())
i++;
}
ui->z_shuzi->append(QString::fromStdString(shuzi.substr(st, i-st)));
}
else
ui->z_shuzi->append(QString::fromStdString(shuzi.substr(i, 1)));
}
cout <<endl;
ui->z_op->clear();
ui->z_op->append(QString::fromStdString("下一步: "+op));
}
void MainWindow::on_showstep_clicked()
{
this->setFixedSize(SHOWWIDTH, SHOWHEIGHT);
vector<string> marker0 = this->ana.marker;
vector<string> inputstring0 = this->ana.inputstring;
vector<string> oper0 = this->ana.oper;
if(Index < marker0.size())
{
cout << "Index = " << Index<<endl;
string ii = "";
PrintStack(inputstring0[Index], marker0[Index], oper0[Index], Index == marker0.size()-1 ? "":oper0[Index+1]);
Index++;
}
}
void MainWindow::on_backinit_clicked()
{
this->setFixedSize(WIDTH, HEIGHT);
Index = 0;
ui->z_op->clear();
ui->z_yufa->clear();
ui->z_shuzi->clear();
}