使用C++实现LR(0)语法分析器的操作_c++lr0-程序员宅基地

技术标签: C++  编译器  语法分析  编译原理  

使用C++ 完成LR(0)的语法分析器

由于最近学校里在学习编译原理,而且要求实现语法分析器,于是我用了几天的时间搞明白了语法分析器的原理并且将其实现了。由于编者还是本科生而且还在学习中,因此出现什么错误请各位指点。
语法分析器的步骤为:

  1. 读入单词序列
  2. 读入语法规则
  3. 构造基于该语法的Clousure(项目集规范族)集合
  4. 基于上一步构造所有规范句型活前缀的DFA
  5. 根据这个DFA来构造Action表与Goto表(统称为分析表)
  6. 根据分析表来进行分析(具体的分析方法不再赘述)

由于编者对于所有的处理都是使用字符串与字符进行的,所以在代码理解方面与执行效率方面可能较差。有什么问题都可以与笔者交流,我的Q是1574143668。
所以相应的代码如下,使用的是IDE是Visual Studio 2017,可以供大家参考:
具体的代码文件在https://download.csdn.net/download/kiva12138/10750255

#include "pch.h"
#include <iostream>
#include <string>
#include <sstream> 
#include <fstream> 
#include <map>
#include <typeinfo>

#define MAXNUM 1000
#define ERROR "err"
#define ACCUTATE "acc"
#define MAXNUMOFCLOUSURE 100
#define MAXNUMOFITEM 100
#define MAXNUMOFCHAR 30

using namespace std;

class StatusStack{
protected:
	int list[MAXNUM];
	int currentPos;
public :
	StatusStack() {
		currentPos = -1;
	}

	int getTop() {
		return this->list[currentPos];
	}

	int getCurrentPos() {
		return this->currentPos;
	}

	int getElement(int pos) {
		return this->list[pos];
	}

	void clear() {
		currentPos = -1;
	}

	void pop() {
		currentPos = currentPos - 1;
	}

	void push(int status) {
		list[currentPos+1] = status;
		currentPos++;
	}
};

class SymbolStack {
protected:
	char list[MAXNUM];
	int currentPos;
public:
	SymbolStack() {
		list[0] = '#';
		currentPos = 0;
	}

	char getTop() {
		return this->list[currentPos];
	}

	int getCurrentPos() {
		return this->currentPos;
	}

	char getElement(int pos) {
		return this->list[pos];
	}

	void clear() {
		list[0] = '#';
		currentPos = 0;
	}

	void pop() {
		currentPos = currentPos - 1;
	}

	void push(char str) {
		list[currentPos + 1] = str;
		currentPos++;
	}
};

class ActionMap {//table[status, inputChar]
protected:
	map <int, map<int, string> > table;
	int numOfStatus;
	int numOfInputChar;

public:
	ActionMap(int numOfStatus, int numOfInputChar){
		this->numOfInputChar = numOfInputChar;
		this->numOfStatus = numOfStatus;
		
		for (int i = 0; i < numOfStatus; i++) {
			for (int j = 0; j < numOfInputChar; j++) {
				table[i][j] = ERROR;
			}
		}
	}

	void insert(int status, int inputChar, string ele) {
		table[status][inputChar] = ele;
	}

	void remove(int status, int inputChar) {
		table[status][inputChar] = ERROR;
	}

	string getElement(int status, int inputChar) {
		return table[status][inputChar];
	}
};

class GotoMap {//table[status, inputStatus]
protected:
	map <int, map<int, int> > table;
	int numOfStatus;
	int numOfInputStatus;

public:
	GotoMap(int numOfStatus, int numOfInputStatus) {
		this->numOfInputStatus = numOfInputStatus;
		this->numOfStatus = numOfStatus;

		for (int i = 0; i < numOfStatus; i++) {
			for (int j = 0; j < numOfInputStatus; j++) {
				table[i][j] = -1;
			}
		}
	}

	void insert(int status, int inputChar, int ele) {
		table[status][inputChar] = ele;
	}

	void remove(int status, int inputChar) {
		table[status][inputChar] = -1;
	}

	int getElement(int status, int inputChar) {
		return table[status][inputChar];
	}
};

class DFAMap {//[a, b]=B 从状态a接受B到达状态b
protected:
	map <int, map<int, char> > table;
	int firstStatus;
	int secondStatus;
public:
	DFAMap(int numOfStatus) {
		this->firstStatus = numOfStatus;
		this->secondStatus = numOfStatus;

		for (int i = 0; i < numOfStatus; i++) {
			for (int j = 0; j < numOfStatus; j++) {
				table[i][j] = '*';
			}
		}
	}

	void insert(int status1, int status2, char ele) {
		table[status1][status2] = ele;
	}

	void remove(int status1, int status2) {
		table[status1][status2] = '*';
	}

	char getElement(int status1, int status2) {
		return table[status1][status2];
	}
};

class NumOfInputChar {
protected:
	map<int, char> table;
	int sum;
public :
	NumOfInputChar() {
		this->sum = 0;
	}
	int getSum() {
		return this->sum;
	}
	void inset(char ch) {
		table [sum++] = ch;
	}
	int getNumber(char ch) {
		for (int i = 0; i <= sum; i++) {
			if (table[i] == ch) {
				return i;
			}
		}
		return -1;
	}
};

class NumOfInputStatus {
protected:
	map<int, char> table;
	int sum;
public:
	NumOfInputStatus() {
		this->sum = 0;
	}
	void inset(int i) {
		table[sum++] = i;
	}
	int getNumber(int in) {
		for (int i = 0; i <= sum; i++) {
			if (table[i] == in) {
				return i;
			}
		}
		return -1;
	}
};

class Item {
public :
	int posOfDot;
	string item;
public :
	Item() {
		for (int i = 0; i < 30; i++) {
			this->item += '\0';
		}
	}
};

class Clousure {
public:
	int numOfItem;
	Item grammer[MAXNUMOFITEM];
};

void printSymbolStack(SymbolStack symbolStack) {
	int num = symbolStack.getCurrentPos();
	cout << "符号栈的内容为:" << endl;
	for (int i = 0; i <= num; i++) {
		cout << symbolStack.getElement(i) << " ";
	}
	cout << endl;
}

void printStatusStack(StatusStack statusStack) {
	int num = statusStack.getCurrentPos();
	cout << "状态栈的内容为:" << endl;
	for (int i = 0; i <= num; i++) {
		cout << statusStack.getElement(i) << " ";
	}
	cout << endl;
}

void getInputSymbol(string strInput[], int * numOfSymbol) {
	//ifstream fp("input.txt");
	ifstream fp("input_test.txt");
	string strRead[MAXNUM];
	string temp;
	if (fp.fail()) {
		std::cout << "Can not open the source file";
		exit(0);
	}
	int num = 0;
	while (getline(fp, temp)) {
		strInput[num++] = temp;
	}
	*numOfSymbol = num;
}

void getGrammer(string grammerInput[], int * numOfGrammer) {
	ifstream fp("grammer_test.txt");
	string temp;
	int grammerHasRead = 0;
	if (fp.fail()) {
		std::cout << "Can not open the source file";
		exit(0);
	}
	int num = 0;
	while (getline(fp, temp)) {
		grammerInput[num++] = temp;
	}
	*numOfGrammer = num;
}

bool grammerAnalysis(string strInput[], ActionMap actionMap, GotoMap gotoMap, 
					StatusStack statusStack, SymbolStack symbolStack,
					NumOfInputStatus numOfInputStatus, NumOfInputChar numOfInputChar, 
					string grammerInput[]) {

	statusStack.push(0);
	int i = 0;
	int lastAction = 0;//记录上一动作,0表示移进, 1表示归约

	while (1) {
		if (lastAction == 0) {

			char temp[1];
			strInput[i].copy(temp, 1, 0);
			char inputChar = temp[0];
			string actionToDo = "";
			actionToDo = actionMap.getElement(statusStack.getTop(), numOfInputChar.getNumber(inputChar));
			if (actionToDo == ACCUTATE) {
				return true;
			}
			else if (actionToDo == ERROR) {
				return false;
			}
			if (actionToDo[0] == 'S') {
				//移进操作
				statusStack.push(actionToDo[1] - 48);
				symbolStack.push(inputChar);
				i++;
				lastAction = 0;

				//打印信息
				cout << "移进操作:" <<"移进"<< inputChar << endl;
				printStatusStack(statusStack);
				printSymbolStack(symbolStack);
				cout << endl;
			}
			else if (actionToDo[0] == 'R') {
				//归约操作 使用actionToDo[1]产生式
				int numOfGrammer = actionToDo[1] - 48;
				int startPosOfGrammer = 0;//产生式开始的位置
				int endPosOfGrammer = 0;//产生式结束的的分号的位置
				
				char temp[1];
				grammerInput[numOfGrammer-1].copy(temp, 1, endPosOfGrammer);
				char todoChar = temp[0];
				while (todoChar != ';') {
					grammerInput[numOfGrammer-1].copy(temp, 1, endPosOfGrammer);
					todoChar = temp[0];
					endPosOfGrammer++;
				}
				endPosOfGrammer--;

				int numOfPop = endPosOfGrammer - startPosOfGrammer - 1;
				for (; numOfPop > 0; numOfPop--) {
					symbolStack.pop();
					statusStack.pop();
				}
				grammerInput[numOfGrammer-1].copy(temp, 1, startPosOfGrammer);
				char charToPush = temp[0];
				symbolStack.push(charToPush);

				lastAction = 1;

				//打印信息
				cout << "归约操作:" << "使用第" << actionToDo[1] - 48 << "个产生式" << endl;
				printStatusStack(statusStack);
				printSymbolStack(symbolStack);
				cout << endl;
			}
			else {
				cout << "符号表识别错误" << endl;
				getchar();
				exit(0);
			}
			continue;
		}
		else if (lastAction == 1) {
			int statusToGo = gotoMap.getElement(statusStack.getTop(), numOfInputStatus.getNumber(symbolStack.getTop()));
			if (statusToGo == -1) {
				return false;
			}
			statusStack.push(statusToGo);
			lastAction = 0;
			//打印信息
			cout << "状态转移:" << "转移到第" << statusToGo << "状态" << endl;
			cout << endl;
			continue;
		}
	}
}

void makeAnalysisChart(string grammerInput[], ActionMap * actionMap, GotoMap * gotoMap, 
						NumOfInputChar * numOfInputChar, NumOfInputStatus * numOfInputStatus, int numOfGrammer) {	
	//构造Clousure, s代表S', 其余为大写S
	//首先构造最基本的0与1号状态
	int numOfClousure = 0;
	Clousure clousure[MAXNUMOFCLOUSURE];
	clousure[0].numOfItem = 1;
	clousure[0].grammer[0].posOfDot = 1;
	clousure[0].grammer[0].item = "s.S";
	clousure[1].numOfItem = 1;
	clousure[1].grammer[0].item = "sS.";
	clousure[1].grammer[0].posOfDot = 2;

	int numOfInitClo = 2;
	for (int i = 0; i < numOfGrammer; i++) {
		char chs[MAXNUMOFCHAR];
		int numOfCh = 0;
		for (int j = 0; j<MAXNUMOFCHAR; j++) {
				char temp[1];
				grammerInput[i].copy(temp, 1, j);
				if (temp[0] == ';') {
					break;
				}
				chs[j] = temp[0];
				numOfCh = j;
			}
		for (int j = 2; j <= numOfCh+1; j++) {
			clousure[numOfInitClo].numOfItem = 1;
			bool b = false;
			for (int k = 0; k <= numOfCh+1; k++) {
				if (k == j) {
					b = true;
					clousure[numOfInitClo].grammer[0].item[j] = '.';
					continue;
				}
				if (b) {
					clousure[numOfInitClo].grammer[0].item[k] = chs[k-1];
				}
				else {
					clousure[numOfInitClo].grammer[0].item[k] = chs[k];
				}
			}
			clousure[numOfInitClo].grammer[0].posOfDot = j;
			numOfInitClo++;
		}
	}

	while (numOfClousure < numOfInitClo) {
		int lastNumOfItem = clousure[numOfClousure].numOfItem;
		while (1) {
			char toDoChar = clousure[numOfClousure].grammer[clousure[numOfClousure].numOfItem - 1].item[clousure[numOfClousure].grammer[clousure[numOfClousure].numOfItem - 1].posOfDot + 1];
			if (toDoChar == '\0') {
				numOfClousure++;
				break;
			}
			for (int i = 0; i < numOfGrammer; i++) {
				char temp[1];
				grammerInput[i].copy(temp, 1, 0);
				char firstGrammerChar = temp[0];

				if (firstGrammerChar == toDoChar) {
					stringstream stream;
					stream << firstGrammerChar;
					string itemToInsert = stream.str() + '.';
					bool ifExist = false;
					for (int k = 1; ; k++) {
						char tempChs[1];
						grammerInput[i].copy(tempChs, 1, k);
						char tempCh = tempChs[0];
						if (tempCh == ';') {
							break;
						}
						itemToInsert = itemToInsert + tempCh;
					}
					for (int k = 0; k < clousure[numOfClousure].numOfItem; k++) {
						if (itemToInsert == clousure[numOfClousure].grammer[k].item) {
							ifExist = true;
							break;
						}
					}
					if (ifExist) {
						continue;
					}

					clousure[numOfClousure].grammer[clousure[numOfClousure].numOfItem].item = itemToInsert;
					clousure[numOfClousure].grammer[clousure[numOfClousure].numOfItem].posOfDot = 1;
					clousure[numOfClousure].numOfItem++;

				}
			}

			if (lastNumOfItem == clousure[numOfClousure].numOfItem) {
				numOfClousure++;
				break;
			}
			lastNumOfItem = clousure[numOfClousure].numOfItem;

		}
	}

	cout << "计算得出的闭包:" << endl << endl;
	for (int ik = 0; ik < numOfInitClo; ik++) {
		cout << "Clousure" << ik << ":" << endl;
		for (int j = 0; j < clousure[ik].numOfItem; j++) {
			cout << clousure[ik].grammer[j].item[0] << "->";
			for (int i = 1; i <= clousure[ik].grammer[j].item.length(); i++) {
				cout << clousure[ik].grammer[j].item[i];
			}
			cout << endl;
		}
	}
	cout << endl;

	//下面构造DFA
	DFAMap * dfaMap = new DFAMap(numOfInitClo);
	for (int n = 0; n < numOfInitClo; n++) {
		for (int m = 0; m < clousure[n].numOfItem; m++) {
			string itemToCal = clousure[n].grammer[m].item;
			char chToMove = clousure[n].grammer[m].item[clousure[n].grammer[m].posOfDot+1];//需要使用的符号
			if (chToMove == '\0') {
				continue;
			}
			itemToCal[clousure[n].grammer[m].posOfDot+1] = '.';
			itemToCal[clousure[n].grammer[m].posOfDot] = chToMove;
			for (int t = 0; t < numOfInitClo; t++) {
				for (int e = 0; e < clousure[t].numOfItem; e++) {
					string itemToCmp = clousure[t].grammer[e].item;
					//cout << itemToCal.c_str() << "==" << itemToCmp.c_str() << "=" << endl;
					if (strcmp(itemToCal.c_str() , itemToCmp.c_str()) == 0) {
						//cout << "OK"<< endl;
						dfaMap->insert(n, t, chToMove);
					}
				}
			}
		}
	}

	//下面构造分析表
	for (int k = 0; k < numOfInitClo; k++) {
		if (k == 1) {//第1号一定是sS.
			actionMap->insert(k, numOfInputChar->getNumber('#'), ACCUTATE);
			continue;
		}
		for (int g = 0; g < clousure[k].numOfItem; g++) {
			string tempItem = clousure[k].grammer[g].item;
			if (tempItem[clousure[k].grammer[g].posOfDot+1] == '\0') {
				tempItem[clousure[k].grammer[g].posOfDot] = '\0';
				for (int h = 0; h < numOfGrammer; h++) {
					string tempGrammmer = grammerInput[h];
					tempGrammmer[tempGrammmer.length() - 1] = '\0';
					if (strcmp(tempGrammmer.c_str(), tempItem.c_str()) == 0) {
						//k状态 全部为R(h+1)
						string str = "R" + to_string(h+1);
						for (int v = 0; v < numOfInputChar->getSum(); v++) {
							actionMap->insert(k, v, str);
						}
						break;
					}
				}
				continue;
			}
			char tempCh = tempItem[clousure[k].grammer[g].posOfDot + 1];
			if (numOfInputChar->getNumber(tempCh) >= 0) {
				for (int d = 0; d < numOfClousure; d++) {
					if (dfaMap->getElement(k, d) == tempCh) {
						string tempStr = "S"+ to_string(d);
						actionMap->insert(k, numOfInputChar->getNumber(tempCh), tempStr);
					}
				}
				continue;
			}
			if (numOfInputStatus->getNumber(tempCh) >= 0) {
				for (int d = 0; d < numOfClousure; d++) {
					if (dfaMap->getElement(k, d) == tempCh) {
						gotoMap->insert(k, numOfInputStatus->getNumber(tempCh),d);
					}
				}
				continue;
			}
			cout << endl << "识别符号出错!" << endl;
			exit(0);
		}
	}
}

int main()
{
	int symbolNum = 0;
	string inputSymbol[MAXNUM];
	getInputSymbol(inputSymbol, &symbolNum);
	cout << "输入序列:" << endl;
	for (int i = 0; i <= symbolNum; i++) {
		cout << inputSymbol[i];
	}
	cout << endl << endl;

	int grammerNum;
	string grammerInput[MAXNUM];
	getGrammer(grammerInput, &grammerNum);
	cout << "语法序列:" << grammerNum << "个" << endl;
	for (int i = 0; i < grammerNum; i++) {
		cout << grammerInput[i] << endl;
	}
	cout << endl;

	cout << "构造语法分析表......" << endl << endl;
	ActionMap *action = new ActionMap(7, 3);//7个状态, 3个终结符
	NumOfInputChar *numOfInputChar = new NumOfInputChar;//与上面相对应的终结符集合
	numOfInputChar->inset('a');
	numOfInputChar->inset('b');
	numOfInputChar->inset('#');
	
	GotoMap *gotoMap = new GotoMap(7, 2);//7个状态,2个非终结符
	NumOfInputStatus *numOfInputStatus = new NumOfInputStatus;//非终结符集合
	numOfInputStatus->inset('S');
	numOfInputStatus->inset('B');
	
	makeAnalysisChart(grammerInput, action, gotoMap, numOfInputChar, numOfInputStatus, grammerNum);

	//Test
	cout << "Action表:" << endl;
	for (int i = 0; i < 7; i++) {
		for (int j = 0; j < 3; j++) {
			cout << action->getElement(i, j) << " ";
		}
		cout << endl;
	}
	cout << endl;

	cout << "Goto表:" << endl;
	for (int i = 0; i < 7; i++) {
		for (int j = 0; j < 2; j++) {
			cout << gotoMap->getElement(i, j) << " ";
		}
		cout << endl;
	}
	cout << endl;
	
	cout << "语法分析表构造完毕......" << endl << endl;

	cout << "开始语法分析......" << endl << endl;
	StatusStack *statusStack = new StatusStack;
	SymbolStack *symbolStack = new SymbolStack;

	bool result = grammerAnalysis(inputSymbol, *action, *gotoMap,
									*statusStack, *symbolStack,
									*numOfInputStatus, *numOfInputChar,
									grammerInput);

	if (result) {
		cout << endl << "成功完成语法分析!"  << endl << endl;
	}
	else {
		cout << endl << "语法分析失败!" << endl << endl;
	}
	cout << "结束语法分析......" << endl;
	
	getchar();
	return 0;
}

最后的结果大家可以看一下:

输入序列:
bab#

语法序列:3个
S->BB;
B->aB;
B->b;

构造语法分析表......

计算得出的闭包:

Clousure0:
s->.S
S->.BB
B->.aB
B->.b
Clousure1:
s->S.
Clousure2:
S->B.B
B->.aB
B->.b
Clousure3:
S->BB.
Clousure4:
B->a.B
B->.aB
B->.b
Clousure5:
B->aB.
Clousure6:
B->b.

Action表:
S4 S6 err
err err acc
S4 S6 err
R1 R1 R1
S4 S6 err
R2 R2 R2
R3 R3 R3

Goto表:
1 2
-1 -1
-1 3
-1 -1
-1 5
-1 -1
-1 -1

语法分析表构造完毕......

开始语法分析......

移进操作:移进b
状态栈的内容为:
0 6
符号栈的内容为:
# b

归约操作:使用第3个产生式
状态栈的内容为:
0
符号栈的内容为:
# B

状态转移:转移到第2状态

移进操作:移进a
状态栈的内容为:
0 2 4
符号栈的内容为:
# B a

移进操作:移进b
状态栈的内容为:
0 2 4 6
符号栈的内容为:
# B a b

归约操作:使用第3个产生式
状态栈的内容为:
0 2 4
符号栈的内容为:
# B a B

状态转移:转移到第5状态

归约操作:使用第2个产生式
状态栈的内容为:
0 2
符号栈的内容为:
# B B

状态转移:转移到第3状态

归约操作:使用第1个产生式
状态栈的内容为:
0
符号栈的内容为:
# S

状态转移:转移到第1状态


成功完成语法分析!

结束语法分析......

最后祝大家学习愉快,大家加油!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/kiva12138/article/details/83477418

智能推荐

用opencv的aruco库生成二维码marker标记_树莓派opencv识别aruco二维码-程序员宅基地

文章浏览阅读1k次。用opencv的aruco库生成二维码marker标记代码来源于官方提供的完整的工作实例create_marker.cpp。在opencv源码中的位置为opencv_contrib-4.4.0/modules/aruco/samples/create_marker.cpp。#include <opencv2/highgui.hpp>#include <opencv2/aruco.hpp>#include <iostream>using namespace cv_树莓派opencv识别aruco二维码

ajax vue写入mysql,vue发送ajax请求详解-程序员宅基地

文章浏览阅读141次。vue本身不支持发送AJAX请求,需要使用vue-resource(vue1.0版本)、axios(vue2.0版本)等插件实现axios是一个基于Promise的HTTP请求客户端,用来发送请求,也是vue2.0官方推荐的,同时不再对vue-resource进行更新和维护本文为大家介绍vue使用axios发送AJAX请求首页安装并引入axios1、npm install axios -S..._vue3 axios 传递 mysql

【技巧】arcgis读取nc格式文件并导出为tif_nc转tif后arcmap不重合-程序员宅基地

文章浏览阅读1.5w次,点赞15次,收藏109次。nc格式数据是遥感领域中常见的一种图像格式,由于其具有灵活性, 能够传输海量的面向阵列(array-oriented)数据, 现在已经成为许多数据采集软件生成文件的格式, 被广泛用于陆地、海洋和大气科学。_nc转tif后arcmap不重合

servlet项目里,通过getParameter方法获取内容是为null的一个原因_servlet数据库this.stmt is null-程序员宅基地

文章浏览阅读1.7k次。就是你在jsp代码的第一行没有加上Encoding=UTF-8这句话导致服务器无法解析你传入的数据,就不会有返回值啦,在这里卡了好久,把方法写出来推荐给大家,大佬勿喷啊..._servlet数据库this.stmt is null

Java项目:ERP管理系统(java+SpringBoot+EasyUI+maven+mysql)_java erp项目-程序员宅基地

文章浏览阅读7.3k次,点赞15次,收藏114次。源码获取:博客首页 "资源" 里下载!项目介绍系统主要功能包括:首页零售管理:零售出库、零售退货;采购管理:采购订单、采购入库、采购退货;销售管理:销售订单、销售出库、销售退货;仓库管理:其它入库、其它出库、调拨出库、组装单、拆卸单;财务管理:收入单、支出单、收款单、付款单、转账单、收预付款;报表查询:库存状况、结算账户、进货统计、销售统计、入库明细、出库明细、入库汇总、出库汇总、客户对账、供应商对账、库存预警;商品管理:商品类别、商品信息、计量单位、序列号;基本资料:供应商信._java erp项目

11月13日任务-程序员宅基地

文章浏览阅读233次。11.10/11.11/11.12 安装PHP5 PHP官网 www.php.net 当前主流版本为5.6/7.1 cd /usr/local/src/ wget http://cn2.php.net/distributions/php-5.6.30...._my_bool

随便推点

Bugku CTF-Web篇writeup 3-11_ctf 3-11-程序员宅基地

文章浏览阅读1.2k次,点赞4次,收藏6次。Flask_FileUpload由题目名得知的信息,显然是个文件上传的题目,flask:一种python的web框架首先Ctrl+U查看页面源代码,一般能看到题目提示支持jpg,png格式的文件上传,绿色的英文提示意思是上传文件,它会解析python代码并返回运行结果,所以上传php木马的并不能成功在txt文档中写一段py程序来调用系统命令导入 os模块 pyhon的os模块包含了普通的系统操作功能,这里os.system('')执行了ls命令因为上传有格式的限制,所以要重命_ctf 3-11

cv2.warpAffine()参数详解_cv2.warpaffine 参数-程序员宅基地

文章浏览阅读5.8k次。官方给出的参数为:cv2.warpAffine(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]]) →dst其中:src - 输入图像。M - 变换矩阵。dsize - 输出图像的大小。flags - 插值方法的组合(int 类型!)borderMode - 边界像素模式(int 类型!)borderValue -..._cv2.warpaffine 参数

strncpy_s 的正确打开方式-程序员宅基地

文章浏览阅读6.1k次,点赞5次,收藏9次。​最近遇到了一个奔溃问题,程序在执行到某个点后,瞬间干干净净的退出,也没有dmp文件生成。这个奔溃在指定场景下出现,于是用Windbg执行程序,准备在奔溃点进行分析。想法很好,但是在奔溃点,看不到堆栈信息。于是通过日志及问题出现场景,确定了怀疑点。但是在怀疑点,并没有看出问题。因为,我先入为主的以为,strncpy_s会做边界检测,不会越界访问及复制。根据Windbg给出的诊断信息以及咨询同事,在TerminateProcess函数上加断点,运行程序,程序在TerminateProces.._strncpy_s

如何使用远程Linux虚拟机的图形界面_linux 远程传输文件 图形界面-程序员宅基地

文章浏览阅读1.7w次,点赞4次,收藏6次。本文介绍了两种操作远程Linux虚拟机图形界面的方法。_linux 远程传输文件 图形界面

C++ 一个简单的判断子网掩码是否有效的函数_c判断子网掩码合法-程序员宅基地

文章浏览阅读3.7k次。简介子网掩码(subnet mask)又叫网络掩码、地址掩码、子网络遮罩,它是一种用来指明一个IP地址的哪些位标识的是主机所在的子网,以及哪些位标识的是主机的位掩码。子网掩码不能单独存在,它必须结合IP地址一起使用。子网掩码只有一个作用,就是将某个IP地址划分成网络地址和主机地址两部分。子网掩码是一个32位的2进制数, 其对应网络地址的所有位都置为1,对应于主机地址的所有位都置为0。所以,子网..._c判断子网掩码合法

Properties文件中反斜杠作用_properties特殊字符转义-程序员宅基地

文章浏览阅读2.1k次。在properties文件中使用反斜杠\的方式:转义字符属性的值有特殊字符时,可以使用反斜杠\转义字符换行太长的属性值如果属性值太长,可以用反斜杠\在分隔test=aaaaaaaaaaaaa\bbbbb等价于:test=aaaaaaaaaaaaabbbbb扩展换行符换行符 \ntest=aaaaa\nbbbbb\nccccc输出:aaaaabbbbbccccc..._properties特殊字符转义

推荐文章

热门文章

相关标签