程序框图到代码的自动转换研究.docx
《程序框图到代码的自动转换研究.docx》由会员分享,可在线阅读,更多相关《程序框图到代码的自动转换研究.docx(41页珍藏版)》请在冰豆网上搜索。
![程序框图到代码的自动转换研究.docx](https://file1.bdocx.com/fileroot1/2022-11/23/f82a3434-2e45-4cad-b838-51e4401f2218/f82a3434-2e45-4cad-b838-51e4401f22181.gif)
程序框图到代码的自动转换研究
摘要1
Abstract1
第1章引言2
第2章程序流程图自动转换为代码的基本思想4
2.1基本思想4
2.2实现自动转换的基本步骤4
第3章系统架构6
3.1硬件系统和开发平台6
3.2系统样式…………………………………………………………………………….…6
3.4 需求分析……………………………………………………………………………………….…..7
第4章系统实现8
4.1系统开发环境8
4.3.1识取预处理10
4.3.2图形的操作和存储10
4.4图形数据的解析与生成………………………………………………………………11
4.4.1数据与关系的定义11
4.4.2关系的解析15
4.4.3代码生成算法44
4.5.1代码的编绎48
4.5.2代码的运行48
5.1结果分析49
5.2程序的局限性51
第6章总结与启示52
致谢…………………………………………………………………………………………………………53
程序框图到代码的自动转换研究
摘要:
程序框图与源代码的自动转换是软件工程领域研究的一个重要课题,有诸多不同的技术和方法。
本文采用的方法是首先对程序框图之间的各种关系及其含义进行解析,将之分解为顺序执行关系、判断嵌套关系、循环嵌套关系和跳转嵌套关系,在此基础上生成一个自动转换系统。
该系统包括用户接口控制模块、图形符号解析模块、代码生成模块、编译执行模块等。
自动生成的仿C语言在本系统开发环境中能正确运行。
关键词:
程序框图;代码;自动转换
Theprocedureframediagramarrivesautomaticconversionresearchofthecode
Theautomaticconversionoftheprocedureframediagramandthesourcecodeisanimportanttopicofthesoftwareengineeringrealmresearch,alsohavingmanydifferenttechniquesandmethod.Themethodofthistextadoptioncarriesontheresolutiontovariousrelationanditsmeaningsbetweentheprocedureframediagramfirst,relatingtoitsdecompositionfortheinproperorderperformance,judgmentthesetrelation,circulationthesetrelationandjumptoturnarelation,bornonthisfoundationanimitatesthelanguagesystemofC.Thistextstillconstructedasimpleeditandtranslatethesystem,makeimitatebornlytherightmovementoftheClanguageability.
KeyWord:
ProcedureFrameDiagram;Code;AutomaticConversion;
第1章引言
软件自动化是提高软件质量与生产效率的根本途径。
而程序框图与源代码的自动转换则是软件开发过程中极富创造性的知识密集型活动,是软件自动化的难点和关键所在。
这里包括两个方面的问题:
一是程序框图转换为源代码的研究;另一个则是相反的方向,即源代码转换为程序框图的研究。
目前公开报道的文献基本上是针对源代码转换为程序框图的研究。
这是因为,在源代码级上分析程序是软件逆向工程的基本任务,其目的是从程序文本中了解程序的高层概念,它主要用于对软件维护的支持,软件可重用知识和部件的获取,以及探测已存在的软件产品等。
软件维护在软件生存周期中是最昂贵的阶段,习惯的软件维护活动占整个生存周期的50—90%。
软件是逻辑产品,维修人员理解软件,要占用47·60%的维护工作量。
没有自动支持,维护时间大部分被花在试图去理解被维护的对象上。
理解的工作极大地依赖于对程序源代码的理解,这不仅对文档很差的软件如此,对于文档较好的软件也是如此,这是因为正向工程产生的文档不足以支持软件的维护活动。
另一方面,软件重用受到越来越广泛的重视,甚至被看作软件工业发达程度的标志。
软件重用虽然在发达国家的很多公司中采用,但无论在理论上还是在技术上,都有许多难题需要研究解决,其中可重用知识相可重用部件的获取被认为是技术难点之一。
软件的最准确的文档就是源代码文本,它是提供可重用知识相部件的丰富资源。
对源程序的分析与理解能帮助人们从程序中获得一些可重用知识与部件。
因此,有的专家认为,下一代的软件工程环境应当是正反向都可用的。
本文研究的程序框图转换为源代码的课题即属于软件开发的正向工程。
它对于提高软件生产效率和软件开发过程的标准化、程序化有着十分重要的意义。
在软件详细设计中,人们常用的程序框图主要有程序流程图、盒图和问题分析图,而程序流程图是使用最为频繁的一种框图,其简便、直观的特点为人们所喜好,在软件设计中有着十分重要的作用。
本文具体讨论了程序流程图自动转换为一种仿C语言代码的处理方法及实现过程。
第2章程序流程图自动转换为代码的基本思想
2.1基本思想
实现程序流程图到源代码的自动转换,首先要解决的一个问题就是对程序流程图的理解,要理解它的逻辑结构,包括顺序、重复、分支及其控制结构。
其中程序控制结构又包括程序总体结构和程序的控制流程结构。
程序的总体结构描述了程序单位(过程、函数或子程序)之间的调用关系及联系信息,并以程序结构树的形式(即程序调用结构图或程序模块图)简明地刻划其慨貌,程序的控制流程结构描述的是程序单位中控制结构的传递和流向.而上述结构关系在流程图中基本上表现在框与框之间的连接。
系统对这些错综复杂的相互关系进行分类解析,从而把流程图蕴藏的程序结构和数据流向能以源代码的方式表现出来,就好像是一种类似编译器的“流程图编译器”。
通过隐藏中间过程,用户在本系统的作图环境中,画出流程图,就能通过“编译”命令来进行查错,如果无错后,能够通过“运行”命令执行,然后就能够生成源代码。
这就实现了本系统的研究目标。
2.2实现自动转换的基本步骤
1.对用户所画的程序流程图,进行存储。
用框结点链表将流程图中所有的框图存入,再用一个线链表将图中所有的线存入。
2.根据上述的框结点链表和线链表,初始化“嵌套表”,“同级表”和“关系再生表”(为实现自动转换而定义的三种数结构,定义情况参看第4章),用来存储解析过程中所进行操作的记录。
3.按“解析”算法,逐步修改“嵌套表”、“同级表”和“关系再生表”。
4.建立“代码生成”算法,把“嵌套表”和“同级表”中的结果,生成仿C语言代码。
5.创建与系统配套的编译模块,对仿C语言代码进行编译,确保代码的正确运行。
第3章系统的总体结构
3.1系统结构
自动转换系统由这样几个功能模块组成:
用户接口控制模块;图形符号解析模块;代码生成模块;编译执行模块。
其结构如图3-1所示。
3.2模块功能简析
1.用户接口控制模块
主要功能:
提供操作界面;提供画程序流程图的环境。
2.图形符号解析模块
主要功能:
根据前一个模块提供的图形对框图数据进行关系解析,生成关系数据。
3.代码生成模块
主要功能:
根据图形符号解析模块提供的关系数据,生成源代码。
4.编译执行模块
主要功能:
对代码生成模块产生的源代码进行编译,执行代码程序,生成并显示结果数据。
3.3系统的数据流图分析
按照软件工程学的思想,可以在任何抽象层次上使用数据流图表示系统或软件。
事实上,可以分层次分模块画出本系统的数据流图,由于受篇幅限制,本文仅简要地画出系统的0层数据流图,如图3-2所示。
通过该图,读者并不难理解系统内部的数据流动状况。
第4章自动转换系统的实现
4.1系统开发和运行环境
系统在运行的过程当中,主要进行的是图像处理,同时也要进行大量的数据处理,所以系统对处理器的要求比较的高。
要求CPU的主频大于400Hz,内存大于等于128MB。
系统的开发环境为WindowsXP+VC6.0。
4.2系统样式
本系统采用VC6.0开发,采用单文档三视图结构,具体为:
用CmyDoument做为文档专门用于数据的管理,分别用CmyView做为流程图画图视图,专门用于,流程图的做图,修改,和保存的功能显示于用户面前,用CcodeView做为代码视图,专门用于,流程图生成的代码的生成,编辑,保存的功能的显示,用CrunView做为代码的运行视图,专门用于,代码运行后的结果显示于用户。
4.3程序流程图的识取
4.3.1识取预处理
(1)流程图的图元的的定义
首先为本系统定义了一个Graphics(图像)类,它是本系统给于用户所画流程图的最基本图像定义,它包含以下属性:
属性类型作用
Ltx…………….int(整型)…………….本图元最左上点的x坐标值。
Lty……………int(整型)…………….本图元最左上点的y坐标值。
Rbx…………..int(整型)……………..本图元最右下点的x坐标值。
Rby…………..int(整型)……………..本图元最右下点的y坐标值。
Text………….char*(字符串型)……..本图元所要显示的类容。
State…………int(整型)……………..本图元当前状态。
State为0时,表示此图元处于’一般’情况下;
State为1时,表示此图元处于’用户选择’情况下;
State为2时,表示此图元处于’用户剪切’情况下.
State为3时,表示此图元处于’用户复制’情况下.
State为4时,表示此图元处于’用户粘贴’情况下
Id..int(整型)…本图元唯一标志号。
用于区别其它图元。
另外还定义了一些专门为这些属性服务的get和set方法,因此,Graphics的C++的定义如参看源程序中的Graphics.h文件。
然后,本系统为用户提供的框图定义了Frame(框)类如下,它是继承于上面的Graphics类的,它具有以下的新增属性:
属性类型作用
Depth…int(整型)……图元的深度值。
就是离开始框的最近距离值。
Type…int(整型)……框图的类型。
当Type为1时,表示此框为begin(开始)框。
当Type为2时,表示此框为end(结束)框。
当Type为3时,表示此框为一般框。
当Type为4时,表示此框为子函数框。
当Type为5时,表示此框为判断框。
SubText…char*(字符串型)……当Type为4时的子函数类容。
Next……Frame*(框型指针)….下个框对象的地址,由此构成框链表。
再加上一些对上述属性的get和set方法,Frame类的C++定义参看源程序中的Frame.h文件。
最后,本系统为用户提供的线图定义了Line(线)类如下,它是继承于上面的Graphics类的,它具有以下的新增属性:
属性类型作用
pTo………..int(整型)……………..此线指向某框的ID号。
pFrom…….int(整型)……………..此线从某框引出的ID号。
Type……int(整型)……………..此线的类型:
当Type为1时,此线为’一般型’直线。
当Type为2时,此线为’判断为真’的直线
当Type为3时,此线为’判断为否’的直线
xs…..int*(整型指针)…此线除起点和终结点外的中间转向点x坐标值的集
ys….int*(整型指针)….此线除起点和终结点外的中间转向点y坐标值的集
Middle…int(整型)……此线除起点和终结点外的中间转向点集的个数
next…Line*(线型指针)…下个线对象的地址,由此构成线链表
再加上对上述属性的一些set和get方法,其C++定义参看原程序中的Line.h文件。
以上就是用户流程图的C++定义。
4.3.2图形的操作和存储
用户在CmyView视图中,可以对用户所画的图进行相应的’编辑’,’修改’,’删除’,由CmyDocumet文档进行存储,另外在此视图中,还通过Graphics类的属性State进行‘剪切’,’复制’,’粘贴’等等的操作。
专门为Frame类和Line类的各个属性设计了一个以字符串格式的存储函数。
相应了也根据此格式编写了相应的打开函数。
存储格式如下:
.->[分隔符](ltx)[分隔符](lty)[分隔符](rbx)[分隔符](rby)[分隔符]+(Depth)[分隔符](Id)[分隔符](State)[分隔符](Text字符串长度)+[分隔符](Text)[分隔符](Type)[分隔符](subText字符串长度)+[分隔符](subText)[分隔符]
类型为0表示为Frame.(字符串长度)[开始符](存储类型).
类型为1表示为Line.->[分隔符](ltx)[分隔符](lty)[分隔符](rbx)[分隔符](rby)[分隔符]+(Id)[分隔符](State)[分隔符](Text字符串长度)[分隔符](Text)+(Type)[分隔符](nTo)[分隔符](nFrom)[分隔符](Middle)[分隔符]+(xs)[分隔符](ys)[分隔符]
存储格式如上所述,在CmyDocument文档类中,分别由fHead(Frame*类型)和lHead(Line*类型)构成框链表和线链表来记录用所画的所有框和所有线,且由fHead和lHead作为接口数据传给下一模块(流程图生成代码模块)。
4.4图形数据解析生成代码
4.4.1数据与关系的定义
对于任一程序流程图,都可以进行如下转换,如下:
图4-1中除了beign和end外,其余的都通过其ID转换成图4-2。
(注:
ID为Frame对象中的ID属性)
而’关系’,则是各个框与框之间的连系,它是用两个整型数组记录的:
intpFrom[nLineNumbers];…………………..线的指出集合
intpTo[nLineNumbers];…………………..线的指进集合
这两个数组初始化,全用–1表示。
即:
pFrom[nLineNumbers]={-1};pTo[nLineNumbers]={-1};
其中,nLineNumbers为int(整型),它是由上个模块提供的,用户所画流程图中框图的总个数。
上述的pFrom和pTo数组构成了“解析记录表”。
其数据结构的特征为:
在pFrom中的位置I的值x和pTo数组中位置I的值y共同表示了用户所画的程序流程图中一条线,它以一个框ID为x为起点,以另一个框ID为y为终点的直线,用xy表示。
如上图中,nLineNumbers=3;对于任一流程图都要求用户必有一个为begin(开始)框做为开始,必有一个end(结束)框做为结尾,对于begin框,将其ID总用‘55555’表示end框,将其ID总用99999表示。
因此,图4-2的关系数据为:
pFrom的内容为:
{55555,1,2}。
pTo的内谷为:
{1,2,99999}。
这是一个求10以内素数的算法的流程图,图4-4是图4-3转换后相应的图。
pFrom={55555,1,2,3,4,4,5,6,7,7,8,8,9,10,11,11,12,13}
pTo={1,2,3,4,5,99999,6,7,8,11,9,11,10,7,12,13,13,4}
在图4-3中,有四个判断框,它们的ID分别为4,7,8,11,也就是对应在图4-4中的:
4,7,8,11的椭圆。
同时这些”判断点”的主要特点是,它们都有两条线从其指出。
在关系数组中,它们的体现就是:
在pFrom中,它们都会出现2次。
这些点是“判断点”。
同时,在图4-3中,也有四个多于一条线指进的框,它们的ID分别为4,7,11,13,也就是对应在图4-4中的4,7,8,11的椭圆,这些点的主要特点是,它们都有多于一条线指向它们。
在关系数组中,它们的体现就是:
在pTo中,它们的出现次数会多于1次。
这些点是“会合点”。
在图4-3和图4-4的例子中,所有“判断点”和所有“会合点”的交集是:
{4,7,11},其中,4和7分别引领了一个循环,因此,我们称4和7是“循环点”。
这种“循环点”一定是“会合点”和“判断点”的交集,但是,“会合点”与“判断点”的交集并不一定就是“循环点”。
另外,在图4-3和图4-4例子中,({pFrom}-{所有“判断点”})∩{所有“会合点”}={11,13},这些点的最大特点是,在pFrom中只出现1次,但是在pTo中出现的次数大于1次。
这些点是“会合点”。
除了“判断点”,“会合点”外,那些单进且单出的点都是“普通点”。
为了对关系解析的过程进行记录,引入了以下几个数组:
intjudgeTable[nJudgeNumbers][nFrameNumbers*2];其中,judgeTable专门用来存储“判断点”的二维数组,nJudgeNumbers为用户所画框图中“判断框”的个数,nFrameNumbers为用户所画框图的总个数。
judgeTable的初始值全为–1。
这里的judgeTable构成在“解析算法”中用到的“嵌套表”。
intsameLeverTable[nFrameNumbers*2];它是用来存储相同级的点的数组,这一级与另一级别间用0做为间隔。
如在图4-3与图4-4的例子中,b,1,2,3,4是同一级别,11,13是同一级别,因此,在sameLeverTable中就可以如下表示:
sameLeverTable={55555,1,2,3,4,0,11,13,-1,-1,-1,-1,-1,-1,-1,…};其中的0,是b,1,2,3,4与11,13这间的间隔。
而-1则是初始值,也就是暂时还没有用到的。
它也构成在“解析算法”中用到的“同级表”。
intgotoTable[nFrameNumbers*2];这是一个用来记录某些“判断点”后用了goto语句的数组。
它也是用0来作分隔的。
intallTable[nFrameNumbers*2];这是一个为“合点”和“循点”进行关系解析时,各框之间关系发生改变时,记录改变,构成了“解析算法”中的“关系再生表”。
intFrom[nLineNumbers];………………..线的指出集合
intTo[nLineNumbers];…………………..线的指进集合
这两个用来存储最先的框与框之间的直达关系。
它们的值也就是最初的pFrom和pTo数组的值。
所谓的“直达关系”,如图4-3和图4-4中,b与1,2与3,3与e之间就是直达关系。
intnFlag_A………………………有无“化简”操作的标志。
intnFlag_I……………………….有无“添加”操作的标志。
这两个整型变量,初始值都为0,一旦分别进行了“化简”和添加操作后,则分别置其值为1和1,以方便后面的检测,详细用法在下面详释。
4.4.2关系的解析
解析的目标:
对应于pFrom和pTo数组中的内容为:
pFrom:
{55555,x,………y}解析{55555,……..}
pTo:
{x,,a……99999}---------------------{99999,……..}
当pFrom中位值为55555的位置I,如果pTo中位置I的值为99999时,就表示解析成功了。
以下为了方便,均用“b”代替pFrom中的55555,用“e”代替pTo中的99999,但是实际在存储中还是用55555表示begin,99999表示end,特此说明。
下面描述解析算法:
第一,进行一些解析前的预处理,步骤如下:
①根据lHead(线链表),给pFrom和pTo赋初值。
②将pFrom的值赋给From数组中去,将pTo的值赋给To数组中去,至此,From和To这两数组中记录了最初的框与框之间彼此间直接的关系。
③将所有的“判断点”的ID存入judgeTable中,具体做法是:
for(intI=0;I<(“判断点”的总数);I++)
{
judgeTable[I][0]=(“判断点”的ID);
}
④分别置nFlag_A和nFlag_I都为0。
即:
nFlag_A=0;nFlag_I=0;
第二,进行解析处理。
其步骤如下:
1.覆盖。
(对应于程序中的voidC();)这是第一个关系化简操作,它是一个级别分层的操作。
“分层”,也就是“嵌套”与不存在“嵌套”的化分,如在if(bool){//do;}和while(bool){//do;}中就存在嵌套关系。
覆盖操作的目标是将所有的“普通点”用层的关系进行解析,具体的含义就是:
如图4-5和图4-6所示。
pFrom:
{55555,1,2}
pTo:
{1,2,99999}
b覆盖1后结果如下:
{55555,2,-1}
{2,99999,-1}
同时,sameLeverTable应进行记录,其值修改为:
{55555,1,-1,-1,…},
pFrom:
{55555,2,-1}
pTo:
{2,99999,-1}
b覆盖2后的结果如下:
{55555,-1,-1}
{99999,-1,-1}
同时,sameLeverTable应进行相修改,其值为:
{55555,1,2,-1}。
那么,覆盖的详细算法如下:
[1]找到一个“普通点”,此点的ID为x(如在图3)和图4)中的ID为1的点),找出其在pTo中的位置i,在C++中,必有*(pTo+i)==x的条件式为“真”。
由此得到*(pFrom+i),设其值为y。
①如果y等于55555,即为Begin框,在sameLeverTable中进行相应的修改,如果sameLeverTable[0]等于-1,则sameLeverTable[0]=55555,sameLeverTable[1]赋值为x,sameLeverTable[2]=0。
否则,在sameLeverTable中,找一位置k,使sameLeverTable[k]==55555为“真”,然后在位置k后,找到第1次出现sameLeverTable中出现值为0的位置,然后,在此位置“插入”x。
②如果ID为y点是个“合点”,找一位置j,使*(pFrom+j)==y的条件式为“真”,将pTo表中位置为i的值设为pForm中位置为j的值,即*(pFrom+i)=