汇编代码生成和编译器的后端

1.前置程序:语义分析和中间代码生成

基于SLR(1)分析的语义分析及中间代码生成程序-CSDN博客icon-default.png?t=N7T8https://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 1000

struct 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}};//19

int 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表示值在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;
        }
        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'); // 终结符i
        else 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

程序运行截图

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Windows11搭建Python环境(2)- Anaconda虚拟环境中安装Git

在搭建MetaGPT运行环境过程中&#xff0c;使用了Anaconda虚拟环境&#xff0c;在运行MetaGPT时出现错误&#xff1a; 可以看到是没有找到git指令。 在Windows上安装Git&#xff0c;可以直接去官网下载.exe文件&#xff0c;然后安装即可。 但是上面安装完成后&#xff0c;是无…

三使用Docker Hub管理镜像

使用Docker Hub管理镜像 Docker Hub是Docker官方维护的Docker Registry&#xff0c;上面存放着很多优秀的镜像。不仅如此&#xff0c;Docker Hub还提供认证、工作组结构、工作流工具、构建触发器等工具来简化我们的工作。 前文已经讲过&#xff0c;我们可使用docker search 命…

【VUE】element-ui+vue-router:实现导航栏跳转路由

实现目的 页面中点击导航栏菜单中的某一选项卡&#xff0c;使用导航栏进行路由跳转。如下图所示。 我们设计三个页面&#xff0c;首页是App.vue, 两个导航页面分别为 About.vue, Home.vue。在App.vue 页面中有导航菜单&#xff0c;点击菜单分别跳转。 1. 安装 npm install v…

2024中国国际光伏展

2024中国国际光伏展将是中国举办的一个重要的展览会&#xff0c;专门展示光伏技术和产业的最新发展。该展览会将吸引国内外光伏企业、研究机构、政府机构和专业人士参展和参观。 在2024年的中国国际光伏展上&#xff0c;参展商将展示他们最新的光伏技术、设备和产品&#xff0c…

Jetson AGX Orin安装archiconda、Pytorch

想在Jetson AGX Orin创建一个虚拟环境&#xff0c;然后安装pytorch&#xff0c;过程中遇到了很多的坑&#xff0c;这篇文章主要用于记录过程~因为Orin本身是Arm架构&#xff0c;X86架构可以装Anaconda&#xff0c;对于ARM要装archiconda。 1.安装archiconda 1.1确定操作系统架…

[自动驾驶算法][从0开始轨迹预测]:二、自动驾驶系统中常用的坐标系及相应的转换关系

自动驾驶中常见的坐标系与坐标转换 1. 传感器坐标系1.1 相机坐标系统1) 相机相关基础知识2) 相机各坐标系图像/像素坐标系相机坐标系像平面坐标系 3) 相机各坐标系之间的转换像平面坐标系到像素坐标系的转换&#xff08;平移缩放变换&#xff09;相机坐标系转像平面坐标系&…

uniCloud ---- uni-captch实现图形验证码

目录 用途说明 组成部分 目录结构 原理时序 云端一体组件介绍 验证码配置&#xff08;可选&#xff09;&#xff1a; 普通验证码组件 公共模块 云函数公用模块 项目实战 创建云函数 创建注册页 创建云函数 关联公用模块 uni-captcha 刷新验证码 自定义实现 验…

【实战记录】 vagrant+virtualbox+docker 轻松用虚拟机集成组件

用途 最近要学一大堆组件&#xff0c;不想直接安装本机上&#xff0c;然后gpt说&#xff1a;你可以用vagrant起个虚拟机&#xff08;然后docker拉取各种组件的镜像&#xff09;&#xff1b;或者k8s 实战的整体思路 首先安装virtualbox和vagrant。然后cmd依次键入三条命令 安…

Linux批量快速修改文件名的三种方法

在Linux中&#xff0c;批量重命名文件是一项常见且有用的操作。以下是三种常用的批量重命名文件的方法&#xff0c;每种方法都附有示例。这些方法既可以适用于新手&#xff0c;也适用于更有经验的用户。 话不多说&#xff0c;直接上干货&#xff01; rename 命令 rename命令是…

ITE IT6801FNBX HDMI接收器 芯片

一、物料概述 IT6801FN是一款单端口HDMI接收器&#xff0c;可在HDMI1.4和MHL2.1双模式下工作&#xff0c;完全兼容MHL2.1、HDMI 1.4a、HDMI 1.4a3D和HDCP1.4&#xff0c;还可向后兼容DVI 1.0规格。IT6801FN具有深彩色功能&#xff08;高达36位&#xff09;&#xff0c;可确保接…

Redis主从+哨兵集群(基于CentOS-8.0)高可用部署方案

目录 一、环境描述 二、Redis 主从集群部署 2.1 Redis下载 2.2 Redis解压 和移动文件 2.4 编译、安装Redis 2.6 新建 bin 和 etc 文件夹 2.7 分发Redis 2.8 配置 2.8.1 主节点配置 2.8.2 从节点配置 2.9 启动Redis服务 2.10 验证主从服务 2.11 查看节点角色信息 2…

k8s的存储卷、数据卷---动态PV创建

当发布PVC之后可以生成PV&#xff0c;还可以在动态服务器上直接生成挂载目录。PVC直接绑定和使用PV。 动态PV需要两个组件 存储卷插件&#xff1a;Provisioner(存储分配器)根据定义的属性创建PV StorageClass&#xff1a;定义属性 存储卷插件 存储卷插件&#xff1a;k8s本…

从“AI证件照”到“AI译制片”,爆款AIGC应用的商业化迷思

文 | 脑极体 让郭德纲飙英文、让霉霉说中文的翻译视频生成工具HeyGen和掀起AI证件照热潮的“妙鸭相机”一样&#xff0c;在一阵疯狂刷屏之后&#xff0c;又迅速在各大群里销声匿迹了。 十月份&#xff0c;由HeyGen制作的各种明星跨语言翻译视频&#xff0c;在全网疯传&#xf…

C#微信公众号HIS预约挂号系统源码

微信公众号预约挂号系统、支付宝小程序预约挂号系统主要是让自费、医保患者在手机上就能实现就医全过程&#xff0c;实时预约挂号、自费、医保结算&#xff0c;同时还可以查询检查检验报告等就诊信息&#xff0c;真正实现了让信息“多跑路”&#xff0c;让群众“少跑腿”。系统…

【C++】- 类和对象(运算符重载!!const!!详解!!)

类和对象③ 介绍运算符重载赋值运算符重载运算符重载const 在学习C语言时&#xff0c;我们首先接触的就是变量&#xff0c;再深入学习&#xff0c;我们可以利用运算符对变量进行操作&#xff0c;当我们使用C编写程序时&#xff0c;经常会遇到一些需要对特殊的例如自定义数据类型…

制造工厂ERP系统:从数字销售-生产到财务管理,掌握企业数字化十大核心!

在快速发展的数字化时代&#xff0c;企业&#xff08;尤其是传统生产制造行业&#xff09;面临着诸多挑战与机遇。无论是客户体验、供应链管理还是内部流程优化&#xff0c;数字化都在发挥着关键作用。为了更好地应对数字化带来的挑战和机遇为了更好地应对市场变化和提高竞争力…

定了!又一电商巨头拥抱鸿蒙生态

鸿蒙生态 未来可期 近日&#xff0c;鸿蒙生态圈又发布一个令人振奋的消息&#xff1a;京东正式适配原生鸿蒙操作系统&#xff01;这是继支付宝、微信之后&#xff0c;又一家大厂拥抱鸿蒙的重要举措。可以说&#xff0c;拥抱鸿蒙已经成为了大势所趋&#xff01; ​ 随着大厂纷…

本地静态资源打包出来,本地配置ng访问服务器(uniapp打包成h5后,使用打包资源连接测试环境测试)

1.下载ng https://nginx.org/en/download.html 2.解压下载的压缩包 3.打包h5静态资源 4.将打包出来的资源放入ng -》html文件夹下面 5.进入ng-》conf-》nginx.conf 进行转发配置 6.启动ng服务&#xff0c;点击nginx.exe 7.浏览器直接访问http://localhost:8081/#/&#x…

Linux------进程的fork()详解

目录 前言 一、fork()的使用 二、fork()的返回值 我们为什么要创建子进程&#xff1f; 父进程与子进程的分流 三、fork的一些难理解的问题 1.fork干了什么事情&#xff1f; 2.fork为什么会有两个返回值 3.fork的两个返回值&#xff0c;为什么会给父进程返回子进程pid…

05--多表操作

1、多表操作 现实生活中&#xff0c;&#xff08;班级&#xff09;实体与&#xff08;学生&#xff09;实体之间肯定是有关系的&#xff0c;那么我们在设计表的时候&#xff0c;就应该体现出&#xff08;班级&#xff09;表与&#xff08;学生&#xff09;表之间的这种关系&am…