189
社区成员
这个作业属于哪个课程 | 构建之法-2021秋-福州大学软件工程 https://bbs.csdn.net/forums/fzuSoftwareEngineering2021 |
---|---|
这个作业要求在哪里 | 2021秋软工实践第一次个人编程作业 https://bbs.csdn.net/topics/600574694 |
这个作业的目标 | C \ C++ 代码关键字提取,git 使用,关键字组合结构的匹配 |
学号 | 031902434 |
PSP2.1 | Personal Software Process Stage | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 20 | 30 |
Estimate | 估计这个任务需要多少时间 | 10 | 5 |
Development | 开发 | ||
Analysis | 需求分析(包括学习新技术) | 300 | 340 |
Design Spec | 生成设计文档 | ||
Design Review | 设计复审 | ||
Coding Standard | 代码规范(为目前的开发制订合适的规范) | 60 | 90 |
Design | 具体设计 | 120 | 150 |
Coding | 具体编码 | 150 | 120 |
Code Review | 代码复审 | ||
Test | 测试(自动测试、修改代码、提交修改) | 120 | 240 |
Reporting | 报告 | 60 | 80 |
Test Report | 测试报告 | ||
Size Measurement | 计算工作量 | 20 | 15 |
Postmortem&Process Improvement | 事后总结并提出过程改进计划 | ||
合计 | 860 | 1070 |
由于本人所会语言的种数限制,本次作业将由 C 和 C++ 所完成。
首先,个人第一反应是字符串匹配,于是草率暴力地以空格、回车分割从文件中提取字符串,再进行匹配,而后课程群之中的讨论使我恍然大悟,关键字提取和字符串匹配之间的不同还挺多。
上述字符串匹配之中的字符串匹配还是能用,问题在于解决如注释、宏定义、独特的输出之中包含的假“关键字”等等。而后,本人随意搜索过程之中发现了词法分析这个玩意儿,于是借鉴了下其中的思维,修改文件读取方式为逐一单个字符读取(含空格、回车),加以条件即可去除我所想到的干扰项。
由于 switch-case 暂时不考虑嵌套,此处较为简单暂且不表。而到了进行 if-else 匹配阶段时,个人感觉也得同时考虑 if-elseif-else 的匹配问题,所以关键来到将 elseif 识别出来。参考同学的一些作业以及询问朋友,最后选择暴力去除elseif之间的空格、制表符、回车以完成elseif的识别。
做好分辨 if, else, else-if 的词项识别后,先是参考“括号匹配问题“用栈的思想对三个词项进行识别,遇到 else 则进行判断。这个方法可应对完整无缺的结构匹配。好笑的是如何做到对残缺的结构进行正确匹配?个人暂时没想到完整办法,可能需要再进行’{}’以及’;’的结合判断。
commit记录:
个人代码文件规范
https://github.com/huuu-code/rabbit#readme
完整代码所存仓库
https://github.com/huuu-code/rabbit
单个字符读取方式,每次进行判断,不同类型字符处理方式不同,直到文件读取完毕。
将 switch 的出现作为一种标记,以区分不同 switch 之中的 case 数量
操作 if, else , else-if 三种标志,出现 else 进行栈顶判断和出栈操作,其余两种则入栈
读取文件,单个字符逐一读取
FILE *fin;
fin = fopen(file,"r");
if (fin == NULL) {
cout << "error!" << endl;
}
char c;
string str;
c = fgetc(fin);
剪切符合命名条件的字符串,进行关键字匹配
else if (isalpha(c) || c=='_' || isalnum(c)) {//字符为字母或数字或下划线时
string str;
while (isalpha(c) && c=='_' || isalnum(c)) {
str += c;
c = fgetc(fin);
}
index = KeySearch(str); //将拼接好的字符与关键字进行匹配查询
匹配关键字,用结构体保存关键字以及其数量
/*结构体数组
struct key {
string word;
Int count;
};*/
int KeySearch(string str){
int index = -1;
for (int i = 0; i < 32; i++) {
if(keytab[i].word == str){
keytab[i].count++;
index = i;
break;
}
}
return index; //返回关键字下标
}
switch 和 case 的组合判断, index=2表明匹配到case,数组记录case数量
if (keytab[25].count != 0) {
if(index == 2) casenum[keytab[25].count-1]++;
}
if-else 和 if-elseif-else 漏洞版匹配,if 与 elseif 都无条件入栈,碰到 else 时需要判断栈中元素是否能与其形成组合。
if (index == 15){ //匹配到 if,将1入栈
s.push(1);
}
if (index == 9) { //匹配到else接下去判断是不是仅为else
int flag=0;
while(c==' ' || c=='\n' || c=='\t') c=fgetc(fin);
if(c=='i'){
if((c=fgetc(fin))=='f'){ //匹配到else if,将3入栈
if(!s.empty()&&(s.top()!=3)) s.push(3);
flag=1;
keytab[15].count++;
}
}
if(flag==0){ //匹配到else,检查栈顶并操作
if(!s.empty()&&(s.top()==1)){
ie_count++; //if-else组合
s.pop();
}
else if(!s.empty()&&(s.top()==3)){
s.pop();
if(!s.empty()&&(s.top()==1)){
iee_count++; //if-elseif-else组合
s.pop();
}
}
}
}
单元测试由于个人代码函数的不规范以及个人能力不足,暂且用提供范例自写范例。
使用作业样例:此样例能支持通过 4 等级
自己编写样例:此样例不支持 3,4 等级
由于暂时没法下载VS,没做性能测试
个人困难与解决
一开始选择哪一种读取文件的方式,就影响到后续写匹配细节。一开始用 string 类提取文件内容,走入了字符串匹配的误区。为了走出这个误区,借鉴了词法分析,开始使用单个字符提取内容,得以解决关键字匹配问题。
在选择如何存储 case 信息,想的比较多且杂,最后也没巧妙且合适的方法,只好使用数组暂做存储,数组大小就成了麻烦之处。
做到后面要求时,了解到了正则表达式,本想学习优化下自己的代码,结果个人原因学不进去,希望以后得空耐心学学。
用栈的思想做 if else 匹配时,发现无法对残缺结构正确匹配,此处最大的困难个人无法解决。
代码并不能做到将功能模块函数化,迫于无奈只能分出简单的输出函数、匹配函数以及一个杂糅的函数。非常不方便。
任务总结
由于个人能力与时间限制,最后提交的版本仍然存在未解决的问题以及一些未知的错误。且此次作业时间大多花费在寻找思路、寻找改进方法、查找资料等等地方,最后仍然无法对已知缺陷进行弥补属实遗憾与失败。
个人感想
算是费心费力的投入比较多时间的一个作业,但由于各种原因导致最后结果也不满意吧。有做出来点什么但是又没做出来什么的感觉,比较让我颓唐且焦虑。学海无涯,坚持才能学得下去也学得更好。编程确实需要投入很多,过程可能非常的崎岖坎坷但是每解决一个小问题的时候还是非常开心的。