首页> 中国专利> 一种遗产代码向现代语言变换过程中的控制流变换方法

一种遗产代码向现代语言变换过程中的控制流变换方法

摘要

本发明涉及一种遗产代码向现代语言变换过程中的控制流变换方法。该方法包括以下步骤:将COBOL程序的一个“过程”转换成一个Java类;在上述Java类中设置一个“入口函数”;设置上述“入口函数”的内容;对COBOL程序的段名进行编号;对COBOL过程体结构进行处理:对PERFORM语句进行处理:对GOTO语句进行处理:对PERFORM语句进行处理:当遇到PERFORM语句时,将其翻译为:执行函数,包括其入口,出口对应的编号,参数列表;在每个段尾增加一条语句:if(出口点=本段编号)return。在遗产代码向现代语言变换过程中利用高级语言的switch和while语句来同时消除GOTO和PERFORM复合控制结构。该方法不改变程序的结构,保持了程序可读性,并较好地控制了代码膨胀。

著录项

  • 公开/公告号CN1680922A

    专利类型发明专利

  • 公开/公告日2005-10-12

    原文格式PDF

  • 申请/专利权人 中国科学院计算技术研究所;

    申请/专利号CN200410030988.2

  • 申请日2004-04-05

  • 分类号G06F9/45;

  • 代理机构11280 北京泛华伟业知识产权代理有限公司;

  • 代理人王凤华

  • 地址 100000 北京市海淀区中关村科学院南路6号

  • 入库时间 2023-12-17 16:38:09

法律信息

  • 法律状态公告日

    法律状态信息

    法律状态

  • 2007-09-12

    授权

    授权

  • 2005-12-07

    实质审查的生效

    实质审查的生效

  • 2005-10-12

    公开

    公开

说明书

技术领域

本发明涉及编译领域中的传统高级语言向现代高级语言的转换技术,尤其涉及用于实现两种语言(cobol和java)控制结构的不同之处的等价变换方法。

背景技术

传统语言(如COBOL、FORTRAN等)从诞生到现在已有近50年的历史。现存的大量商用与科学计算程序是采用这些传统语言编写的。目前在银行、证券和保险业中运行的程序,有许多诞生于那个时期。据不完全统计,大约1000亿行代码是用传统语言COBOL编写的。由于现代语言以其优越性替代了传统语言,很少有软件从业人员去学习和使用传统语言,因此用这些语言所编写的程序就成为了遗产代码。由此导致了一系列问题的出现,第一个问题是遗产代码的维护,目前仅有极少数了解传统语言的程序员去维护大量的遗产代码,无疑是一个巨大的负担,并且随着新语言的继续产生将有更多的编程语言被替代,由这些语言编写的程序也就转变成新的遗产代码。随着时间的推移,遗产代码的种类和数量会不断地增加,维护遗产代码的负担将会越来越大,最后导致无法承受。维护遗产代码的一个好的方法是将遗产代码翻译成现代语言。第二个问题,遗产代码的存在影响了软件的互操作性。采用现代语言编写的新软件和同一行业的旧软件由于采用不同的编程语言,再加上新软件的编程者大多对传统语言不熟悉,从而导致新旧软件之间的链接和交互成为一个新的技术屏障。第三个问题是不利于代码的跨平台迁移。计算机网络的出现使计算机不再是一台独立的机器,而是整个信息网络的组成部分。各种不同类型、不同平台的计算机组成了复杂的系统,如何使该系统充分发挥其作用,是目前的网格技术研究的一项课题。一套软件能否跨平台工作决定了其是否具有更强的生命力。为了使代码顺利迁移,于是产生了如Java、.Net这样的平台无关的程序设计语言。采用这类代码编写的程序,可以基本不受约束地在各个平台上迁移。因此,寻求一种将遗产代码转化成现代语言的技术,是实现代码迁移,使旧代码焕发新活力的一项很有意义的尝试。

目前,许多研究机构和公司都开展了这方面的研究,如圣彼得堡大学、SoftwareMining、Corporola、LegacyJ Corporation、Micro-Processor Service等等。由于COBOL语言诞生较早,其遗产代码的数量大,且与现代语言的语法语义差别较大,因此选择它作为一个典型的传统语言。而Java则是一种典型的现代语言,它除了具备其它现代语言的特点外,还对跨平台提供支持,并且摒弃了影响程序结构化的语句。与其他现代语言相比,Java与传统语言的差距最大。因此,代码转化多选择COBOL和Java作为典型的研究对象。

现代语言为追求程序结构化而不提倡使用GOTO语句,甚至一些新的语言(如Java)已不再提供该语句。但那些诞生于计算机发展早期的遗产代码中大量使用GOTO语句,甚至在COBOL语言的代码中,除GOTO语句外还大量使用了PERFORM语句。因此在将这些遗产代码翻译成现代语言时,必须将这些控制流语句通过等价变换进行消除。

目前的文献和一些研究机构推出的方法可以分为两类:

(1)通过对遗产代码的控制流进行分析,将GOTO转化成循环,再用现代语言的while语句来实现这些循环。该方法虽能实现有效地消除GOTO和PERFORM语句,但改变了程序的结构,变换后的代码可读性差。另外,为了从复杂的GOTO和PERFORM结构中转化出相应的循环,必要时需进行代码复制,从而引起了代码的膨胀,经测试该类方法引起的平均膨胀率为一至两个数量级。像Java这样的语言对一个函数内的代码总量存有限制,过于膨胀的代码可能会导致一个函数过大而无法执行。

(2)采用函数递归来模拟GOTO和PERFORM语句。该方法的一个明显特点是利用递归实现循环,而对于循环次数较多的结构,可能会导致过深的递归从而使堆栈无法承受造成溢出,引起程序的执行意外中止。另外,该类方法也破坏了程序的结构,变换后的程序可读性差。

由于GOTO语句影响了程序的结构化,多年来一直有人在研究如何消除GOTO语句,并提出了许多的方法,但这些方法并不太适合COBOL语言中PERFORM和GOTO语句形成的复合结构,变换后的程序可读性较差,代码的膨胀率高。

发明内容

本发明要解决的技术问题是提供一种遗产代码向现代语言变换过程中的控制流变换方法,消除传统语言中的“goto”和“perform”语句,在保证程序可读性的同时,较好地控制了代码的膨胀率。

为解决上述技术问题,本发明提供一种遗产代码向现代语言变换过程中的控制流变换方法,包括以下步骤:

a)将COBOL程序的一个过程转换成一个Java类;

b)在上述Java类中设置一个入口函数,该函数的参数列表对应于原COBOL过程的参数列表;

c)设置入口函数的内容,入口函数中包含一条复合语句,用于对另一个执行函数进行调用,并捕捉所述执行函数在运行结束时抛出的例外,所述执行函数用于实现COBOL过程的过程体;

d)对COBOL中的段名进行编号;

e)对过程体结构进行如下处理:将整个程序置于一个循环中,其中每条case语句依次对应于COBOL程序中的一个段标号,其后面的代码对应于一个段的内容;

f)对GOTO语句进行处理:遇到GOTO语句时,可以将其翻译为:{标号变量=跳转目标所对应的编号;continue end;};或{标号变量=跳转目标所对应的编号;break end;};

g)对PERFORM语句进行处理:当遇到PERFORM语句时,将其翻译为:执行函数(入口,出口对应的编号,参数列表);

h)在每个段尾增加一条语句:if(出口点==本段编号)return。

在上述方案中,用一个特定的入口函数来作为整个COBOL过程的入口,用现代语言中函数来模拟COBOL的过程,所述特定的入口函数包含三个参数,分别是入口点、出口点和原COBOL语言自身的参数,将整个过程翻译成一个由循环语句和switch语句组合一起的结构,每个COBOL段对应一个case语句,用条件判断来决定是否退出函数。

在上述方案中,用Java子函数自身的递归调用来实现PERFORM的语义,通过两个参数来表示PERFORM语句的范围。

在上述方案中,所述步骤c)中所述执行函数的参数列表中包含与入口函数具有同名的函数列表,还在前面增加了两个参数入口点和出口点。

在上述方案中,所述入口点参数作为PERFORM语句执行时的入口,所述出口点参数作为PERFORM语句执行对象的出口。

在上述方案中,步骤d)中,从COBOL程序的第一个段开始,依次从0向下进行编号直到最后一条语句,在程序结束前增加一个编号。

在上述方案中,用高级语言的switch和循环语句来同时消除GOTO和PERFORM复合控制结构。

由上可知,本发明提供的一种控制流变换方法,保持了程序可读性,并较好地控制了代码膨胀。

附图说明

图1是本发明现有技术中PERFORM语法结构图;

图2是本发明现有技术中由GOTO和PERFORM语句构成的控制流图;

图3是本发明具体实施例消除图2中所示的GOTO和PERFORM语句的Java程序图;

图4是本发明具体实施例中_entry函数的形式结构图;

图5是本发明具体实施例中Java语言中控制流结构的形式图。

图6是本发明控制流变换方法流程图。

具体实施方式

下面结合附图和以下实施例详细说明本发明的技术方案。

当需要将遗产代码(COBOL程序)翻译成现代语言Java时,需要将COBOL语言中存在而Java语言无法表示的PERFORM和GOTO语句消除,以便顺利地实现代码翻译。

本发明用Java中所存在的控制流语句Switch和while语句来仿真COBOL中的PERFORM和GOTO语句。

COBOL中GOTO语句的作用与C语言中的GOTO语句相同,就是将控制转入过程中的另一个位置。

PERFORM语句的是具有两种功能的语句,一方面它相当于一个循环语句,在某种循环条件下来执行循环对象。另一方面它具有调用功能,调用某个节或几个节执行,其基本语法结构如图1所示。分析这个貌似复杂的结构,我们不难发现,无论是PERFORM_until、PERFORM_varying还是PERFORM_times,其区别主要在于对循环条件的控制。这一点我们可以轻松地用Java语言中的while语句来实现。

PERFORM语句在向Java转换的时候,其最大的问题不是循环的转换,而是PERFORM对被执行对象的调用方式,以及该方式与GOTO语句结合起来所形成的复合控制结构。为了能够清晰地说明问题,我们抹去循环,单纯来分析其调用方式。

参见图2,段L1内有一条PERFORM语句,该语句带有一个Through子句,其语义是当条件condition-1成立时,从执行段L1到L3(包括L3所指示的段),执行到L4之前,返回该PERFORM语句。在段L2中有两条GOTO语句,分别跳转到段L0和段L1。第一个跳转语句是向前跳转,实际上构成了一个循环控制流。而第二个则是向后跳转,如果前面的PERFORM L1 thru L3语句在执行L2段时,条件condition-3满足,则控制转向L4。但如果控制不再转回的话,则顺序执行到exit-program程序结束,不再返回到前面的PERFORM语句。如果在L4到exit-program之间有跳转语句将控制返回到L3或L3之前,当程序执行到段L3的结尾时,控制还可以重新返回前面的PERFORM语句。

可以看出,PERFORM语句对每个段的执行很类似于现代语言中对函数的调用,但不同的是,段不像函数那样独立,而是一个松散的结构,它允许GOTO语句在段之间跳转,这样势必使段不具有其它语言中函数的封闭性。当GOTO语句跳出了PERFORM所执行的对象,控制流将继续向下进行,直到程序结束或满足PERFORM的返回条件。因此,并不能简单地将每个段构造成一个过程,通过函数调用来模拟COBOL中的PERFORM和GOTO语句。

上述例子比较简单,其实还可能出现更为复杂的情况。比如一个PERFORM语句所执行的若干个段中可能还包含其它的PERFORM语句,这些PERFORM语句理论上将是允许不受任何限制地执行其它任意范围的若干个段。从本质上来讲,上述问题的产生源自于COBOL语言中段的非结构化。

这一问题成为COBOL向Java程序变换过程中一个极为棘手的问题,控制结构变换是否合理决定了语言转换的成败。

本发明提供如下实施例:

参见图6,

步骤100,将COBOL程序的一个过程转换成一个同名的Java类。假设Cobol中的过程名为CobolProcedure,则新构造的Java类如下:

class CobolProcedure{

......

}

步骤110,在上述Java类中设置一个入口函数,该函数的参数列表对应于原COBOL过程的参数列表,即在上述Java类中设置一个入口函数(我们将它命名为_entry)。

步骤120,设置入口函数的内容,该函数中包含一条复合语句,用于对同一个类中另一个执行函数进行调用,并捕捉执行函数在运行结束时抛出的例外,执行函数用于实现COBOL过程的过程体;参见图4,该函数的参数列表中除了包含与_entry函数具有同名的函数列表外,还在前面增加了两个参数entrance(入口点)和exit(出口点)。entrance作为PERFORM语句执行时的入口。exit作为PERFORM语句执行对象的出口。我们可以认为,原来的整个程序相当于从第一个段进入,从最后一个段退出。因此,在_entry中,执行函数sub的实参为0和last+1)。

步骤130,对COBOL程序的段名进行编号,从COBOL程序的第一个段开始,依次从0向下进行编号直到最后一条语句。为了便于程序一致性的维护,要求在程序结束前增加一个编号。

步骤140,对COBOL过程体结构进行如下处理:将整个程序置于一个循环中,其中每条case语句依次对应于COBOL程序中的一个段标号,其后面的代码对应于一个段的内容;

在步骤140中,将整个程序置于一个循环中,其基本形式如图5所示。其中每条case语句依次对应于COBOL程序中的一个段标号,其后面的代码对应于一个段的内容。语句throw new Exception()对应于COBOL中的exit-program,用于结束一个过程。另外,为了程序的一致性,在结束语句前增加了一条Case语句,其序号为last+1。

步骤150,对GOTO语句进行处理。遇到GOTO语句时,可以将其翻译成如下形式:

{标号变量=跳转目标所对应的编号;continue结束点;};或{标号变量=跳转目标所对应的编号;break结束点;},即{label=dest;continue end;}或{label=dest;break end;}//这里dest是跳转目标所对应的编号。

步骤160,对PERFORM语句进行处理。当遇到PERFORM语句时,将其翻译成如下形式:执行函数(入口,出口对应的编号,参数列表),即sub(en,ex,paraList);//其中en为入口,ex为出口对应的段的编号。

步骤170,在每个段尾增加一条语句:if(出口点==本段编号)return。

在步骤170中,为了让sub执行完ex所对应的段后返回PERFORM语句,还需要在每个段尾增加一条语句:if(exit==segNumber)return;//其中segNumber是本段的编号。

此外,PERFORM语句还可能带有循环条件,循环条件的实现非常简单,只需要用while和for语句来完成即可。例如图二中标号为L4中的语句:perform L3 until var EQUAL 0和perform L1 thru L3 varying I from 1 by 2 until 10,我们将它们变为图三中对应的形式。

对于图2所示的例子,我们可以用图3所示的Java程序模拟。

本发明实现PERFORM语句转换实质上是通过递归调用来实现的。这样就会增加一次压栈操作,将sub的活动记录压入堆栈中。从空间开销上讲,每执行一次PERFORM需要压栈一次,实际上向栈中压入一个活动记录。为了减小活动记录,我们将除了entrance和exit以外的参数放置于一个Vector中,用指向该对象的指针作为参数,从而将sub的参数数量限制成三个。活动记录的大小则成为了一个较小的常数。

此外,COBOL程序执行PERFORM语句时,同样需要保留返回地址,进行压栈操作。因此,本发明中所述方法与COBOL的空间开销比实际上是一个较小常数。GOTO语句是通过switch语句实现的,因此没有增加空间开销。

众所周知,语言之间的转换势必会引起代码的膨胀,采用本方法实现GOTO和PERFORM的变换。其语句膨胀关系如下表所示:

语法现象 所需语句数量switch和while框架 3条/文件段结构 2条/段GOTO 2条/GOTOPERFORM 1条/PERFORM

         表1语句膨胀关系

本发明可以通过下述公式计算语句膨胀率:

3+(2count段+2countGOTO+countPERFORM)/(countGOTO+countPERFORM)。

通过对被测试文件分析发现,由于GOTO和PERFORM变换导致的语句膨胀率一般在2.5倍左右。

而本发明人所掌握的文献中,对于类似情况的处理,其膨胀率一般在20倍以上。

综上所述,本发明所述遗产代码向现代语言变换过程中的一种控制流变换方法,利用高级语言中的switch和while语句来同时消除GOTO和PERFORM复合控制结构。该方法不改变程序的结构,保持了程序可读性,并较好地控制了代码膨胀。目前该方法已经在我们正在开发的“C2J翻译系统”中进行应用,并通过了400万行实际应用程序的测试。

去获取专利,查看全文>

相似文献

  • 专利
  • 中文文献
  • 外文文献
获取专利

客服邮箱:kefu@zhangqiaokeyan.com

京公网安备:11010802029741号 ICP备案号:京ICP备15016152号-6 六维联合信息科技 (北京) 有限公司©版权所有
  • 客服微信

  • 服务号