编译技术实验三之编译器的构造和设计
一、实验目的:
我们将设计多个不同的综合实验项目提供给学生选择。(如:LL(1)文法自动生成语法分析程序的设计;单词的自动识别与智能纠错;语言的程序编辑器;数学计算式的识别等)学生可在这些项目中选择1个项目,体现了实验技术的全面性和先进性。综合实验将以编译原理、技术为基础,结合前期课程,加上实际需求和学生自己的设计才能完成。这些前期课程接口包括离散数学、数据结构、C++程序设计语言、操作系统、汇编语言、数据库原理等。通过综合实验使学生设计制作出有一定水平的编译程序,使学生更好地掌握编译原理和基本技术
设计一个小型编译器。
二、实验内容及原理
以高级程序设计语言的编译原理和基本技术,加上实际编辑程序过程的需求,把综合实验项目分层次展开,经过小组学生的分工与合作加上创意才能完成。
设计的语言上可以使用编译性语言,也可以使用解释性语言。实验的结果是一个编译器或一个综合编译技术的应用软件。




三、实验过程原始数据记录
主要结构:
char terminal[50]; //终结符
set<string>Noter; //非终结符
vector<string>nt;
vector<string>t;
int tNum;//终结符个数
int nNum;//非终结符个数
string Production[50] = { "" };//产生式
string ReProduction[50] = { "" };//新产生式
int ProNum;//产生式个数
int ReProNum = 0;//新产生式个数
vector<pair<string, string>>I;//所有项目
vector<pair<string, string>>closure;//项目的闭包
vector<pair<string, string>>project;
vector<pair<string, string>>Start;
map<pair<int, string>, int>table;
string str;
unordered_map<int, vector<pair<int, string>>>LRtable;
unordered_map<int, vector<pair<string, int>>>state;
string lrtable[100][100] = { "-1" };
vector<int>sq;//状态栈
vector<char>inputStr, sign;//全体字符以及符号栈
主要函数:
void Gramma()
void GrammaF()
void get_project()
vector<pair<string, string>> get_closure(const vector<pair<string, string>>& pro)
vector<pair<string, string>> Goto(const vector<pair<string, string>>& pro, const string& flag)
vector<vector<pair<string, string>>> get_all_closure(const vector<pair<string, string>>& pro)
int get_num(string s)
int getChar(char ch)
int get_rnext(string s)
void get_LRTable(vector<vector<pair<string, string>>>allclosure)
void init()
string outPut(int i)
void check()
void analyst()
源代码:
#include<iostream>
#include<vector>
#include<string>
#include<set>
#include<unordered_map>
#include<iomanip>
#include<map>
using namespace std;char terminal[50]; //终结符
set<string>Noter; //非终结符
vector<string>nt;
vector<string>t;
int tNum; //终结符个数
int nNum; //非终结符个数
string Production[50] = { "" }; //产生式
string ReProduction[50] = { "" }; //新产生式
int ProNum; //产生式个数
int ReProNum = 0; //新产生式个数
vector<pair<string, string>>I; //所有项目
vector<pair<string, string>>closure; //项目闭包
vector<pair<string, string>>project;
vector<pair<string, string>>Start;
map<pair<int, string>, int>table;
string str;
unordered_map<int, vector<pair<int, string>>>LRtable;
string lrtable[100][100] = { "-1" };
unordered_map<int, vector<pair<string, int>>>state;
vector<int>sq;//状态栈
vector<char>inputStr, sign;//全体字符以及符号栈void Gramma() {cout << "--------------------------" << endl;cout << "请输入终结符的个数:";cin >> tNum;cout << "请输入终结符:" << endl;for (int i = 0; i < tNum; i++) {cin >> terminal[i];string st;st.push_back(terminal[i]);t.push_back(st);}cout << "请输入非终结符的个数:";cin >> nNum;cout << "请输入非终结符:" << endl;for (int i = 0; i < nNum; i++) {string s;cin >> s;Noter.insert(s);nt.push_back(s);t.push_back(s);}cout << "请输入产生式的个数:";cin >> ProNum;cout << "请输入产生式:" << endl;for (int i = 0; i < ProNum; i++) {cin >> Production[i];}
}void GrammaF() {int x = 0, z = 1;//x为第z个产生式的第x个字符for (int i = 0; i < ProNum; i++) {x = 3;int k = 0;while (x < Production[i].size()) {for (k = 0; k < 3; k++) {//获取产生式的左部以及箭头ReProduction[z] += Production[i][k];}while (x < Production[i].size() && Production[i][x] != '|') {ReProduction[z] += Production[i][x];x++;}z++;x++;}}string s = ReProduction[1].substr(0, 1) + "'";str = s;ReProduction[0] = s + "->" + ReProduction[1].substr(0, 1);t.push_back(s);Noter.insert(s);nt.push_back(s);nNum++;ReProNum = z;project.push_back({ s,ReProduction[1].substr(0, 1) });for (int i = 1; i < ReProNum; i++) {string fir = ReProduction[i].substr(0, 1);string sec = ReProduction[i].substr(3);project.push_back({ fir,sec });}
}void get_project() {I.push_back({ ReProduction[0].substr(0,2),"." + ReProduction[0].substr(4) });Start.push_back({ ReProduction[0].substr(0,2),"." + ReProduction[0].substr(4) });I.push_back({ ReProduction[0].substr(0,2),ReProduction[0].substr(4) + "." });for (int i = 1; i < ReProNum; i++) {string First = "";First += ReProduction[i][0];string Second = ReProduction[i].substr(3);for (int j = 0; j <= Second.size(); j++) {string tmp = Second;tmp.insert(j, ".");I.push_back({ First,tmp });}}for (int i = 0; i < I.size(); i++) {cout << I[i].first << " " << I[i].second << endl;}
}vector<pair<string, string>> get_closure(const vector<pair<string, string>>& pro) {vector<pair<string, string>>closure = pro;auto Size = closure.size();string first;for (int i = 0; i < Size; i++) {auto pos = closure[i].second.find(".");if (pos == string::npos) {cout << "error" << endl;cout << closure[i].first << "-->>" << closure[i].second << endl;return closure;}auto c = closure[i].second[pos + 1];first.push_back(c);if (Noter.find(first) == Noter.end()) {first.clear();continue;}for (int i = 0; i < project.size(); i++) {if (first == project[i].first) {auto second = project[i].second;second.insert(0, ".");bool flag = 0;for (int j = 0; j < Size; j++) {if (second == closure[j].second) {flag = 1;break;}}if (flag == 0) {closure.push_back({ first,second });}}}first.clear();Size = closure.size();}return closure;
}vector<pair<string, string>> Goto(const vector<pair<string, string>>& pro, const string& f) {vector<pair<string, string>>nextJ;for (int i = 0; i < pro.size(); i++) {auto p = pro[i].second.find(".");if (p == string::npos) {cout << "error" << endl;return nextJ;}else {auto ch = pro[i].second[p + 1];if (ch == '\0')continue;string temp;temp.push_back(ch);if (temp != f)continue;else{auto first = pro[i].first;auto second = pro[i].second;second[p] = second[p + 1];second[p + 1] = '.';nextJ.push_back({ first, second });}}}auto T = nextJ;nextJ = get_closure(T);return nextJ;
}vector<vector<pair<string, string>>> get_all_closure(const vector<pair<string, string>>& pro) {vector<vector<pair<string, string>>>allclosure;allclosure.push_back(pro);auto size = allclosure.size();for (int i = 0; i < size; i++) {set<string>flag;auto len = allclosure[i].size();for (int j = 0; j < len; j++) {auto pos = allclosure[i][j].second.find(".");if (pos == string::npos) {cout << "error" << endl;return allclosure;}else {auto ch = allclosure[i][j].second[pos + 1];if (ch == '\0') {continue;}string str;str.push_back(ch);flag.insert(str);}}for (set<string>::iterator it = flag.begin(); it != flag.end(); it++) {auto closure = Goto(allclosure[i], *it);if (closure.size() == 0)continue;else {bool stop = 0;for (int j = 0; j < size; j++) {if (allclosure[j] == closure) {table.insert({ {i,*it},j });stop = 1;break;}}if (stop == 1) {continue;}allclosure.push_back(closure);int sz = allclosure.size() - 1;table.insert({ {i,*it}, sz });}}size = allclosure.size();}return allclosure;
}int get_num(string s) {for (int i = 0; i < t.size(); i++) {if (t[i] == s) {return i;}}return -1;
}int get_rnext(string s) {for (int i = 0; i < project.size(); i++) {if (s == project[i].second) {return i;}}return -1;
}void get_LRTable(vector<vector<pair<string, string>>>allclosure) {for (int i = 0; i < allclosure.size(); i++) {for (int j = 0; j < t.size(); j++) {lrtable[i][j] = "-1";}}vector<pair<int, int>>nums;bool st[100] = { false };int acc;for (map<pair<int, string>, int>::iterator it = table.begin(); it != table.end(); it++){int from = it->first.first;int next = it->second;string s = it->first.second;auto Inext = allclosure[next];auto Ifrom = allclosure[from];lrtable[from][get_num(s)] = "s" + to_string(next);for (int j = 0; j < Ifrom.size(); j++) {auto pos = Ifrom[j].second.find(".");if (pos == Ifrom[j].second.size() - 1 && Ifrom[j].first != str) {int rnext = get_rnext(Ifrom[j].second.substr(0, Ifrom[j].second.size() - 1));nums.push_back({ from,rnext });}if (pos == Ifrom[j].second.size() - 1 && Ifrom[j].first == str) {acc = from;}}st[from] = true;}lrtable[acc][get_num("#")] = "acc";for (int i = 0; i < allclosure.size(); i++) {if (!st[i]) {for (int j = 0; j < allclosure[i].size(); j++) {auto pos = allclosure[i][j].second.find(".");if (pos == allclosure[i][j].second.size() - 1) {int rnext = get_rnext(allclosure[i][j].second.substr(0, allclosure[i][j].second.size() - 1));nums.push_back({ i,rnext });}}}}for (int i = 0; i < nums.size(); i++) {int f = nums[i].first, rnext = nums[i].second;for (int j = 0; j < tNum; j++) {lrtable[f][j] = "r" + to_string(rnext);}}for (int i = 0; i < allclosure.size(); i++) {for (int j = 0; j < t.size(); j++) {if (lrtable[i][j] != "-1") {LRtable[i].push_back({ j,lrtable[i][j] });}}}
}int getChar(char ch) {string s;s.push_back(ch);for (int i = 0; i < t.size(); i++) {if (t[i] == s)return i;}return -1;
}
void init() {for (map<pair<int, string>, int>::iterator it = table.begin(); it != table.end(); it++){state[it->first.first].push_back({ it->first.second,it->second });}
}string outPut(int i) {char buf[100];int count = 0;if (i == 0) {string str;for (vector<int>::iterator it = sq.begin(); it != sq.end(); it++) {int c = *it;str += to_string(c);}return str;}else if (i == 1) {for (vector<char>::iterator it = sign.begin(); it != sign.end(); it++) {buf[count++] = *it;}}else {for (vector<char>::iterator it = inputStr.begin(); it != inputStr.end(); it++) {buf[count++] = *it;}}buf[count] = '\0';string str(buf);return str;
}
void check() {int step = 1;sign.push_back('#');sq.push_back(0);cout << setw(10) << "步骤" << setw(10) << "状态栈" << setw(10) << "符号栈" << setw(10) << "输入串" << setw(25) << "动作说明" << endl;int s = 0;int oldstatus;char ch = inputStr.front();int c = getChar(ch);if (c == -1) {cout << "error" << endl;return;}while (lrtable[s][getChar(ch)] != "acc") {string sstr = lrtable[s][getChar(ch)];int s1 = 0;for (int i = 1; i < sstr.size(); i++) {s1 = s1 * 10 + (sstr[i] - '0');}s = s1;if (sstr == "-1") {cout << "error" << endl;return;}if (sstr.substr(0, 1) == "s") {cout << setw(10) << step << setw(10) << outPut(0) << setw(10) << outPut(1) << setw(10) << outPut(2) << setw(10) << "A" << "CTION[" << sq.back() << "," << ch << "]=S" << s << "," << "状态" << s << "入栈" << endl;sign.push_back(ch);inputStr.erase(inputStr.begin());sq.push_back(s);}else if (sstr.substr(0, 1) == "r") {string formu = ReProduction[s];string stop = project[s].first;int strlen = formu.size();int popnum = strlen - 3;int i = 0;for (vector<int>::reverse_iterator it = sq.rbegin(); it != sq.rend(); it++) {i++;if (i == popnum + 1) {oldstatus = *it;break;}}int r = s;for (int i = 0; i < state[oldstatus].size(); i++) {if (state[oldstatus][i].first == stop) {s = state[oldstatus][i].second;}}cout << setw(10) << step << setw(10) << outPut(0) << setw(10) << outPut(1) << setw(10) << outPut(2) << setw(10) << "r" << r << (string)":" + Production[r] + (string)"归约,GOTO{" << oldstatus << "," << 'E' << ")=" << s << "入栈" << endl;for (int i = 0; i < popnum; i++) {sq.pop_back();sign.pop_back();}sq.push_back(s);sign.push_back(stop[0]);}step++;s = sq.back();ch = inputStr.front();}cout << setw(10) << step << setw(10) << outPut(0) << setw(10) << outPut(1) << setw(10) << outPut(2) << setw(10) << "A" << "cc:分析成功" << endl;
}
void analyst() {init();string s;cout << "请输入字符串(+,-,*,/,E,i,(,),#):" << endl;cin >> s;for (int i = 0; i < s.size(); i++)inputStr.push_back(s[i]);if (inputStr.back() != '#')inputStr.push_back('#');check();
}int main() {Gramma();GrammaF();get_project();auto S = get_closure(Start);auto allclosure = get_all_closure(S);for (int i = 0; i < allclosure.size(); i++) {cout << "I" << i << ":" << endl;for (int j = 0; j < allclosure[i].size(); j++) {cout << allclosure[i][j].first << "->" << allclosure[i][j].second << endl;}}cout << table.size() << endl;cout << "\n转换关系:" << endl;for (map<pair<int, string>, int>::iterator it = table.begin(); it != table.end(); it++){cout << "[ " << it->first.first << ", " << it->first.second << " ] -> " << it->second << endl;}get_LRTable(allclosure);for (int i = 0; i < project.size(); i++) {cout << ReProduction[i] << endl;}for (int i = 0; i < allclosure.size(); i++) {for (int j = 0; j < t.size(); j++) {cout << lrtable[i][j] << " ";}cout << endl;}analyst();}
结果:

语法分析:

生成项目集

拓广文法

生成LR分析表


四、实验总结
通过这个实验,我认识到编译器的重要性和复杂性。在设计和构造编译器的过程中,我需要考虑语法分析、词法分析、语义分析等多个环节,同时还要处理错误处理、优化等问题。在实验中,我需要将学习到的几个章节的理论知识转化为实际可执行的代码。我学会了如何根据给定的文法和规则构建语法分析树,如何设计和实现词法分析器,如何进行语义分析和中间代码生成等。在设计和构造编译器的过程中,我遇到了很多困难和挑战,需要不断地debug,这有利于巩固了我的编程能力,提高我的设计思维和解决问题的能力。
相关文章:
编译技术实验三之编译器的构造和设计
一、实验目的: 我们将设计多个不同的综合实验项目提供给学生选择。(如:LL(1)文法自动生成语法分析程序的设计;单词的自动识别与智能纠错;语言的程序编辑器;数学计算式的识别等)学生可在这些项目中选择1个项…...
数据挖掘——数据预处理
数据挖掘——数据预处理 数据预处理数据预处理 ——主要任务数据清洗如何处理丢失的数据如何处理噪声数据如何处理不一致数据 数据集成相关分析相关系数(也成为皮尔逊相关系数)协方差 数据规约降维法:PCA主成分分析降数据——抽样法数据压缩 数据预处理 数据预处理…...
ECharts饼图下钻
背景:项目上需要对Echarts饼图进行功能定制,实现点击颜色块,下钻显示下一层级占比说明:饼图实现点击下钻/面包屑返回的功能 数据结构 [{name: a,value: 1,children: [...]},... ]点击下钻 // 为图表绑定点击事件(需要…...
【RK3568笔记】Android修改开机动画
概述 Android 的开机动画是由一系列连续的 PNG 图片作为帧组成的动画形式,不是一张 GIF 图片。将各帧 PNG 图片以压缩方式进行保存(压缩方式要求是存储压缩),并将保存的文件名命名为 bootanimation.zip,这个 bootanim…...
嵌入式技术之Linux(Ubuntu) 一
一、Linux入门 1.硬件和操作系统以及用户的关系 一个传感器,获得数据后,需要向服务器发送数据。传感器传数据给上位机。 上位机需要一个程序来接收数据,那么这个上位机是什么机器? 我们的笔记本电脑就可以当成上位机。 两个手…...
代码随想录day39 动态规划7
打家劫舍 题目:198.打家劫舍 213.打家劫舍II 337.打家劫舍III 需要重做:全部 198.打家劫舍 思路:第i个房子偷与不偷,取决于第i-2个房子和第i-1个房子 注意:注意下标的一致性。现在的下标含义是房子的下标&#x…...
ESP32-S3模组上实现低功耗(5)
接前一篇文章:ESP32-S3模组上实现低功耗(4) 本文内容参考: 系统低功耗模式介绍 - ESP32-S3 - — ESP-IDF 编程指南 latest 文档 电源管理 - ESP32-S3 - — ESP-IDF 编程指南 latest 文档...
PDF转文本以及转图片:itextpdf
文章目录 🐒个人主页:信计2102罗铠威🏅JavaEE系列专栏📖前言:🎀 1. itextpdf1.1导入itextpdf的maven依赖1.2 提取文本代码1.3 pdf转换成图片代码(本地图片地址还是线上PDF的URL地址均支持&#…...
AnaConda下载PyTorch慢的解决办法
使用Conda下载比较慢,改为pip下载 复制下载链接到迅雷下载 激活虚拟环境,安装whl,即可安装成功 pip install D:\openai.wiki\ChatGLM2-6B\torch-2.4.1cu121-cp38-cp38-win_amd64.whl...
移动端自动化测试Appium-java
一、Appium的简介 移动端的自动化测试框架 模拟人的操作进行功能自动化常用于功能测试、兼容性测试 跨平台的自动化测试 二、Appium的原理 核心是web服务器,接受客户端的连接,接收客户端的命令,在手机设备上执行命令,收集命令…...
IO: 作业:Day1
思维导图 main.c #include"student.h" int main(int argc, const char *argv[]) { stuPtr hcreat(); int n0; add_node(h); add_node(h); add_node(h); show(h); save(h,"student.txt"); stuPtr ptrc…...
ue5 替换角色的骨骼网格体和动画蓝图
一开始动画蓝图,骨骼网格体都是用的女性角色 现在把它换成男性 编译 保存 运行 把动画类换成ABP_Manny 进入ABP_Manny中 进入到idle 找到这个拖进来 编译 就变成站着端枪 运行一下,没有问题...
el-cascader 树状选择-点击父级禁用子级
背景:项目上需要实现树状选择,点击父级禁用子级的功能,element组件本身没有该配置项说明:需要实现几个功能点:点击父级禁用子级;再次点击取消禁用;仅回填所选级;上下级不关联实现代码…...
AWS re:Invent 的创新技术
本月早些时候,Amazon 于 12 月 1 日至 5 日在内华达州拉斯维加斯举行了为期 5 天的 re:Invent 大会。如果您从未参加过 re:Invent 会议,那么最能描述它的词是“巨大”——不仅从与会者人数(60,000 人)来看&…...
PHP7和PHP8的最佳实践
php 7 和 php 8 的最佳实践包括:使用类型提示以避免运行时错误;利用命名空间组织代码并避免命名冲突;采用命名参数、联合类型等新特性增强可读性;用错误处理优雅地处理异常;关注性能优化,如避免全局变量和选…...
Debian、Ubuntu 22.04和ubuntu 24.04国内镜像源(包括 docker 源)
Debian 更换国内清华源 1、备份原文件mv /etc/apt/sources.list /etc/apt/sources.list.old 2、写入新源,以下是 Debian 11 的: cat > /etc/apt/sources.list << EOF deb https://mirrors.tuna.tsinghua.edu.cn/debian/ bullseye main contrib…...
点亮一个esp32 的led
最近入了一个ESP32 兄弟们,这玩意还可以,买来肯定是给它点亮啊对吧 我就是点灯侠🎇 😭千万不要不接天线啊,不然你会一直找不到你的wifi 1.点灯第一步你得有IDE Arduino 就是这个绿东西 可是怎么下载安装呢ÿ…...
C++ shared_ptr进一步认知,为什么引用计数>2退出作用域都可以调用析构
1.使用智能指针需要#include <memeroy> 2.上代码: #include <memory> #include <iostream> using namespace std; struct lifePeriod {lifePeriod():a(1){cout << "无参构造!" << endl;}virtual ~lifePeriod(…...
JavaScript代码片段二
见过不少人、经过不少事、也吃过不少苦,感悟世事无常、人心多变,靠着回忆将往事串珠成链,聊聊感情、谈谈发展,我慢慢写、你一点一点看...... JavaScript统计文字个数、特殊字符转义、动态插入js代码、身份证验证 统计文字个数 f…...
【计算机视觉】单目深度估计模型-Depth Anything-V2
概述 本篇将简单介绍Depth Anything V2单目深度估计模型,该模型旨在解决现有的深度估计模型在处理复杂场景、透明或反射物体时的性能限制。与前一代模型相比,V2版本通过采用合成图像训练、增加教师模型容量,并利用大规模伪标签现实数据进行学…...
ollama部署本地大模型|granite-4.0-h-350m在在线教育平台智能答疑中的应用
ollama部署本地大模型|granite-4.0-h-350m在在线教育平台智能答疑中的应用 1. 在线教育答疑的痛点与解决方案 在线教育平台最头疼的问题之一,就是学生随时提出的各种问题。传统的人工答疑方式存在明显瓶颈:老师回复不及时、夜间无人值守、重…...
系统流程图绘制技巧与Visio实战指南
1. 系统流程图基础与Visio入门 第一次接触系统流程图时,我也被那些奇怪的符号搞得一头雾水。直到接手一个库存管理系统项目,才真正理解这些图形背后的逻辑。系统流程图就像建筑师的蓝图,用标准化符号展示数据在系统中的流动路径。Visio作为流…...
解决Python虚拟环境激活脚本PowerShell执行权限问题
1. 为什么你的Python虚拟环境激活脚本无法运行? 最近在Windows上使用Python虚拟环境时,是不是经常遇到这样的错误提示:"无法加载文件...\Activate.ps1,因为在此系统上禁止运行脚本"?这个问题困扰过不少Pytho…...
别光看exp!深入理解pwn1_sctf_2016中C++字符串替换引发的栈溢出
从C字符串替换到栈溢出:pwn1_sctf_2016漏洞的深层解析 当我们在CTF比赛中遇到一个看似简单的栈溢出题目时,往往会习惯性地寻找明显的缓冲区溢出点。但pwn1_sctf_2016这道题却巧妙地利用了C字符串处理的特性,将简单的"I"替换为"…...
告别‘为发烧而生’:UE5.3手游这样调,中低端机也能满帧跑
让UE5.3手游在中低端设备上流畅运行的实战指南 当你的UE5.3手游项目在高端测试机上跑得风生水起,却在千元机上卡成幻灯片时,那种挫败感每个技术负责人都深有体会。设备性能的"天花板"与用户设备的"地板"之间的矛盾,正是移…...
Wavelet-SRNet: Enhancing Face Super Resolution with Multi-scale Wavelet Transform and CNN
1. 从模糊到清晰:Wavelet-SRNet如何重塑人脸超分辨率技术 想象一下,你手里有一张20年前的老照片,分辨率只有1616像素,人脸模糊得连五官都难以辨认。传统超分辨率技术就像用放大镜看马赛克,放大后依然是一团糊。这正是W…...
MGeo门址解析模型实际作品分享:1000+真实地址文本结构化结果集
MGeo门址解析模型实际作品分享:1000真实地址文本结构化结果集 1. 引言:从混乱文本到清晰结构,地址解析的价值有多大? 想象一下,你收到了一条用户留言:“麻烦送到朝阳区望京SOHO塔3B座15层1501室ÿ…...
通义千问1.5-1.8B-Chat-GPTQ-Int4 Java面试备战:八股文解析与模拟面试
通义千问1.5-1.8B-Chat-GPTQ-Int4 Java面试备战:八股文解析与模拟面试 1. 引言:当AI面试官遇上Java八股文 又到了金三银四的招聘季,后台收到不少朋友的私信,都在问同一个问题:“Java面试到底该怎么准备?八…...
Win11 WSL2 + Ubuntu 24.04 下,如何让nRF开发板(DK)被VS Code和NCS v3.0.0正确识别?
Win11 WSL2环境下nRF开发板与NCS v3.0.0深度集成指南 当嵌入式开发遇上WSL2的Linux高效编译环境,硬件连接往往成为最后一道障碍。本文将彻底解决nRF开发板在Windows主机与WSL2 Ubuntu子系统间的识别难题,打造无缝硬件调试体验。 1. 环境准备与核心工具链…...
Phi-3 Forest Lab免配置环境:Docker镜像+Streamlit美学前端部署
Phi-3 Forest Lab免配置环境:Docker镜像Streamlit美学前端部署 1. 项目概述 "在森林的深处,听见智慧的呼吸。"Phi-3 Forest Lab是一个基于微软Phi-3 Mini 128K Instruct模型构建的极简主义AI对话终端,将前沿AI技术与自然美学设计…...
