南京邮电大学《基于编译原理的表达式计算器》

news2024/11/27 1:44:28

文章目录

  • 一、课题内容和要求
  • 二、课题需求分析
    • 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”, "T
F”, “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();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/940733.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第十套教程序言:阻止对Sub和Functions的直接访问

【分享成果&#xff0c;随喜正能量】引擎利用后退的力量&#xff0c;引发更大的动能&#xff1b;空气经过压缩&#xff0c;更具爆破的威力。所谓"退一步想&#xff0c;海阔天空。"正可点破我们迷妄执着的盲点。。 《VBA高级应用30例》&#xff08;10178985&#xff0…

前端Excel导入数据后端数据库表未添加主键导致Excel导入数据重复

Java对Excel等文档解析上传到数据库或服务器问题记录 临时功能展示数据库表未添加主键导致Excel导入数据重复 如图,问题发现是因为Excel表中只有两千多条数据但导入数据库后却有五千多条,当时在代码中疯狂找原因也未果,最后尝试给数据库添加主键解决问题! 去除重复数据 总条…

渗透测试漏洞原理之---【CSRF跨站请求伪造】

文章目录 1、CSRF概述1.1、基本原理1.1.1、基本概念1.1.2、关键点1.1.3、目标 1.2、CSRF场景1.2.1、银行支付转账1.2.2构造虚假网站1.2.3、场景建模 1.3、CSRF类别1.3.1、POST方式 1.4、CSRF验证1.4.1、CSRF PoC Generator 2、CSRF攻防2.1、CSRF实战2.1.1、与XSS 漏洞相结合 2.…

构建简单的Node.js HTTP服务器,发布公网远程访问的快速方法

文章目录 前言1.安装Node.js环境2.创建node.js服务3. 访问node.js 服务4.内网穿透4.1 安装配置cpolar内网穿透4.2 创建隧道映射本地端口 5.固定公网地址 前言 Node.js 是能够在服务器端运行 JavaScript 的开放源代码、跨平台运行环境。Node.js 由 OpenJS Foundation&#xff0…

超实用的快递单号一键查询方法,帮你省时又省力

快递查询是我们日常生活中经常需要进行的操作&#xff0c;然而&#xff0c;当我们有多个快递单号需要查询时&#xff0c;逐个查询就显得非常繁琐和耗时。为了解决这个问题&#xff0c;今天给大家推荐一款实用的软件——【固乔快递查询助手】。 首先&#xff0c;在浏览器中搜索并…

单片机最小系统构成

51单片机最小系统构成 &#xff1a; 四部分组成 &#xff08;1&#xff09;晶振电路 &#xff08;2&#xff09;复位电路 &#xff08;3&#xff09;电源电路 &#xff08;4&#xff09;下载电路 &#xff08;1&#xff09;晶振电路干嘛的&#xff1f; 单片机需要 时钟 来…

day27 String类 正则表达式

String类的getBytes方法 String s "腻害"; byte[] bytes s.getBytes(StandardCharsets.UTF_8); String类的new String方法 String ss "ss我的"; byte[] gbks ss.getBytes("gbk"); String gbk new String(gbks, "gbk"); String类的…

CSDN每日一练 |『异或和』『生命进化书』『熊孩子拜访』2023-08-27

CSDN每日一练 |『异或和』『生命进化书』『熊孩子拜访』2023-08-27 一、题目名称&#xff1a;异或和二、题目名称&#xff1a;生命进化书三、题目名称&#xff1a;熊孩子拜访 一、题目名称&#xff1a;异或和 时间限制&#xff1a;1000ms内存限制&#xff1a;256M 题目描述&…

bp利用CSRF漏洞(dvwa)

打开dvwa&#xff0c;将难度调为low&#xff0c;点击CSRF&#xff0c;打开后发现有一个修改密码的输入框&#xff1a; 在这里修改密码&#xff0c;并用bp抓包&#xff0c;在http history查看数据包&#xff0c;点击engagement tools中的Generate CSRF Poc根据请求包生成一个CSR…

checkstyle检查Java编程样式:工具类应该隐藏default或者public构造器

所谓工具类&#xff0c;就是在API中只有静态的方法或者属性。对工具类应该隐藏default或者public构造器&#xff0c;方法就是构造器的访问属性设为private的、或者protected&#xff08;如果希望有子类的话&#xff09;。 背后的原理&#xff1a;对工具类进行实例化没有意义。…

Redis数据类型(list\hash)

"we had our heads in the clouds" String类型 字符串类型是Redis最基础的数据类型&#xff0c;关于字符串需要特别注意的是: ● Redis中所有的键类型都是字符串类型.⽽且其他⼏种数据结构也都是在字符串类似基础上构建的&#xff0c;例如列表和集合的元素类型是字符…

社保先关事宜

个人账户实行完全积累制 在社保账户中&#xff0c;有“统筹账户”和“个人账户”&#xff0c;缴费基数均为当地上年度在岗职工平均工资&#xff0c;单位所缴费用相当于缴费基数的20%&#xff0c;进入社会统筹账户。个人所缴费用相当于缴费基数的8%&#xff0c;进入个人账户&am…

抖店总是有人给中差评怎么办?聊下抖店的运营,对你有帮助的!

我是王路飞。 做抖店的商家&#xff0c;最想要的就是店铺爆单以及客户给出好评了。 但是也只能是想想了&#xff0c;每个做抖店或者说做网店的&#xff0c;不可能没遇到过中差评&#xff0c;我们能做的就是尽量避免。 那么抖店总是有人给中差评怎么办呢&#xff1f; 给你们…

分布式锁之mysql实现

本地jvm锁 搭建本地卖票案例 package com.test.lockservice.service.impl;import com.test.lockservice.mapper.TicketMapper; import com.test.lockservice.service.TicketService; import org.springframework.beans.factory.annotation.Autowired; import org.springframew…

定时任务库的详解与魅力应用:探索schedule的无尽可能性

文章目录 摘要一些示例其他的示例向任务传递参数取消任务运行一次任务获取所有任务取消所有任务按标签获取多个任务以随机间隔运行作业运行一项作业&#xff0c;直到某个时间距离下次执行的时间立即运行所有作业&#xff0c;无论其计划如何在后台运行多个调度器 记录日志自定义…

海康机器人工业相机 Win10+Qt+Cmake 开发环境搭建

文章目录 一. Qt搭建海康机器人工业相机开发环境 一. Qt搭建海康机器人工业相机开发环境 参考这个链接安装好MVS客户端 Qt新建一个c项目 cmakeList中添加海康机器人的库&#xff0c;如下&#xff1a; cmake_minimum_required(VERSION 3.5)project(HIKRobotCameraTest LANG…

微信小程序隐私协议接入

自2023年9月15日起&#xff0c;对于涉及处理用户个人信息的小程序开发者&#xff0c;微信要求&#xff0c;仅当开发者主动向平台同步用户已阅读并同意了小程序的隐私保护指引等信息处理规则后&#xff0c;方可调用微信提供的隐私接口。 相关公告见&#xff1a;关于小程序隐私保…

计算机竞赛 基于机器视觉的二维码识别检测 - opencv 二维码 识别检测 机器视觉

文章目录 0 简介1 二维码检测2 算法实现流程3 特征提取4 特征分类5 后处理6 代码实现5 最后 0 简介 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于机器学习的二维码识别检测 - opencv 二维码 识别检测 机器视觉 该项目较为新颖&#xff0c;适合作为竞赛课…

格创校园跑腿小程序独立版v2.0.7+前端

应用介绍 格创校园跑腿SAAS管理系统小程序独立版v2.0.7前端 格创校园跑腿小程序系统独立版是一款基于ThinkPHP6框架开发的多校园专业跑腿平台&#xff0c;可应用至小区、街区、园区、厂区等。 格创校园跑腿小程序系统是校园创业版块热门应用&#xff0c;全新UI界面&#xff0c…

(202308)科研论文配图 task5 安装LaTex + 书籍第二章SciencePlots部

SciencePlots 序言阅读笔记绘图包介绍Windows下安装Windows下的安装MikTexWindows下的安装ghostscript加入系统环境变量安装scienceplots 序言 有幸在这次的组队学习活动中&#xff0c;拜读宁海涛先生的《科研论文配图绘制指南——基于python》一书&#xff0c;这本书文辞亲切…