汇编代码生成和编译器的后端
1.前置程序:语义分析和中间代码生成
基于SLR(1)分析的语义分析及中间代码生成程序-CSDN博客https://blog.csdn.net/lijj0304/article/details/135097554?spm=1001.2014.3001.5501
2.程序目标
在前面编译器前端实现的基础上,将所生成的中间代码翻译成某种目标机的汇编代码,实现编译器后端实现的任务。然后进一步实现程序的输入是源程序,输出是汇编语言目标代码小型实验语言编译器。最终程序是实现了算式的识别和汇编代码生成的功能
3.主要数据结构
生成汇编代码用到的寄存器我直接用字符串来实现,因为寄存器仅需要存储变量名即可
char rs0[MAX_LEN];
char rs1[MAX_LEN]; // 设置两个寄存器
rs0[0] = '\0';
rs1[0] = '\0';
对于四元式构造了一个专门的数据结构来存储他的四个变量,同时构建一个四元式的数组来管理,四元式数组的大小刚好也对应了中间变量的数量。
struct quadruple {char op[MAX_LEN];char arg1[MAX_LEN];char arg2[MAX_LEN];char result[MAX_LEN];
}; // 四元式数据结构
3.程序描述
先初始化了两个寄存器R0和R1,如何通过遍历四元式的数据结构数组来生成汇编代码。主要思路是先考虑寄存器中的值,即这个四元式中是否有变量存储在了R0或者R1中。
int flag = 0; // flag为0表示两个寄存器都空闲,1表示找到第一个操作数,2表示找到第二个操作数, 3表示两个操作数都找到
int tag = -1; // tag为0表示值在rs0,1表示值在rs1
if((strcmp(rs0, quad[i].arg1) == 0 && strcmp(rs1, quad[i].arg2) == 0) || (strcmp(rs0, quad[i].arg2) == 0 && strcmp(rs1, quad[i].arg1) == 0)) { flag = 3;
}
else if(strcmp(rs0, quad[i].arg1) == 0) { flag = 1, tag = 0;
}
else if(strcmp(rs1, quad[i].arg1) == 0) { flag = 1, tag = 1;
}
else if(strcmp(rs0, quad[i].arg2) == 0) { flag = 2, tag = 0;
}
else if(strcmp(rs1, quad[i].arg2) == 0) { flag = 2, tag = 1;
}
在生成了对应四元式的汇编代码后,还需考虑这个结果值是是否在之后要被使用若不需要使用则可以直接把寄存器置空。
int use0(int p) { // 判断是否还会用到寄存器rs0内容for(int i = p; i <= quadTop; i++) {if(strcmp(quad[i].arg1, rs0) == 0 || strcmp(quad[i].arg2, rs0) == 0) {return 1;}}return 0;
}
int use1(int p) { // 判断是否还会用到寄存器rs1内容for(int i = p; i <= quadTop; i++) {if(strcmp(quad[i].arg1, rs1) == 0 || strcmp(quad[i].arg2, rs1) == 0) {return 1;}}return 0;
}
若寄存器R0和R1都不含有变量,则需要找空的及存储变量,若没有可用寄存器则需要报错
if(flag == 0) {if(rs0[0] == '\0') {printf("MOV R0, %s\n", quad[i].arg1);printf("%s R0, %s\n", opstr, quad[i].arg2);strcpy(rs0, quad[i].result);if(use0(i + 1) == 0) {rs0[0] = '\0';}}else if(rs1[0] == '\0') {printf("MOV R1, %s\n", quad[i].arg1);printf("%s R1, %s\n", opstr, quad[i].arg2);strcpy(rs1, quad[i].result);if(use1(i + 1) == 0) {rs1[0] = '\0';}}else {printf("Assembly failed\n");return;}}
如果R0和R1中有变量,则直接操作对应寄存器,生成代码即可
else if(flag == 2) {if(tag == 0) {printf("%s R0, %s\n", opstr, quad[i].arg1);strcpy(rs0, quad[i].result);if(use0(i + 1) == 0) {rs0[0] = '\0';}}else {printf("%s R1, %s\n", opstr, quad[i].arg1);strcpy(rs1, quad[i].result);if(use1(i + 1) == 0) {rs1[0] = '\0';}}}else if(flag == 3) {if(use0(i + 1) == 0) {printf("%s R0, R1\n", opstr);strcpy(rs0, quad[i].result);}else {printf("%s R1, R0\n", opstr);strcpy(rs1, quad[i].result);}}}
4.完整代码
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAX_LEN 1000struct stack {char s[MAX_LEN];int i[MAX_LEN];int point[MAX_LEN];int top;
}; // 分析栈数据结构struct quadruple {char op[MAX_LEN];char arg1[MAX_LEN];char arg2[MAX_LEN];char result[MAX_LEN];
}; // 四元式数据结构struct quadruple quad[MAX_LEN]; // 存储四元式
int quadTop = 0; // 四元式栈顶char rs0[MAX_LEN];
char rs1[MAX_LEN]; // 设置两个寄存器// 1.S→V=E 2.E→E+T 3.E→E-T 4.E→T 5.T→T*F 6.T→T/F 7.T→F 8.F→(E) 9.F→i 10.V→i
// 表中大于0对应移进,小于0则对应先归约后移进,0为不存在的状态// GOTO | ACTION//i, =, +, -, *, /, (, ), #, S, E, T, F, V
int table[20][14] ={{ 3, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2},// 0{ 0, 0, 0, 0, 0, 0, 0, 0,-11,0,0, 0, 0, 0},// 1{ 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},// 2{-10,-10,-10,-10,-10,-10,-10,-10,-10, 0, 0, 0, 0, 0},//3{ 9, 0, 0, 0, 0, 0, 8, 0, 0, 0, 5, 6, 7, 0},// 4{-1,-1,10,11,-1,-1,-1,-1,-1, 0, 0, 0, 0, 0},// 5{-4,-4,-4,-4,12,13,-4,-4,-4, 0, 0, 0, 0, 0},// 6{-7,-7,-7,-7,-7,-7,-7,-7,-7, 0, 0, 0, 0, 0},// 7{ 9, 0, 0, 0, 0, 0, 8, 0, 0, 0,14, 6, 7, 0},// 8{-9,-9,-9,-9,-9,-9,-9,-9,-9, 0, 0, 0, 0, 0},// 9{ 9, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0,15, 7, 0},//10{ 9, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0,16, 7, 0},//11{ 9, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0,17, 0},//12{ 9, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0,18, 0},//13{ 0, 0,10,11, 0, 0, 0,19, 0, 0, 0, 0, 0, 0},//14{-2,-2,-2,-2,12,13,-2,-2,-2, 0, 0, 0, 0, 0},//15{-3,-3,-3,-3,12,13,-3,-3,-3, 0, 0, 0, 0, 0},//16{-5,-5,-5,-5,-5,-5,-5,-5,-5, 0, 0, 0, 0, 0},//17{-6,-6,-6,-6,-6,-6,-6,-6,-6, 0, 0, 0, 0, 0},//18{-8,-8,-8,-8,-8,-8,-8,-8,-8, 0, 0, 0, 0, 0}};//19int english(char ch) {if((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) return 1;else return 0;
}
int number(char ch) {if(ch >= '0' && ch <= '9') return 1;else return 0;
}
int reserved(char str[]) {if(strcmp(str, "void") == 0) return 3;else if(strcmp(str, "int") == 0) return 4;else if(strcmp(str, "float") == 0) return 5;else if(strcmp(str, "double") == 0) return 6;else if(strcmp(str, "if") == 0) return 7;else if(strcmp(str, "else") == 0) return 8;else if(strcmp(str, "for") == 0) return 9;else if(strcmp(str, "do") == 0) return 10;else if(strcmp(str, "while") == 0) return 11;else if(strcmp(str, "break") == 0) return 12;else if(strcmp(str, "return") == 0) return 13;else return 1;
}
int symbol(char ch) {if(ch == ';') return 14;else if(ch == ',') return 15;else if(ch == '(') return 16;else if(ch == ')') return 17;else if(ch == '{') return 18;else if(ch == '}') return 19;else if(ch == '[') return 20;else if(ch == ']') return 21;else if(ch == '%') return 22;else if(ch == '?') return 23;else if(ch == ':') return 24;else if(ch == '\'') return 25;else if(ch == '\"') return 26;else if(ch == '.') return 27;else return 0;
}int getindex(char ch) {switch(ch) {case 'i': return 0;case '=': return 1;case '+': return 2;case '-': return 3;case '*': return 4;case '/': return 5;case '(': return 6;case ')': return 7;case '#': return 8;case 'S': return 9;case 'E': return 10;case 'T': return 11;case 'F': return 12;case 'V': return 13;default: return -1;}
}int use0(int p) { // 判断是否还会用到寄存器rs0内容for(int i = p; i <= quadTop; i++) {if(strcmp(quad[i].arg1, rs0) == 0 || strcmp(quad[i].arg2, rs0) == 0) {return 1;}}return 0;
}
int use1(int p) { // 判断是否还会用到寄存器rs1内容for(int i = p; i <= quadTop; i++) {if(strcmp(quad[i].arg1, rs1) == 0 || strcmp(quad[i].arg2, rs1) == 0) {return 1;}}return 0;
}void assembly() {printf("Assembly Code:\n"); for(int i = 1; i <= quadTop; i++) {char opstr[MAX_LEN];if(quad[i].op[0] == '=') { // 赋值语句的处理if(strcmp(quad[i].arg1, rs0) == 0){printf("MOV %s, R0\n", quad[i].result);}if(strcmp(quad[i].arg1, rs1) == 0) {printf("MOV %s, R1\n", quad[i].result);}continue;}else if(quad[i].op[0] == '+') { // 获取对应操作码字符串strcpy(opstr, "ADD");}else if(quad[i].op[0] == '-') {strcpy(opstr, "SUB");}else if(quad[i].op[0] == '*') {strcpy(opstr, "MUL");}else if(quad[i].op[0] == '/') {strcpy(opstr, "DIV");}int flag = 0; // flag为0表示两个寄存器都空闲,1表示找到第一个操作数,2表示找到第二个操作数, 3表示两个操作数都找到int tag = -1; // tag为0表示值在rs0,1表示值在rs1if((strcmp(rs0, quad[i].arg1) == 0 && strcmp(rs1, quad[i].arg2) == 0) || (strcmp(rs0, quad[i].arg2) == 0 && strcmp(rs1, quad[i].arg1) == 0)) {flag = 3;}else if(strcmp(rs0, quad[i].arg1) == 0) {flag = 1, tag = 0;}else if(strcmp(rs1, quad[i].arg1) == 0) {flag = 1, tag = 1;}else if(strcmp(rs0, quad[i].arg2) == 0) {flag = 2, tag = 0;}else if(strcmp(rs1, quad[i].arg2) == 0) {flag = 2, tag = 1;}if(flag == 0) {if(rs0[0] == '\0') {printf("MOV R0, %s\n", quad[i].arg1);printf("%s R0, %s\n", opstr, quad[i].arg2);strcpy(rs0, quad[i].result);if(use0(i + 1) == 0) {rs0[0] = '\0';}}else if(rs1[0] == '\0') {printf("MOV R1, %s\n", quad[i].arg1);printf("%s R1, %s\n", opstr, quad[i].arg2);strcpy(rs1, quad[i].result);if(use1(i + 1) == 0) {rs1[0] = '\0';}}else {printf("Assembly failed\n");return;}}else if(flag == 1) {if(tag == 0) {printf("%s R0, %s\n", opstr, quad[i].arg2);strcpy(rs0, quad[i].result);if(use0(i + 1) == 0) {rs0[0] = '\0';}}else {printf("%s R1, %s\n", opstr, quad[i].arg2);strcpy(rs1, quad[i].result);if(use1(i + 1) == 0) {rs1[0] = '\0';}}}else if(flag == 2) {if(tag == 0) {printf("%s R0, %s\n", opstr, quad[i].arg1);strcpy(rs0, quad[i].result);if(use0(i + 1) == 0) {rs0[0] = '\0';}}else {printf("%s R1, %s\n", opstr, quad[i].arg1);strcpy(rs1, quad[i].result);if(use1(i + 1) == 0) {rs1[0] = '\0';}}}else if(flag == 3) {if(use0(i + 1) == 0) {printf("%s R0, R1\n", opstr);strcpy(rs0, quad[i].result);}else {printf("%s R1, R0\n", opstr);strcpy(rs1, quad[i].result);}}}
}int SLR(char *str, struct stack *stk) { // SLR1分析函数quadTop = 0;int i = 0;int next;while(i < strlen(str)) {if(stk->top < 0) return 0; // 分析栈不可能为空int y; // 列坐标if (str[i] >= 'a' && str[i] <= 'z') y = getindex('i'); // 终结符ielse y = getindex(str[i]);if(y == -1 || table[stk->i[stk->top]][y] == 0) { // 表中不存在的状态,分析报错return 0;}if(table[stk->i[stk->top]][y] > 0) { // 移进操作next = table[stk->i[stk->top]][y];stk->top++;stk->s[stk->top] = str[i];stk->i[stk->top] = next;stk->point[stk->top] = i;i++;}else if(table[stk->i[stk->top]][y] < 0) { // 归约操作int tmp = -table[stk->i[stk->top]][y]; // 查GOTO表if(tmp == 4 || tmp == 7 || tmp == 9 || tmp == 10) {stk->top--; // 要归约1位}else if(tmp == 2 || tmp == 3 || tmp == 5 || tmp == 6){// 生成四元式quadTop++;if(tmp == 2) strcpy(quad[quadTop].op, "+");else if(tmp == 3) strcpy(quad[quadTop].op, "-");else if(tmp == 5) strcpy(quad[quadTop].op, "*");else strcpy(quad[quadTop].op, "/");if(stk->point[stk->top - 2] < 0) sprintf(quad[quadTop].arg1, "t%d", -stk->point[stk->top - 2]);else {char arg1[2] = {str[stk->point[stk->top - 2]], '\0'};strcpy(quad[quadTop].arg1, arg1);}if(stk->point[stk->top] < 0) sprintf(quad[quadTop].arg2, "t%d", -stk->point[stk->top]);else {char arg2[2] = {str[stk->point[stk->top]], '\0'};strcpy(quad[quadTop].arg2, arg2);}sprintf(quad[quadTop].result, "t%d", quadTop);stk->top -= 3; // 归约3位stk->point[stk->top + 1] = -quadTop; // 记录归约产生的中间变量}else if(tmp == 8) {stk->top -= 3; // 归约3位stk->point[stk->top + 1] = stk->point[stk->top + 2]; // 消除括号规约}else if(tmp == 1){quadTop++;strcpy(quad[quadTop].op, "=");if(stk->point[stk->top] < 0) sprintf(quad[quadTop].arg1, "t%d", abs(stk->point[stk->top]));else {char arg1[2] = {str[stk->point[stk->top]], '\0'};strcpy(quad[quadTop].arg1, arg1);}sprintf(quad[quadTop].arg2, " ");char res[2] = {str[stk->point[stk->top - 2]], '\0'};strcpy(quad[quadTop].result, res);stk->top -= 3; // 归约V=E}else stk->top -= 3;if(tmp == 1) { y = getindex('S');next = table[stk->i[stk->top]][y]; // 查ACTION表stk->top++;stk->s[stk->top] = 'S';stk->i[stk->top] = next; // 归约要修改栈顶}else if(tmp == 2 || tmp ==3 || tmp == 4) {y = getindex('E');next = table[stk->i[stk->top]][y]; stk->top++;stk->s[stk->top] = 'E';stk->i[stk->top] = next;}else if(tmp == 5 || tmp == 6 || tmp == 7) {y = getindex('T');next = table[stk->i[stk->top]][y];stk->top++;stk->s[stk->top] = 'T';stk->i[stk->top] = next;}else if(tmp == 8 || tmp == 9) {y = getindex('F');next = table[stk->i[stk->top]][y];stk->top++;stk->s[stk->top] = 'F';stk->i[stk->top] = next;}else if(tmp == 10) {y = getindex('V');next = table[stk->i[stk->top]][y];stk->top++;stk->s[stk->top] = 'V';stk->i[stk->top] = next;}else if(tmp == 11) {return 1; }}}return 0;
}int main() {for(int i = 1; i <= 2; i++){char txt1[] = "./test/test";char num[8];sprintf(num, "%d.txt", i);strcat(txt1, num);FILE *fp = fopen(txt1, "r");int flag = 0;char ch = fgetc(fp); while(!feof(fp)) {int j = 0;if(ch == ' ' || ch == '\t') {ch = fgetc(fp);continue;}else if(ch == '\n'){ch = fgetc(fp);continue;}else if(english(ch)) {do{ch = fgetc(fp);}while(english(ch)||number(ch));}else if(number(ch)) {do{ch = fgetc(fp);}while(number(ch));}else if(symbol(ch) != 0) {ch = fgetc(fp);}else if(ch == '>') {ch = fgetc(fp);if(ch == '=') {ch = fgetc(fp);}else if(ch == '>') {ch = fgetc(fp);}}else if(ch == '<') {ch = fgetc(fp);if(ch == '=') {ch = fgetc(fp);}else if(ch == '<') {ch = fgetc(fp);}}else if(ch == '!') {ch = fgetc(fp);if(ch == '=') {ch = fgetc(fp);}}else if(ch == '=') {ch = fgetc(fp);if(ch == '=') {ch = fgetc(fp);}}else if(ch == '/') {ch = fgetc(fp);if(ch == '*') {do {ch = fgetc(fp);if(ch == '*') {ch = fgetc(fp);if(ch == '/') {ch = fgetc(fp);break;}}}while(1);}else if(ch == '/') {do {ch = fgetc(fp);}while(ch != '\n');ch = fgetc(fp);}else if(ch == '=') {ch = fgetc(fp);}}else if(ch == '&') {ch = fgetc(fp);if(ch == '&') {ch = fgetc(fp);}}else if(ch == '|') {ch = fgetc(fp);if(ch == '|') {ch = fgetc(fp);}}else if(ch == '+') {ch = fgetc(fp);if(ch == '=') {ch = fgetc(fp);}else if(ch == '+') {ch = fgetc(fp);}}else if(ch == '-') {ch = fgetc(fp);if(ch == '=') {ch = fgetc(fp);}else if(ch == '-') {ch = fgetc(fp);}}else if(ch == '*') {ch = fgetc(fp);if(ch == '=') {ch = fgetc(fp);}}else if(ch == '\\') {ch = fgetc(fp);if(ch == 'n') {ch = fgetc(fp);}}else {printf("\ntest%d: Undefined Symbol!\n", i); flag = 1;break;}}if(flag == 0) printf("\ntest%d: Lexical Legal\n", i);else continue;fclose(fp);FILE *fa = fopen(txt1, "r");char input[MAX_LEN] = "";fgets(input, MAX_LEN, fa);printf("Input scentence: %s\n", input); // input为输入串int len = strlen(input);input[len] = '#';fclose(fa);struct stack *stk;stk = (struct stack *)malloc(sizeof(struct stack));stk->s[0] = '#';stk->i[0] = 0;stk->point[0] = -1;stk->top = 0; //初始化分析栈if(!SLR(input, stk)) {printf("Gramma illegal\n");}else {//printQuad(); // 打印四元式rs0[0] = '\0';rs1[0] = '\0';assembly(); // 生成汇编代码}}return 0;
}
5.测试运行
tets1:a=(b+c*d)/f+e*g
test2:a=b+(c+d)*/e
程序运行截图
相关文章:

汇编代码生成和编译器的后端
1.前置程序:语义分析和中间代码生成 基于SLR(1)分析的语义分析及中间代码生成程序-CSDN博客https://blog.csdn.net/lijj0304/article/details/135097554?spm1001.2014.3001.5501 2.程序目标 在前面编译器前端实现的基础上,将所生成的中间代码翻译成某…...
MySQL 8.0中新增的功能(九)
FROM_UNIXTIME()、UNIX_TIMESTAMP()和CONVERT_TZ()的64位支持 根据MySQL 8.0.28版本的更新,FROM_UNIXTIME()、UNIX_TIMESTAMP() 和 CONVERT_TZ() 函数现在在支持64位的平台上处理64位值。这包括64位版本的Linux、MacOS和Windows。在兼容的平台上,UNIX_T…...
QT基础篇(8)QT5模型视图结构
1.概述 QT5的模型视图结构主要包括模型(Model)、视图(View)和委托(Delegate)三个部分。 模型(Model):模型是数据的抽象表示,负责存储和管理数据。它可以是自…...

vue3-响应式基础之reactive
reactive() 还有另一种声明响应式状态的方式,即使用 reactive() API。与将内部值包装在特殊对象中的 ref 不同,reactive() 将使对象本身具有响应性: 「点击按钮1」 <script lang"ts" setup> import { reactive } from vuec…...
【ceph】如何将osd的内容挂载出来---ceph-objectstore-tool 实现
本站以分享各种运维经验和运维所需要的技能为主 《python零基础入门》:python零基础入门学习 《python运维脚本》: python运维脚本实践 《shell》:shell学习 《terraform》持续更新中:terraform_Aws学习零基础入门到最佳实战 《k8…...

怎样实现安全便捷的网间数据安全交换?
数据安全交换是指在数据传输过程中采取一系列措施来保护数据的完整性、机密性和可用性。网间数据安全交换,则是需要进行跨网络、跨网段甚至跨组织地进行数据交互,对于数据的传输要求会更高。 大部分企业都是通过网闸、DMZ区、VLAN、双网云桌面等方式实现…...

微信小程序定义并获取日志/实时log信息
步骤一:开通实时日志 可以在开发者工具->详情->性能质量->实时日志,点击前往,在浏览器打开we分析界面: 也可登录小程序管理后台,点击统计进入we分析: 在we分析界面找到性能质量,打开实…...

海外代理IP怎么用?常见使用问题及解决方案
海外代理IP是指提供全球范围内的代理服务器,代理服务器充当IP与目标网站之间的中介,可以起到安全匿名、提高网速、突破网络壁垒的作用。在使用代理IP的过程中,用户可能会遇到各种挑战,如连接问题、速度慢等。理解这些问题的原因并…...
DP:数位DP
数位DP的大致思想:枚举每一位能选取的合法值。 1. LC 2376 统计特殊整数 说是DP,但实际上状态转移方程挺难写的,毕竟是枚举集合论,这里就不贴状态转移方程了。总体的写法其实是搜索记忆化。之所以称之为DP,是因为&am…...

js逆向第21例:猿人学第20题新年挑战
文章目录 一、前言二、定位加密参数1、定位wasm加密2、反编译wasm3、定位sign加密三、代码实现四、参考文献一、前言 新春福利:抓取这5页的数字,计算加和并提交结果 二、定位加密参数 通过get请求地址可以看到需要搞定参数有page、sign、t如下图: 进入堆栈不难发现这样一…...
贪心+蓝桥杯
原题路径 题目思路 : 思路很简单,肯定是贪心做法,要使总代价最小,需用那些出现次数比avg多的数来替换那些没有出现或者是出现次数少于avg的数, 所以我们存当前数每次出现的代价是多少 ,枚举每一个 0 - 9 之间的数 ,如果当前数出现…...

第二篇:新建node项目并运行
🎬 江城开朗的豌豆:个人主页 🔥 个人专栏 :《 VUE 》 《 javaScript 》 📝 个人网站 :《 江城开朗的豌豆🫛 》 ⛺️ 生活的理想,就是为了理想的生活 ! 安装 Node.js:首先,确保你的…...

阳光保险选择OceanBase稳定运行超700天
阳光保险集团成立于 2005 年 7 月,旗下拥有财产保险、人寿保险、信用保证保险、资产管理等多家专业子公司,是全球市场化企业中成长最快的集团公司之一,目前位列中国保险行业前八。随着数字化升级趋势的不断加速,很多企业产生将软硬…...
最强大脑闪电心算草稿1
#include<bits/stdc.h> #include<windows.h> using namespace std; int main() {double speed,n,op,sum0;int ans;srand(time(NULL));cout<<"请输入加(1)/减(2)/加减混合(3):";cin>>op;cout<<"请输入题目数量:";cin>>…...
融优学堂-艺术史
导论4 1.【单选题】根据导论的讲解,下列表述正确的是()。(1)艺术品是因人的活动而被创造出来的人工制品。(2)许多物品被制造出来时,最初的目的是满足某种实用的用途,而不…...

༺༽༾ཊ—设计-七个-07-原则-模式—ཏ༿༼༻
第七原则:迪米特职责 类与类之间的耦合度尽可能低 换言之,我们可以理解成———只与直接朋友说话,不跟陌生人说话 直接朋友: 通过方法传参传进来的朋友, 类自己的字段, 构造函数进来的也是直接朋友&…...

一篇文章带你搞懂---全排序
顾得泉:个人主页 个人专栏:《Linux操作系统》 《C/C》 《LeedCode刷题》 键盘敲烂,年薪百万! 全排序(Permutation)是指将一组元素按照一定的顺序进行排列的过程。在计算机科学中,全排序是一…...
提升问题检索的能力
事实上,在信息极度丰富的时代,信息检索和筛选能力格外重要。一些搜索引擎的出现已极大地方便了我们日常的信息检索,此处需要注意的是我们不能仅仅局限于常见的搜索引擎,也需要关注和积累一些专业平台或是具有集成功能的引擎&#…...

软件测试|SQLAlchemy query() 方法查询数据
简介 上一篇文章我们介绍了SQLAlchemy 的安装和基础使用,本文我们来详细介绍一下如何使用SQLAlchemy的query()方法来高效的查询我们的数据。 创建模型 我们可以先创建一个可供我们查询的模型,也可以复用上一篇文章中我们创建的模型,代码如…...

FlinkCDC的分析和应用代码
前言:原本想讲如何基于Flink实现定制化计算引擎的开发,并以FlinkCDC为例介绍;发现这两个在表达上不知以谁为主,所以先分析FlinkCDC的应用场景和技术实现原理,下一篇再去分析Flink能在哪些方面,做定制化计算…...

【Python】 -- 趣味代码 - 小恐龙游戏
文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...

React第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...

以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...

centos 7 部署awstats 网站访问检测
一、基础环境准备(两种安装方式都要做) bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats࿰…...

P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序
一、开发环境准备 工具安装: 下载安装DevEco Studio 4.0(支持HarmonyOS 5)配置HarmonyOS SDK 5.0确保Node.js版本≥14 项目初始化: ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...

在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...
C#中的CLR属性、依赖属性与附加属性
CLR属性的主要特征 封装性: 隐藏字段的实现细节 提供对字段的受控访问 访问控制: 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性: 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑: 可以…...