李 菊,傅向华,马军超
(深圳技术大学大数据与互联网学院,广东 深圳 518000)
在线评测(Online Judge,OJ)系统是一种在教学实验、程序设计竞赛、企业软件类岗位招聘、培训、计算机等级认证等活动中用来评测代码的在线系统。该系统由前端和后端两部分组成;用户可以在前端Web 界面提交源代码及测试用例,然后在后端对所提交的源代码进行编译;最后系统将根据测试用例基线对源代码输出进行评估,将源代码的准确性、内存占用及运行时间输出在前端Web 界面。目前著名的OJ系统有北京大学的Peking University Online Judge(POJ)、浙江大学的Zhejiang University Online Judge(ZOJ)、杭州电子科技大学的Hangzhou Dianzi University Online Judge(HDOJ)等[1]。这些在线评测系统只能对学生提交的源代码的正确性、内存及性能进行评测,而无法对代码的规范性进行评测。这导致学生代码编程规范意识薄弱,编写的代码可读性差、低效、稳定性及可扩展性差,提交的代码质量无法保证。
随着互联网的快速发展,各软件企业也开始逐步重视软件的代码质量。无论是阿里发布的《Java 开发手册》;还是华为投入20亿美元,计划用五年时间提高代码质量,都充分突显出软件企业对软件代码质量的重视程度[2]。高质量代码体现为:正确性、可读性、高效性、稳定性、可维护性、可扩展性。因此编码不仅要实现完整的功能,而且要保证代码具有良好的可读性、高效性、稳定性、可维护性、可扩展性。遵循代码编程规范的习惯是代码高质量特性的保证。因此为了更好的适应企业人才需求,急需基于代码编程规范,对现有实验教学的在线判题系统进行改造升级,以让学生养成遵循代码编程规范的习惯,提高学生的代码质量。
本系统架构由上至下主要分为三层,即Web 界面层、业务逻辑层、数据层。Web 服务器主要用于用户题目录入,代码测试用例输入,源代码提交,评测结果反馈。业务逻辑层主要为代码编译,代码运行,代码结果与基线的比对评测。数据库层主要为源代码或题目的增,删,改,查。详情见图1。
图1 系统架构图
本系统主要在原在线判题系统的动态判题得分基础上[3],增加基于代码编程规范的静态判题得分,系统实施图如图2所示。
图2 系统实施图
目前国内各大软件企业使用比较多的代码规范有Google、华为、腾讯、阿里巴巴等公司制定的代码编程规范,其中使用最多的是Google 的开源代码编程规范。为了更好的对接企业人才需求,本系统的检测代码规范标准,主要参考Google 开源的CC++、Java、Python 语言代码规范,制定出适用于C、C++、Java、Python计算机语言类课程实验教学的七大类规范规则:
⑴ 布局类:缩进、空格、空行、大括号的位置的规范等。
●程序块使用缩进风格,缩进的空格数为4个。
●大扩号(‘{’和‘}’)与它们的语句左对齐,并各独占一行。
●函数、类独立的模块之间必须加空行。
●操作符前后加空格,进行对等操作时,若是关系密切的操作符(如.)后不加空格。
●每行语句的字符数不能超过80个。
●一行只写一条语句(包括赋值语句)。
●if、for、do、while、case、switch、default 等语句独占一行。
⑵命名类:类、对象、函数和变量的命名等。
●类、对象、接口名,使用首字母大写的大小写混合法。
●函数、变量名,使用首字母使用小写,剩余单词使用首字母大写的大小写混合法。
●常量、枚举名,使用全大写字母。
⑶ 注释类:注释位置、数量、哪些变量常量要注释等;
●注释要放在其代码上方相邻位置或右方。
●注释与所描述内容进行同样的缩进。
●源程序的注释量必须在占总代码10%以上。
⑷逻辑类:缺少分支语句、浮点数比较、运算错误(除0)、死循环等;
●在switch 中每个case 语句都应该包含break 或者return。
●不要对浮点数进行比较运算,尤其是不要进行==、!=运算,减少>、<运算。
●进行除法或取模运算,要对分母为零的情况进行特殊处理。
●在for循环中提供终止条件。
●不要在if语句中使用等号=进行赋值操作。
⑸冗余类:冗余变量、冗余参数、重复代码等;
●避免局部变量与全局变量同名。
●避免定义未使用到的变量及参数。
●一个源文件的代码重复度不超过10%。
⑹复杂类:过大函数、过大对象、过大类、函数复杂度等;
●一个函数的代码行不超过50行(非空,非注释)。
●一个函数的代码嵌套不超过4层。
●一个类的代码行不超过50行(非空,非注释)。
●一个函数使用的if、while、for、switch语句要在10个以内。
⑺内存类:数据越界、内存泄漏等。
●避免超过整数的最大值及最小值,导致上溢和下溢。
●写代码时new 与delete、malloc 与free 要成对出现,避免内存泄漏。
本系统主要在原系统使用动态分析技术评测程序功能准确性的基础上,融合编译原理中的静态分析技术进行代码规范评测。静态分析技术是一种程序分析技术,不需要实际执行程序,不受程序输入输出的影响,与运行环境无关[4],因而比动态程序分析技术的分析速度快。静态分析技术的主要流程为:通过词法分析、语法分析等流程,将源代码转换成抽象语法树,再进行缺陷检测、代码规范、系统检测等研究分析。通过静态分析技术中的控制流分析及语义分析,可以弥补动态分析代码规范判别方面的不足,对代码进行较全面的分析。本系统实现过程如图3所示。
图3 代码规范检测过程图
⑴词法分析:对输入的源代码逐行进行字符串扫描,利用正则表达式技术提取每行代码的有意义词法单元,包括关键字、标记符,再将词法单元成非语法节点(空格及注释)和语法节点(非空格及非注释字符串),存储在链表中,形成符号表[5]。
⑵语法分析:根据词法分析中形成的符号表,结合语法规则,组成函数声明、变量定义、循环语句、条件判断等语句,再生成抽象语法树[5]。
⑶语义分析:根据抽象语法树及源代码的语句结构,进行变量类型、数组大小、函数调用信息等的上下文关联,以识别出代码语句是否存在漏洞。
⑷控制流分析:根据抽象语法树识别函数内部的if、while、for 调用嵌套关系,形成函数调用流向图,以检测代码的逻辑关系,检查函数内部的嵌套是否会导致死循环,除此之外还可以通过流向图分析函数的复杂度。
⑸规则匹配:结合语义分析及控制流分析分析结果,匹配代码规范标准,挖掘不规范的代码语句及位置。
本次系统实验验证,仅针对本系统中的静态代码规范检测结果进行分析。实验的验证环境为本校当前在线评测系统环境,详情如表1。
表1 系统实验环境
为了验证系统检测代码规范的准确性,本次实验针对C/C++、Java、Python 分别构造了较为全面的测试用例,可以覆盖本系统检测标准中的七大类27 条规则,详情见表2。表中的总耗时为系统10 次随机实验的平均耗时,由表2 可知不同语言由于语法和关键词的差异,导致在代码检测实现过程的差异,造成了代码规范检测耗时的差异。其中C/C++语言比Java语言在单文件代码行数相当的情况下,要快一倍左右。四种语言的单文件耗时均在2s 以内,且代码规范检测准确率均达100%。
表2 不同语言代码规范检测测试结果
为了更好的验证本系统的实用性,本次实验还从本校的17次面向对象课程实验中,抽取了五次实验的一个行政班的结果,针对代码规范检测结果进行比对,测试结果详情见表3。该课程使用的语言为C++,学生每次提交的代码行数在30~90 行之间,由表3 可知,在这个代码行范围内,每个文件的耗时受代码行数影响不大,耗时在0.66s 左右,且比较稳定。每个行政班的人数在30~40 人之间,每次实验的题目数在4~7 道之间,且因为题目难度不同,存在一题多交的现象,由表3 可知,每个班单次实验提交到系统的文件数在250~430之间,总耗时在170~300s之间,由于每个行政班每次上机实验的时间为200min,因此该系统的代码规范检测速度较快。
表3 面向对象程序课程上机实验测试结果
此外,本次实验还对本校Python 语言程序设计、Java 程序设计课程的上机实验结果进行分析,结果与表3类似。
由上面的实验结果和分析可知,本系统中的代码规范检测功能,能有效、全面的检测出代码规范问题,并且检查速度较快,也比较稳定。
本系统采用静态分析技术,对原有的在线判题系统进行改造,在保证原有系统正确性功能评测的基础上,增加了代码规范检测评测功能。经系统实验验证,该系统能快速、稳定、全面有效的检测出代码中存在的代码规范问题,有助于学生养成遵循代码编程规范的习惯,提升代码质量。本系统还有很多需要完善之处,其中最需要完善的是,对代码的规范进行更精确的测评,同时又不损失太多效率。