c编译器自动测试工具的剖析与移植

编译器是使用频度非常高的系统软件,并且是其所编译的软件的质量的基础,如何提高编译器的质量一直是编译器研究的一个重要方面。目前,世界上对面向过程的编译器自动测试的研究已经比较成熟,并且已经开发出一些自动测试工具用于商业用途,但是我国在这方面还比较欠缺,仍没有成熟的此类测试软件产品问世。本课题研究的目的是通过详细地剖析S UN 公司开发的一个比较成熟的专用 C编译器自动测试工具—— Ctcgen的设计思想和算法技巧,掌握其关键技术,并对其进行移植、改进和扩展,进而应用到更广泛的领域中。
1编译器测试技术

编译器的测试目标定位在功能测试和性能测试上。在设计测试用例时,不必考虑编译器的内部实现,重点考虑编译器是否能正确处理源语言的语法、语义规则。在编译器测试中,测试程序可以无穷无尽,然而测试用例并不是越多越好,我们必须根据测试策略,系统、科学地设计测试用例,才能达到理想的测试效果。为了使用有限的测试用例,达到预定的测试效果,在编译器测试中,引入了两个重要的概念:宽度测试和深度测试。其中,宽度测试主要考虑测试用例应覆盖符合源语言标准的所有语法和语义点,其测试重点是对每一个语法语义点都无遗漏地进行测试。深度测试主要涉及测试用例中各语法、语义点间任意复杂的组合问题。

编译器或许可以正确地处理简单的语言要素和语法、语义点,但当这些语法点进行组合、嵌套时,很难保证编译器还能正确无误地处理。深度测试可以利用正交试验设计法与随机算法结合,取得比较理想的测试效果。

2 Ctcgen的关键设计思想

2.1对比验证测试模式

传统的编译器测试方法遵循的模式是:根据源语言的语法规则,按照某种算法,设计测试程序生成器,该测试程生成器能自动产生测试程序(  测试用例 )。然后用待测的编译器来编译这些测试用例。由于自动产生的测试用例中包含着期待的测试结果,因而,运行这些编译好的测试程序,将其运行结果与期待的结果进行比较就可得出测试结论。这种模式对于面向过程的语言的编译器来说是行之有效的,它在编译器的宽度测试方面表现良好,但不足的是在深度测试方面还有欠缺,而这种欠缺又使其虽能有效地测试出编译器前端的错误,但是很难发现编译器后端的错误,导致对编译器测试的不完全。

导致传统测试模式的不足的根本原因在于,测试用例中包含了预想的测试结果。如果在产生的测试用例中不加入预想测试结果,则上述不足可以消除。但由此带来的新问题是,无法进行测试结果的比较。若在测试过程中增加一个性能稳定的参考编译器,问题则可迎刃而解。C tcgen工具对传统的测试模式进行了改进。C tcgen工具在测试过程中引入了一个经过长期实践证明的性能稳定的参考编译器,并假设这个参考编译器是完全正确的,根据 C语言语法规则,采用某种随机算法设计测试程序生成器,随机生成测试用例集,然后用待测编译器和参考编译器同时编译该测试用例集,并在同一目标机上运行,分别得到各自运行结果集,比较这两个结果集,得出测试结论。C tcgen 的测试模式如图 1所示。这种测试模式只需考虑产生有效的测试用例,且测试用例中不包含预期的测试结果,因而可以降低测试用例生成器的设计难度,提高生成测试用例的随机性与灵活性。并且,这种测试模式既考虑了宽度测试又考虑了深度测试,使测试更加全面,而且容易实现测试过程自动化。

2.2随机的思想和算法

Ctcgen测试工具在自动生成测试用例的设计中引入随机的思想和算法,在自动生成测试用例的构成要素的各个环节中都利用随机的概念生成测试用例。采用“任何测试点都可

能测到”的思想代替“每个测试点都必须测到”的思想,从而在测试用例的数量达到一定规模时,在满足应用的条件下代替“穷举”方法解决证明正确性的问题。

概率算法是指算法中某些步骤或某些步骤中的某些动作是随机性 (某 些步可以随机选择下一步 )的算法。解决实际问题P  的概率算法A '定义如下:

设I  是 P 的一个实例,I 的 尺度 |I|=n, 在用 A'解  I的某些时刻,随机地选取一个数b (1 ≤b ≤ n ) ,b i表 示第 i次 选择 b ,r =(b1,b2,… , bm)表 示 m次 随机选取 b的 序列。由 bi决定算法的下一步选取,  除了选取b i的 动作外,  A'的其它动作是确定的。

概率算法适用于在大范围中查找某一特定对象的问题,解这类问题常用分治法,而“分”的这个步骤可以作为随机化的入口。自动生成测试用例的问题可以看作是从所有用例库中查找“适合测试”的用例,所以,概率算法适用于解决这一问题。概率算法的一般模式如下:

设集合S  有 n个 元素,要在由S 所 决定的某一结构 C(S)上查找某一对象x  ,一般有|  C(S)|>>|S|。解这个问题的分治方Υk法是选择S 的 一个分解 D ={B1,  B2, …, BK}, i =1C(Bi)? C(S)且  =S, 从而得到相应的 k 个结构 C(B1) ,…,C(Bk) ,分别在C (Bi)上 寻找x i(i =1,… , k), 然后在{x1,…,xk}上寻找 x', 最后论证x '即 为所要查找的 x 。在分解 D之下,一般 只 有Υki= 1? Υki =1C(Bi) C(S) ,而不一定有 C(Bi) ?C(S),这样会产生 x' ≠ x的 问题。如果对每个 I ∈ P, | I| = n ,A '产生不正确解( 具体到生成 C测 试用例问题来说,就是没有找到能检测到C编译器错误的测试用例) 的 概率小于ε (0<ε  <1) ,则称A '以大于1 - ε 的置信度解决问题P 。

针对C 编译器测试问题来说,ε 的值可以通过对多次实验数据的分析估算,根据经验,适当选择以上各种指标参数,会得到非常好的近似结果。

概率算法的关键是随机入口的设计,本程序随机入口设计的基本思想为:根据实践经验预先构造两个哈希表,分别将变量类型和出现概率、流程控制语句类型和出现概率对应起来,程序根据概率随机生成不同类型变量和引用不同流程控制语句,构造运算符数组,在生成表达式时从中随机选择运算符 ( 根据情况剔除不合法的引用) , 用参数给定 length和depth(见 前 )的最大值,在构造表达式、语句、函数时随机选择这两个最大值以内的一个整数作为上限。可以看出,C 语言的每种语言要素都做到“随机”,避免人为干预,当用例足够多时,所能涵盖的“任意复杂性”范围就会很广泛,这样生成的用例,能够满足“近似正确”的要求。

3 Ctcgen测试工具的移植与改造

3.1 Ctcgen测试工具移植的主要问题和难点

Perl是一种解释执行的智能化的高级语言,其最大的优点就是用很少的代码完成其他语言用大量代码完成的工作,使得用P erl语言编写的程序很难移植到其他程序设计语言环

境下。

(1)变 量说明和变量类型:在 Perl语言中,数据定义和引用具有“随意性”,既不要求提前声明,也不要求有确定的变量类型,它的变量可以是字符串 ( 含一个字符 )、数值或是布尔值,可以在上一句中给变量赋值一个字符串值,而在下一句中赋给它一个浮点数,或者在前一句中将一个变量作为字符串来用,而在下一句将同一变量直接当作整数来用。C++语言要求使用变量必须提前声明,并严格区分数字和字符串类型,两种类型的变量不能互相引用或赋值。

(2)数 据结构:P erl语言包括两种非常重要的基本数据结构,哈希表和动态数组。哈希表查找效率相当高。 Perl语言不但将哈希表作为一种基本的数据结构,而且提供了方便的哈希表操作功能,极大地扩充了哈希表的应用;动态数组,是可以动态增长和缩短的数组,无须提前规定数组的长度、元素的类型,可以随心所欲地使用。C tcgen程序中大量应用到这两种数据结构,充分发挥了这两种数据结构的优点,而使程序更加简练、紧凑和有效,而 C++语言没有哈希表类型,其数组也必须提前声明大小和元素类型。由于 Ctcgen程序自动生成测试用例的语言要素甚至整个用例的算法实现都以哈希表和动态数组为基本数据结构,因此,数据结构差异是将C tcgen 程序向 C++语言移植的比较大的困难。

(3)字 符串操作:P erl语言的最大亮点是其强大的字符串处理功能,尤其是其特有的模式匹配法则是C ++所没有的。由于模式匹配是 Ctcgen程序实现自动生成“程序”强有力的工具,而 C++语言在这方面几乎是空白,因此,实现模式匹配在C tcgen程序的作用是移植的又一大难点。

3.2移植过程中几个难点问题的解决方案

(1)变量说明和变量类型:本课题所做的移植工作不是简单地用 C++ 语言重写代码,而是借用 Ctcgen程序的思想来重新设计,从而使代码更适合于 C++语言的规范。为解决变

量说明和变量类型问题,具体实现时我们将所有全局变量和不能确定使用范围的数据的声明都放在一个头文件里,并且针对在P erl语言中不区分数值变量和字符串变量的问题,在移植过程中,建立了S tring 类,兼容 char*类型,并重载了逻辑操作符,使其应用于判断字符串是否相等或为空,重载了赋值操作符用于拷贝字符串,重载了“ +=”运算符使其可以将一个字符串追加到另一个字符串后面 ,也包含了需要的一些基本操作。

(2)哈 希结构和动态数组:C tcgen程序对哈希表和动态

数组的动态应用十分复杂,但是这些复杂的操作要实现的功能主要包括查找、读取、添加、插入、删除、追加字符串,是一些很基本的字符串操作,P erl语言将这些操作变得很简单,但就功能而言, C++完 全可以实现。移植时用 C++针对Ctcgen程序需要用到的功能写一个类,包括数据结构和操作,代替哈希表和动态数组 , 选择带有模板t emplate的单链表List 类来实现 Perl中 的动态数组。在 List类中,由于使用到了template ,可以根据L ist中 的d ata type来分配内存,以节省存储空间,对一些操作符进行重载,使对象的某些操作更接近于动态数组。为简化实现过程,放弃哈希表在查找上的优势,不再采用哈希结构,哈希表中使用的一些主要功能在逻辑上通过对 List对象的操作来实现。具体来说就是通过对List中数据的格式做一些规定来实现。同时,采用临时文件来代替C tcgen中的用于临时存储的哈希表,实现一些很长的字符串的临时存储功能。

(3)模 式匹配:P erl语言的最大亮点就是其强大的字符串处理功能,即模式匹配功能,短短的一二个语句完成的功能如果要用 C++来实现的话,可能需要很长的函数才能完成,而其搭配应用的灵活性远非C ++ 能及。但是具体到C tcgen程序来说,用到的模式匹配的类型很有限,再加上在移植时数据结构的改动,使得使用模式匹配功能的必要性大大降低。由于使用了临时文件,可以在生成函数体中每个语句的同时就将其按一定格式写入对应的临时文件,这样就可以避免使用模式匹配功能。类似这样,可以对在C tcgen程序中使用模

式匹配功能的地方的算法做一些改动,就可以避开这一难点,而不必机械地沿用C tcgen程序的具体算法。

4总结与展望

通过仔细剖析P erl语 言下 Ctcgen程序的思想、结构和算法,并在认真研究原程序算法的基础上,将适用范围很有限的P erl语 言程序移植到了 C++语言环境下,大大扩展了该自动测试程序的应用范围。程序移植过程成功地吸收了原程序概率算法的思想,却不拘泥于原程序的具体算法,而是根据 C++语言自身的语法特点,大胆地对原程序进行重新设计。该课题的实现为研究面向对象编译器的自动测试技术提供了一种思路, 并做好了基础储备。

参考文献

1 Boujarwah A S, Saleh K. Compiler Test Case Generation Methods: ASurvey and Assessment. Information and Software Technology,1997 ,( 39) :617-625

2 Appel A W, Ginsburg M. Modern Compiler Implementation in C.Cambridge: Cambridge University Press ,1998

3 Gan Qitao, Sun Tong. Compiler Evaluation Methodology and Engineering. Motorola Internal Papers,1999

4 Boujarwah A,Saleh K. Compiler Test Suite: Evaluation and Use in an Automated Test Environment. Information and Technology, 1994,36(10): 607-614

5 寇贝斯. 加 . 胡  敏译 .Perl高 级开发.  北京:机械工业出版社

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值